python 报告 XML 节点的行/列来源
我现在在用python的xml.dom.minidom来解析一些XML文件。解析完之后,我想对内容进行一些报告,特别是想报告一下标签在源XML文档中开始的位置(行和列),但是我不知道怎么做到这一点。
如果可以的话,我希望继续使用xml.dom / xml.dom.minidom,但如果需要用SAX解析器来获取这些位置信息,我也可以这样做——理想情况下,我希望用SAX来追踪节点的位置,但最后还是能得到一个DOM来进行后续处理。
有没有什么建议可以做到这一点?希望我只是没有在文档中找到相关内容,这个问题其实很简单。
2 个回答
0
解决这个问题的另一种方法是在解析文档之前,把行号信息添加到文档里。大概是这个意思:
LINE_DUMMY_ATTR = '_DUMMY_LINE' # Make sure this string is unique!
def parseXml(filename):
f = file.open(filename, 'r')
l = 0
content = list ()
for line in f:
l += 1
content.append(re.sub(r'<(\w+)', r'<\1 ' + LINE_DUMMY_ATTR + '="' + str(l) + '"', line))
f.close ()
return minidom.parseString ("".join(content))
然后你可以用下面的方式获取某个元素的行号:
int (element.getAttribute (LINE_DUMMY_ATTR))
很明显,这种方法也有自己的缺点。如果你真的需要列号的话,添加列号的过程会复杂一些。而且,如果你想提取文本节点或者注释,或者使用 Node.toXml()
,你需要确保把任何意外匹配的 LINE_DUMMY_ATTR 去掉。
这个方法相比 aknuds1 的答案有一个好处,就是它不需要去修改 minidom 的内部结构。
5
通过对minidom内容处理器进行“猴子补丁”,我能够记录每个节点的行号和列号(作为'parse_position'属性)。这有点不太规范,但我找不到任何“官方认可”的方法来做到这一点 :) 这是我的测试脚本:
from xml.dom import minidom
import xml.sax
doc = """\
<File>
<name>Name</name>
<pos>./</pos>
</File>
"""
def set_content_handler(dom_handler):
def startElementNS(name, tagName, attrs):
orig_start_cb(name, tagName, attrs)
cur_elem = dom_handler.elementStack[-1]
cur_elem.parse_position = (
parser._parser.CurrentLineNumber,
parser._parser.CurrentColumnNumber
)
orig_start_cb = dom_handler.startElementNS
dom_handler.startElementNS = startElementNS
orig_set_content_handler(dom_handler)
parser = xml.sax.make_parser()
orig_set_content_handler = parser.setContentHandler
parser.setContentHandler = set_content_handler
dom = minidom.parseString(doc, parser)
pos = dom.firstChild.parse_position
print("Parent: '{0}' at {1}:{2}".format(
dom.firstChild.localName, pos[0], pos[1]))
for child in dom.firstChild.childNodes:
if child.localName is None:
continue
pos = child.parse_position
print "Child: '{0}' at {1}:{2}".format(child.localName, pos[0], pos[1])
它输出了以下内容:
Parent: 'File' at 1:0
Child: 'name' at 2:2
Child: 'pos' at 3:2