tags:

views:

70

answers:

1

I have an xml output like this:

<data>
    <item-types>
        <entry id="1" items="5">
            <category>Frozen</category>
        </entry>
        <entry id="2" items="4">
            <category>Breakfast</category>
        </entry>
    </item-types>

    <items>
        <entry id="28">
            <item-number>1115</item-number>
            <name>Marion Berries, IQF</name>
            <area>
                <item id="1">Groceries - Frozen</item>
            </area>
        </entry>
        <entry id="29">
            <item-number>1117</item-number>
            <name>Peach Cups</name>
            <area>
                <item id="1">Groceries - Frozen</item>
            </area>
        </entry>
        <entry id="35">
            <item-number>1570</item-number>
            <name>Sausage Patty</name>
            <area>
                <item id="2">Groceries - Breakfast</item>
            </area>
        </entry>
        <entry id="32">
            <item-number>1575</item-number>
            <name>French Toast Stix, WG</name>
            <area>
                <item id="2">Groceries - Breakfast</item>
            </area>
        </entry>
    </items>
</data>

The items-types are the categories of the items below. item-types/entry/@id relates directly to items/entry/area/item/@id and I'm trying to organize the items in to the categories for my output.

So far I am using the following XSL transformation.

<xsl:template match="item-types/entry">
    <h3><xsl:value-of select="concat(@id,'. ',category)" /></h3>
    <ul>
        <xsl:apply-templates select="/data/items/entry[area/item/@id = @id]" />
    </ul>
</xsl:template>
<xsl:template match="items/entry">
    <li>
        <xsl:value-of select="concat(item-number,'. ',name,' (',area/item/@id,')')" />
    </li>
</xsl:template>

The problem is it's not working. I believe the problem is the predicate on line 4 of the transformation: [area/item/@id = @id] When I remove this, it shows all the items in every category.

Is there a way to show the "Frozen" items in the "Frozen" category and the "Breakfast" items in the "Breakfast" category?

Thanks!

+4  A: 

Easily done with an XSL key.

<xsl:key name="kEntryByAreaId" match="items/entry" use="area/item/@id" />

<!-- this is just for the sake of the test -->
<xsl:template match="/data">
  <xsl:apply-templates select="item-types/entry" />
</xsl:template>

<xsl:template match="item-types/entry">
  <h3>
    <xsl:value-of select="concat(@id,'. ',category)" />
  </h3>
  <ul>
    <xsl:apply-templates select="key('kEntryByAreaId', @id)" />
  </ul>
</xsl:template>

<xsl:template match="items/entry">
  <li>
    <xsl:value-of select="
      concat(
        item-number, 
        '. ', name,
        ' (', area/item/@id, ')'
      )
    " />
  </li>
</xsl:template>

Now to answer the question why your try did not work.

This expression:

/data/items/entry[area/item/@id = @id]

says: "all the /data/items/entry elements with their area/item/@id value equal to their @id value". Trouble is - they have no @id value.

What you mean is this:

/data/items/entry[area/item/@id = current()/@id]

This would work, but the key will be faster.

Tomalak
You always beat me to these.
Welbog
I'm sorry. I usually try to have the answers prepared, though. :-D
Tomalak
(You should not have deleted your answer, though. It is good.
Tomalak
@Tomalak: Yours is better, so I don't mind. I always forget about keys because I don't get much opportunity to use them. Next time, Tomalak! Next time!
Welbog
@Welbog: Honestly, the only place where I get to use keys (or any XSLT, for that matter) is SO.
Tomalak
Thank you very much! I've never known when to use `xsl:key`.
sirlancelot