首页 > 解决方案 > 向 lxml 元素添加行号

问题描述

我正在尝试找到一种方法,将原始 XML 文本中的行号添加到从 python 的 lxml 模块构建在 XML 树中的每个元素中。可以让我从树中获取一个元素并简单地做一些事情的东西

       line_num = element.xml_line_num

我知道 lxml 树元素中有一个 sourceline 属性,但这并不可靠。它并不总是正确的。使用 python 2.7 默认提供的基本 ElementTree,默认解析器有一个称为 GetInputContext() 的方法,我可以通过循环原始 XML 文本中的行并与从该输入上下文方法获得的文本进行比较来使用该方法。我很快发现默认解析器中的 CurrentLineNumber 不可靠。不得不求助于 XML 源字符串比较。

无论如何,我对模块的子类化部分和让事情正常工作的理解还不够好。成熟且广泛使用的 Python 模块在使用 Python 的许多方面时往往非常彻底和广泛,当您处理底层基类的 c 代码实现时,它会变得混乱。所以,一些帮助,也许是一些示例代码,将不胜感激。提前致谢!

让我补充一些说明。我想要看起来像这样的代码:

from lxml import etree as ET


xml_tree = ET.fromstringlist(xml_file_lines)

for xml_element in xml_tree.iter():

    line_num = xml_element.xml_line_num

'xml_file_lines' 是从文件中读取的 XML 文件行的列表。其中一些是空行。关于我正在处理的文件中的 XML 行,我可以说的是,非空白行和非注释行确实显示为打开、关闭、自动关闭或打开/关闭元素。也就是这样说:

<tag>text</tag>
<tag1 />
<tag2 id = "yum" />
<tag2 id = "delicious" name = "tasty">text</tag>
<tag3>
     <tag4>hungry</tag4>
<tag3>

在这些 XML 文件的任何一行中,永远不会有超过一个打开或关闭 XML 标记。有任何想法吗?

标签: xmlpython-2.7parsinglxml

解决方案


好的,所以,我想通了。如果您从 XML 文件行的字符串列表将 XML 数据加载到 lxml etree 中,然后使用提要解析器,您可以获得 lxml etree 元素的 sourceline 属性,以获取每个 XML 元素源自的 XML 文件行。下面的代码演示了我所做的:

from lxml import etree as ET

class LineNumberingParser(ET.XMLParser):

      def __init__(self, *args, **kwargs):

          super(self.__class__, self).__init__(*args, **kwargs)

      def feed(self, data):

           line = data.strip() + "\n"
           super(self.__class__, self).feed(line)     

然后你需要做的就是告诉 lxml 使用你的行解析器:

from lxml import etree as ET

class LineNumberingParser(ET.XMLParser):

      def __init__(self, *args, **kwargs):

          super(self.__class__, self).__init__(*args, **kwargs)

      def feed(self, data):

           line = data.strip() + "\n"
           super(self.__class__, self).feed(line)     

with open(file.xml, "rU") as FILE:
     xml_file_lines = FILE.readlines()

xml_tree = ET.fromstringlist(xml_file_lines, parser=LineNumberingParser()) 

for xml_element in xml_tree.iter():
    print "XML tag " + xml_element.tag + " found on file line " + str(xml_element.sourceline) + "\n" 

甚至可能不需要子类化 lxml XMLParser。可能需要的只是将 XML 文件的行读取为字符串列表并使用 etree.fromstringlist() 只要每行末尾有一个换行符,我认为这一切都很好。


推荐阅读