A document-buffered pull XML parser for MoonBit
Dependencies
// From string
let xml = "<root><item id=\"1\">Hello</item></root>"
let reader = @xml.Reader::from_string(xml)
// From file
let reader = @xml.Reader::from_file("document.xml")
while true {
let event = reader.read_event()
match event.kind {
Start(elem) => println("Start: \{elem.name}")
End(name) => println("End: \{name}")
Text(content) => println("Text: \{content}")
Eof => break
_ => continue
}
}let reader = @xml.NamespaceReader::from_string(
"<p:root xmlns:p=\"urn:example\" p:id=\"1\"/>",
)
match reader.read_event().kind {
Empty(element) => {
println(element.name.local_name) // root
println(element.name.namespace_uri) // Some("urn:example")
}
_ => ()
}let input = "<root id='a&b'/>"
let reader = @xml.Reader::from_string(input)
let parsed = reader.read_event()
let authored = input[parsed.span.start.offset:parsed.span.end.offset]
assert_eq(authored, input)
guard parsed.kind is Empty(element) else { abort("expected empty element") }
assert_eq(element.attributes[0].value, "a&b")| Event | Description |
|---|---|
| Start(XmlElement) | Opening tag <name> |
| End(String) | Closing tag </name> |
| Empty(XmlElement) | Self-closing tag <name/> |
| Text(String) | Text content (entities decoded) |
| CData(String) | CDATA section <![CDATA[...]]> |
| Comment(String) | Comment <!-- ... --> |
| PI(target, data) | Processing instruction <?target data?> |
| Decl(version, encoding, standalone) | XML declaration |
| DocType(String) | DOCTYPE declaration |
| Eof | End of document |
| Category | Tests | Description |
|---|---|---|
| Valid (with events) | 448 | Parser produces correct event sequence |
| Valid (error-only) | 6 | Parser does not error on valid XML |
| Not-well-formed | 281 | Parser correctly rejects malformed XML |
| Unit tests | 82 | Reader, writer, escape, namespace, source spans, conformance tests |
# Download the W3C test suite
curl -L -o xmlts.tar.gz "https://www.w3.org/XML/Test/xmlts20130923.tar.gz"
tar -xzf xmlts.tar.gz && mv xmlconf . && rm xmlts.tar.gz
# Run tests
moon test# Requires: libxml2 (xmllint), lxml (pip install lxml)
python3 scripts/generate_conformance_tests.pypub(all) enum EventKind {
Start(XmlElement)
End(String)
Empty(XmlElement)
Text(String)
CData(String)
Comment(String)
PI(target~ : String, data~ : String)
Decl(version~ : String, encoding~ : String?, standalone~ : String?)
DocType(String)
Eof
} derive(Eq, Debug)pub struct NamespaceAttribute {
name : XmlName
value : String
span : SourceSpan
name_span : SourceSpan
value_span : SourceSpan
} derive(Eq, Debug)pub struct NamespaceDeclaration {
prefix : String?
namespace_uri : String
span : SourceSpan
name_span : SourceSpan
value_span : SourceSpan
} derive(Eq, Debug)pub struct NamespaceElement {
name : XmlName
attributes : Array[NamespaceAttribute]
namespace_declarations : Array[NamespaceDeclaration]
} derive(Eq, Debug)pub(all) enum NamespaceEventKind {
Start(NamespaceElement)
End(XmlName)
Empty(NamespaceElement)
Text(String)
CData(String)
Comment(String)
PI(target~ : String, data~ : String)
Decl(version~ : String, encoding~ : String?, standalone~ : String?)
DocType(String)
Eof
} derive(Eq, Debug)fn NamespaceReader::read_events_until_eof(self : NamespaceReader) -> Array[NamespaceEvent] raise XmlErrorpub struct Reader {
input : Array[Char]
pos : Int
offset : Int
line : Int
column : Int
entities : Map[String, String]
entity_expansion_remaining : Int
attr_types : Map[String, String]
tag_stack : Array[(String, SourceSpan)]
seen_root : Bool
root_closed : Bool
seen_content : Bool
just_saw_decl : Bool
pending_events : Array[Event]
internal_subset_events : Array[Event]
just_saw_doctype : Bool
had_bom : Bool
}pub struct Writer {
buffer : StringBuilder
element_stack : Array[String]
seen_root : Bool
wrote_anything : Bool
doctype_root : String?
}fn Writer::empty_element(self : Writer, name : String, attributes : Array[(String, String)]) -> Unit raise WriterErrorfn Writer::start_element(self : Writer, name : String, attributes : Array[(String, String)]) -> Unit raise WriterErrorpub struct XmlAttribute {
name : String
value : String
span : SourceSpan
name_span : SourceSpan
value_span : SourceSpan
} derive(Eq, Debug)impl Show for XmlElementimpl Debug for XmlElementInstall
Download zipA document-buffered pull XML parser for MoonBit
Dependencies