Re: [xsl] Stuck on how to properly use 'preceding' axis

Subject: Re: [xsl] Stuck on how to properly use 'preceding' axis
From: "Jay Bryant" <jay@xxxxxxxxxxxx>
Date: Wed, 12 Jul 2006 16:18:41 -0500
> Hi All,
>
> I recently posted the same issue under a different
> subject but have had no responses. I believe I may not
> have expressed my problem correctly so here it goes:
>
> PROBLEM: Trying to return a distinct list of
> 'DistributorCode' values for each 'Item' node. My
> expression using the preceding axis is not removing my
> duplicates (most likely due to my noobness of
> understanding the language).
>
> -------MY SAMPLE XML:----------
> <Items
> xmlns:loader="http://xxx/loader/1.0";;
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";;
> xsi:schemaLocation="http://xxx/ns/pioneer/1.0
> http://xxx/xsd/pioneer.xsd";;>
> - <Item ItemId="640308"
> createDate="2002-10-30T10:06:24Z"
> lastChangeDate="2006-03-29T12:27:13Z">
>   <CatalogNumber>123456</CatalogNumber>
>   <CEMark>CE0086</CEMark>
> -   <ItemsAsMade>
> -    <ItemAsMade>
>        <ManufacturerCode>SHC</ManufacturerCode>
>        <SupplierCode>SHC</SupplierCode>
>        <Currency>EUR</Currency>
> -      <ItemsAsSold>
> -       <ItemAsSold>
>           <DistributorCode>SIG</DistributorCode>
>           <CanOrderFlag>true</CanOrderFlag>
>           <CanShipFlag>true</CanShipFlag>
>         </ItemAsSold>
> -       <ItemAsSold>
>           <DistributorCode>ARG</DistributorCode>
>           <CanOrderFlag>true</CanOrderFlag>
>           <CanShipFlag>true</CanShipFlag>
>           </ItemAsSold>
> -       <ItemAsSold>
>           <DistributorCode>FRA</DistributorCode>
>           <CanOrderFlag>true</CanOrderFlag>
>           <CanShipFlag>true</CanShipFlag>
>         </ItemAsSold>
>       </ItemsAsSold>
>     </ItemAsMade>
> -    <ItemAsMade>
>        <ManufacturerCode>END</ManufacturerCode>
>        <SupplierCode>END</SupplierCode>
>        <Currency>US</Currency>
> -      <ItemsAsSold>
> -       <ItemAsSold>
>           <DistributorCode>SIG</DistributorCode>
>           <CanOrderFlag>true</CanOrderFlag>
>           <CanShipFlag>true</CanShipFlag>
>         </ItemAsSold>
> -       <ItemAsSold>
>           <DistributorCode>EME</DistributorCode>
>           <CanOrderFlag>false</CanOrderFlag>
>           <CanShipFlag>false</CanShipFlag>
>           </ItemAsSold>
> -       <ItemAsSold>
>           <DistributorCode>FRA</DistributorCode>
>           <CanOrderFlag>true</CanOrderFlag>
>           <CanShipFlag>true</CanShipFlag>
>         </ItemAsSold>
>       </ItemsAsSold>
>     </ItemAsMade>
> -    <ItemAsMade>
>        <ManufacturerCode>BIO</ManufacturerCode>
>        <SupplierCode>BIO</SupplierCode>
>        <Currency>US</Currency>
> -      <ItemsAsSold>
> -       <ItemAsSold>
>           <DistributorCode>SIG</DistributorCode>
>           <CanOrderFlag>true</CanOrderFlag>
>           <CanShipFlag>true</CanShipFlag>
>         </ItemAsSold>
> -       <ItemAsSold>
>           <DistributorCode>EME</DistributorCode>
>           <CanOrderFlag>true</CanOrderFlag>
>           <CanShipFlag>false</CanShipFlag>
>           </ItemAsSold>
> -       <ItemAsSold>
>           <DistributorCode>FRA</DistributorCode>
>           <CanOrderFlag>true</CanOrderFlag>
>           <CanShipFlag>true</CanShipFlag>
>         </ItemAsSold>
>       </ItemsAsSold>
>     </ItemAsMade>
>    </ItemsAsMade>
>   </Item>
>   <Item Id = "xxxxx">
>     ....thousand more Items..
> </Items>
>
>
> --------My v1.0 XSLT code:----------
>
> <xsl:variable name="distributorVal">
> <!-- only process distributorCodes if canShip
> andcanOrder are both true -->
>  <xsl:for-each select="*/ItemAsMade">
>   <xsl:for-each select="*/ItemAsSold">
>    <xsl:if test="(CanOrderFlag = 'true') and
> (CanShipFlag = 'true')">
>      <xsl:if test="//ItemAsSold[not(DistributorCode =
> preceding::DistributorCode)]">
>         <xsl:value-of select="DistributorCode" />
>         <xsl:text>,</xsl:text>
>      </xsl:if>
>    </xsl:if>
>   </xsl:for-each>
>  </xsl:for-each>
> </xsl:variable>
>
>
> <xsl:call-template name="attrvalue_template">
>   <xsl:with-param
> name="stringValue"select="substring($distributorVal,
> 1,string-length($distributorVal)-1)" />
> </xsl:call-template>
>
>
>
> ----Current Results Returned based on Code used
> above---
> stringvalue="SIG,ARG,FRA,SIG,EME,FRA,SIG,EME,FRA"
>
>
> -------Result set I want to have-----------
> stringvalue="SIG,ARG,FRA,EME"
>
>
> I am hoping its simply an alteration of the tag:
>   <xsl:if test="//ItemAsSold[not(DistributorCode =
> preceding::DistributorCode)]">
>
> I have tried a number of different methods to no
> avail..PLEASE help!!
>
> Thanks,
>
> -Rusty

Hi, Rusty,

Here's one possible XSLT 1.0 solution

Note that I didn't try to call a named template. Instead, I just matched the
topmost element to get output as simply as possible. I suspect you can adapt
that part to your needs.

I tested the solution with Xalan and got the expected output. Note, EME did
not appear in the output; however, when I examine your data, EME's
CanShipFlag is always false, so it shouldn't appear (assuming I interpreted
your rules correctly).

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

  <xsl:template match="Items">
    <xsl:for-each
select="Item/ItemsAsMade/ItemAsMade/ItemsAsSold/ItemAsSold[CanOrderFlag =
'true'][CanShipFlag = 'true'][not(DistributorCode =
preceding::DistributorCode)]/DistributorCode">
      <xsl:value-of select="."/><xsl:if test="not(position() =
last())"><xsl:text>, </xsl:text></xsl:if>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

HTH

Jay Bryant
Bryant Communication Services

Current Thread