如何将同一类型的多个xml节点合并到一个节点中?

时间:2015-01-19 22:00:51

标签: python xml xpath xml-parsing

我有一个相当大的xml文档,看起来像:

<products>
  <product>
    <id>1</id>
    <other>y</other>
    <notarget>x</notarget>
    <target>num1</target>
    <target>num2</target>
    <target>num3</target>
  </product>
</products>

但我需要它看起来像:

<products>
  <product>
    <id>1</id>
    <other>y</other>
    <notarget>x</notarget>
    <target>num1,num2,num3</target>
  </product>
</products>

我对xml没有多少经验,所以我甚至不确定使用哪些技术来浏览文件来进行这些更改。可以有多个产品,但这个例子只有一个。我正在使用python,但我也可以使用shell。

3 个答案:

答案 0 :(得分:0)

需要从一个XML转换为另一个XML,这就是XSLT的原因。

所以,这是使用中的的纯解决方案:

file.xml:

<products>
  <product>
    <id>1</id>
    <other>y</other>
    <notarget>x</notarget>
    <target>num1</target>
    <target>num2</target>
    <target>num3</target>
  </product>
</products>

xsl文件:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <products>
      <product>
        <id>1</id>
        <other>y</other>
        <notarget>x</notarget>
        <target><xsl:value-of select="string-join(//target/text(), ',')" /></target>
      </product>
    </products>
  </xsl:template>
</xsl:stylesheet>

命令行:

$ java -cp 'saxon9he.jar' net.sf.saxon.Transform -xsl:xsl -s:file.xml '!indent=yes'

输出:

<?xml version="1.0" encoding="UTF-8"?>
<products>
  <product>
    <id>1</id>
    <other>y</other>
    <notarget>x</notarget>
    <target>num1,num2,num3</target>
  </product>
</products>

检查http://saxon.sourceforge.net/saxon6.5/using-xsl.html

答案 1 :(得分:0)

这听起来像是xslt transformation的工作,但这是一种特定于python的方法。

对于每个product找到所有target元素,请将收集文本的每个target元素移除到列表中。循环遍历目标后,将新的target项附加到product

使用lxml实施:

from lxml import etree

data = """
<products>
  <product>
    <id>1</id>
    <other>y</other>
    <notarget>x</notarget>
    <target>num1</target>
    <target>num2</target>
    <target>num3</target>
  </product>
</products>
"""

root = etree.fromstring(data)
for product in root.iterfind('product'):
    text = []
    for target in product.iterfind('target'):
        text.append(target.text)
        product.remove(target)

    if text:
        new_target = etree.Element('target')
        new_target.text = ','.join(text)
        product.append(new_target)

print etree.tostring(root)

打印:

<products>
  <product>
    <id>1</id>
    <other>y</other>
    <notarget>x</notarget>
    <target>num1,num2,num3</target>
  </product>
</products>

如您所见,它适用于您提供的输入。

答案 2 :(得分:0)

对于希望在Mac OS上执行此操作的任何人,您都需要安装JDK from Oracle,然后可以从终端通过homebrew通过以下方式安装Saxon:

brew install saxon

然后在终端中,我使用的命令是:

saxon -s:input_file.xml -xsl:transform.xsl -o:output.xml '!indent=yes'

像魅力一样工作!