'XSLT distinct node
Set 1:
<?xml version='1.0' encoding='UTF-8'?>
<aa:Details xmlns:aa="urn:com.report">
<aa:Row>
<aa:Place>AAA</aa:Place>
<aa:PlaceID>A123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>BBB</aa:Place>
<aa:PlaceID>B123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>CCC</aa:Place>
<aa:PlaceID>C123</aa:PlaceID>
</aa:Row>
</aa:Details>
Set 2
<?xml version='1.0' encoding='UTF-8'?>
<aa:Details xmlns:aa="urn:com.report">
<aa:Row>
<aa:Place>AAA</aa:Place>
<aa:PlaceID>A123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>EEE</aa:Place>
<aa:PlaceID>E123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>FFF</aa:Place>
<aa:PlaceID>F123</aa:PlaceID>
</aa:Row>
</aa:Details>
I have two sets of data above coming from different sources.
I will be combining two sets of data as below
<?xml version='1.0' encoding='UTF-8'?>
<aa:Details xmlns:aa="urn:com.report">
<aa:Row>
<aa:Place>AAA</aa:Place>
<aa:PlaceID>A123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>BBB</aa:Place>
<aa:PlaceID>B123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>CCC</aa:Place>
<aa:PlaceID>C123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>AAA</aa:Place>
<aa:PlaceID>A123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>EEE</aa:Place>
<aa:PlaceID>E123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>FFF</aa:Place>
<aa:PlaceID>F123</aa:PlaceID>
</aa:Row>
</aa:Details>
I would like to transform and get below desired output based on below condition
The result of the output should be from Set 2 by removing any node when PlaceID value from Set 2 is equal to Set 1
Desired Output
<?xml version="1.0" encoding="UTF-8"?>
<aa:Details xmlns:aa="urn:com.report">
<aa:Row>
<aa:Place>EEE</aa:Place>
<aa:PlaceID>E123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>FFF</aa:Place>
<aa:PlaceID>F123</aa:PlaceID>
</aa:Row>
</aa:Details>
I tried below XSLT code but it only removes the duplicates
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:aa="urn:com.report">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="aa:Row[aa:PlaceID = following::aa:Row/aa:PlaceID]"/>
</xsl:stylesheet>
Solution 1:[1]
Define a key
<xsl:key name="placeKey" match="aa:Row" use="aa:Place">
Make the second input document your primary input, and select document 1 as
<xsl:variable name="doc1" select="document('input1.xml')">
Then process document2 as
<xsl:template match="/">
<aa:Details xmlns:aa="urn:com.report">
<xsl:copy-of select="aa:Row[exists(key('placeKey', ., $doc1)]"/>
</aa:Details>
</xsl:template>
That's XSLT 2.0. If you're still using an XSLT 1.0 processor then as usual you'll have to jump through a few more hoops. It's a long time since I used XSLT 1.0 but I think you'll have to replace the copy-of with something like
<xsl:for-each select="aa:Row">
<xsl:variable name="row" select="."/>
<xsl:for-each select="$doc1">
<xsl:if test="key('placeKey', $row/Place)">
<xsl:copy-of select="$row"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
Solution 2:[2]
If the input to the transformation is the combined set of data shown in your question, then the stated task is impossible because the processor has no way of knowing which nodes come from which set.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Michael Kay |
| Solution 2 | michael.hor257k |
