Files
Alexander Medvednikov 11c71fbd59 encoding.xml: fix valueless attributes, text order around comments and CDATA, and empty error messages (fix #30021) (#30064)
The DOM parser had six defects, all in parser.v:

- parse_attributes took everything up to a "=" as the key, so a name without
  a value was merged into the key of the next attribute (`<a disabled k="v">`
  gave `{'disabled k': 'v'}`), or dropped after the last value. It is an error
  now, as XML requires `name="value"`. A value also ended at the first quote
  of any kind; only the quote that opened it closes it now, so that the rest
  of `k="it's"` is not taken for a name without a value.
- parse_children added the pending text only before a child node and at the
  end of the node, so text in front of a comment or a CDATA section came
  after it, merged with the text behind it. The text is added at every "<".
- parse_prolog returned as soon as the document did not start with "<?", so
  a comment or a DOCTYPE in front of the root was read as the root tag. They
  are parsed the same way with and without an XML declaration.
- An input that ended early returned an io.Eof, which has no message. The
  error says what was not closed: the tag, node, comment, CDATA or DOCTYPE.
- "<?" in content or before the root was read as a node. It is reported as
  an unsupported processing instruction: the tree has no node type for it.
- `<>` was a node named `><`, `</>` a node without a name, and `< >` a
  panic. A tag without a name is an error.
2026-10-13 04:14:18 +03:00
..
2023-11-25 10:02:51 +03:00

Description

xml is a module to parse XML documents into a tree structure. It also supports validation of XML documents against a DTD.

Note that this is not a streaming XML parser. It reads the entire document into memory and then parses it. This is not a problem for small documents, but it might be a problem for extremely large documents (several hundred megabytes or more).

The public function parse_single_node can be used to parse a single node from an implementation of io.Reader, which can help parse large XML documents on an element-by-element basis. Sample usage is provided in the parser_test.v file.

Usage

Parsing XML Files

There are three different ways to parse an XML Document:

  1. Pass the entire XML document as a string to XMLDocument.from_string.
  2. Specify a file path to XMLDocument.from_file.
  3. Use a source that implements io.Reader and pass it to XMLDocument.from_reader.
import encoding.xml

//...
doc := xml.XMLDocument.from_file('test/sample.xml')!

Attribute names must be unique within an element. Repeated attribute names produce a parse error.

External DOCTYPE Identifiers

SYSTEM and PUBLIC DOCTYPE identifiers are accepted with or without an XML declaration. DocumentType.external_id retains the quoted identifier for serialization. An optional internal subset is retained in DocumentType.dtd. External DTD resources are not loaded or fetched. Malformed or unterminated identifiers produce a descriptive parse error.

Validating XML Documents

Simply call validate on the parsed XML document.

Querying

Check the get_element... methods defined on the XMLDocument struct.

Escaping and Un-escaping XML Entities

Parsing decodes predefined entities, decimal and hexadecimal character references, and entities declared in the document's internal DTD in text and attribute values. Unknown entities and references to invalid XML characters produce an error. Numeric references to whitespace are preserved, including at the edges of text nodes. CDATA is left unchanged. Literal formatting whitespace is trimmed at element boundaries. Comments and CDATA split text fragments without removing separator whitespace inside the same text run.

validate checks the parsed tree without decoding its text again.

When the XML document is serialized (using str or pretty_str), text and attributes are escaped. Significant whitespace at text edges and carriage returns are written as character references so parsing the serialized document preserves them. Adjacent text, comments, and CDATA are kept together to avoid adding formatting whitespace inside text runs.

The escaping and un-escaping can also be done manually using the escape_text and unescape_text methods.

XML attributes require a name and a quoted value. Missing values, unterminated quotes and attributes without a name produce parse errors. Values may contain the other kind of quote. Text, comments and CDATA retain their document order and the separator whitespace between fragments. Truncated nodes and markup produce errors naming the construct that was left open. Processing instructions are reported as unsupported.