2

i am beginner in XSLT and using to transform XML to XML.

I require to get Prices tag which has lowest sum.

Source XML:

<Result>
    <Fares>
        <Fare>
            <Prices>
                <Price type="adt" ticket="15"/>
                <Price type="chd" ticket="10"/>
                <Price type="inf" ticket="10"/>
            <Prices>
        </Fare>
        <Fare>
            <Prices>
                <Price type="adt" ticket="10"/>
                <Price type="chd" ticket="10"/>
                <Price type="inf" ticket="10"/>
            <Prices>
        </Fare>
        <Fare>
            <Prices>
                <Price type="adt" ticket="5"/>
                <Price type="chd" ticket="5"/>
                <Price type="inf" ticket="5"/>
            <Prices>
        </Fare>
        <Fare>
            <Prices>
                <Price type="adt" ticket="10"/>
                <Price type="chd" ticket="5"/>
                <Price type="inf" ticket="5"/>
            <Prices>
        </Fare>
    </Fares>
</Result>

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="xml" indent="yes" />

    <xsl:template match="Result">
        <xsl:element name="Lowest">
            <xsl:variable name="lowest" select="Fares/Fare/Prices[not(sum(Price/@ticket) &gt; //Fares/Fare/Prices[sum(Price/@ticket)])]"/>
            <xsl:copy-of select="$lowest"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Output:

<Lowest>
    <Prices>
        <Price type="adt" ticket="15"/>
        <Price type="chd" ticket="10"/>
        <Price type="inf" ticket="10"/>
    <Prices/>
    </Prices>
</Lowest>

Expected Output:

<Lowest>
    <Prices Total="15">
        <Price type="adt" ticket="5"/>
        <Price type="chd" ticket="5"/>
        <Price type="inf" ticket="5"/>
    <Prices>
</Lowest>

As shown above output should have the Prices tag with lowest value as attribute also.

Please help.

Ankur Raiyani
  • 1,509
  • 5
  • 21
  • 49
  • Hi, could you share your XSLT code..? What have you tried? – Kent Pawar Dec 05 '12 at 12:32
  • Are you sure the XSLT you're showing actually gives the output that you say it does? For me, using Saxon 6.5.5, it gives different output: it outputs all four `` elements with their descendants. – LarsH Dec 05 '12 at 14:32
  • @LarsH - i am using java to transform XML to XML and engine is JAXP (default one). – Ankur Raiyani Dec 13 '12 at 07:44

3 Answers3

2

You can sort and take the one that is first in sort order:

<xsl:template match="Result">
  <Lowest>
    <xsl:for-each select="Fares/Fare/Prices">
      <xsl:sort select="sum(Price/@ticket)" data-type="number"/>
      <xsl:if test="position() = 1">
         <Prices Total="{sum(Price/@ticket)}">
           <xsl:copy-of select="node()"/>
         </Prices>
      </xsl:if>
    </xsl:for-each>
  </Lowest>
</xsl:template>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
2

You are not closing your <Prices> tags!

But this should do the trick:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" omit-xml-declaration="yes"/>
  <xsl:template match="/">
    <Lowest>
      <xsl:for-each select="/Result/Fares/Fare/Prices">
        <xsl:sort select="sum(./Price/@ticket)" data-type="number" order="ascending"/>
        <xsl:if test="position() = 1">
          <Prices>
            <xsl:attribute name="Total">
              <xsl:value-of select="sum(./Price/@ticket)"/>
            </xsl:attribute>
            <xsl:copy-of select="./Price"/>
          </Prices>
        </xsl:if>
      </xsl:for-each>
    </Lowest>
  </xsl:template>
</xsl:stylesheet>
Reinder Wit
  • 6,490
  • 1
  • 25
  • 36
  • Using this solution i got ``. – Ankur Raiyani Dec 05 '12 at 12:58
  • what are you developing this in then? I used the Visual Studio 2010 XSLT debugger and got the correct result... – Reinder Wit Dec 05 '12 at 13:13
  • 1
    make sure you've fixed the closing tags! – Reinder Wit Dec 05 '12 at 13:43
  • 1
    @Ankur: warning, that purplegene.com page uses whatever XSLT processor is available *in the browser*. Not all browser-provided XSLT processors adhere to the standard. If you need your stylesheet to work in a particular browser, best to say which browser you're using. – LarsH Dec 05 '12 at 14:53
1

This transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
     <xsl:for-each select="/*/*/Fare">
       <xsl:sort select="sum(Prices/Price/@ticket)" data-type="number"/>

       <xsl:if test="position()=1">
         <Lowest Total="{sum(Prices/Price/@ticket)}">
           <xsl:copy-of select="Prices"/>
         </Lowest>
       </xsl:if>
     </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document (with several malformities corrected!!!):

<Result>
    <Fares>
        <Fare>
            <Prices>
                <Price type="adt" ticket="15"/>
                <Price type="chd" ticket="10"/>
                <Price type="inf" ticket="10"/>
            </Prices>
        </Fare>
        <Fare>
            <Prices>
                <Price type="adt" ticket="10"/>
                <Price type="chd" ticket="10"/>
                <Price type="inf" ticket="10"/>
            </Prices>
        </Fare>
        <Fare>
            <Prices>
                <Price type="adt" ticket="5"/>
                <Price type="chd" ticket="5"/>
                <Price type="inf" ticket="5"/>
            </Prices>
        </Fare>
        <Fare>
            <Prices>
                <Price type="adt" ticket="10"/>
                <Price type="chd" ticket="5"/>
                <Price type="inf" ticket="5"/>
            </Prices>
        </Fare>
    </Fares>
</Result>

produces the wanted, correct result:

<Lowest Total="15">
   <Prices>
      <Price type="adt" ticket="5"/>
      <Price type="chd" ticket="5"/>
      <Price type="inf" ticket="5"/>
   </Prices>
</Lowest>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • Dimitre, the OP wants to add a `Total` attribute to the `` element. BTW, it would be helpful to add an explanation of why the OP's original XPath expression doesn't work, so we have to use for-each with sort. Something to do with the limitations of `sum()` in XSLT 1.0? – LarsH Dec 05 '12 at 14:33