Languages guide
Validate XML in Python with lxml
Parse XML defensively, compile an XMLSchema once, inspect lxml's error log, and keep document validity separate from application acceptance.
8 min read · Updated 2026-08-21
The short answer
Create an lxml parser with network and entity expansion disabled for untrusted input, parse the XSD into an etree.XMLSchema object, and validate parsed documents with schema.validate or schema.assertValid. Read schema.error_log for line-level violations, reuse the compiled schema across documents, and add explicit checks for the vocabulary and business constraints the XSD does not express.Construct a defensive parser
Parser options are part of the trust boundary. For input you did not author, disable network access, DTD loading, and entity resolution unless the application has a reviewed reason to enable them. Apply byte and time limits outside the parser as well.
from lxml import etree
parser = etree.XMLParser(
no_network=True,
load_dtd=False,
resolve_entities=False,
)
schema_doc = etree.parse("contract.xsd", parser)
schema = etree.XMLSchema(schema_doc)
document = etree.parse("payload.xml", parser)
if not schema.validate(document):
for problem in schema.error_log:
print(problem.line, problem.message)
raise ValueError("payload does not satisfy contract.xsd")Compile once and classify failures
XMLSchema construction compiles the grammar; failure there is a schema-set problem. schema.validate checks one instance and returns a boolean, while assertValid raises DocumentInvalid. Choose one control flow and keep the error log attached to the validation operation that produced it.
- Resolve includes and imports from a controlled local catalog.
- Cache the immutable compiled schema for repeated validations.
- Do not catch XMLSyntaxError and report it as an XSD violation.
- Preserve line numbers and the schema filename in logs.
Test beyond the XSD boundary
An XSD-valid SAML assertion can still target the wrong audience; a valid SOAP envelope can still carry an expired security timestamp. Follow schema validity with application checks, and compare the exact signed or authorized node rather than searching the document again by a convenient path.
Keep negative fixtures for malformed XML, invalid schemas, invalid instances, and policy failures. They should fail at different layers and produce different messages.
Prove the fix
- Exercise the schemaCheck positive and negative fixtures against the same contract.
- Review schema namespacesFix the qualification mismatch behind many lxml errors.
- Inspect parser errorsSeparate XMLSyntaxError causes before working on validation.
Related guides
- Validate XML in JavaScript and TypeScriptBuild a layered JavaScript validation path that separates XML syntax, namespace and vocabulary diagnostics, XSD validation, and application rules.
- Validate XML in Java with JAXPUse Java's built-in validation API safely, compile reusable Schema objects, collect SAX errors, and control external schema resolution.
- How to validate XML against an XSDSeparate parsing from schema validation, load the complete schema set, and reduce validation errors to the smallest failing instance.
Get started
Bring order to the XML your team can't afford to ignore.
Create a free account and get a private workspace to search, validate, diff, and monitor your XML feeds, sitemaps, schemas, and vendor integrations.