bhylu.com

Advertisements

XML Syntax

Well-formed XML follows strict syntax rules. Correct nesting and exact case matter even when a browser could repair a similar mistake in HTML.

How it works

Every start tag needs a matching end tag unless it uses empty-element syntax. Names are case-sensitive: packet and Packet are different names. Attribute values must be quoted, a name cannot occur twice on the same element, and there must be exactly one document element. A parser should reject a malformed record instead of guessing how its structure was intended to look. The application can then report a useful failure to the sender.

XML to inspect online

syntax.xml

<packet id="p1"><name>Marigold</name><returned/></packet>

This checks syntax only. Importing does not run the check. Select Run when ready; DTD and entity declarations are not supported.

Run the code

Use Python 3 with lxml 6.1.1 in a separate virtual environment. The complete listing embeds its own XML and any schema or stylesheet; run python syntax.py. It does not need Apache or MySQL. The shared restrictive parse function rejects declarations for untrusted input. The trusted DTD/entity and streaming lessons explicitly explain their separate fixed-input boundaries.

Download the complete syntax.py source. Keep each lab in its own folder. Sources are served as text, not as public executable server scripts. Review the starting setup.

Example

syntax.py

from lxml import etree as E

class DenyExternal(E.Resolver):
    def resolve(self, url, public_id, context):
        raise ValueError("External resources are disabled")

def parse(text):
    if "<!DOCTYPE" in text.upper() or "<!ENTITY" in text.upper():
        raise ValueError("Declarations are disabled for untrusted XML")
    parser = E.XMLParser(resolve_entities=False, load_dtd=False,
                         no_network=True, huge_tree=False)
    parser.resolvers.add(DenyExternal())
    return E.fromstring(text.encode("utf-8"), parser)

source = "<packet id=\"p1\"><name>Marigold</name><returned/></packet>"
root = parse(source)
print(root.get("id"))
try:
    parse("<packet><name>Marigold</packet>")
except E.XMLSyntaxError:
    print("Rejected mismatched tags")

Expected result

p1
Rejected mismatched tags

The valid input uses a quoted identifier and an empty returned element. The second input closes packet before name, so parsing fails. Catch the specific syntax exception rather than treating an invalid document as an empty record.

Check the exact contract in the XML specification, XPath 1.0, the XSD 1.0 primer, lxml validation documentation and Saxon’s processor documentation.

Advertisements