减肥xml

时间:2012-06-19 07:20:37

标签: python xml xslt compression

我有一个程序每天生成一个大的xml,我想节省空间,并且有一些信息在一段时间后没用。我想删除这些信息,例如我的xml现在是:

<owner name="thename">
   <datasets ndatasets="10" size="10000">
       <dataset size="100" creationdate="...">mydataset1</dataset>
       <dataset size="200" creationdate="...">mydataset2</dataset>
       ...
   </datasets>
</owner>
<owner name="thename2">
  ...
</owner>

我想删除有关单个数据集的信息,因此我想将其转换为:

<owner name="thename">
   <datasets ndatasets="10" size="10000" />
</owner>
<owner name="thename2">
  ...
</owner>

最简单的方法是什么?我正在使用python,但也欢迎其他简单易用的解决方案

3 个答案:

答案 0 :(得分:4)

这是一个XSLT 1.0样式表:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

<xsl:template match="dataset" />

</xsl:stylesheet>

以下是一些可以帮助您开始XSLT之旅的指示:

答案 1 :(得分:4)

一个XSLT解决方案(Sean的解决方案很好,但是如果dataset以外的元素或节点成为datasets的子节点,它将停止工作:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

将此转换应用于提供的骨架XML (包装到单个顶部元素中以使其成为格式良好的XML文档):

<t>
    <owner name="thename">
        <datasets ndatasets="10" size="10000">
            <dataset size="100" creationdate="...">mydataset1</dataset>
            <dataset size="200" creationdate="...">mydataset2</dataset>
        </datasets>
    </owner>
    <owner name="thename2">
        <datasets ndatasets="10" size="10000">
            <dataset size="100" creationdate="...">mydataset1</dataset>
            <dataset size="200" creationdate="...">mydataset2</dataset>
        </datasets>
    </owner>
</t>

产生了想要的正确结果:

<t>
   <owner name="thename">
      <datasets ndatasets="10" size="10000"/>
   </owner>
   <owner name="thename2">
      <datasets ndatasets="10" size="10000"/>
   </owner>
</t>

<强>解释

正确使用身份规则并使用与datasets的任何子节点匹配的空体模板覆盖它。

答案 2 :(得分:2)

我认为@Sean B. Durkin的回答比较简单,但是如果你想用lxml做到这一点很难:

from lxml import etree
from StringIO import StringIO

xml = etree.parse(StringIO('''<owner name="thename">
      <datasets ndatasets="10" size="10000">
        <dataset size="100" creationdate="...">mydataset1</dataset>
        <dataset size="200" creationdate="...">mydataset2</dataset>
      </datasets>
      </owner>'''))

[d.getparent().remove(d) for d in  xml.findall('.//dataset')]
print etree.tostring(xml, pretty_print=True)

结果:

<owner name="thename">
<datasets ndatasets="10" size="10000">
   </datasets>
</owner>