我使用ElementTree在python中编写了一个相当简单的过滤器,以调整某些xml文件的上下文。它或多或少地起作用。
但是它重新排序了各种标签的属性,我希望它不要这样做。
有谁知道我可以抛出的开关使其保持在指定的顺序?
我正在使用一个粒子物理工具,该工具具有基于xml文件的复杂但奇怪的配置系统。以这种方式设置的许多事物中包括各种静态数据文件的路径。这些路径被硬编码到现有的xml中,没有基于环境变量设置或更改它们的功能,在我们的本地安装中,它们必须位于不同的位置。
这不是灾难,因为我们使用的源代码控制和构建控制工具相结合,使我们可以使用本地副本对某些文件进行阴影处理。但是,即使以为数据字段是静态的,xml也不是静态的,所以我写了一个脚本来修复路径,但是由于属性重排,本地版本和主版本之间的差异很难理解,因此不必要。
这是我第一次带ElementTree旋转(而且只有我的第五个或第六个python项目),所以也许我只是做错了。
为简化起见,代码摘要如下:
tree = elementtree.ElementTree.parse(inputfile) i = tree.getiterator() for e in i: e.text = filter(e.text) tree.write(outputfile)
在@bobince的答案和这两个帮助下(设置属性顺序,覆盖模块方法)
我设法修复了这只猴子的脏污,建议使用另一个模块更好地处理这种情况,但是在这种情况下是不可能的:
# ======================================================================= # Monkey patch ElementTree import xml.etree.ElementTree as ET def _serialize_xml(write, elem, encoding, qnames, namespaces): tag = elem.tag text = elem.text if tag is ET.Comment: write("<!--%s-->" % ET._encode(text, encoding)) elif tag is ET.ProcessingInstruction: write("<?%s?>" % ET._encode(text, encoding)) else: tag = qnames[tag] if tag is None: if text: write(ET._escape_cdata(text, encoding)) for e in elem: _serialize_xml(write, e, encoding, qnames, None) else: write("<" + tag) items = elem.items() if items or namespaces: if namespaces: for v, k in sorted(namespaces.items(), key=lambda x: x[1]): # sort on prefix if k: k = ":" + k write(" xmlns%s=\"%s\"" % ( k.encode(encoding), ET._escape_attrib(v, encoding) )) #for k, v in sorted(items): # lexical order for k, v in items: # Monkey patch if isinstance(k, ET.QName): k = k.text if isinstance(v, ET.QName): v = qnames[v.text] else: v = ET._escape_attrib(v, encoding) write(" %s=\"%s\"" % (qnames[k], v)) if text or len(elem): write(">") if text: write(ET._escape_cdata(text, encoding)) for e in elem: _serialize_xml(write, e, encoding, qnames, None) write("</" + tag + ">") else: write(" />") if elem.tail: write(ET._escape_cdata(elem.tail, encoding)) ET._serialize_xml = _serialize_xml from collections import OrderedDict class OrderedXMLTreeBuilder(ET.XMLTreeBuilder): def _start_list(self, tag, attrib_in): fixname = self._fixname tag = fixname(tag) attrib = OrderedDict() if attrib_in: for i in range(0, len(attrib_in), 2): attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1]) return self._target.start(tag, attrib) # =======================================================================
然后在您的代码中:
tree = ET.parse(pathToFile, OrderedXMLTreeBuilder())