I have the following xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<employee>
<name>a</name>
<company>1</company>
</employee>
<employee>
<name>b</name>
<company>2</company>
</employee>
<employee>
<name>c</name>
<company>1</company>
</employee>
<employee>
<name>d</name>
<campany>2</campany>
</employee>
<employee>
<name>e</name>
<company>2</company>
</employee>
<employee>
<name>f</name>
<company>1</company>
</employee>
</root>
I would like to have sth like
<root>
<company>
<id>1</id>
<employee>a</employee>
<employee>c</employee>
<employee>f</employee>
</company>
<company>
<id>2</id>
<employee>b</employee>
<employee>d</employee>
<employee>e</employee>
</company>
<root>
I tried using loops
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mdti="urn:com.workday/multiDocumentTransform/Input" xmlns:bc="urn:com.workday/bc"
exclude-result-prefixes="xs" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<root>
<xsl:variable name="companies" select="distinct-values(root/employee/company)"/>
<xsl:for-each select="$companies">
<company>
<companyID> <xsl:value-of select="."/></companyID>
<employees>
<xsl:for-each select="root/employee[company=.]">
<employee><xsl:value-of select="."/></employee>
</xsl:for-each>
</employees>
</company>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
But it gives me the following error in the second for each:
The required item type of the context item for the child axis is node(), but the supplied expression {.} has item type xs:anyAtomicType
Is it possible to use nested loops here? I know I can get what I want with grouping.
Thanks
Przemek
CodePudding user response:
I know I can get what I want with grouping.
Not sure why you would not want to do exactly that. To do it with distinct-values()
instead, you'd need something like:
XSLT 2.0
<xsl:stylesheet version="2.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="/root">
<xsl:variable name="root" select="." />
<root>
<xsl:for-each select="distinct-values(employee/company)">
<company>
<companyID>
<xsl:value-of select="."/>
</companyID>
<employees>
<xsl:for-each select="$root/employee[company=current()]">
<employee>
<xsl:value-of select="name"/>
</employee>
</xsl:for-each>
</employees>
</company>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
This is because distinct-values()
creates a sequence that is separate from the input XML.
Note also that using a predicate to select the employees of each company is inefficient. Using a key would be much better.