Delimiting the output for xslt (in non trivial cases)

丶灬走出姿态 提交于 2019-12-11 11:42:46

问题


I would like to know the best way to delimit xml output in an xsl transform. "position() != last()" doesn't always work because it makes assumptions about the input.

This toy example demonstrates:

  <xsl:template match="/">
    <html>
      <body>
        <xsl:for-each select="//cd">
          <xsl:if test="title !='Unchain my heart'">
            <xsl:value-of select="title" />
            <xsl:if test="position() != last()">
              <xsl:text>; </xsl:text>  <!-- sometimes the delimiter will end if last element is a duplicate; -->
            </xsl:if>
          </xsl:if>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

will result in

... Pavarotti Gala Concert; The dock of the bay; Picture book; Red; 

note the trailing semicolon.

Any ideas?

(xml data from this example http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog)


回答1:


Change it to:

    <xsl:for-each select="//cd[title !='Unchain my heart']">
        <xsl:value-of select="title" />
        <xsl:if test="position() != last()">
          <xsl:text>; </xsl:text>
        </xsl:if>
    </xsl:for-each>

or in XSLT 2.0,

<xsl:value-of select="//cd/title[. !='Unchain my heart']" separator="; "/>



回答2:


One thing you can do is use the following:: axis to see if you're in the last title.

Example:

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

    <xsl:template match="/">
        <html>
            <body>
                <xsl:apply-templates select="catalog/cd/title[. != 'Unchain my heart']"/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="title">
        <xsl:value-of select="."/>
        <xsl:if test="following::cd/title[. != 'Unchain my heart']">
            <xsl:text>; </xsl:text>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

You can still use that in your xsl:for-each if you want to keep it.

Also, if you're using XSLT 2.0 you can use the separator attribute on xsl:value-of.

Example:

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

    <xsl:template match="/">
        <html>
            <body>
                <xsl:value-of select="catalog/cd/title[. != 'Unchain my heart']" separator="; "/>
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>

Also, if you're trying to drop the "Unchain my heart" title, try putting it in a predicate instead of the xsl:if (it's not wrong, just less efficient and a lot more code to do the same thing).

Example:

//cd[title != 'Unchain my heart']

or

title[. != 'Unchain my heart']



回答3:


One way would be to make a preparatory sweep on the XML to pipeline it into a better structure.

The concept here is you make your own XML then evaluate it as a node-set (separate from the source XML). This is achieved via EXSLT's node-set() method'

I just knocked up this XMLPlayground session - hope it helps. As you can see, no trailing colon.

http://www.xmlplayground.com/054Mj7



来源:https://stackoverflow.com/questions/10954091/delimiting-the-output-for-xslt-in-non-trivial-cases

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!