XSLT有Split()函数吗?

43
我有一个字符串在一个节点中,我想在'?'上分割字符串并返回数组中的最后一项。
例如,在下面的块中:
<a>
    <xsl:attribute name="href">
        /newpage.aspx?<xsl:value-of select="someNode"/>
    </xsl:attribute>
    Link text
</a>

我想要分割someNode的值。

编辑: 这是我用于为我的Asp.Net页面加载Xsl的VB.Net代码:

Dim xslDocPath As String = HttpContext.Current.Server.MapPath("~/App_Data/someXslt.xsl")
Dim myXsltSettings As New XsltSettings()
Dim myXMLResolver As New XmlUrlResolver()

myXsltSettings.EnableScript = True
myXsltSettings.EnableDocumentFunction = True

myXslDoc = New XslCompiledTransform(False)
myXslDoc.Load(xslDocPath, myXsltSettings, myXMLResolver)

Dim myStringBuilder As New StringBuilder()
Dim myXmlWriter As XmlWriter = Nothing

Dim myXmlWriterSettings As New XmlWriterSettings()
myXmlWriterSettings.ConformanceLevel = ConformanceLevel.Auto
myXmlWriterSettings.Indent = True
myXmlWriterSettings.OmitXmlDeclaration = True

myXmlWriter = XmlWriter.Create(myStringBuilder, myXmlWriterSettings)

myXslDoc.Transform(xmlDoc, argumentList, myXmlWriter)

Return myStringBuilder.ToString()

更新:这里是在特定节点上拆分XML的示例


3
与ASP.Net没有什么实质关联。 - Ikke
8个回答

51

使用递归方法:

<xsl:template name="output-tokens">
    <xsl:param name="list" /> 
    <xsl:variable name="newlist" select="concat(normalize-space($list), ' ')" /> 
    <xsl:variable name="first" select="substring-before($newlist, ' ')" /> 
    <xsl:variable name="remaining" select="substring-after($newlist, ' ')" /> 
    <id>
        <xsl:value-of select="$first" /> 
    </id>
    <xsl:if test="$remaining">
        <xsl:call-template name="output-tokens">
            <xsl:with-param name="list" select="$remaining" /> 
        </xsl:call-template>
    </xsl:if>
</xsl:template>

2
请注意,如果列表中没有令牌,则此模板仍将输出一个空的<id>元素,而不是没有<id>元素。 - LarsH
6
我很兴奋尝试这个,但不幸的是Firefox显示出错了:“XSLT转换期间发生错误:XSLT样式表(可能)包含递归。” 是的,Firefox应该是递归的...嗯... - monojohnny

12

如果您可以使用XSLT 2.0或更高版本,则可以使用tokenize(string, separator):

tokenize("XPath is fun", "\s+")
Result: ("XPath", "is", "fun")

请参阅w3schools XPath函数参考

默认情况下,.NET不支持XSLT 2.0,更不用说XSLT 3.0了。目前已知的.NET 2.0+处理器包括:Saxon for .NETIKVM、目前仍处于beta版的.NET XSLT 3.0处理器Exselt以及XMLPrime XSLT 2.0处理器。


4
唯一的缺点是需要 XSLT 2.0 :-( - Greg Beech
1
是的,我遇到了“'tokenize()'是未知的XSLT函数。”错误。 - travis
你使用的是哪个处理器? - James Sulak

8

我最终使用了substring-after()函数。以下是对我有效的内容:

<a>
    <xsl:attribute name="href">
        /newpage.aspx?<xsl:value-of select="substring-after(someNode, '?')"/>
    </xsl:attribute>
    Link text
</a>

即使我将XSLT的版本设置为2.0,但在尝试使用tokenize()时仍然出现了"'tokenize()'是未知的XSLT函数。"错误。


我希望我能保留那段代码,但在我之前的雇主那里,我写了一个 XSLT 1.0 函数来获取字符串的第 n 个标记。一旦你理解了函数式编程的概念,这并不太困难。 - Moe

6
如果您的模板引擎支持EXSLT,那么您可以使用其中的tokenize()函数。
例如:
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:str="http://exslt.org/strings"
                extension-element-prefixes="str">

...
  <a>
    <xsl:attribute name="href">
      <xsl:text>/newpage.aspx?</xsl:text>
      <xsl:value-of select="str:tokenize(someNode)[2]"/>
    </xsl:attribute>              
  </a>
...
</xsl:stylesheet>

你在.NET中成功使用过这个吗? - travis

3

.NET不支持XSLT 2.0,很遗憾。但我相信它支持EXSLT,其中有一个split()函数。Microsoft在其EXSLT实现上有一个旧页面


2
您可以使用 string-beforestring-after 函数编写模板,并在多个场景下使用它。我曾在我的博客上介绍了这个方法。
最后,我编写了一个 XSLT 模板来将分隔符分割的字符串拆分成子字符串。虽然我不会声称这是最聪明的脚本,但肯定解决了我的问题。
样式表:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="Paths/Item">
<xsl:call-template name="SplitText">
<xsl:with-param name="inputString" select="Path"/>
<xsl:with-param name="delimiter" select="Delimiter"/>
</xsl:call-template>
<br/>
</xsl:for-each>
</xsl:template>
<xsl:template name="SplitText">
<xsl:param name="inputString"/>
<xsl:param name="delimiter"/>
<xsl:choose>
<xsl:when test="contains($inputString, $delimiter)">
<xsl:value-of select="substring-before($inputString,$delimiter)"/>
<xsl:text disable-output-escaping = "no"> </xsl:text>
<xsl:call-template name="SplitText">
<xsl:with-param name="inputString" select="substring-after($inputString,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$inputString = ''">
<xsl:text></xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$inputString"/>
<xsl:text> </xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

XML文件(待转换):

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="textSpliter.xslt"?>
<Paths>
  <Item>
    <Path>C:\ProgramFiles\SomeWierdSoftware</Path>
    <Delimiter>\</Delimiter>
  </Item>
</Paths> 

1

XSLT 1.0本身没有split函数,但你可以通过substring-before和substring-after函数来实现你想要的功能。

另外,如果你使用的是Microsoft XSLT引擎,你可以使用内联C#。


1

仅供参考,如果您正在使用1.0版本,并且确实需要拆分/分词,则需要xslt扩展


有趣,我该如何在上面的例子中使用它? - travis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接