开发者

Variable increment in XSLT

i've an xml file like

<node>
 <elm val="data1"/>
 <elm val="data2"/>
 <elm val="data3"/>
 <elm val="d开发者_如何学Cata4"/>
 <elm val="data5"/>
 <elm val="data6"/>
 <elm val="data7"/>
</node>

i need to write an xslt for this xml file to display in a table fomat like

  1 dat1
  2 dat2
  3 dat3
  4 dat4
  5 dat5
  6 dat6
  7 dat7

please help me to do this


<xsl:tempate match="node">
  <table>
    <xsl:call-template select="elm"/>
  </table>
</xsl:template>

<xsl:template match="elm">
  <tr>
    <td>
      <xsl:value-of select="count(preceding-sibling::elm) + 1"/>
    </td>
    <td>
      <xsl:value-of select="@val"/>
    </td>
  </tr>
</xsl:template>

Alternatively if the exact ouput is required use the following template for elm.

<xsl:template match="elm">
  <xsl:param name="pos" select="count(preceding-sibling::elm) + 1"/>
  <tr>
    <td>
      <xsl:value-of select="$pos"/>
    </td>
    <td>
      <xsl:text>dat</xsl:text>
      <xsl:value-of select="$pos"/>
    </td>
  </tr>
</xsl:template>

Or in case of text output:

<xsl:tempate match="node">
  <xsl:foreach select="elm">
     <xsl:value-of select="count(preceding-sibling::elm) + 1"/>
     <xsl:text> dat</xsl:text>
     <xsl:value-of select="count(preceding-sibling::elm) + 1"/>
     <xsl:text  disable-output-escaping="yes">&amp;#xA;</xsl:text>
  </xsl:foreach>
</xsl:template>


This is wrong:

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

 <xsl:template match="elm">
     <xsl:value-of select="concat(position(), ' ', @val)"/>
 </xsl:template>
</xsl:stylesheet>

When run with many XSLT processors this will produce the following (unwanted) output:

 2 data1
 4 data2
 6 data3
 8 data4
 10 data5
 12 data6
 14 data7

The reason is that when templates are applied to the children of the top element, this includes the children that are white-space-only text nodes -- between every two consecutive elm elements.

So, Oded's solution is wrong.

Here is one correct solution (and one of the shortest possible):

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

 <xsl:template match="elm">
     <xsl:value-of select="concat(position(), ' ', @val, '&#xA;')"/>
 </xsl:template>
</xsl:stylesheet>

This transformation produces the correct result:

1 data1
2 data2
3 data3
4 data4
5 data5
6 data6
7 data7

Do note:

  1. The use of the <xsl:strip-space elements="*"/> to direct the XSLT processor to discard any white-space-only text nodes.

  2. The use of the XPath concat() function to glue together the position, the data and the NL character.


You can use the position() function

<xsl:template match="elm">
   <xsl:value-of select="concat(position(), ' ', @val)" />
</xsl:template>

Note: The table format in your example does not match the value of the val attribute, but I have assumed that you want both to be the same (output of first line should be 1 data1 instead of 1 dat1.

As @Dimitre Novatchev noted in his answer, this assumes that your original document has no white-space-only nodes. In his answer he deals with this by removing all white-space-only nodes from the input document (using the <xsl:strip-space elements="*"/> directive) and appending a new line character (&#xA;) at the end of the concatenation.


<xsl:template match="node">
   <table>
      <xsl:apply-templates select="elm"/>
   </table>
</xsl:template>

<xsl:template match="elm">
   <tr>
      <td><xsl:value-of select="position()"/></td>
      <td>dat<xsl:value-of select="position()"/></td>
   </tr>
</xsl:template>


XSLT "variables" are unvarying variables. Once you set them, you can't arbitrarily change them.

The only hacks around it is to use the position() function and other "+1" functions, but you don't get the flexibility of a true variable.

There are many articles about the unvariability of XSLT "variables".

Quoting article on "http://www.xml.com/pub/a/2001/02/07/trxml9.html"

XSLT variables actually have a lot more in common with constants in many programming languages and are used for a similar purpose.

Counters in XSLT are not possible because XSLT is not a procedural language, it's declarative. To the downvoter: please provide reason. If this is wrong, then please prove otherwise.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜