This question follows on from query XSLT: Sorting based on sum of values from other nodes
I have this piece of xslt (thanks to Demitre) which I've modified to receive a parameter 'Gait' which can have values 'P' (Pace), 'T' (Trot) or 'A' (All):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kOffspring" match="Horse" use="SireID"/>
<xsl:param name="Gait"/>
<xsl:template match="/*">
<xsl:apply-templates select="Sires/Sire">
<xsl:sort select="sum(key('kOffspring', ID)/*/Stakes)"
data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Sire">
Sire <xsl:value-of select="concat(ID,' (', Name, ') Stakes: ')"/>
<xsl:value-of select="sum(key('kOffspring', ID)/*/Stakes)"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
In the above code is this piece
sum(key('kOffspring', ID)/*/Stakes
Is there a way to substitute the asterisk part with the name of a node in xml tree depending on what value was passed in for gait?
Super simplified xml is:
<t>
<Horses>
<Horse>
<ID>5</ID>
<Name>hrsE</Name>
<SireID>101</SireID>
<Pace>
<Stakes>100</Stakes>
</Pace>
<Trot>
<Stakes>300</Stakes>
</Trot>
</Horse>
</Horses>
<Sires>
<Sire>
<ID>101</ID>
<Name>srA</Name>
<LiveFoalsALL>117</LiveFoalsALL>
</Sire>
</Sires>
</t>
When $Gait is 'A' I want sum(key('kOffspring', ID)/*/Stakes (look in all sub-nodes of Horse)
When $Gait is 'P' I want sum(key('kOffspring', ID)/Pace/Stakes (look in the Pace node only to find Stakes)
When $Gait is 'T' I want sum(key('kOffspring', ID)/Trot/Stakes (look in the Trot node only to find Stakes)
So this is super-simplified example. I'm trying to stop having to duplicate hundred lines of code to cater to different values of $Gait. I played around trying use variables but couldn't see how to change the value of the node path when it is using a key in the path. I saw I could potentially use a choose statement in the 'match="/*"' template but that was only for sorting, I was still stuck when I got to the 'Sire' template - didn't want to have to put 'choose' around all the multitude of 'value-of select' statements I have.
Thanks for any suggestions.
Regards,
Bryce Stenberg.
Just use
sum(key('kOffspring', ID)/*[name()=$Gait]/Stakes
<xsl:value-of select="sum(key('kOffspring', ID)/*/Stakes)" />
Is there a way to substitute the asterisk part with the name of a node
in xml tree depending on what value was passed in for gait?
Yes... one way would be to have a "switch statement" inside the XPath expression:
sum(key('kOffspring', ID)/*[
$Gait = 'A' or
(local-name() = (if ($Gait = 'P') then 'Pace' else
if ($Gait = 'T') then 'Trot'))
]/Stakes)
Alternatively, you could write three different versions of the <xsl:value-of>, one for each possible value of $Gait, and use <xsl:choose> to choose which one to use:
<xsl:choose>
<xsl:when test="$Gait = 'A'">
<xsl:value-of select="sum(key('kOffspring', ID)/*/Stakes)" />
</xsl:when>
<xsl:when test="$Gait = 'P'">
<xsl:value-of select="sum(key('kOffspring', ID)/Pace/Stakes)" />
</xsl:when>
etc.
The <xsl:choose> seems more readable to me, and might be more efficient, depending on the processor; but it's largely a matter of preference.
Related
I do a XSLT to HTML transformation using the method recommended in Qt doc:
QXmlQuery query(QXmlQuery::XSLT20);
query.setFocus(QUrl("myInput.xml"));
query.setQuery(QUrl("myStylesheet.xsl"));
query.evaluateTo(out);
Inside XSLT I use generate-id() method to generate unique ids for different DIV blocks. It works perfectly in Qt4.8, but not in Qt5.4
¿Anyone knows a reason for that, and how to solve this?
Edit: I get no error. What I get in Qt5 is always the same ID, while in Qt4 I get a different, unique ID each time i call generate-id().
I generate the ID this way:
<xsl:variable name="tc_id" select="generate-id()"/>
And I use it this way:
<xsl:value-of select="$tc_id"/>
This is the cpp code doing the transformation:
// generate output string
QXmlQuery query(QXmlQuery::XSLT20);
QString output;
query.setFocus(QUrl(_final_output_filepath.c_str()));
query.setQuery(xslt_code.c_str());
query.evaluateTo(&output);
Edit 2:
When I use this code...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:template match="/">
<xsl:for-each select="trial/testsuite">
<xsl:for-each select="testcase">
<xsl:variable name="tc_index" select="position()"/>
<xsl:variable name="tc_id" select="generate-id(.)"/>
<xsl:value-of select="$tc_id"/>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
...I get always the same ID.
<xsl:template match="/">
<xsl:value-of select="generate-id()"/> --
<xsl:value-of select="generate-id()"/> --
<xsl:value-of select="generate-id()"/>
Thanks for the snippet. This was indeed why I kept bugging you about giving a reproducible example.
What happens here is that you call the generate-id() function multiple times without changing the context node. The default argument for this function is the context node (here: /, or the root node).
Unless you change the context node, this function is deliberately designed to be stable. That means that, if called repeatedly with the same argument (also meaning: the same default argument, the same context), it must return the same string.
It is also designed such that it always returns a unique string per distinct node. Two nodes are distinct if they have different position in the document (i.e., they are distinct even if they look the same, but appear on multiple places).
Bottom line: you didn't hit a bug in the Qt implementation of XSLT 2.0, but you hit a resolved issue that was a bug and was incidentally used as a feature.
If you require a unique ID in XSLT 2.0, and you are bound to giving the same context, there is probably something else that changes: for instance, you can be in a loop going over a set of numbers or strings. You can use this info to create a unique string.
Another "hack" in XSLT 2.0 is to use a single point in the specification where determinism is not guaranteed: on creation of new nodes:
<xsl:function name="my:gen-id" as="xs:string">
<xsl:sequence select="generate-id(my:gen-id-getnode())" />
</xsl:function>
<xsl:function name="my:gen-id-getnode" as="element()">
<node />
</xsl:function>
This small function touches on some advanced concepts and recently, people discussing in the XSL Working Group, have agreed that optimizing away the creation of the new node is allowed if the node identity is not required. Whether or not a processor correctly detects this is unclear.
In XSLT 3.0 a new property has been introduced on xsl:function: #new-each-time, which informs the processor that the function should be evaluated each time and not get inlined.
Update: tests with Qt 5.5 or 5.4
I have tested a variant of your code with Qt because I couldn't believe that identity (which is a core concept of XSLT) doesn't work with it. So, I created a document with similar-looking nodes of all six types (I ignored namespace nodes, as support for it is optional).
Input test document
<root test="bla">
<?pi do-something ?>
<row></row>
<!-- comment here -->
<row>content</row>
<row>content</row>
<row id="bla" xml:id="bla">content</row>
</root>
XSLT 2.0 code
Code slightly adjusted due to Qt not supporting #separator correctly.
<xsl:stylesheet
xmlns:my="my-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:value-of select="string-join(
('gen-id(',
my:decorate(.), '[', my:depth(.), ']', ') = ', generate-id(.),
'
'), '')" />
<xsl:apply-templates select="#*|node()" />
</xsl:template>
<!-- remove prev. and use this if you think for-each is different -->
<!--xsl:template match="/">
<xsl:for-each select="//node() | //#*">
<xsl:value-of select="string-join(
('gen-id(',
my:decorate(.), '[', my:depth(.), ']', ') = ', generate-id(.),
'
'), '')" />
</xsl:for-each>
</xsl:template-->
<xsl:function name="my:depth" as="xs:string">
<xsl:param name="node" />
<xsl:sequence select="
string(count($node/(/)//node()[$node >> .]) + 1)" />
</xsl:function>
<xsl:function name="my:decorate">
<xsl:param name="node" />
<xsl:sequence select="
($node/self::text(), 'text')[2],
($node/self::element(), concat('Q{}', name($node)))[2],
($node/self::document-node(), 'document')[2],
($node/self::comment(), 'comment')[2],
($node/self::attribute(), concat('#', name($node)))[2],
($node/self::processing-instruction(), 'processing-instruction')[2]
" />
</xsl:function>
</xsl:stylesheet>
Output using Exselt
gen-id(Q{}root[1]) = x1e2
gen-id(#test[2]) = x1e2a0
gen-id(processing-instruction[2]) = x1p3
gen-id(Q{}row[3]) = x1e4
gen-id(comment[4]) = x1c5
gen-id(Q{}row[5]) = x1e6
gen-id(text[6]) = x1t7
gen-id(Q{}row[7]) = x1e8
gen-id(text[8]) = x1t9
gen-id(Q{}row[9]) = x1e10
gen-id(#id[10]) = x1e10a0
gen-id(#xml:id[10]) = x1e10a1
gen-id(text[10]) = x1t11
Output using Qt 5.5 or 5.4
I used the pre-build xmlpatterns.exe and called it as xmlpatterns test.xsl input.xml, but its code uses the same libraries you are using:
gen-id(Q{}root[1]) = T756525610
gen-id(#test[2]) = T756525620
gen-id(text[2]) = T756525630
gen-id(processing-instruction[3]) = T756525640
gen-id(text[4]) = T756525650
gen-id(Q{}row[5]) = T756525660
gen-id(text[6]) = T756525670
gen-id(comment[7]) = T756525680
gen-id(text[8]) = T756525690
gen-id(Q{}row[9]) = T7565256100
gen-id(text[10]) = T7565256110
gen-id(text[11]) = T7565256120
gen-id(Q{}row[12]) = T7565256130
gen-id(text[13]) = T7565256140
gen-id(text[14]) = T7565256150
gen-id(Q{}row[15]) = T7565256160
gen-id(#id[16]) = T7565256170
gen-id(#xml:id[16]) = T7565256180
gen-id(text[16]) = T7565256190
gen-id(text[17]) = T7565256200
As this shows, stripping space does not work with Qt, as it considers them text nodes. But as you can also see, the generate-id function works for each and every node, whether they are processing instructions, text nodes, look the same, are empty elements etc. It didn't matter whether:
Using generate-id() vs generate-id(.)
Putting it in xsl:for-each or normal template processing
Using a variable to store the result prior to using
Hiding generate-id() inside another function
All returned the same, valid result.
UPDATE: Workaround
There's a relative expensive, yet workable workaround that you may be able to use, assuming that the generated ID in itself must be unique per document and node, but is not used in another way then for uniqueness (for instance, if used for cross-references, this will work).
<xsl:variable name="doc" select=".//node()" />
<xsl:function name="my:gen-id" as="xs:integer">
<xsl:param name="elem" as="node()" />
<xsl:sequence select="
for $i in 1 to count($doc)
return if($doc[$i] is $elem then $i else ())" />
</xsl:function>
This obviously has a performance hit, but if your documents are not that big and/or you do not call this function too often, it should be ok. You may consider creating a key if the subset for which you need this is defined.
A call to generate-id() returns a generated id of the context node and of course, if the context does not change, you will always get the same value.
I found out a solution for this problem. It seems to be some differences between Qt4 and Qt5 XSLT transformation engine in Linux.
The following code worked fine in Qt4, but not in Qt5. tc_id has always the same value:
<xsl:for-each select="testcase">
<xsl:choose>
<xsl:when test="#result != 'pass'">
<xsl:variable name="tc_id" select="generate-id(.)"/>
<xsl:attribute name="onClick">
ExpandCollapse('<xsl:value-of select="$tc_id"/>');
</xsl:attribute>
<div style="display:none">
<xsl:attribute name="id"><xsl:value-of select="$tc_id"/></xsl:attribute>
</div>
</xsl:when>
<xsl:otherwise>
...
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
And the following code works fine both in Qt4 and Qt5:
<xsl:for-each select="testcase">
<xsl:choose>
<xsl:when test="#result != 'pass'">
<xsl:attribute name="onClick">
ExpandCollapse('<xsl:value-of select="generate-id(.)"/>');
</xsl:attribute>
<div style="display:none">
<xsl:attribute name="id"><xsl:value-of select="generate-id(.)"/></xsl:attribute>
</div>
</xsl:when>
<xsl:otherwise>
...
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
It seems there is some problem with declaring the variable.
I have following xml
<xml>
<xref>
is determined “in prescribed manner”
</xref>
</xml>
I want to see if we can process xslt 2 and return the following result
<xml>
<xref>
is
</xref>
<xref>
determined
</xref>
<xref>
“in prescribed manner”
</xref>
</xml>
I tried few options like replace the space and entities and then using for-each loop but not able to work it out. May be we can use tokenize function of xslt 2.0 but don't know how to use it. Any hint will be helpful.
# JimGarrison: Sorry, I couldn't resist. :-) This XSLT is definitely not elegant but it does (I assume) most of the job:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:variable name="left_quote" select="'<'"/>
<xsl:variable name="right_quote" select="'>'"/>
<xsl:template name="protected_tokenize">
<xsl:param name="string"/>
<xsl:variable name="pattern" select="concat('^([^', $left_quote, ']+)(', $left_quote, '[^', $right_quote, ']*', $right_quote,')?(.*)')"/>
<xsl:analyze-string select="$string" regex="{$pattern}">
<xsl:matching-substring>
<!-- Handle the prefix of the string up to the first opening quote by "normal" tokenizing. -->
<xsl:variable name="prefix" select="concat(' ', normalize-space(regex-group(1)))"/>
<xsl:for-each select="tokenize(normalize-space($prefix), ' ')">
<xref>
<xsl:value-of select="."/>
</xref>
</xsl:for-each>
<!-- Handle the text between the quotes by simply passing it through. -->
<xsl:variable name="protected_token" select="normalize-space(regex-group(2))"/>
<xsl:if test="$protected_token != ''">
<xref>
<xsl:value-of select="$protected_token"/>
</xref>
</xsl:if>
<!-- Handle the suffix of the string. This part may contained protected tokens again. So we do it recursively. -->
<xsl:variable name="suffix" select="normalize-space(regex-group(3))"/>
<xsl:if test="$suffix != ''">
<xsl:call-template name="protected_tokenize">
<xsl:with-param name="string" select="$suffix"/>
</xsl:call-template>
</xsl:if>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
<xsl:template match="*|#*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="xref">
<xsl:call-template name="protected_tokenize">
<xsl:with-param name="string" select="text()"/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
Notes:
There is the general assumption that white space only serves as a token delimiter and need not be preserved.
“ and rdquo; seem to be invalid in XML although they are valid in HTML. In the XSLT there are variables defined holding the quote characters. They will have to be adapted once you find the right XML representation. You can also eliminate the variables and put the characters right into the regular expression pattern. It will be significantly simplified by this.
<xsl:analyze-string> does not allow a regular expression which may evaluate into an empty string. This comes as a little problem since either the prefix and/or the proteced token and/or the suffix may be empty. I take care of this by artificially adding a space at the beginning of the pattern which allows me to search for the prefix using + (at least one occurence) instead of * (zero or more occurences).
What I want to do is given an element as context, I want to determine if it has a child with a given name and determine if that child has a node with a given name so I can do operations with it. It is important that I do this in XPath 1.0 syntax.
The code that I've gotten so far is this.
<xsl:for-each select="child::*">
<xsl:if test="contains(name(), 'description')">
<xsl:for-each select="child::*">
<xsl:if test="contains(name(), 'text')">
<xsl:value-of select="node()"/>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
It works, but it's big and ugly and I know that there's a way to condense it. The for-eachs there are unnecessary, since I'm only expecting one child node to be named description, and for it to only have one text node.
I feel like this solution should work
<xsl:for-each select="./description/text">
..
</xsl:for-each>
But it isn't, and I'm not really good enough with XPath Syntax to know why.
The reason I'm asking is because though I've found answers that detect whether a child node has a name, and I've found answers that can get to that child node's context, I haven't found an answer that combines the two, though maybe I just haven't been searching hard enough, in which case I apologize.
Edit: Woops, sorry yeah I forgot to mention that the contains() part of the code was also just a hack because I wasn't sure how to compare their values with equality.
Also as long as the answer is there, <xsl:for-each select="description/text"> does not work either.
A sample of the XML in question is this
<leaf>
<description>
<text> Various Words
</text>
</description>
</leaf>
where the context is the leaf and I am trying to get to the text node.
Edit: The Second Coming:
The problem for me was that my XSLT file was using a default namespace (in my case named a). If I had added that then Borodin's answer would have been correct.
To be specific, this is the code which ended up working for me in the end, in case anyone wants to know.
<xsl:for-each select="a:description/a:text>
<xsl:value-of select="node()"/>
</xsl:for-each>
Thanks Guys ^-^
Do you really want to check whether the element names contain those strings? Or, as your narrative says, do you want elements with that exact name?
To do something like what you have already written, use
<xsl:for-each select="*[contains(name(), 'description')]/*[contains(name(), 'text')]">
<xsl:value-of select="node()"/>
</xsl:for-each>
But if you know the complete names it is a lot neater:
<xsl:for-each select="description/text">
<xsl:value-of select="node()"/>
</xsl:for-each>
If that doesn't work then we need to see more of your source XML and your transform.
Update
If I use this XML
<leaf>
<description>
<text>Various Words</text>
</description>
<description>
<text>More Words</text>
</description>
<description>
<text>Other Words</text>
</description>
</leaf>
and apply this stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/leaf">
<xsl:for-each select="description/text">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
the output is the expected Various WordsMore WordsOther Words. I don't know how to help you unless you describe your situation better, except to say that transforms should be written with another template rather than for-each wherever possible. Like this variation which produces the same output as above.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/leaf">
<xsl:apply-templates select="description/text"/>
</xsl:template>
<xsl:template match="text">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
hi all i have written a logic based on a requirement concact more than two data at a time in my xslt code but i m not reaching my expected output can any one give some suggestions
here is my xml
<Swift>
<block4>
<tag>
<name>50K</name>
<value>
0101/0457887750
SAMAROCA
MENENDEZ Y PELAYO
</value>
</tag>
</block4>
</Swift>
i have written an xslt here :
<xsl:template match="swift/message/block4/tag [name='50K']">
<xsl:variable name ="del50k" select ="(translate(substring-after(value,'
'),'
','~'))"/>
<xsl:value-of select="concat(substring(value, 1, 5), ',',substring(substring-before(value,'
'),6), ',',$del50k)" />
</xsl:template>
is that way doing is correct or not ? can any one help
EXPECTED OUTPUT:
0101/,0457887750,SAMAROCA~MENENDEZ Y PELAYO
I'm giving you a full working example based on your input. A few notes:
Use normalize-space() and split the string by space.
Just play with substring-before and substring-after.
make sure to use xsl:strip-space.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output omit-xml-declaration="yes" method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="space" select="' '"/>
<xsl:template match="block4/tag[name='50K']">
<xsl:variable name="value" select="normalize-space(value)"/>
<xsl:variable name="code" select="substring-before($value,$space)"/>
<xsl:variable name="string1" select="concat(
substring-before($code,'/'),
'/,',
substring-after($code,'/'))"/>
<xsl:variable name="string2" select="substring-before(
substring-after($value,$space),
$space)"/>
<xsl:variable name="string3" select="substring-after(
substring-after($value,$space),
$space)"/>
<xsl:value-of select="concat($string1,',',$string2,'~',$string3)"/>
</xsl:template>
<xsl:template match="name|value"/>
</xsl:stylesheet>
Your biggest problem is that value is you context node (defined in your template's match attribute), but you're referring to value in your XPath. This will look for a value node within the value node, which is obviously wrong.
In your <xsl:variable> and <xsl:value-of> statements, change refences to value to ., to refer to the current node instead.
I think that's probably not the only issue, but given that your template isn't going to match anything in that document anyway, it's difficult to derive where else it could be going wrong. One possible additional problem is that your substring-before(value,'
') predicate within your <xsl:value-of> isn't going to return anything with the formatting given, as there's a newline before the 0101/etc... Now I think about it, that's also going to be issue in the substring-after in the previous line. That's very dependent on how it's actually formatted though, but from what you've given here, it is a problem.
I am having an issue trying to figure out var scoping on xslt. What I actually want to do it to ignore 'trip' tags that have a repeated 'tourcode'.
Sample XML:
<trip>
<tourcode>X1</tourcode>
<result>Budapest</result>
</trip>
<trip>
<tourcode>X1</tourcode>
<result>Budapest</result>
</trip>
<trip>
<tourcode>X1</tourcode>
<result>Budapest</result>
</trip>
<trip>
<tourcode>Y1</tourcode>
<result>london</result>
</trip>
<trip>
<tourcode>Y1</tourcode>
<result>london</result>
</trip>
<trip>
<tourcode>Z1</tourcode>
<result>Rome</result>
</trip>
XSLT Processor:
<xsl:for-each select="trip">
<xsl:if test="not(tourcode = $temp)">
<xsl:variable name="temp" select="tour"/>
// Do Something (Print result!)
</xsl:if>
</xsl:for-each>
Desired Output:
Budapest london Rome
You can't change variables in XSLT.
You need to think about it more as functional programming instead of procedural, because XSLT is a functional language. Think about the variable scoping in something like this pseudocode:
variable temp = 5
call function other()
print temp
define function other()
variable temp = 10
print temp
What do you expect the output to be? It should be 10 5, not 10 10, because the temp inside the function other isn't the same variable as the temp outside that function.
It's the same in XSLT. Variables, once created, cannot be redefined because they are write-once, read-many variables by design.
If you want to make a variable's value defined conditionally, you'll need to define the variable conditionally, like this:
<xsl:variable name="temp">
<xsl:choose>
<xsl:when test="not(tourcode = 'a')">
<xsl:text>b</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>a</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="$temp = 'b'">
<!-- Do something -->
</xsl:if>
The variable is only defined in one place, but its value is conditional. Now that temp's value is set, it cannot be redefined later. In functional programming, variables are more like read-only parameters in that they can be set but can't be changed later. You must understand this properly in order to use variables in any functional programming language.
Desired Output: Budapest london Rome
What you are after is grouping output by city name. There are two common ways to do this in XSLT.
One of them is this:
<xsl:template match="/allTrips">
<xsl:apply-templates select="trip" />
</xsl:template>
<xsl:template match="trip">
<!-- test if there is any preceding <trip> with the same <result> -->
<xsl:if test="not(preceding-sibling::trip[result = current()/result])">
<!-- if there is not, output the current <result> -->
<xsl:copy-of select="result" />
</xsl:if>
</xsl:template>
And the other one is called Muenchian grouping and #Rubens Farias just posted an answer that shows how to do it.
Try this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="trip" match="trip" use="result" />
<xsl:template match="/trips">
<xsl:for-each select="trip[count(. | key('trip', result)[1]) = 1]">
<xsl:if test="position() != 1">, </xsl:if>
<xsl:value-of select="result"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>