Python生成XML时在根元素前添加注释的报错解决方法
问题描述
使用Python库xml.etree.ElementTree将CSV数据解析转换为XML格式时,需要在首个根节点前添加注释,期望输出格式如下:
<?xml version="1.0" encoding="iso-8859-1"?> <!-- Comment --> <a xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <b> <c>xxxxx</c> </b> </a>
原有代码与报错
自行编写的实现代码如下:
from lxml import etree import xml.dom.minidom import xml.etree.ElementTree as et name_space = { # namespace defined below "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance" } comment = et.Comment root = et.Element('') root.tag = None root.insert(0, comment) root2 = et.Element('a', namespace) root.insert(1, root2) xml_data = et.tostring(root, encoding='iso-8859-1', method='xml') xmlstr = xml.dom.minidom.parseString(xml_data, parser=None).toprettyxml(indent=" ", encoding='iso-8859-1')
执行最后一行xml.dom.minidom.parseString()时抛出错误:xml.parsers.expat.ExpatError: junk after document element: line 2, column 135
打印生成的xml_data内容如下:
<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>\n<!--Comment--><a xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /><b><c>xxxx</c></b>
可行实现方案
原有代码报错的核心原因有两个:
- XML规范要求文档有且仅有一个顶层根节点,你创建了无标签的虚拟根节点,将注释和实际根节点
a作为同级子节点插入,生成的内容存在多个顶层元素,不符合XML语法要求 - 代码中定义命名空间的变量名为
name_space,创建a节点时误写为namespace,会直接触发变量未定义的报错
可以选择以下两种方式实现根节点前加注释的需求:
方式1:使用lxml库(写法最简洁)
lxml对XML注释的支持更完善,不需要创建虚拟节点,直接调用addprevious方法即可在根节点前插入同级注释:
from lxml import etree # 构建节点结构 root = etree.Element('a', nsmap={'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}) b_ele = etree.SubElement(root, 'b') c_ele = etree.SubElement(b_ele, 'c') c_ele.text = 'xxxxx' # 在根节点前插入注释 root.addprevious(etree.Comment(' Comment ')) # 生成格式化的XML内容 result = etree.tostring( root, xml_declaration=True, encoding='iso-8859-1', pretty_print=True, indent=' ' ) print(result.decode('iso-8859-1'))
运行输出和期望格式完全匹配。
方式2:纯Python标准库实现
如果不想安装第三方依赖,可以先生成根节点的XML内容,再手动将注释插入到XML声明之后、根节点之前的位置,最后做格式化处理:
import xml.etree.ElementTree as ET import xml.dom.minidom # 构建节点结构 root = ET.Element('a', {'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance'}) b_ele = ET.SubElement(root, 'b') c_ele = ET.SubElement(b_ele, 'c') c_ele.text = 'xxxxx' # 生成基础XML内容 raw_xml = ET.tostring(root, encoding='iso-8859-1') # 手动拼接XML声明、注释、根节点内容 xml_with_comment = b'<?xml version="1.0" encoding="iso-8859-1"?>\n<!-- Comment -->\n' + raw_xml # 格式化输出 dom = xml.dom.minidom.parseString(xml_with_comment) pretty_result = dom.toprettyxml(indent=" ", encoding='iso-8859-1') print(pretty_result.decode('iso-8859-1'))
内容的提问来源于stack exchange,提问作者vll1990
相关产品推荐
相关产品推荐

