Win a copy of Re-engineering Legacy Software this week in the Refactoring forum
or Docker in Action in the Cloud/Virtualization forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Walk distinct values in xsl key 4 at a time

 
R Lynn
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

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.
 
R Lynn
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
<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
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Right.
 
Madhav Lakkapragada
Ranch Hand
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There is a separate string element within mtpr:IT that they sort on.
 
Madhav Lakkapragada
Ranch Hand
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Great - Thanks!! And with no recursion, maybe .NET won't freeze up on me!
 
Madhav Lakkapragada
Ranch Hand
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic