bhylu.com

Advertisements

XML First Document

Save UTF-8 plain text rather than a formatted word-processing file. A declaration can state the XML version and encoding before the root element.

How it works

Install Python 3 and lxml in a separate virtual environment for the downloadable labs. Run python -m venv .venv, activate that environment, then python -m pip install lxml==6.1.1. Save each Python listing as the filename shown and run python filename.py. The examples embed their input so they work independently. XML-only listings can also be pasted into the syntax playground. Nothing is uploaded to a database or saved as a production record.

XML to inspect online

first-document.xml

<?xml version="1.0" encoding="UTF-8"?>
<packet><name>Marigold</name></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 first-document.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 first-document.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

first-document.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 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><packet><name>Marigold</name></packet>"
root = parse(source)
print(E.tostring(root, encoding="unicode"))

Expected result

<packet><name>Marigold</name></packet>

The parser receives UTF-8 bytes, so the encoding declaration agrees with the actual data. Serializing a tree may change quotation style or declaration placement; compare meaning rather than assuming byte-for-byte identity.

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