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
<?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
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.