This week's book giveaway is in the Servlets forum.
We're giving away four copies of Murach's Java Servlets and JSP and have Joel Murach on-line!
See this thread for details.
The moose likes XML and Related Technologies and the fly likes Walk distinct values in xsl key 4 at a time Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Engineering » XML and Related Technologies
Bookmark "Walk distinct values in xsl key 4 at a time" Watch "Walk distinct values in xsl key 4 at a time" New topic
Author

Walk distinct values in xsl key 4 at a time

R Lynn
Greenhorn

Joined: Feb 12, 2004
Posts: 11
I need to process distinct occurences of an object of a specific type 4 at a time. I am having trouble getting the 2nd, 3rd and 4th values when they do not directly follow the first value in the XML. Currently I'm using:
<xsl:for-each select="//mtpr:IT[generate-id()=generate-id(key('distinct-IT',@id))][position() mod 4 = 1]">
for the outer loop, using a key that contains distinct IT values. I then attempt to get the next 3 values with:

<xsl:variable name="value2" select="following-sibling::mtpr:IT[generate-id()=generate-id(key('distinct-IT',@id))][position() = $pos + 1]/@id"/>
<xsl:variable name="value3" select="following-sibling::mtpr:IT[generate-id()=generate-id(key('distinct-IT',@id))][position() = $pos + 2]/@id"/>
<xsl:variable name="value4" select="following-sibling::mtpr:IT[generate-id()=generate-id(key('distinct-IT',@id))][position() = $pos + 3]/@id"/>
My problem seems to be that 'following-sibling' gives the instance of IT that follows directly in the XML, but sometimes the next value in the key is in a completely different location in the xml document and I get blanks for values 2-4. How do I get the next 3 key values?
Thanks!
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040

having trouble getting the 2nd, 3rd and 4th values when they do not directly follow the first value in the XML.....
My problem seems to be that 'following-sibling' gives the instance of IT that follows directly in the XML, but sometimes the next value in the key is in a completely different location in the xml document

That's the behavior of the following-sibiling. Acc to the definition:

following-sibling::chapter[position()=1] selects the next chapter sibling of the context node

So, it will always look below the context node,
in this case your context will be the node selected
in the for-each loop (assuming your for-each loop
has these variables defined
, its hard to tell from
the code you posted).
You might want to replace the following-sibiling
with //, which corresponds to for-each.
This will enable the parser to look in the entire document
rather than the sibilings of the context node and to quote

//para selects all the para descendants of the document root and thus selects all para elements in the same document as the context node

This way you are searching all the nodes.
Hope this helps.


Take a Minute, Donate an Hour, Change a Life
http://www.ashanet.org/workanhour/2006/?r=Javaranch_ML&a=81
R Lynn
Greenhorn

Joined: Feb 12, 2004
Posts: 11
Thanks for your reply.
I tried // (among other things) and get duplicates (the same item could exist in many places.) I was able to get a distinct list using recursion, but I can't sort (no for-each or apply-templates) and when I left my Xalan test environment and went into the .NET production environment, the application hung.
Here's a little more code (slightly modified from before with the latest I tried (BTW, I'm creating a table):
<xsl:key name="distinct-IT" match="//mtpr:IT" use="@id"/>
...
<xsl:for-each select="//mtpr:IT[generate-id()=generate-id(key('distinct-IT',@id))][position() mod 4 = 1]">

<xsl:variable name="pos" select="position()"/>
<xsl:variable name="value1" select="@id"/>

...
<xsl:variable name="value2" select="key('distinct-IT', //mtpr:IT/@id)[$pos + 1]/@id"/>
<xsl:variable name="value3" select="key('distinct-IT', //mtpr:IT/@id)[$pos + 2]/@id"/>
<xsl:variable name="value4" select="key('distinct-IT', //mtpr:IT/@id)[$pos + 3]/@id"/>
<xsl:message>
<xsl:value-of select="$value1"/> is value1, <xsl:value-of select="$value2"/> is value2,
<xsl:value-of select="$value3"/> is value3, <xsl:value-of select="$value4"/> is value4
</xsl:message>
...

<!-- Call template to populate all CT rows for the preceding 4 ITs. -->
<xsl:call-template name="generateRows">
<xsl:with-param name="value1"><xsl:value-of select="$value1"/></xsl:with-param>
<xsl:with-param name="value2"><xsl:value-of select="$value2"/></xsl:with-param>
<xsl:with-param name="value3"><xsl:value-of select="$value3"/></xsl:with-param>
<xsl:with-param name="value4"><xsl:value-of select="$value4"/></xsl:with-param>
</xsl:call-template>

...
</xsl:for-each>
Thanks!
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
<xsl:for-each select="//mtpr:IT[generate-id()=generate-id(key('distinct-IT',@id))][position() mod 4 = 1]">
<xsl:variable name="pos" select="position()"/>
<xsl:variable name="value1" select="@id"/>

Could you please explain what you are selecting in the for-each
stmt above. Also, what is the context element for the for-each ?
I have written a lot of recursive templates and am really curious.
I agree that the for-each isn't helpful in a lot of situations.
R Lynn
Greenhorn

Joined: Feb 12, 2004
Posts: 11
I am trying to select every 4th (mtpr:IT) element in the key, which is a distinct list of mtpr:IT elements, starting with the first element in the list. I'm sitting on the root node when I make the call (not sure exactly what you mean by 'context-element.) From that element, I am tryint to get the next 3 mtpr:IT elements in the key.
I could use a different type of solution if this is not solvable in XSLT: I am also putting together the xml/schema, so I could include in it a list of distinct mtpr:IT elements there then just walk the list for my table header. Even using the for-each, .NET takes a really long time to process this stylesheet, and this is just one small part of the transformation I will be needing to create.
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
Ok, that clarifies. It is very much solvable in XSLT.
Give me sometime, I will post something. Stay tuned....
Here you go, something that I would do -
Input -

Style Sheet -

The output -

Hope this helps.
- m
[ March 11, 2004: Message edited by: Madhav Lakkapragada ]
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
This is my way of getting around these problems.
If someone can suggest a better solution, please
let me know so I can fix my sytle sheets.
Thanks.
R Lynn
Greenhorn

Joined: Feb 12, 2004
Posts: 11
Thanks!! I'll try this out.
I will make some changes to your sample xml though (still need results like the ones you got from the first xml sample):
<?xml version="1.0"?><!-- edited with XMLSPY v5 U (http://www.xmlspy.com) by Madhav Lakkapragada --><mtpr oc xmlns:mtpr="http://www.RLynn.com/">
<mtpr bject>
<mtpr:CT>
<mtpr:IT id="id1"/>
<mtpr:IT id="id6"/>
</mtpr:CT>
<mtpr:CT>
<mtpr:IT id="id10"/>
<mtpr:IT id="id4"/>
<mtpr:IT id="id7">
<mtpr:subIT>
<mtpr:IT id="id2"/>
<mtpr:IT id="id7"/>
</mtpr:subIT>
</mtpr:IT>
<mtpr:IT id="id8">
<mtpr:subIT>
<mtpr:IT id="id9"/>
</mtpr:subIT>
</mtpr:IT>
</mtpr:CT>
<mtpr:CT>
<mtpr:IT id="id3"/>
<mtpr:IT id="id1"/>
<mtpr:IT id="id8"/>
</mtpr:CT>
</mtpr bject>
</mtpr oc>
The results compare CTs to ITs.
[ March 11, 2004: Message edited by: Ernest Friedman-Hill ]
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
But, earlier you said the IT elements come in a 4-pack
and you need to select them. In the example above you have
IT elements which are in bundles of 2, 3, etc.
So which 4 IT elements are in order.
- m
ps:
You might not have said it, but that I thought.
[ March 11, 2004: Message edited by: Madhav Lakkapragada ]
R Lynn
Greenhorn

Joined: Feb 12, 2004
Posts: 11
They don't start out in groups of 4, but I need to end up with them in groups of 4 and no values repeating (and sorted.) The reason for the groups of 4 is that my table will only fit 4 of them in 1 row, and I need to make a new table for the next 4...
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
hmmm...that's interesting.
A different set of requirements.............
Need more coffee and some more time.
Also, its possible that there are only 10 IT elements
rather than 8 or 12 (something divisible by 4), right ?
(as in your modified example above).
- m
[ March 11, 2004: Message edited by: Madhav Lakkapragada ]
R Lynn
Greenhorn

Joined: Feb 12, 2004
Posts: 11
Right.
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
I need to end up with them in groups of 4 and no values repeating (and sorted.)
Also, sorted based on what, the id attribute value or do you have another interger attribute ?
- m
R Lynn
Greenhorn

Joined: Feb 12, 2004
Posts: 11
There is a separate string element within mtpr:IT that they sort on.
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
Groups of four and sorting was easy and straigh forward.
Really stumped on the duplicate thingy...........and then
if and when we remove the Dups, groups of four will be
out-of-wack. (?Egg or Chicken?)
I surely can appreciate the challenge in the problem, but
the solution is tricky. Let me on these thoughts...maybe the
dream fairy will tell me something(!)
Later...........
- m
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
I didn't get a chance to complete this assignment but
got it to a stage almost there.....
TODO: Need to break it up into groups of four.
Style sheet -

Output -

Hope this helps...............
R Lynn
Greenhorn

Joined: Feb 12, 2004
Posts: 11
Great - Thanks!! And with no recursion, maybe .NET won't freeze up on me!
Madhav Lakkapragada
Ranch Hand

Joined: Jun 03, 2000
Posts: 5040
Actually, I still favor recursion inorder to break it up into
groups of four. We know we have 9 distince IT elements. Then we
know that we sorted them and their positions are in sequential
order. We do need to combine that info and write some logic to
break it up into groups of four.
But, right now, my head hurts and so wanted to take a break.
- m
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Walk distinct values in xsl key 4 at a time
 
Similar Threads
XSL 2.0 (looking for ideas)
need to generate some numbers using loop, the number of times condition met
Remove sibling elements according to the value of the attribute of another element
Getting Last sibling that had an attribute value
XSL question: position() strangeness