Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selecting the lowest value from and xml without sorting

Tags:

xml

xslt

xslt-1.0

I'm transforming an xml document to an html table using xslt, and now what I want to do is to change the background color of the cell containing the lowest "price" value without sorting my list.

I'm new on this, so what I'm doing is following the W3C schools examples. The xml file looks like this:

    <?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<catalog>
<cd>
    <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <country>USA</country>
    <company>Columbia</company>
    <price>10.90</price>
    <year>1985</year>
</cd>
<cd>
    <title>Black angel</title>
    <artist>Savage Rose</artist>
    <country>EU</country>
    <company>Mega</company>
    <price>11.90</price>
    <year>1995</year>
</cd>
<cd>
    <title>For the good times</title>
    <artist>Kenny Rogers</artist>
    <country>UK</country>
    <company>Mucik Master</company>
    <price>8.70</price>
    <year>1995</year>
</cd>
</catalog>

And what I want to obtain is something similar to this but without ordering the elements in the list by price. So I want to maintain the original order in the XML document.

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!-- Edited by XMLSpy® -->
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
     <html>
      <body>
        <h2>My CD Collection</h2>
        <table border="1">
          <tr bgcolor="#9acd32">
          <th>Title</th>
          <th>Artist</th>
          <th>Price</th>
        </tr>
        <xsl:for-each select="catalog/cd">
        <xsl:sort select="price" order="ascending" data-type="number"/>
          <tr>
            <td><xsl:value-of select="title"/></td>
            <td><xsl:value-of select="artist"/></td>
            <xsl:choose>
              <xsl:when test="(position() = 1)">
                <td bgcolor="#ff00ff">
                <xsl:value-of select="price"/></td>
              </xsl:when>
            <xsl:otherwise>
                <td><xsl:value-of select="price"/></td>
            </xsl:otherwise>
            </xsl:choose>
          </tr>
        </xsl:for-each>
        </table>
      </body>
      </html>
    </xsl:template>
    </xsl:stylesheet>

Thanks in advance for your help.


EDIT: I think I have found a solution for my question:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
        <th>Price</th>
      </tr>
      <xsl:for-each select="catalog/cd">
       <tr>
        <td><xsl:value-of select="title"/></td>
        <td><xsl:value-of select="artist"/></td>
        <xsl:choose>
          <xsl:when test="price=/catalog/cd/price[not(. &gt; ../../cd/price)][1]">
            <td bgcolor="#ff00ff">
            <xsl:value-of select="price"/></td>
          </xsl:when>
        <xsl:otherwise>
            <td><xsl:value-of select="price"/></td>
        </xsl:otherwise>
        </xsl:choose>
      </tr>

      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

like image 627
ogogu Avatar asked Feb 16 '23 21:02

ogogu


1 Answers

And what I want to obtain is something similar to this but without ordering the elements in the list by price.

The fact that sorting is used for finding the minimum doesn't mean that any elements will be re-ordered. Finding the minimum using <xsl:sort> is in practice the fastest way to do so in XSLT 1.0 -- and doesn't require any extension functions:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:variable name="vLowest">
     <xsl:for-each select="/*/*/price">
      <xsl:sort data-type="number"/>
      <xsl:if test="position()=1"><xsl:value-of select="."/></xsl:if>
     </xsl:for-each>
    </xsl:variable>

 <xsl:template match="/*">
          <html>
          <body>
            <h2>My CD Collection</h2>
            <table border="1">
              <tr bgcolor="#9acd32">
                <th>Title</th>
                <th>Artist</th>
                <th>Price</th>
              </tr>
              <xsl:apply-templates select="cd"/>
            </table>
          </body>
          </html>
 </xsl:template>

 <xsl:template match="cd">
        <tr>
          <td><xsl:value-of select="title"/></td>
          <td><xsl:value-of select="artist"/></td>
          <td>
            <xsl:if test="price=number($vLowest)">
              <xsl:attribute name="bgcolor">#ff00ff</xsl:attribute>
            </xsl:if>
            <xsl:value-of select="price"/>
          </td>
        </tr>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<catalog>
    <cd>
        <title>Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Black angel</title>
        <artist>Savage Rose</artist>
        <country>EU</country>
        <company>Mega</company>
        <price>11.90</price>
        <year>1995</year>
    </cd>
    <cd>
        <title>For the good times</title>
        <artist>Kenny Rogers</artist>
        <country>UK</country>
        <company>Mucik Master</company>
        <price>8.70</price>
        <year>1995</year>
    </cd>
</catalog>

the wanted, correct result is produced:

<html>
   <body>
      <h2>My CD Collection</h2>
      <table border="1">
         <tr bgcolor="#9acd32">
            <th>Title</th>
            <th>Artist</th>
            <th>Price</th>
         </tr>
         <tr>
            <td>Empire Burlesque</td>
            <td>Bob Dylan</td>
            <td>10.90</td>
         </tr>
         <tr>
            <td>Black angel</td>
            <td>Savage Rose</td>
            <td>11.90</td>
         </tr>
         <tr>
            <td>For the good times</td>
            <td>Kenny Rogers</td>
            <td bgcolor="#ff00ff">8.70</td>
         </tr>
      </table>
   </body>
</html>
like image 197
Dimitre Novatchev Avatar answered Feb 19 '23 10:02

Dimitre Novatchev