主流XML解析器默认忽略注释和处理指令,需显式启用保留模式:ElementTree需自定义TreeBuilder,lxml支持parse_comments=True,DOM需设置domConfig参数。

XML解析器默认忽略注释和处理指令
绝大多数主流XML解析器(如Python的xml.etree.ElementTree、Java的DOMParser、JavaScript的DOMParser)在构建文档树时,会直接跳过和节点。这不是bug,而是W3C规范允许的“非信息项”处理策略——除非显式启用保留模式,否则它们不会出现在childNodes或iter()结果中。
ElementTree需用XMLParser(target=)捕获注释
Python标准库的ElementTree不提供开箱即用的注释访问接口,但可通过自定义TreeBuilder配合XMLParser实现。关键在于重写comment()和pi()方法:
from xml.etree import ElementTree as ET from xml.etree.ElementTree import TreeBuilderclass CommentPreservingBuilder(TreeBuilder): def comment(self, data): self.start(ET.Comment, {}) self.data(data) self.end(ET.Comment)
def pi(self, target, data): self.start(ET.PI, {'target': target, 'data': data}) self.end(ET.PI)parser = ET.XMLParser(target=CommentPreservingBuilder()) root = ET.parse("doc.xml", parser).getroot()
注释节点现在是真实元素,可用findall查找
comments = root.findall(".//{*}comment") # 注意命名空间通配
-
ET.Comment和ET.PI是特殊节点类型,不能用字符串标签名直接匹配 - 必须用
.//{*}comment这种带通配命名空间的XPath,否则findall("comment")找不到 - 注释内容通过
node.text获取,而非node.attrib
lxml支持parse_comments=True一键开启
如果你能引入第三方库,lxml是最省心的选择。它原生支持注释和PI节点保留,并提供清晰的API:
from lxml import etreeparser = etree.XMLParser(remove_comments=False, recover=True) tree = etree.parse("doc.xml", parser) root = tree.getroot()
直接遍历所有节点,包括注释
for node in root.iter(): if isinstance(node, etree._Comment): print("Comment:", node.text.strip()) elif isinstance(node, etree._ProcessingInstruction): print("PI:", node.target, node.text)
-
remove_comments=False是必须参数,缺省为True -
etree._Comment和etree._ProcessingInstruction是具体类型,不能用字符串判断 - 注意
recover=True可容忍部分格式错误,避免解析中断
DOM解析中需手动设置domConfig特性
浏览器环境或Java DOM中,注释节点默认存在但可能被过滤。必须显式启用"comments"和"CDATA-sections"特性:
// JavaScript示例(浏览器环境)
const parser = new DOMParser();
const doc = parser.parseFromString(xmlString, "application/xml");
// 启用注释保留(部分浏览器需此步)
doc.domConfig?.setParameter("comments", true);
doc.domConfig?.setParameter("CDATA-sections", true);
// 现在可以安全遍历
Array.from(doc.childNodes).forEach(node => {
if (node.nodeType === Node.COMMENT_NODE) {
console.log("Comment:", node.textContent);
}
});
- 现代Chrome/Firefox通常默认保留注释,但Safari和旧版IE可能需要
domConfig -
Node.COMMENT_NODE值为8,Node.PROCESSING_INSTRUCTION_NODE为7 - 服务端DOM(如JAXP)必须调用
setFeature("http://apache.org/xml/features/dom/include-comments", true)
注释和处理指令的映射不是“有没有”的问题,而是“要不要主动打开开关”的问题。不同解析器的默认行为差异极大,最容易踩的坑是:以为iter()或childNodes天然包含它们,结果调试半天发现根本没进循环。










