Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Go Back   Wrox Programmer Forums > XML > XSLT
Password Reminder
Register
Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developersí questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old February 17th, 2012, 04:44 PM
Authorized User
Points: 153, Level: 3
Points: 153, Level: 3 Points: 153, Level: 3 Points: 153, Level: 3
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Sep 2008
Location: , , .
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
Default XSLT sorting issue?

XSLT: 1.0

XML:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <sub-root>
        <vps>
            <run y="34" t="1"/>
                 <name value="bob"/>
                 <name-id id="5435"/>
             </run>
             <run y="46" t="4"/>
                 <name value="jim"/>
                 <name-id id="9425"/>
              </run>
              <run y="27" t="0"/>
                 <name value="steve"/>
                 <name-id id="7725"/>
              </run>
              <pass y="122" t="0">
                <name value="tim"/>
                 <name-id id="9905"/>
              </pass>
             <receive y="322" t="1">
                <name value="greg"/>
                 <name-id id="1205"/>
              </receive >
        </vps>
       <hps>
             <run y="56" t="1"/>
                 <name value="steve"/>
                 <name-id id="9425"/>
              </run>
              <run y="47" t="0"/>
                 <name value="carl"/>
                 <name-id id="7715"/>
              </run>
              <pass y="132" t="0">
                <name value="drew"/>
                 <name-id id="9988"/>
              </pass>
              <pass y="500" t="1">
                <name value="mike"/>
                 <name-id id="1115"/>
              </pass>
             <receive y="34" t="1">
                 <name value="greg"/>
                 <name-id id="1885"/>
              </receive >
        </hps>
  </sub-root>
</root>
XML Details:
Assume every name-id attribute value is unique.

Details regarding desired output:
I'm trying to copy the content of the XML and then at the bottom, I'm trying to sort the data set to retrieve the top three values based on the following sort value: (run/@y * 1 + run/@t * 50 + pass/@y * .5 + pass/@t * 5 + receive/@y * .5 + receive/@t * 5) in descending order.

I want to the output displayed in the following format at the bottom of the file:
<rank position="" name="" id="" y="" t=""/>

Desired Output:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <sub-root>
        <vps>
            <run y="34" t="1"/>
                 <name value="bob"/>
                 <name-id id="5435"/>
             </run>
             <run y="46" t="4"/>
                 <name value="jim"/>
                 <name-id id="9425"/>
              </run>
              <run y="27" t="0"/>
                 <name value="steve"/>
                 <name-id id="7725"/>
              </run>
              <pass y="122" t="0">
                <name value="tim"/>
                 <name-id id="9905"/>
              </pass>
             <receive y="322" t="1">
                <name value="greg"/>
                 <name-id id="1205"/>
              </receive >
        </vps>
       <hps>
             <run y="56" t="1"/>
                 <name value="steve"/>
                 <name-id id="9425"/>
              </run>
              <run y="47" t="0"/>
                 <name value="carl"/>
                 <name-id id="7715"/>
              </run>
              <pass y="132" t="0">
                <name value="drew"/>
                 <name-id id="9988"/>
              </pass>
              <pass y="500" t="1">
                <name value="mike"/>
                 <name-id id="1115"/>
              </pass>
             <receive y="34" t="1">
                 <name value="greg"/>
                 <name-id id="1885"/>
              </receive >
        </hps>
       <rank position="1" player-id="1115" name="mike" run-y="" run-t="" pass-y="500" pass-t="1" receive-y="" receive-t=""/>
       <rank position="2" player-id="1205" name="greg" run-y="" run-t="" pass-y="" pass-t="" receive-y="322" receive-t="1"/>
       <rank position="3" player-id="9425" name="jim" run-y="46" run-t="4" pass-y="" pass-t="" receive-y="" receive-t=""/>
 </sub-root>
</root>
This is what I have in the XSL so far, but it doesn't seem to be working:
Code:
<!DOCTYPE xsl:stylesheet 
[<!ENTITY newline "<xsl:text>&#xA;</xsl:text>">
]>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template>
<outputfile>TEST.XML</outputfile>
<root>
<apply-template select="//sub-root"/>
</root>
</xsl:template>

<xsl:template match="sub-root">
<xsl:copy-of select="current()/vps"/>
<xsl:copy-of select ="current()/hps"/>
<xsl:call-template name="RankRecord"/>
</xsl:template>

<xsl:template  name="RankRecord">
	<xsl:for-each select="//sub-root/*/*">
		<xsl:sort select="(run/@y * 1 + run/@t * 10 + pass/@y * .5 + pass/@t * 5 + receive/@y * .5 + receive/@t * 5)" data-type="number" order="descending"/>
			<xsl:if test="position()=1 or position()=2 or position()=3">					
					<xsl:variable name="nCode" select="name-id/@id"/>
					<xsl:variable name="name"  select="name/@value"/>
					<xsl:variable name="ry"  select="run/@y"/>
					<xsl:variable name="rt"  select="run/@t"/>
					<xsl:variable name="py"  select="pass/@y"/>
					<xsl:variable name="pt"  select="pass/@t"/>
					<xsl:variable name="recy"  select="receive/@y"/>
					<xsl:variable name="rect"  select="receive/@t"/>
					<top-player rank="{position()}" id="{$nCode}" first="{name}" pass-yards="{$py}" pass-tds="{$pt}" rush-yards="{$ry}" rush-tds="{$rt}" rec-yards="{$recy}" rec-tds="{$recy}"/>&newline;
			</xsl:if>
	</xsl:for-each> 
</xsl:template>
</xsl:stylesheet>

Last edited by vb89; February 21st, 2012 at 12:50 PM. Reason: Modified requirements
Reply With Quote
  #2 (permalink)  
Old February 18th, 2012, 06:12 AM
mhkay's Avatar
Wrox Author
Points: 17,773, Level: 58
Points: 17,773, Level: 58 Points: 17,773, Level: 58 Points: 17,773, Level: 58
Activity: 8%
Activity: 8% Activity: 8% Activity: 8%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,839
Thanks: 0
Thanked 267 Times in 262 Posts
Default

Let's just pick out a few things that are wrong with your code.

* Don't try to generate an XML declaration by hand, leave it to the serializer. The serializer knows what encoding it is using, you don't.

* Worse still, don't try to output <rank> elements using text nodes with disable-output-escaping. This is just horrible and quite unnecessary.

* You appear to use an entity reference & newline that hasn't been declared.

* The line
Code:
<xsl:for-each: //sub-root/*>
isn't well-formed XML

* There's a lot of redundant code, for example the expression current()/@x is just a long-winded way of writing @x. This kind of code suggests what I call "magic fairy dust" programming - "I don't know what it means but I've seen it used and perhaps it will make it work". If you're in that position, stop coding and do some reading.

* Please don't tell us that code "doesn't seem to be working". Tell us how it fails.

If the line that isn't well-formed actually reads xsl:for-each select="sub-root/*", then it's wrong: it should be sub-root/*/*.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
Reply With Quote
  #3 (permalink)  
Old February 21st, 2012, 12:20 PM
Authorized User
Points: 153, Level: 3
Points: 153, Level: 3 Points: 153, Level: 3 Points: 153, Level: 3
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Sep 2008
Location: , , .
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
Default

Michael,
Thank you for your reply. I actually slightly modified my requirement -- I've emboldened the changes in the original post. What I changed was the logic used in the sort. Instead of just sorting based off of this:
(@y + @t )
I wanted to sort based off of this:
(run/@y * 1 + run/@t * 50 + pass/@y * .5 + pass/@t * 5 + receive/@y * .5 + receive/@t * 5)

I attempted to modify the XSL -- the XSL in my original post reflects my changes -- but unfortunately, my output currently look like this:

Code:
<?xml version="1.0" encoding="utf-8"?>
...  <!-- original nodes are successfully copied here -->
<rank position="1" player-id="5435" name="bob" run-y="" run-t="" pass-y="" pass-t="" receive-y="" receive-t=""/>
<rank position="2" player-id="9425" name="jim" run-y="" run-t="" pass-y="" pass-t="" receive-y="" receive-t=""/>
<rank position="3" player-id="7725" name="steve" run-y="" run-t="" pass-y="" pass-t="" receive-y="" receive-t=""/>
I want the bottom of the file to display the following:

Code:
...
<rank position="1" player-id="1115" name="mike" run-y="" run-t="" pass-y="500" pass-t="1" receive-y="" receive-t=""/>
<rank position="2" player-id="1205" name="greg" run-y="" run-t="" pass-y="" pass-t="" receive-y="322" receive-t="1"/>
<rank position="3" player-id="9425" name="jim" run-y="46" run-t="4" pass-y="" pass-t="" receive-y="" receive-t=""/>
It basically just gives me the order of the first three nodes in the XML. Any thoughts on what I'm doing wrong here?
Reply With Quote
  #4 (permalink)  
Old February 21st, 2012, 12:38 PM
mhkay's Avatar
Wrox Author
Points: 17,773, Level: 58
Points: 17,773, Level: 58 Points: 17,773, Level: 58 Points: 17,773, Level: 58
Activity: 8%
Activity: 8% Activity: 8% Activity: 8%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,839
Thanks: 0
Thanked 267 Times in 262 Posts
Default

Please get rid of all that disable-output-escaping. This simply isn't a way of writing XSLT code that I'm capable of debugging. XSLT is designed to help you produce a result tree containing element and attribute nodes, not to write your own home-grown serializer.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
Reply With Quote
  #5 (permalink)  
Old February 21st, 2012, 12:50 PM
Authorized User
Points: 153, Level: 3
Points: 153, Level: 3 Points: 153, Level: 3 Points: 153, Level: 3
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Sep 2008
Location: , , .
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
Default

Sorry about that Michael. I went ahead and updated my original XSL to exlcude the use of disable-output-escaping.
Reply With Quote
  #6 (permalink)  
Old February 21st, 2012, 01:26 PM
mhkay's Avatar
Wrox Author
Points: 17,773, Level: 58
Points: 17,773, Level: 58 Points: 17,773, Level: 58 Points: 17,773, Level: 58
Activity: 8%
Activity: 8% Activity: 8% Activity: 8%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,839
Thanks: 0
Thanked 267 Times in 262 Posts
Default

You are sorting //sub-root/*/* which selects elements such as run, pass etc, but then you are selecting things like run/@y. If you're positioned on a run element then run/@y looks for a child called run, which doesn't exist.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
Reply With Quote
  #7 (permalink)  
Old February 21st, 2012, 01:43 PM
Authorized User
Points: 153, Level: 3
Points: 153, Level: 3 Points: 153, Level: 3 Points: 153, Level: 3
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Sep 2008
Location: , , .
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
Default

Yeah, that makes sense.
I went ahead and tried adding the parent node in the sort. So something like this:
Code:
(../run/@y * 1 + ../run/@t * 50 + ../pass/@y * .5 + ../pass/@t * 5 + ../receive/@y * .5 + ../receive/@t * 5)
That caused the new file to return empty values for each "top-player" attribute. (e.g., pass-yards, pass-tds, etc).

Now, if I change my for-each statement to this:
Code:
<xsl:for-each: //sub-root/*>
And subsequently, I update the nCode and name variables to this:
Code:
<xsl:variable name="nCode" select="*/name-id/@id"/>
<xsl:variable name="name"  select="*/name/@value"/>
I only get two results in the output which just grab the highest hps and vps attribute values for each variable. So it looks like this:
Code:
<rank position="1" id="5435" first="" pass-yards="122" pass-tds="0" rush-yards="34" rush-tds="1" rec-yards="322" rec-tds="322"/>
<rank position="2" id="9425" first="" pass-yards="132" pass-tds="0" rush-yards="56" rush-tds="1" rec-yards="34" rec-tds="34"/>
Which is clearly wrong as well.

I'm really out of ideas at this point. The only other thought that I had is that I could somehow incorporate predicates here, but I'm not really sure how they would apply within the context of my current XSL. Any hints or suggestions would be greatly appreciated.

Last edited by vb89; February 22nd, 2012 at 11:32 AM.
Reply With Quote
  #8 (permalink)  
Old February 21st, 2012, 05:55 PM
mhkay's Avatar
Wrox Author
Points: 17,773, Level: 58
Points: 17,773, Level: 58 Points: 17,773, Level: 58 Points: 17,773, Level: 58
Activity: 8%
Activity: 8% Activity: 8% Activity: 8%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,839
Thanks: 0
Thanked 267 Times in 262 Posts
Default

I think there's a basic problem here, which is that I don't understand your data. I suspect it relates to events in a sport with which I am unfamiliar. Without that understanding, it's very hard to work out what you are trying to do, or to help you achieve it.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
Reply With Quote
  #9 (permalink)  
Old February 21st, 2012, 08:00 PM
Authorized User
Points: 153, Level: 3
Points: 153, Level: 3 Points: 153, Level: 3 Points: 153, Level: 3
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Sep 2008
Location: , , .
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
Default

Hey Michael,
I can understand your concern regarding being unfamiliar with the data content in my XML. But for the sake of this example --from strictly a logical perspective--, do you think you could help me retrieve the desired result?

Code:
<rank position="1" player-id="1115" name="mike" run-y="" run-t="" pass-y="500" pass-t="1" receive-y="" receive-t=""/>
<rank position="2" player-id="1205" name="greg" run-y="" run-t="" pass-y="" pass-t="" receive-y="322" receive-t="1"/>
<rank position="3" player-id="9425" name="jim" run-y="46" run-t="4" pass-y="" pass-t="" receive-y="" receive-t=""/>
While using the following "formula" as the sort logic:
Code:
(run/@y * 1 + run/@t * 50 + pass/@y * .5 + pass/@t * 5 + receive/@y * .5 + receive/@t * 5)
If not understanding the data is preventing you from being able to reproduce my desired output, I completely understand. Thanks either way.
Reply With Quote
  #10 (permalink)  
Old February 22nd, 2012, 04:34 AM
mhkay's Avatar
Wrox Author
Points: 17,773, Level: 58
Points: 17,773, Level: 58 Points: 17,773, Level: 58 Points: 17,773, Level: 58
Activity: 8%
Activity: 8% Activity: 8% Activity: 8%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,839
Thanks: 0
Thanked 267 Times in 262 Posts
Default

I don't understand what the objects are that you are sorting (players?) and how they are represented in the source. Hence confusion over what the sorting xsl:for-each is actually iterating over.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
Simple sorting issue dcschafer XSLT 1 August 4th, 2009 07:45 AM
sorting issue nguna XSLT 3 July 28th, 2009 07:45 AM
sorting issue JohnBampton XSLT 10 February 23rd, 2009 07:13 AM
sorting issue moin.khan Struts 0 June 21st, 2007 09:37 AM
Sorting in XSLT hchaudh1 XSLT 1 November 30th, 2005 04:37 AM



All times are GMT -4. The time now is 01:24 AM.


Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.