xml解析(删除父节点)

时间:2015-12-02 00:10:36

标签: python xml parsing

嗨我在尝试过滤掉我的xml文档时严重受阻。以下是一些内容示例:

<sentence id="1" document_id="Perseus:text:1999.02.0029" >
    <primary>millermo</primary>
    <word id="1" />
    <word id="2" />
    <word id="3" />
    <word id="4" />
</sentence>


<sentence id="2" document_id="Perseus:text:1999.02.0029" >
    <primary>millermo</primary>
    <word id="1" />
    <word id="2" />
    <word id="3" />
    <word id="4" />
    <word id="5" />
    <word id="6" />
    <word id="7" />
    <word id="8" />
</sentence>

有很多句子(超过3000),但我想要做的就是编写一些代码(最好是java或python),这些代码将通过我的xml文件并删除所有超过5个单词id的句子,  所以换句话说,我将只留下5个或更少单词ID的句子标签。谢谢。 (只是要注意我的xml不是很好,我混淆了节点/标签/元素/ ID。

我尝试这个atm但不确定:

import xml.etree.ElementTree as ET

tree = ET.parse('treebank.xml')
root = tree.getroot()
parent_map = dict((c, p) for p in tree.getiterator() for c in p)

iterator = list(root.getiterator('word id'))

for item in iterator:
  old = item.find('word id')
  text = old.text
  if 'id=16' in text:
      parent_map[item].remove(item)
      continue

tree.write('out.xml')

2 个答案:

答案 0 :(得分:0)

问题是word是一个标记,id是它的属性;你不能将它们都传递给.find()。 此外,解析的结果是树,其中属性和文本的表示方式与XML文件中的不同。

我想你有一个根元素,它有<sentence>个元素作为子元素。 您必须查看每个<sentence>节点,计算其<word>元素,并在需要时删除该句子。

# We cannot iterate over a tree and modify it at the same time.
# Remember the nodes to remove later.
elements_to_kill = []

for sentence_node in root.getiterator('sentence'):
    if len(sentence_node.findall('word')) <= 5:
        elements_to_kill.append(sentence_node)

# Now it's safe to remove them
for node in elements_to_kill:
    root.remove(node)

# Serialize as file, etc

希望这有帮助。

您似乎缺乏对ETree如何运作的把握。请随意read the docs并尝试使用Python REPL来获得理解。

答案 1 :(得分:0)

考虑一个不需要循环的XSLT解决方案。作为信息,XSLT是一种声明性的,专用的语言,旨在将XML文档转换为各种格式,样式,结构以供最终用途。具体来说,身份转换按原样复制整个文档,并将空模板写入位置大于5的所有<word>个节点。

XSLT脚本 (另存为.xsl或.xslt文件)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>

  <!-- Identity Transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="word[position() &gt; 5]"/>

</xsl:transform>

Python 脚本

import os, sys
import lxml.etree as ET

# LOAD XML AND XSL
dom = ET.parse('C/Path/To/Input.xml')  
xslt = ET.parse('C/Path/To/XSLTscript.xsl')

# TRANSFORM XML
transform = ET.XSLT(xslt)
newdom = transform(dom)

# PRETTY PRINT OUTPUT
tree_out = ET.tostring(newdom, encoding='UTF-8', pretty_print=True,  xml_declaration=True)
print(tree_out.decode("utf-8"))

# SAVE TO FILE
xmlfile = open('Output.xml'),'wb')
xmlfile.write(tree_out)
xmlfile.close()

XSLT的优点在于它可以传输,因为几乎所有通用语言都支持包括Java在内的XSLT处理器:

Java脚本

import javax.xml.transform.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

public class Sentence {

    public static void main(String[] args) throws IOException, URISyntaxException, TransformerException {

        String currentDir = new File("").getAbsolutePath();
        String xml = "C:/Path/To/Input.xml";
        String xsl = "C:/Path/To/XSLTScript.xsl";

        // Transformation
        TransformerFactory factory = TransformerFactory.newInstance();
        Source xslt = new StreamSource(new File(xsl));
        Transformer transformer = factory.newTransformer(xslt);

        Source text = new StreamSource(new File(xml));
        transformer.transform(text, new StreamResult(new File("C:/Path/To/Output.xml")));

   }

}

输出 (使用发布的内容)

<?xml version='1.0' encoding='UTF-8'?>
<root>
  <sentence id="1" document_id="Perseus:text:1999.02.0029">
    <primary>millermo</primary>
    <word id="1"/>
    <word id="2"/>
    <word id="3"/>
    <word id="4"/>
  </sentence>
  <sentence id="2" document_id="Perseus:text:1999.02.0029">
    <primary>millermo</primary>
    <word id="1"/>
    <word id="2"/>
    <word id="3"/>
    <word id="4"/>
    <word id="5"/>
  </sentence>
</root>