1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-06-14 11:57:40 +00:00

[PR #12148/5004c9f7 backport][stable-13] xml: preserve DOCTYPE declaration when writing XML files (#12249)

xml: preserve DOCTYPE declaration when writing XML files (#12148)

* fix(xml): preserve DOCTYPE declaration when writing XML files

Pass `doctype=tree.docinfo.doctype` to all `ElementTree.write()` calls
so lxml does not silently drop the DOCTYPE on serialization. Also replace
`etree.tostring()` with BytesIO+write() in the diff and xmlstring paths
for consistency.

Fixes #2762



* test(xml): add integration test for DOCTYPE preservation



* feat(changelog): add fragment for xml DOCTYPE fix (#12148)



---------


(cherry picked from commit 5004c9f70f)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
patchback[bot] 2026-06-13 17:33:15 +02:00 committed by GitHub
parent 58d8bbf164
commit 3bc92d03c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 99 additions and 8 deletions

View file

@ -813,9 +813,15 @@ def children_to_nodes(module=None, children=None, type="yaml"):
def make_pretty(module, tree):
xml_string = etree.tostring(
tree, xml_declaration=True, encoding="UTF-8", pretty_print=module.params["pretty_print"]
buf = BytesIO()
tree.write(
buf,
xml_declaration=True,
encoding="UTF-8",
pretty_print=module.params["pretty_print"],
doctype=tree.docinfo.doctype or None,
)
xml_string = buf.getvalue()
result = dict(
changed=False,
@ -830,7 +836,11 @@ def make_pretty(module, tree):
if module.params["backup"]:
result["backup_file"] = module.backup_local(module.params["path"])
tree.write(
xml_file, xml_declaration=True, encoding="UTF-8", pretty_print=module.params["pretty_print"]
xml_file,
xml_declaration=True,
encoding="UTF-8",
pretty_print=module.params["pretty_print"],
doctype=tree.docinfo.doctype or None,
)
elif module.params["xmlstring"]:
@ -859,10 +869,23 @@ def finish(module, tree, xpath, namespaces, changed=False, msg="", hitcount=0, m
if result["changed"]:
if module._diff:
result["diff"] = dict(
before=etree.tostring(orig_doc, xml_declaration=True, encoding="UTF-8", pretty_print=True),
after=etree.tostring(tree, xml_declaration=True, encoding="UTF-8", pretty_print=True),
before_buf = BytesIO()
orig_doc.write(
before_buf,
xml_declaration=True,
encoding="UTF-8",
pretty_print=True,
doctype=orig_doc.docinfo.doctype or None,
)
after_buf = BytesIO()
tree.write(
after_buf,
xml_declaration=True,
encoding="UTF-8",
pretty_print=True,
doctype=tree.docinfo.doctype or None,
)
result["diff"] = dict(before=before_buf.getvalue(), after=after_buf.getvalue())
if module.params["path"] and not module.check_mode:
if module.params["backup"]:
@ -872,12 +895,19 @@ def finish(module, tree, xpath, namespaces, changed=False, msg="", hitcount=0, m
xml_declaration=True,
encoding="UTF-8",
pretty_print=module.params["pretty_print"],
doctype=tree.docinfo.doctype or None,
)
if module.params["xmlstring"]:
result["xmlstring"] = etree.tostring(
tree, xml_declaration=True, encoding="UTF-8", pretty_print=module.params["pretty_print"]
xmlstring_buf = BytesIO()
tree.write(
xmlstring_buf,
xml_declaration=True,
encoding="UTF-8",
pretty_print=module.params["pretty_print"],
doctype=tree.docinfo.doctype or None,
)
result["xmlstring"] = xmlstring_buf.getvalue()
module.exit_json(**result)