Reputation: 93
I've seen a lot of information on how to break down XML cross-references in XSL (for example XSL cross-reference). I'm completely stuck on how to do the opposite. I don't even know what it's technically called, so I don't know where to look to find out.
Given the XML
<shoes>
<shoe>
<colour>brown</colour>
<make>Shoeco</make>
</shoe>
<shoe>
<colour>black</colour>
<make>Shoeco</make>
</shoe>
<shoe>
<colour>purple</colour>
<make>Footfine</make>
</shoe>
<shoe>
<colour>brown</colour>
<make>Footfine</make>
</shoe>
<shoe>
<colour>blue</colour>
<make>Leathers</make>
</shoe>
</shoes>
I want the output
<inventory>
<shoelist>
<item>
<colour>brown</colour>
<shopref>1</shopref>
</item>
<item>
<colour>black</colour>
<shopref>1</shopref>
</item>
<item>
<colour>purple</colour>
<shopref>1</shopref>
</item>
<item>
<colour>brown</colour>
<shopref>2</shopref>
</item>
<item>
<colour>blue</colour>
<shopref>2</shopref>
</item>
</shoelist>
<shoeshops>
<shop>
<refno>1</refno>
<name>ShoeCo</name>
</shop>
<shop>
<refno>2</refno>
<name>FootFine</name>
</shop>
<shop>
<refno>3</refno>
<name>Leathers</name>
</shop>
</shoeshops>
</inventory>
How can I (a) create a list of each unique shoe shop, with an incrementing ID number, and (b) reference the correct shoeshop by ID number in each shoe element?
Upvotes: 0
Views: 51
Reputation: 163575
I would first build the list of shoeshops in a variable:
<xsl:variable name="shops">
<shoeshops>
<xsl:for-each-group select="shoe" group-by="make">
<shop>
<refno>{position()}</refno>
<name>{current-grouping-key()}</name>
</shop>
</xsl:for-each-group>
</shoeshops>
</xsl:variable>
Then create the shoelist:
<xsl:mode on-no-match="shallow-copy"/>
<inventory>
<shoelist>
<xsl:apply-templates select="shoes/shoe"/>
</shoelist>
<xsl:copy-of select="$shops"/>
</inventory>
<xsl:template match="make">
<shopref>{$shops//shop[name="current()"]/refno}</shopref>
</xsl:template>
This uses some XSLT 3.0 constructs for brevity. Converting to XSLT 2.0 is fairly easy, converting to XSLT 1.0 is much harder.
Upvotes: 2