I have two sets of XML nodes, and I want to find elements that have identical "phone" child. For example:
<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>
Now I want to get the following:
<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>
I'm a beginner in xslt, and i managed to merge two xml's and put them in a html table. But this pairing is one level over me.
Use a key
<xsl:key name="phone" match="node" use="phone"/>
then group with Muenchian grouping as follows:
<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>
For readability add
<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>
Command:
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>