 |
| 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 software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
|
|
|
|

February 17th, 2012, 05:44 PM
|
|
Authorized User
|
|
Join Date: Sep 2008
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
|
|
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>
</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 01:50 PM..
Reason: Modified requirements
|
|

February 18th, 2012, 07:12 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
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
|
|

February 21st, 2012, 01:20 PM
|
|
Authorized User
|
|
Join Date: Sep 2008
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
|
|
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?
|
|

February 21st, 2012, 01:38 PM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
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
|
|

February 21st, 2012, 01:50 PM
|
|
Authorized User
|
|
Join Date: Sep 2008
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
|
|
Sorry about that Michael. I went ahead and updated my original XSL to exlcude the use of disable-output-escaping.
|
|

February 21st, 2012, 02:26 PM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
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
|
|

February 21st, 2012, 02:43 PM
|
|
Authorized User
|
|
Join Date: Sep 2008
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
|
|
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 12:32 PM..
|
|

February 21st, 2012, 06:55 PM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
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
|
|

February 21st, 2012, 09:00 PM
|
|
Authorized User
|
|
Join Date: Sep 2008
Posts: 37
Thanks: 5
Thanked 0 Times in 0 Posts
|
|
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.
|
|

February 22nd, 2012, 05:34 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
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
|
|
 |