如何将适当的 xml 元素与 xmlstarlet 配对?

问题描述 投票:0回答:1

我有两组 XML 节点,我想查找具有相同“phone”子元素的元素。例如:

<set1>
  <node>
    <phone>111</phone>
    <name>John</name>
  </node>
  <node>
    <phone>444</phone>
    <name>Amy</name>
  </node>
  <node>
    <phone>777</phone>
    <name>Robin</name>
  </node>
</set1>

<set2>
  <node>
    <phone>111</phone>
    <city>Moscow</city>
  </node>
  <node>
    <phone>444</phone>
    <city>Prag</city>
  </node>
  <node>
    <phone>999</phone>
    <city>Rome</city>
  </node>
</set2>

现在我想要得到以下内容:

<result>
  <node>
    <phone>111</phone>
    <name>John</name>
    <city>Moscow</city>
  </node>
  <node>
    <phone>444</phone>
    <name>Amy</name>
    <city>Prag</city>
  </node>
  <node>
    <phone>777</phone>
    <name>Robin</name>
  </node>
  <node>
    <phone>999</phone>
    <city>Rome</city>
  </node>
</result>

我是 xslt 的初学者,我设法合并两个 xml 并将它们放入 html 表中。但这对比我高一级。

xslt xpath
1个回答
2
投票

使用钥匙

<xsl:key name="phone" match="node" use="phone"/>

然后使用 Muenchian 分组 进行分组,如下所示:

<xsl:template match="/">
  <result>
    <xsl:apply-templates select="//node[generate-id() = generate-id(key('phone', phone)[1])]"/>
  </result>
</xsl:template>

<xsl:template match="node">
  <xsl:copy>
    <xsl:copy-of select="phone"/>
    <xsl:copy-of select="key('phone', phone)/*[not(self::phone)]"/>
  </xsl:copy>
</xsl:template>

为了可读性添加

<xsl:output indent="yes"/>

完整示例

input.xml

<?xml version="1.0"?>
<myxml>
  <set1>
    <node>
      <phone>111</phone>
      <name>John</name>
    </node>
    <node>
      <phone>444</phone>
      <name>Amy</name>
    </node>
    <node>
      <phone>777</phone>
      <name>Robin</name>
    </node>
  </set1>
  <set2>
    <node>
      <phone>111</phone>
      <city>Moscow</city>
    </node>
    <node>
      <phone>444</phone>
      <city>Prag</city>
    </node>
    <node>
      <phone>999</phone>
      <city>Rome</city>
    </node>
  </set2>
</myxml>

stylesheet.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
  <xsl:key name="phone" match="node" use="phone"/>
  
  
  <xsl:template match="/">
    <result>
      <xsl:apply-templates select="//node[generate-id() = generate-id(key('phone', phone)[1])]"/>
    </result>
  </xsl:template>
  
  <xsl:template match="node">
    <xsl:copy>
      <xsl:copy-of select="phone"/>
      <xsl:copy-of select="key('phone', phone)/*[not(self::phone)]"/>
    </xsl:copy>
  </xsl:template>
  
  
  <xsl:output indent="yes"/>
  
</xsl:stylesheet>

命令:

xmlstarlet transform stylesheet.xsl input.xml > output.xml

output.xml

<?xml version="1.0"?>
<result>
  <node>
    <phone>111</phone>
    <name>John</name>
    <city>Moscow</city>
  </node>
  <node>
    <phone>444</phone>
    <name>Amy</name>
    <city>Prag</city>
  </node>
  <node>
    <phone>777</phone>
    <name>Robin</name>
  </node>
  <node>
    <phone>999</phone>
    <city>Rome</city>
  </node>
</result>

© www.soinside.com 2019 - 2024. All rights reserved.