Skip to content

ADR-004 — XML construction and parsing

Status: Accepted

Context

The module must build SOAP XML envelopes for 6 distinct operations and parse their responses. An approach that is maintainable, testable, and free of external dependencies is required.

Options evaluated

Envelope construction

Option Pros Cons
f-string template Readable, predictable output, easily testable Manual escaping required if data contains special XML characters
xml.etree.ElementTree builder Automatic safe escaping Verbose, less readable for complex envelopes
lxml Powerful API, schema validation External C dependency, not needed
Jinja2 template Separation of template from code External dependency, overhead

Response parsing

Option Pros Cons
xml.etree.ElementTree stdlib Zero dependencies, sufficient for simple structures Non-intuitive API for namespaces
lxml Powerful XPath, better namespace handling External C dependency
xmltodict Dict-friendly External dependency, loses XML structure

Decision

Construction: f-string templates in _xml.py, with mandatory escaping of user values via a helper function _xml_escape(value: str) -> str that replaces &, <, >, ", '.

Parsing: xml.etree.ElementTree stdlib with explicit namespaces passed as a dict to find() / findall() calls.

Organisation of _xml.py

_xml.py
├── Template constants (ENVELOPE_*)
├── _xml_escape(value) → str
├── build_*(…) → str          # one function per operation
└── parse_*(xml_text) → dict  # one function per operation

Each build_X / parse_X pair corresponds to a SOAP operation.

Special character handling

Values inserted into envelopes (article_number, article_name, job_number) are passed through _xml_escape before interpolation. This prevents XML injection and ensures that payloads containing characters such as & or < do not produce malformed envelopes.

Namespace handling in responses

t-Server responses use the namespaces http://main.jws.com.hanel.de and http://main.jws.com.hanel.de/xsd. The namespace dict is defined as a constant in _xml.py and reused across all parse_* functions.

Consequences

  • XML templates are visible and editable without knowledge of a builder API
  • Tests verify the exact output of envelopes (see ADR-007)
  • XML response fixtures (tests/fixtures/*.xml) are the reference data for parsers
  • If the t-Server changes its XML structure, modifications are isolated in _xml.py