如何在xsl:matching-substring中使用last()?

时间:2014-09-09 10:55:04

标签: xml regex xpath xslt-2.0

有没有办法确定xsl:matching-substring是否是last()匹配的子字符串?

示例数据:

<data>
    <value>1 A 1 2 B 2 1 C 3</value>
</data>

示例XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output media-type="xhtml" encoding="UTF-8" />
    <xsl:template match="/">
        <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
                <title>xsl:matching-substring problem</title>
            </head>
            <body>
                <h1>xsl:matching-substring problem</h1>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="//value">
        <xsl:element name="p" namespace="http://www.w3.org/1999/xhtml">
            <xsl:analyze-string select="." regex="\p{{Nd}}\s\p{{Lu}}\s\p{{Nd}}" flags="i">
                <xsl:matching-substring>
                    <xsl:value-of select="."/>
                    <xsl:if test="not(last())">
                        <xsl:element name="br" namespace="http://www.w3.org/1999/xhtml" />
                    </xsl:if />
                </xsl:matching-substring>
            </xsl:analyze-string>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

结果:

<?xml version="1.0" encoding="UTF-8"?><html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <meta http-equiv="Content-Type" content="xhtml; charset=UTF-8" />
      <title>xsl:matching-substring problem</title>
   </head>
   <body>
      <h1>xsl:matching-substring problem</h1>
      <p>1 A 12 B 21 C 3</p>
   </body>
</html>

因此,似乎last()对于第一个和第二个匹配子字符串也是如此(事实上,last()似乎返回匹配子字符串的最后一个字符的位置。)

没有xsl:if,我得到:

<?xml version="1.0" encoding="UTF-8"?><html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <meta http-equiv="Content-Type" content="xhtml; charset=UTF-8" />
      <title>xsl:matching-substring problem</title>
   </head>
   <body>
      <h1>xsl:matching-substring problem</h1>
      <p>1 A 1<br />2 B 2<br />1 C 3<br /></p>
   </body>
</html>

但我更喜欢<p>1 A 1<br />2 B 2<br />1 C 3</p>。有没有办法使用XSLT 2.0实现这一目标? (我使用Saxon HE作为xslt引擎)。

2 个答案:

答案 0 :(得分:3)

@ Joel_M.Lamsen在您的代码中发现了一个错误,但他的解决方案并不正确。

规范说明:在处理每个子字符串时,子字符串的内容将是上下文项(作为xs:string类型的值);匹配和非匹配子串序列中子串的位置将是上下文位置;匹配和不匹配的子串的数量将是上下文大小。

So(position()= last())测试您是否正在处理最后一个子字符串,该子字符串可以是匹配的子字符串,也可以是不匹配的子字符串。如果你在xsl:matching-substring中,处理最后一个匹配的子字符串,那么(position()= last())如果还有一个不匹配的子字符串,则返回false。

由于您对不匹配的子字符串不感兴趣,更好的解决方案是使用tokenize():

<xsl:template match="value">
    <xhtml:p>
       <xsl:for-each select="tokenize(., '\p{{Nd}}\s\p{{Lu}}\s\p{{Nd}}', 'i')">
          <xsl:if test="position() ne 1"><xhtml:br/></xsl:if> 
          <xsl:value-of select="."/>
        </xsl:for-each>
   </xhtml:p>
</xsl:template>

另请注意我对您的代码所做的其他一些风格改进:

  • 模式//值几乎肯定只是&#34;值&#34;
  • 用文字结果元素替换xsl:element
  • 不是在除了最后一项之外的每个项目之后插入分隔符,而是在除第一项之外的每个项目之前插入它。测试项目是否是最后一项涉及预测,这可能是低效的;测试它是否是第一个更简单。

我也倾向于避免使用“我”。正则表达式中的标志;而是将\p{Lu}替换为更大的类别。

答案 1 :(得分:1)

<xsl:if test="position()!=last()">

代替