Get value of item from some elements before with condition

I have such XML

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="do.xsl"?>
<catalog>
  <cd>
    <title_>Empire Burlesque</title_>
    <artist>Bobby</artist>
    <company>Columbia</company>
  </cd>
  <cd>
    <title_>Shirt2</title_>
    <artist>Bobby</artist>
    <company>Columbia2</company>
  </cd>
  <cd>
    <title_>Fingers</title_>
    <artist>Bobby</artist>
    <company>Columbia3</company>
  </cd>
  <cd>
    <title_>Zip1</title_>
    <artist>Bobby</artist>
    <company>---</company>
  </cd>
  <cd>
    <title_>Zip2</title_>
    <artist>Bobby</artist>
    <company>---</company>
  </cd>
</catalog>

I need to replace --- with previous meaningful data - Columbia3 I do next

<?xml version="1.0" encoding="utf-8"?>

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

<xsl:output method="html" version="4.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/">
  <html>
  <body>
  <h2>My CD Collection</h2>
  <table border="1">
    <tr bgcolor="#9acd32">
      <th>Title</th>
      <th>Artist</th>
    </tr>
    <xsl:for-each select="catalog/cd">
    <tr>
      <td><xsl:value-of select="title_"/></td>
      <td><xsl:value-of select="artist"/></td>
      <td>
          <xsl:variable name="NotStarted" select="preceding-sibling::cd[1]/company" />
          <xsl:choose>
            <xsl:when test="company != '---'">
              <xsl:value-of select="company"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:copy-of select="$NotStarted" />
            </xsl:otherwise>
          </xsl:choose>
      </td>
    </tr>
    </xsl:for-each>
  </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet> 

As expected i got next html

Title   Artist
Empire Burlesque    Bobby   Columbia
Shirt2  Bobby   Columbia2
Fingers Bobby   Columbia3
Zip1    Bobby   Columbia3
Zip2    Bobby   ---

How i can iterate back to get last meaningful string to replace with or any other way? Thanks.

Answers


This is can be achieved by changing your NotStarted variable

<xsl:variable name="NotStarted" select="preceding-sibling::cd[1]/company" />

What this is currently doing is finding the immediately preceding sibling, regardless of content, and the getting its company element. What you need to do is find the first preceding sibling which has a valid company name

<xsl:variable name="NotStarted" 
   select="preceding-sibling::cd[company != '---'][1]/company/text()"/>

It is worth noting, it is usually preferable to avoid the use of xsl:for-each and xsl:choose in XSLT, and try to utilitise the power of template matching. Here is an alternate XSLT which demonstrates this

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="html" version="4.0" encoding="utf-8" indent="yes"/>

   <xsl:template match="/">
      <html>
         <body>
            <h2>My CD Collection</h2>
            <table border="1">
               <tr bgcolor="#9acd32">
                  <th>Title</th>
                  <th>Artist</th>
               </tr>
               <xsl:apply-templates select="catalog/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:apply-templates select="company"/>
         </td>
      </tr>
   </xsl:template>

   <xsl:template match="company[text() = '---']">
      <xsl:value-of select="../preceding-sibling::cd[company != '---'][1]/company"/>
   </xsl:template>
</xsl:stylesheet>

When applied to your XML sample, the following is output

<html>
   <body>
      <h2>My CD Collection</h2>
      <table border="1">
         <tr bgcolor="#9acd32">
            <th>Title</th>
            <th>Artist</th>
         </tr>
         <tr>
            <td>Empire Burlesque</td>
            <td>Bobby</td>
            <td>Columbia</td>
         </tr>
         <tr>
            <td>Shirt2</td>
            <td>Bobby</td>
            <td>Columbia2</td>
         </tr>
         <tr>
            <td>Fingers</td>
            <td>Bobby</td>
            <td>Columbia3</td>
         </tr>
         <tr>
            <td>Zip1</td>
            <td>Bobby</td>
            <td>Columbia3</td>
         </tr>
         <tr>
            <td>Zip2</td>
            <td>Bobby</td>
            <td>Columbia3</td>
         </tr>
      </table>
   </body>
</html>

Need Your Help

How can I improve Java2D performance of TextLayout.draw(..)

performance text java-2d

I'm using the Java2D TextLayout class together with a LineBreakMeasurer and an AttributedCharacterIterator to draw a piece of text into a box. The text is wrapped.

GridView is not smooth. How to optimize the grideview

android android-gridview

I have created simple image gallery which displays images stored in res/drawable folder , but the grid view is very laggy and slow. How can I optimized the gridview further more so that the movemen...