带有大文件的lxml:根据属性过滤出子树



我试图解决的高级问题是,我有一个1.5 GB的SMS数据转储,我试图过滤该文件,以只保留往来于单个联系人的消息。

我在Python中使用lxml来解析文件,但请告诉我是否有更好的选项。

XML文件的结构如下:

SMSES (root node)
'count': 'xxxx',
(Children):
MMS
'address': 'xxxx',
'foo':     'bar',
... : ...,
(Children)
'other fields': 'that _do not_ specify address',
MMS
'address': 'xxxx',
'foo':     'bar',
... : ...,
(Children)
'other fields': 'that _do not_ specify address'

即,我想遍历根节点的子节点,对于每个"地址"与特定值不匹配的MMS,删除该MMS及其所有子节点(子节点倾向于保存图像等项目(。

我尝试过的:

我发现了这样的问题/答案:如何删除lxml中的元素

但是这些线程往往具有简单的示例,而没有嵌套的元素。

  • 我不清楚如何使用tree.xpath()来查找与值不匹配的元素
  • 我不清楚调用remove(item)是否会删除该项的子项(在本例中我希望这样(

我尝试了一种非常天真的方法,即获得一个迭代器,然后遍历树,边走边删除元素:

from lxml.etree import XMLParser, parse
p = XMLParser(huge_tree=True)
tree = parse('backup.xml', parser=p)
it = tree.iter()
item = next(it) # consume root node
for item in it:
if item.attrib['address'] != '0000':
item.getparent().remove(item)

此脚本的问题是迭代器执行DFS,并且MMS元素的子元素没有地址字段。所以,我正在寻找:

  • 完成任务最有效、最简单的方法是什么
  • 否则,我怎么能强迫tree.iter()只在根的一级邻居上给我一个BFS迭代器呢
  • remove(item(确实删除了所有子项,还是将子项附加到父项

感谢您抽出时间阅读。很抱歉,如果这是一个天真的问题——解析XML文件并不是我真正的面包和黄油,而且LXML文档对我这个新手来说很难阅读。

谢谢!

上周发布了一个带有Python语言绑定的Saxon/C新版本,其中包含XSLT3.0流功能:这是一个非常新的软件,但您可以尝试一下(使用saxonic.com提供的SaxonEE评估许可证(。样式表非常简单:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode streamable="yes"/>
<xsl:template match="/">
<SMSES>
<xsl:copy-of select="SMS[@address='specific value']"/>
</SMSES>
</xsl:template>
</xsl:transform>

不幸的是,您已经抽象了XML,所以我无法判断"address"实际上是一个元素还是一个属性,而且它在流式传输时会产生很大的差异。我在这里假设它是一个属性,但如果您提供一个真正的XML示例,那么我可以帮助您生成一些真正有效的XSLT代码。

如果没有必须从Python运行的真正约束,那么您也可以使用已建立的Saxon/Java产品直接从命令行运行它。但无论哪种方式,流媒体都需要Saxon的企业版。

最新更新