atisha1410
atisha1410

Reputation: 11

XSLT comparing values from different branches of XML document

I need help with XSLT... In the input xml, I have:

<shop>
  <categories>
    <category categoryId="63" parentCategoryId="239">
      <name>Fruit</name>
    </category>
    <category categoryId="62" parentCategoryId="239">
      <name>Vegetable</name>
    </category>
    <category categoryId="60" parentCategoryId="221">
      <name>Furniture</name>
    </category>
    ...
  <categories>
  <products>
    <product productId="3" productCode="1.05">
      <name>Chair</name>
      <categories>
        <category>60</category>
      </categories>
    </product>
    <product productId="21" productCode="1.59">
      <name>Apple</name>
      <categories>
        <category>63</category>
      </categories>
    </product>
    ...
  </products>
</shop>

I need to create list of products, where I have name of product and name of its category. How can I do that? This don't work for me...

<xsl:stylesheet
   version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

  <xsl:template match="shop">
    <export>
      <xsl:apply-templates select="products" />
    </export>
  </xsl:template>


  <xsl:template match="products">
    <xsl:for-each select="product">
      <polozka>
        <product_name>
          <xsl:value-of select="name" />
        </product_name>
        <xsl:for-each select="/shop/categories/category">
          <xsl:if test="boolean(@categoryId = /shop/products/product/categories/category)">
            <category_name>
              <xsl:value-of select="name" />
            </category_name>
          </xsl:if>
        </xsl:for-each>
      </polozka>    
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

I'd be glad if there is anybody who can help me...

Upvotes: 1

Views: 311

Answers (2)

Tim C
Tim C

Reputation: 70618

If you want to look up a category based on its @categoryId then consider using a key to do the looking up

<xsl:key name="category" match="category" use="@categoryId"/>

Then, assuming each Product belongs to only one category, you can simply look up the name of category for a product like so

<xsl:value-of select="key('category', categories/category)/name"/>

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:key name="category" match="category" use="@categoryId"/>

   <xsl:template match="shop">
      <export>
         <xsl:apply-templates select="products"/>
      </export>
   </xsl:template>

   <xsl:template match="products">
      <xsl:for-each select="product">
         <polozka>
            <product_name>
               <xsl:value-of select="name"/>
            </product_name>
            <category_name>
               <xsl:value-of select="key('category', categories/category)/name"/>
            </category_name>
         </polozka>
      </xsl:for-each>
   </xsl:template>
</xsl:stylesheet>

If a Product element could have multiple characters, then you would need to use a for-each loop instead

 <xsl:for-each select="categories/category">
     <category_name>
         <xsl:value-of select="key('category', .)/name"/>
     </category_name>
 </xsl:for-each>

Upvotes: 1

helderdarocha
helderdarocha

Reputation: 23637

You are comparing the @CategoryId of each category to all the products:

@categoryId = /shop/products/product/categories/category

which will always be true, since each product is related to an existing category.

You have to compare it to the category of the current product. You don't need a <xsl:if> for that. It can be done with a predicate. Replace your for-each with this one:

<xsl:for-each select="/shop/categories/category[@categoryId = current()/categories/category]">
     <category_name>
         <xsl:value-of select="name" />
     </category_name>
</xsl:for-each>

Now it should filter out the categories that don't match the categories of the current product.

Upvotes: 0

Related Questions