Ktos Ktos
Ktos Ktos

Reputation: 3

How to filter xml elements based on the value of different element?

I got this xml (the 'other' elements have different names, just skipped them for clarity):

<root>
<elements1>
<element>
<id>1</id>
<other>a</other>
<other>b</other>
<other>c</other>
</element>
<element><id>2</id>
<other>a</other>
<other>b</other>
<other>c</other>
</element>
<element><id>3</id>
<other>a</other>
<other>b</other>
<other>c</other>
</element>
</elements1>

<elements2>
<element>
<id2>1</id2>
<other2>a</other2>
<other2>b</other2>
<other2>c</other2>
</element>
<element>
<id2>2</id2>
<other2>a</other2>
<other2>b</other2>
<other2>c</other2>
</element>
<elements2>
</root>

I need to filter it so it shows something like this:

<root>
 <elements>
  <element>
   <id>1</id>
   <id2>1</id2>
   <other>a</other>
   <other>b</other>
   <other>c</other>
   <other2>a</other2>
   <other2>b</other2>
   <other2>c</other2>
  </element>
  <element>
   <id>2</id>
   <id2>2</id2>
   <other>a</other>
   <other>b</other>
   <other>c</other>
   <other2>a</other2>
   <other2>b</other2>
   <other2>c</other2>
  </element>
</elements>
</root>

So it should take the children of two different elements and put them together as one element filtering by the id and id2.

Not sure how to do it. I've tried two for-each elements to filter the xml but it wouldnt work.

Upvotes: 0

Views: 963

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167571

Here is an XSLT 2.0 stylesheet using a key:

<xsl:stylesheet 
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output indent="yes"/>

<xsl:key name="id2" match="elements2/element" use="id2"/>

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

<xsl:template match="root">
  <xsl:copy>
    <elements>
      <xsl:apply-templates select="elements1/element[key('id2', id)]"/>
    </elements>
  </xsl:copy>
</xsl:template>

<xsl:template match="elements1/element">
  <xsl:variable name="el2" select="key('id2', id)"/>
  <xsl:copy>
    <xsl:copy-of select="id, $el2/id2, (., $el2)/(* except (id, id2))"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

A similar approach with XSLT 1.0 is

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output indent="yes"/>

<xsl:key name="id2" match="elements2/element" use="id2"/>

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

<xsl:template match="root">
  <xsl:copy>
    <elements>
      <xsl:apply-templates select="elements1/element[key('id2', id)]"/>
    </elements>
  </xsl:copy>
</xsl:template>

<xsl:template match="elements1/element">
  <xsl:variable name="el2" select="key('id2', id)"/>
  <xsl:copy>
    <xsl:copy-of select="id | $el2/id2 | *[not(self::id)] | $el2/*[not(self::id2)]"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions