Skip to content

Pretty-printing exported XML introduces ns0: namespace prefix, rejected by German bank #78

@ralfblask

Description

@ralfblask

When the output of sepa.export() is parsed and re-serialized using Python's xml.etree.ElementTree for pretty-printing (indentation), the resulting XML contains ns0: prefixes on all elements. German banks (tested with Volksbank using DK-SEPA validator v1.13.1) reject this with 577 warnings:

Line 2, Col 2: Das Setzen von individuellen Präfixen ist unzulässig (ns0).
Line 3, Col 4: Das Setzen von individuellen Präfixen ist unzulässig (ns0).
...

Steps to reproduce

import xml.etree.ElementTree as ET
from sepaxml import SepaTransfer
import datetime

config = {
    "name": "Test GmbH",
    "IBAN": "DE12345678901234567890",
    "BIC": "TESTDE99XXX",
    "batch": True,
    "currency": "EUR",
}
sepa = SepaTransfer(config, clean=True)
sepa.add_payment({
    "name": "Recipient",
    "IBAN": "DE98765432109876543210",
    "BIC": "EMPFDE99XXX",
    "amount": 1500,
    "execution_date": datetime.date(2026, 3, 17),
    "description": "Test",
})
xml_bytes = sepa.export(validate=True)

# Pretty-print via ElementTree
ET.register_namespace("", "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03")
root = ET.fromstring(xml_bytes)
print(ET.tostring(root, encoding="unicode")[:200])
# Output contains: <ns0:Document xmlns:ns0="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">

Root cause

ET.register_namespace() must be called before ET.fromstring(). Once the document is parsed, ElementTree has already assigned internal namespace prefixes and register_namespace() has no effect on already-parsed nodes.

Workaround

Regex-based cleanup after serialization:

import re

serialised = ET.tostring(root, encoding="unicode")
serialised = re.sub(r'<ns\d+:(\w)', r'<\1', serialised)
serialised = re.sub(r'</ns\d+:', r'</', serialised)
serialised = re.sub(r'\bxmlns:ns\d+="', 'xmlns="', serialised)

Suggested fix

The library could register all its namespaces as default namespaces at module import time, so that ET.fromstring() already uses the correct prefix mapping. Alternatively, the library could expose a export(pretty=True) option that returns properly indented XML without namespace prefix issues.

Environment

  • python-sepaxml version: latest (pip)
  • Python: 3.12
  • Tested schema: pain.001.001.03
  • Validator: DK-SEPA v1.13.1 (used by German Volksbank/Raiffeisenbank)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions