// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
/// An XML element with tag name and attributes
pub struct XmlElement {
name : String
attributes : Array[XmlAttribute]
} derive(Eq)
///|
priv struct DebugXmlElement {
name : String
attributes : Array[(String, String)]
} derive(Debug)
///|
/// Get an attribute value by name
pub fn XmlElement::get(self : XmlElement, attr_name : String) -> String? {
for pair in self.attributes {
if pair.name == attr_name {
return Some(pair.value)
}
}
None
}
///|
/// An XML event returned by the parser
pub(all) enum EventKind {
/// Start of an XML element:
Start(XmlElement)
/// End of an XML element:
End(String)
/// Self-closing element:
Empty(XmlElement)
/// Text content between elements
Text(String)
/// CDATA section:
CData(String)
/// XML comment:
Comment(String)
/// Processing instruction:
PI(target~ : String, data~ : String)
/// XML declaration:
Decl(version~ : String, encoding~ : String?, standalone~ : String?)
/// DOCTYPE declaration
DocType(String)
/// End of file
Eof
} derive(Debug, Eq)
///|
/// XML parsing error
pub(all) suberror XmlErrorKind {
UnexpectedEof
InvalidSyntax(String)
UnmatchedTag(expected~ : String, found~ : String)
InvalidAttribute(String)
InvalidEntity(String)
} derive(Debug, Eq)
///|
pub impl Show for XmlElement with fn output(self, logger) {
logger.write_string("{name: ")
logger.write_object(self.name)
logger.write_string(", attributes: ")
logger.write_object(
Repr(
self.attributes.map(fn(attribute) { (attribute.name, attribute.value) }),
),
)
logger.write_string("}")
}
///|
pub impl Debug for XmlElement with fn to_repr(self) {
let debug : DebugXmlElement = {
name: self.name,
attributes: self.attributes.map(fn(attribute) {
(attribute.name, attribute.value)
}),
}
Repr(debug)
}
///|
pub impl Debug for Event with fn to_repr(self) {
Repr(self.kind)
}
///|
pub impl Show for Event with fn output(self, logger) {
logger.write_object(self.kind)
}
///|
pub impl Show for EventKind with fn output(self, logger) {
match self {
Start(elem) => {
logger.write_string("Start(")
logger.write_object(elem)
logger.write_string(")")
}
End(name) => {
logger.write_string("End(")
logger.write_object(name)
logger.write_string(")")
}
Empty(elem) => {
logger.write_string("Empty(")
logger.write_object(elem)
logger.write_string(")")
}
Text(content) => {
logger.write_string("Text(")
logger.write_object(content)
logger.write_string(")")
}
CData(content) => {
logger.write_string("CData(")
logger.write_object(content)
logger.write_string(")")
}
Comment(content) => {
logger.write_string("Comment(")
logger.write_object(content)
logger.write_string(")")
}
PI(target~, data~) => {
logger.write_string("PI(target=")
logger.write_object(target)
logger.write_string(", data=")
logger.write_object(data)
logger.write_string(")")
}
Decl(version~, encoding~, standalone~) => {
logger.write_string("Decl(version=")
logger.write_object(version)
logger.write_string(", encoding=")
logger.write_object(Repr(encoding))
logger.write_string(", standalone=")
logger.write_object(Repr(standalone))
logger.write_string(")")
}
DocType(name) => {
logger.write_string("DocType(")
logger.write_object(name)
logger.write_string(")")
}
Eof => logger.write_string("Eof")
}
}
///|
pub impl Show for XmlErrorKind with fn output(self, logger) {
match self {
UnexpectedEof => logger.write_string("UnexpectedEof")
InvalidSyntax(message) => {
logger.write_string("InvalidSyntax(")
logger.write_object(message)
logger.write_string(")")
}
UnmatchedTag(expected~, found~) => {
logger.write_string("UnmatchedTag(expected=")
logger.write_object(expected)
logger.write_string(", found=")
logger.write_object(found)
logger.write_string(")")
}
InvalidAttribute(message) => {
logger.write_string("InvalidAttribute(")
logger.write_object(message)
logger.write_string(")")
}
InvalidEntity(message) => {
logger.write_string("InvalidEntity(")
logger.write_object(message)
logger.write_string(")")
}
}
}
///|
pub impl Show for XmlError with fn output(self, logger) {
match self {
At(error~, span~) => {
logger.write_object(error)
logger.write_string(" at ")
logger.write_object(span.start.line)
logger.write_string(":")
logger.write_object(span.start.column)
logger.write_string("-")
logger.write_object(span.end.line)
logger.write_string(":")
logger.write_object(span.end.column)
}
}
}
///|
pub extend Event with Debug::{to_repr}
///|
pub extend Event with Show::{to_string, output}
///|
pub extend EventKind with Debug::{to_repr}
///|
pub extend EventKind with Eq::{not_equal, equal}
///|
pub extend EventKind with Show::{to_string, output}
///|
pub extend XmlElement with Debug::{to_repr}
///|
pub extend XmlElement with Eq::{not_equal, equal}
///|
pub extend XmlElement with Show::{to_string, output}
///|
pub extend XmlError with Show::{to_string, output}
///|
pub extend XmlErrorKind with Debug::{to_repr}
///|
pub extend XmlErrorKind with Eq::{not_equal, equal}
///|
pub extend XmlErrorKind with Show::{to_string, output}