I have this xsl 1.0 call-template. It takes the two xml-elements, given as parameters and returns an element created from both parameters, but with distinct Elements. All doubles should be removed
<xsl:template name="distinctElements">
<xsl:param name="xml1"/>
<xsl:param name="xml2"/>
<xsl:variable name="combined-nodes">
<xsl:copy-of select="$xml1"/>
<xsl:copy-of select="$xml2"/>
</xsl:variable>
<xsl:variable name="distinct-elements">
<xsl:for-each select="$combined-nodes/*[not(. = preceding-sibling::*)]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$distinct-elements/*">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
My problem is, it does not work. Specifically this code makes problems:
<xsl:variable name="distinct-elements">
<xsl:for-each select="$combined-nodes/*[not(. = preceding-sibling::*)]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
It seems as it is not possible to iterate through "$combined-nodes" at all. This code-fragment works if I use $xml1 or $xml2 instead of $combined-nodes.
I don't get it. Does someone see what is my problem here?
Thank you for your help.
I swapped $combined-nodes with $xml1 and $xml2 and the code worked. Only when using the combined element, the code does not work.
EDIT: I loked at the muenchian method and will ivestigate that deeper. For the moment I do not really know how to adapt it into my special situation. Because the XML I have to handle is quite generic:
<someuserdata>
<item>
<name>foo</name>
<value>bar</value>
</item>
<item>
<name>foo</name>
<value>bar</value>
</item>
...
</someuserdata>
<someappointmentdata>
<item>
<name>foo</name>
<value>bar</value>
</item>
<item>
<name>foo</name>
<value>bar</value>
</item>
...
</someappointmentdata>
It contains data from different databases with different information all combined in one xml-file, nested in different levels.
The xsl handles this xml in a generic way, just differed by checking for certain "Name"-Values.
i tried the code-example provided by John Ernst, but cannot get it to work. I decided to dismiss the usage of a call-template and tried to reduce the code to work just in the calling part of my code:
<xsl:template name="table_parent">
<xsl:param name="basis1" />
<xsl:param name="basis2" />
<xsl:variable name="basis3">
<xsl:copy-of select="xmlns:node-set($basis1 | $basis2)/*[not(. = preceding-sibling::*)]"/>
</xsl:variable>
<xsl:for-each select="$basis3/*">
As you see, I just wanted to iterate through a distinct sum of my two xml-elements (basis1 and basis2).
but even this simple lines do not work. My prefix is xmlns, which I changed already in this example.
Shouldn't this work?
Thank you for your patience and your help
EDIT: I have some sample-code here: xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="TEST.xsl"?>
<Root>
<source1>
<Zusatzinformation>
<item>
<Name>Bemerkung</Name>
<Wert>yyy</Wert>
<Attribut>NEU</Attribut>
</item>
<item>
<Name>Versicherungsart</Name>
<Wert>-kein Eintrag-</Wert>
<Attribut>Unverändert</Attribut>
</item>
<item>
<Name>Zusatzversichert</Name>
<Wert>nein</Wert>
<Attribut>Unverändert</Attribut>
</item>
<Anordner>
<CTSmartMitarbeiter>
<CTSmartId>
<item>
<Name>ID</Name>
<Wert>-1</Wert>
<Attribut>Unverändert</Attribut>
</item>
</CTSmartId>
</CTSmartMitarbeiter>
</Anordner>
</Zusatzinformation>
</source1>
<source2>
<Zusatzinformation>
<item>
<Name>Versicherungsart</Name>
<Wert>-kein Eintrag-</Wert>
<Attribut>Unverändert</Attribut>
</item>
<item>
<Name>Zusatzversichert</Name>
<Wert>nein</Wert>
<Attribut>Unverändert</Attribut>
</item>
<Anordner>
<CTSmartMitarbeiter>
<CTSmartId>
<item>
<Name>ID</Name>
<Wert>-1</Wert>
<Attribut>Unverändert</Attribut>
</item>
</CTSmartId>
</CTSmartMitarbeiter>
</Anordner>
</Zusatzinformation>
</source2>
</Root>
xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl">
<xsl:template match="/">
<xsl:variable name="source1" select="//source1"/>
<xsl:variable name="source2" select="//source2"/>
<xsl:variable name="combined-nodes" select="$source1 | $source2"/>
<xsl:variable name="distinct-elements" select="exsl:node-set($combined-nodes)"/>
<xsl:variable name="basis3">
<xsl:copy-of select="exsl:node-set($distinct-elements)/*[not(. = preceding-sibling::*)]"/>
</xsl:variable>
<xsl:for-each select="basis3/*">
<xsl:value-of select="."/><xsl:text> - </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The xsl should output just a distinct list of:
Bemerkung Versicherungsart Zusatzversichert
Thank you all. With your help I came to this solution:
<xsl:template name="distinctElements">
<xsl:param name="xml1"/>
<xsl:param name="xml2"/>
<xsl:variable select="exsd:node-set($xml1|$xml2)" name="combined-nodes"/>
<xsl:variable name="result">
<xsl:for-each select="$combined-nodes/item[count(. | key('item-by-name', Name)[1]) = 1]">
<itemname><xsl:copy-of select="."/></itemname>
</xsl:for-each>
</xsl:variable>
<xsl:copy-of select="$result"/>
</xsl:template>
Because I needed the output of the template as a nodeset, I converted it after the call:
<xsl:variable name="basis3Rtf">
<xsl:call-template name="distinctElements">
<xsl:with-param name="xml1" select="$basis1"/>
<xsl:with-param name="xml2" select="$basis2"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="basis3" select="exsd:node-set($basis3Rtf)/itemname" />
<xsl:for-each select="$basis3/*">
Consider the following example:
XML
<Root>
<source1>
<Zusatzinformation>
<item>
<Name>Bemerkung</Name>
<Wert>yyy</Wert>
<Attribut>NEU</Attribut>
</item>
<item>
<Name>Versicherungsart</Name>
<Wert>-kein Eintrag-</Wert>
<Attribut>Unverändert</Attribut>
</item>
<item>
<Name>Zusatzversichert</Name>
<Wert>nein</Wert>
<Attribut>Unverändert</Attribut>
</item>
<Anordner>
<CTSmartMitarbeiter>
<CTSmartId>
<item>
<Name>ID</Name>
<Wert>-1</Wert>
<Attribut>Unverändert</Attribut>
</item>
</CTSmartId>
</CTSmartMitarbeiter>
</Anordner>
</Zusatzinformation>
</source1>
<source2>
<Zusatzinformation>
<item>
<Name>Versicherungsart</Name>
<Wert>-kein Eintrag-</Wert>
<Attribut>Unverändert</Attribut>
</item>
<item>
<Name>Zusatzversichert</Name>
<Wert>nein</Wert>
<Attribut>Unverändert</Attribut>
</item>
<Anordner>
<CTSmartMitarbeiter>
<CTSmartId>
<item>
<Name>ID</Name>
<Wert>-1</Wert>
<Attribut>Unverändert</Attribut>
</item>
</CTSmartId>
</CTSmartMitarbeiter>
</Anordner>
</Zusatzinformation>
</source2>
</Root>
Using (the first part of) Muenchian grouping:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:key name="item-by-name" match="item" use="Name" />
<xsl:template match="/Root">
<xsl:for-each select="*/Zusatzinformation/item[count(. | key('item-by-name', Name)[1]) = 1]">
<xsl:value-of select="Name"/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Result
Bemerkung
Versicherungsart
Zusatzversichert
Note that some XSLT 1.0 processors support a distinct()
extension function which could make this task much easier.