Re: [xsl] XSL For-Each Help!

Subject: Re: [xsl] XSL For-Each Help!
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Mon, 17 Jul 2006 15:53:19 -0400
Rusty,

XSLT keys are very useful for this sort of thing.

Declare a key that returns ItemsAsSold elements based on the values of their Distributor children:

<xsl:key name="items-by-distributor" match="ItemAsSold" use="DistributorCode"/>

(You might need or want to qualify this further by matching only ItemAsSold elements with the criteria you want: match="ItemAsSold[CanOrderFlag='true'][CanShipFlag = 'true']".)

Invoking this key with a given value will return the set of all ItemAsSold elements (or all those with the given attribute values) whose DistributorCode is that value.

If you simply want a list of the unique DistributorCode values, get that by selecting all of them and filtering in those whose ItemAsSold parent is the first ItemAsSold with that value, as retrieved by the key. We commonly use a test on the generated id of an element (since it is unique to that element) to determine "node identity" in such cases.

In XPath this looks like:

//DistributorCode[generate-id(parent::ItemAsSold) =
                  generate-id(key('items-by-distributor',current())[1]) ]

which can be bound to a variable, iterated over or what have you.

Such use of the key() function is, indeed, the core of the "Muenchian method" of grouping in XSLT 1.0.

This is complex (and non-intuitive) enough that XPath 2.0 cuts the Gordian knot by providing us a distinct-values() function

distinct-values(//ItemAsSold[CanOrderFlag='true'][CanShipFlag = 'true']/DistributorCode)

which returns a sequence of strings rather than a set of DistributorCode elements.

I hope this helps,
Wendell

At 03:17 PM 7/17/2006, you wrote:
Hi All,

Please see the below, I am in desperate need to
resolve this issue and cannot figure it out for the
life of me...

----Problem----:
I am trying to obtain a distinct list of
values('DistributorCodes') for each 'Item' from a
large XML file containing thousands of items.


----Needs-----: I need to store the result in a variable within my stylesheet in order to satisfy other dependencies


---Sample XML-----: <Items> <Item ID="1234"> <ItemsAsMade> <ItemAsMade> <SupplierCode>SHO</SupplierCode> <ItemsAsSold> <ItemAsSold> <DistributorCode>MEX</DistributorCode> <CanOrder>true</CanOrder> <CanShip>true</CanShip> </ItemAsSold> <ItemAsSold> <DistributorCode>CAN</DistributorCode> <CanOrder>false</CanOrder> <CanShip>false</CanShip> </ItemAsSold> <ItemAsSold> <DistributorCode>USA</DistributorCode> <CanOrder>true</CanOrder> <CanShip>true</CanShip> </ItemAsSold> </ItemsAsSold> </ItemAsMade> <ItemAsMade> <SupplierCode>SHC</SupplierCode> <ItemsAsSold> <ItemAsSold> <DistributorCode>CAN</DistributorCode> <CanOrder>true</CanOrder> <CanShip>true</CanShip> </ItemAsSold> <ItemAsSold> <DistributorCode>USA</DistributorCode> <CanOrder>false</CanOrder> <CanShip>false</CanShip> </ItemAsSold> <ItemAsSold> <DistributorCode>MEX</DistributorCode> <CanOrder>false</CanOrder> <CanShip>false</CanShip> </ItemAsSold> </ItemsAsSold> </ItemAsMade> </ItemsAsMade> </Item> .....lots more Items... </Items>


-----My Current Stylesheet snippet----- <xsl:variable name="distributorVal"> <!-- only process distributorCodes if canShip and canOrder are both true --> <xsl:for-each select="//ItemAsMade/ItemsAsSold/ItemAsSold[CanOrderFlag ='true'][CanShipFlag = 'true'][not(DistributorCode = preceding::DistributorCode)]/DistributorCode"> <xsl:value-of select="."/> <xsl:text>,</xsl:text> </xsl:for-each> </xsl:variable>


---Curent results based on above code------ CAN


---Expected results--------------------- MEX,CAN,USA


---Findings-------------------- It seems that if any second <ItemAsMade> element within the <ItemsAsMade> has a 'false' value it overrides the first <ItemAsMade> even if that one is set to true, where as if either <ItemAsMade> has both the canorder and canship flags set to true then that distributor should be extracted.

---Plea for Help--------------------
PLEASE...PLEASE....can any of you UBER Gods of XSL
help me!!
I have been mucking with this for the past week and
cannot figure it out!


Thanks!!


-Rusty

Current Thread