Reputation: 60
I have a XML which have two parent nodes (Base, Sub). I need to write a XSLT to get the values for below condition.
Condition: Need to get different elements in both parents.
Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Base>
<Student_ID>1234</Student_ID>
<Student_ID>1267</Student_ID>
<Student_ID>1890</Student_ID>
<Student_ID>5678</Student_ID>
<Student_ID>6743</Student_ID>
<Student_ID>8743</Student_ID>
</Base>
<Sub>
<Student_ID>5678</Student_ID>
<Student_ID>6743</Student_ID>
<Student_ID>3226</Student_ID>
<Student_ID>8123</Student_ID>
</Sub>
</Data>
Expected Output:
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Student_ID>1234</Student_ID>
<Student_ID>1267</Student_ID>
<Student_ID>1890</Student_ID>
<Student_ID>8743</Student_ID>
<Student_ID>3226</Student_ID>
<Student_ID>8123</Student_ID>
</Data>
Upvotes: 0
Views: 75
Reputation: 163352
Another option:
<xsl:for-each select="distinct-values(*/Student_ID)">
<Student_ID>{.}</Student_ID>
</xsl:for-each>
Upvotes: 0
Reputation: 167581
In XSLT 3 you could also consider xsl:merge
, that would allow you to handle duplicates in each branch; drawback is that merging requires sorting input sequences on merge key(s) so the result of
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
expand-text="yes"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Data">
<xsl:copy>
<xsl:merge>
<xsl:merge-source name="base" select="Base/Student_ID" sort-before-merge="yes">
<xsl:merge-key select="."/>
</xsl:merge-source>
<xsl:merge-source name="sub" select="Sub/Student_ID" sort-before-merge="yes">
<xsl:merge-key select="."/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:if test="count(current-merge-group('base')) = 0 and count(current-merge-group('sub')) = 1 or count(current-merge-group('base')) = 1 and count(current-merge-group('sub')) = 0">
<xsl:copy-of select="current-merge-group()"/>
</xsl:if>
</xsl:merge-action>
</xsl:merge>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
has the right elements but in sorted order:
<Data>
<Student_ID>1234</Student_ID>
<Student_ID>1267</Student_ID>
<Student_ID>1890</Student_ID>
<Student_ID>3226</Student_ID>
<Student_ID>8123</Student_ID>
<Student_ID>8743</Student_ID>
</Data>
Of course we could re-sort into original input order using
<xsl:template match="Data">
<xsl:copy>
<xsl:variable name="unique-ids" as="element(Student_ID)*">
<xsl:merge>
<xsl:merge-source name="base" select="Base/Student_ID" sort-before-merge="yes">
<xsl:merge-key select="."/>
</xsl:merge-source>
<xsl:merge-source name="sub" select="Sub/Student_ID" sort-before-merge="yes">
<xsl:merge-key select="."/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:if test="count(current-merge-group('base')) = 0 and count(current-merge-group('sub')) = 1 or count(current-merge-group('base')) = 1 and count(current-merge-group('sub')) = 0">
<xsl:sequence select="current-merge-group()"/>
</xsl:if>
</xsl:merge-action>
</xsl:merge>
</xsl:variable>
<xsl:copy-of select="$unique-ids/."/>
</xsl:copy>
</xsl:template>
Upvotes: 2
Reputation: 117003
Another way you could look at it:
XSLT 2.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Data">
<xsl:copy>
<xsl:for-each-group select="*/Student_ID" group-by=".">
<xsl:if test="count(current-group())=1">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note that this assumes there are no duplicates within each branch.
Upvotes: 0
Reputation: 3171
Maybe something like this?
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="student" match="Student_ID" use="." />
<xsl:template match="/Data">
<xsl:copy>
<xsl:copy-of select="Base/Student_ID[not(key('student', ., ../../Sub))]"/>
<xsl:copy-of select="Sub/Student_ID[not(key('student', ., ../../Base))]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1