如何在使用Python / ElementTree解析XML时保留注释

14

当前使用Python 2.4.3版本,无法升级。

我想要更改一个或多个标记中给定属性的值,并且也要更新文件中的XML注释。

我已经编写了一个Python脚本,它以XML文件作为参数,并针对每个指定的标记更改一个属性,如下所示:

def update(file, state):
    global Etree
    try:
        from elementtree import ElementTree
        print '*** using ElementTree'
    except ImportError, e:
        print '***'
        print '*** Error: Must install either ElementTree or lxml.'
        print '***'
        raise ImportError, 'must install either ElementTree or lxml'
    #end try

    doc = Etree.parse(file)
    root = doc.getroot()

    for element in root.findall('.//StateManageable'):
        element.attrib['initialState'] = state
    #end for
    doc.write(file)
#end def

这一切都很好,"initialState"属性已经更新,只是我的原始XML包含了很多XML注释,但它们已经消失了,这很糟糕。

怀疑parse只检索XML结构,但我认为XML注释是结构的一部分。我也意识到,我的原始文档的“可读性”格式已经消失了,但我已经意识到这是预期行为,需要使用xmllint --format或XSL进行格式化。


你说得没错,当我开始创建我的第一个脚本时,我很困难,因为我发现所有好的例子都是针对2.7版本的。 - rhellem
1个回答

19

我知道这个问题现在已经老掉牙了,但我偶然发现了上面关于如何保留注释的回答。Frederik在他的发布说明中提到了如何将注释放入树中,这种方式在当前版本的ElementTree中仍然有效,但对于我的使用来说它做了比我需要的更多的事情。至少我不希望XML被包装在一个<comment>元素中,因为这样对我来说是不可取的。我也不需要保留处理指令,只需要注释而已。所以,我将他在网站上提供的类简化为以下内容:

import xml.etree.ElementTree as ET

class PCParser(ET.XMLTreeBuilder):

   def __init__(self):
       ET.XMLTreeBuilder.__init__(self)
       # assumes ElementTree 1.2.X
       self._parser.CommentHandler = self.handle_comment

   def handle_comment(self, data):
       self._target.start(ET.Comment, {})
       self._target.data(data)
       self._target.end(ET.Comment)
要使用此功能,请创建此对象的实例作为“解析器”,然后将其作为参数传递给ElementTree.parse(),如下所示:

parser = PCParser()
self.tree = ET.parse(self.templateOut, parser=parser)

我对这段代码或使用ElementTree的未记录用法完全不负责,但在保留注释而不影响原始文档结构方面,它对我很有效。请注意,如果将来对ElementTree进行任何更改(尽管这些年来看起来不太可能),都将破坏此功能。


我正在使用 lxml 并尝试让它工作。我正在导入 from lxml import etree as et。我认为我可以用 et 替换 self._parser,但是无法弄清楚该使用什么来替代 self._target。你能帮忙吗? - eoinzy
3
这对于Python3无效(已测试v3.5.4),因为API已更改。请参见此处获取Python3解决方案。 - akhan
@Jon,链接无效 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接