Sign in

    xml

    Minimal streaming XML pull-parser and writer

    Download zip
    Version
    0.2.2
    License
    Apache-2.0
    Last updated
    3 hours ago
    Downloads
    27

    #marianoguerra/xml

    A minimal, dependency-free streaming XML pull-parser and writer for MoonBit, in the spirit of Rust's quick-xml.

    • Reader: Event stream (Start, Empty, End, Text, CData, Comment, Eof) with predefined + numeric entity decoding. Malformed markup raises XmlError::Syntax with a code-unit offset.
    • Writer: escaping helpers (escape_text, escape_attr), CDATA section splitting, namespace-free element emission.

    ///|
    test {
    let r = @xml.Reader::new("<a k=\"v &amp; co\">text</a>")
    let ev1 = try! r.next()
    let ev2 = try! r.next()
    assert_true(ev1 is Start(name="a", attrs=[{ key: "k", value: "v & co", }]))
    assert_true(ev2 is Text("text"))
    }

    The parser intentionally does not validate DTDs or resolve external entities. Processing instructions and DOCTYPE declarations are skipped.

    XmlError

    pub(all) suberror XmlError {
    Syntax(pos~ : Int, msg~ : String)
    } derive(Eq,
    Debug
    )

    Errors raised while scanning malformed XML.

    Attribute

    pub(all) struct Attribute {
    key : String
    value : String
    } derive(Eq,
    Debug
    )

    A single attribute of an XML start tag.

    Document

    pub struct Document {
    root : Element
    } derive(Eq,
    Debug
    )

    A parsed XML document: its single root element.

    The declaration, processing instructions, DOCTYPE and comments are not represented because the underlying reader skips them.

    Document::read_from

    fn Document::read_from(input : String) -> Document raise XmlError

    Parse a complete XML document into a [Document] tree.

    The input must contain exactly one root element; character data is only allowed inside it (top-level whitespace is ignored). A mismatched or unexpected tag raises [XmlError::Syntax].

    Example

    test {
    let doc = @xml.Document::read_from("<a x=\"1\">hi</a>")
    inspect(doc.root.name, content="a")
    }

    Document::to_xml

    fn Document::to_xml(self : Document) -> String

    Serialize the document with an XML declaration.

    Element

    pub(all) struct Element {
    name : String
    attrs : Array[Attribute]
    children : Array[Node]
    } derive(Eq,
    Debug
    )

    An element node: a qualified tag name, its attributes and its children in document order.

    Element::attr

    fn Element::attr(self : Element, key : String) -> String?

    The value of the attribute named key, or None when absent.

    Element::element

    fn Element::element(self : Element, name : String) -> Element?

    The first direct child element whose raw tag name equals name, or None when absent. Use [Element::elements] and [Element::local_name] for prefix-insensitive lookups.

    Element::elements

    fn Element::elements(self : Element) -> Array[Element]

    The direct child elements, in document order.

    Element::local_name

    fn Element::local_name(self : Element) -> String

    The local part of the qualified tag name: "itunes:author" → "author".

    Element::new

    fn Element::new(name~ : String, attrs? : Array[Attribute], children? : Array[Node]) -> Element

    Create an element.

    Element::text_content

    fn Element::text_content(self : Element) -> String

    The concatenated character data of all descendant Text and CData nodes, like DOM's textContent.

    Element::to_xml

    fn Element::to_xml(self : Element) -> String

    Serialize just this element (no XML declaration).

    Event

    pub(all) enum Event {
    Start(name~ : String, attrs~ : Array[Attribute])
    Empty(name~ : String, attrs~ : Array[Attribute])
    End(String)
    Text(String)
    CData(String)
    Comment(String)
    Eof
    } derive(Eq,
    Debug
    )

    A streaming XML event.

    Node

    pub(all) enum Node {
    Text(String)
    CData(String)
    Element(Element)
    } derive(Eq,
    Debug
    )

    A child node of an element.

    Reader

    pub struct Reader {
    // private fields
    } derive(
    Debug
    )

    A pull-parser over an in-memory XML document.

    The parser is lenient about constructs that do not affect RSS/Atom interpretation (processing instructions and DOCTYPE declarations are skipped) but strict about malformed tags, attributes and CDATA sections.

    Reader::new

    fn Reader::new(input : String) -> Reader

    Create a reader over input. A leading BOM is skipped.

    Reader::next

    fn Reader::next(self : Reader) -> Event raise XmlError

    Scan and return the next event.

    Reader::position

    fn Reader::position(self : Reader) -> Int

    Current code-unit offset of the scanner (for diagnostics).

    Writer

    pub struct Writer {
    // private fields
    } derive(
    Debug
    )

    A minimal streaming XML writer.

    Writer::cdata

    fn Writer::cdata(self : Writer, content : String) -> Unit

    Write a CDATA section, splitting any ]]> occurrences so the section stays well-formed.

    Writer::close

    fn Writer::close(self : Writer, name : String) -> Unit

    Write a closing tag </name>.

    Writer::empty

    fn Writer::empty(self : Writer, name : String, attrs? : Array[(String, String)]) -> Unit

    Write a self-closing tag; attributes are escaped.

    Writer::new

    fn Writer::new() -> Writer

    Writer::open

    fn Writer::open(self : Writer, name : String) -> Unit

    Write an opening tag <name>.

    Writer::open_with

    fn Writer::open_with(self : Writer, name : String, attrs~ : Array[(String, String)]) -> Unit

    Write an opening tag with attributes, <name k="v" ...>. Attribute values are escaped.

    Writer::raw

    fn Writer::raw(self : Writer, content : String) -> Unit

    Write pre-escaped / raw markup. The caller guarantees well-formedness.

    Writer::text

    fn Writer::text(self : Writer, content : String) -> Unit

    Write escaped character data.

    Writer::to_string

    fn Writer::to_string(self : Writer) -> String

    Return the accumulated document.

    Writer::write_decl

    fn Writer::write_decl(self : Writer) -> Unit

    Write the XML declaration used by RSS/Atom output.

    decode_entities

    fn decode_entities(input : String) -> String

    Decode predefined (&amp; &lt; &gt; &quot; &apos;) and numeric (&#NNN;, &#xHHH;) character references. Unknown or malformed references are left verbatim (lenient, mirroring quick-xml defaults).

    escape_attr

    fn escape_attr(s : String) -> String

    Escape attribute-value content.

    escape_text

    fn escape_text(s : String) -> String

    Escape text-node content.

    local_name

    fn local_name(qname : String) -> String

    The local part of a qualified name: "itunes:author" → "author".

    prefix_of

    fn prefix_of(qname : String) -> String?

    The prefix part of a qualified name, or None when unprefixed.

    split_qname

    fn split_qname(qname : String) -> (String?, String)

    Split a qualified name into (prefix?, local). "itunes:author" becomes (Some("itunes"), "author"); "title" becomes (None, "title").

    trim

    fn trim(s : String) -> String

    Trim ASCII whitespace from both ends.