XSL:从分隔字符串构建数组

16
我有一个字符串,其中数据由分隔符 "|" 分隔,并存在一个变量中。我想通过在 XSL 中基于分隔符来拆分上述字符串并创建一个数组,并想在 for 循环中访问它。
请帮我解决这个问题。如果需要更多信息,请告诉我。
字符串是 "Test1|Test2|Test3|Test4",希望得到一个名为 TEMP 的变量,该变量是来自字符串的数据数组,并可使用 TEMP[index] 访问。
我尝试使用 tokenize 函数从论坛成员的输入中获取字符串值,但没有成功。我无法在循环中获取字符串值。
<xsl:variable name="temp" xmlns:str="http://exslt.org/strings" select="str:tokenize(normalize-space(' Test1$,$Test2$,$Test3$,$Test4 '),'$,$')"/>
<xsl:for-each xmlns:str="http://exslt.org/strings" select="str:split(normalize-space(' 1$,$2$,$3$,$4$,$5$,$6 '),'$,$')">
    <xsl:variable name="index" select="position()"/>
    <xsl:value-of select="$temp[$index]"/>
</xsl:for-each>

敬礼, Lakshman


FYI,XSLT没有数组。在XSLT 1.0 / EXSLT中,tokenize()扩展函数返回一个节点集结果树片段(可以使用另一个扩展函数node-set()将其转换为节点集)。这个节点集可以按照你指定的索引访问,因为表示令牌的元素与父节点的子节点一一对应,顺序排列。 - LarsH
@LarsH:是的,但是OP想要的可以在XSLT 1.0中通过包含每个元素令牌的元素节点集来建模--请看我的答案。 - Dimitre Novatchev
@Dimitre:是的,我在我的评论中暗示了这一点。当我写下我的评论时,已经有很好的答案描述了如何做到这一点。我只是想多加一点关于“数组”术语的内容。 - LarsH
4个回答

16

有一个字符串"Test1|Test2|Test3|Test4",想要创建一个名为TEMP的变量,该变量将是该字符串的数据数组,并且可以通过TEMP[index]访问。

+1 点赞!

这是一个XSLT 1.0转换:

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

 <xsl:variable name="vrtfTokens">
  <xsl:apply-templates/>
 </xsl:variable>

 <xsl:variable name="vTokens" select=
   "ext:node-set($vrtfTokens)/*"/>
 <xsl:template match="/">
  <xsl:for-each select=
   "document('')//node()[not(position() > count($vTokens))]
   ">
   <xsl:variable name="vPos" select="position()"/>
    <xsl:copy-of select="$vTokens[$vPos+0]"/>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="text()" name="split">
  <xsl:param name="pText" select="."/>

  <xsl:if test="string-length($pText)">
   <xsl:variable name="vToken" select=
    "substring-before(concat($pText,'|'), '|')"/>
   <s><xsl:value-of select="$vToken"/></s>

   <xsl:call-template name="split">
    <xsl:with-param name="pText" select=
    "substring-after($pText, '|')"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

当应用于此 XML 文档时

<t>Test1|Test2|Test3|Test4</t>

创建一个名为vTokens的变量,其中包含名为s的元素,每个元素的唯一文本子节点都是来自以'|'分隔的字符串"Test1|Test2|Test3|Test4"的一个标记。

然后转换使用"索引"输出每个这些s元素。

所需的正确结果已生成:

<s>Test1</s>
<s>Test2</s>
<s>Test3</s>
<s>Test4</s>

如果我们只需要标记(字符串)本身,我们会使用:

string($vTokens[someIndex])

@Bugude:不用谢。也许你需要知道,在SO上说“谢谢”是通过接受最佳答案(点击旁边的复选标记——你现在可以这样做)和点赞任何答案(点击其 ^ 箭头——当你自己累积了50分时,你将被允许这样做)来正式完成的。 - Dimitre Novatchev

10

它不会是一个数组,而是一个序列,您必须拥有一个XSLT 2.0处理器。 您可以使用tokenize()函数:

<xsl:variable name="temp" as="xs:string*" select="tokenize('Test1|Test2|Test3|Test4','\|')"/>

您也可以将字符串变量作为tokenize的第一个参数传递。

然后您可以使用:

<xsl:value-of select="$temp[$index]"/>

编辑:在 xslt 1.0 中实现这个功能是不可能的,除非你使用一些扩展。


谢谢Vincent...这个帮助对我在单独使用和使用XSLT 2.0时非常有用并且有效。不幸的是,应用程序正在使用旧版本,有没有办法在1.0版本中完成这个操作? - Bugude
不幸的是,它不在xpath 1.0标准中,正如马丁所指出的,您必须使用exslt扩展。 - Vincent Biragnet
@VincentBiragnet: 你说必须使用XSLT 2.0处理器才能实现OP的要求,这是不正确的。请看我的XSLT 1.0解决方案。 - Dimitre Novatchev

3

谢谢大家。 我尝试使用tokenize函数从字符串中获取值,但没有成功。 在循环中我无法获取字符串值。<xsl:variable name="temp" xmlns:str="http://exslt.org/strings" select="str:tokenize(normalize-space(' Test1$,$Test2$,$Test3$,$Test4 '),'$,$')"/> <xsl:for-each xmlns:str="http://exslt.org/strings" select="str:split(normalize-space(' 1$,$2$,$3$,$4$,$5$,$6 '),'$,$')"> <xsl:variable name="index" select="position()"/> <xsl:value-of select="$temp[$index]"/> </xsl:for-each> - Bugude
上述所提到的代码用于填充工作簿中的表格。在for循环中获取的值将分别放入工作簿(Excel)中表格的每一行。 - Bugude

3

我尝试了这个,修改了“Dimitre Novatchev”的代码,并且对我有用:(请原谅我的英语水平)

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:msxsl="urn:schemas-microsoft-com:xslt"
            exclude-result-prefixes="msxsl">

<xsl:template match="/*">
        <xsl:variable name="_keywords">
            <xsl:call-template name="split-to-values">
                <xsl:with-param name="_text" select="Keywords-comma-separated"/>
            </xsl:call-template>
        </xsl:variable>

        <xsl:for-each select="msxsl:node-set($_keywords)/value">
            <xsl:variable name="_keyword" select="."/>
            <!-- ANY CODE -->
        </xsl:for-each>
</xsl:template>

<xsl:template match="text()" name="split-to-values">
    <xsl:param name="_text"/>

    <xsl:if test="string-length($_text)">
        <xsl:variable name="_value" select="substring-before($_text, ',')"/>
        <xsl:variable name="_next" select="substring-after($_text, ',')"/>
        <value>
            <xsl:value-of select="$_value"/>
        </value>

        <xsl:call-template name="split-to-values">
            <xsl:with-param name="_text" select="$_next"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

我希望能对你有所帮助

@Bugude问:

我有一个字符串,其中数据由分隔符“|”分隔,并存储在一个变量中。我想通过在XSL中根据分隔符划分上述字符串来创建一个数组,并希望在一个for循环中访问该数组

那么,该字符串可能是:“alfa,beta,gama,delta”

分隔符以变量形式呈现:

<xsl:variable name="_delimiter">,</xsl:variable>

我将模板修改为以下内容:
<xsl:template match="text()" name="split-to-values">
    <xsl:param name="_text"/>
    <xsl:param name="_delimiter"/>

    <xsl:if test="string-length($_text)">
        <xsl:variable name="_value" select="substring-before($_text, $_delimiter)"/>
        <xsl:variable name="_next" select="substring-after($_text, $_delimiter)"/>
        <value>
            <xsl:value-of select="$_value"/>
        </value>

        <xsl:call-template name="split-to-values">
            <xsl:with-param name="_text" select="$_next"/>
            <xsl:with-param name="_delimiter" select="$_delimiter"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

我们可以像使用数组一样使用for循环访问节点。

<xsl:template match="/*">
        <!-- _keyword as set a node -->
        <xsl:variable name="_keywords">
            <xsl:call-template name="split-to-values">
                <xsl:with-param name="_text" select="'alfa,beta,gama,delta'"/>
                <xsl:with-param name="_delimiter" select="$_delimiter"/>
            </xsl:call-template>
        </xsl:variable>

        <xsl:for-each select="msxsl:node-set($_keywords)/value">
            <xsl:variable name="_keyword" select="."/>
            <!-- ANY CODE -->
            <xsl:value-of select="$_keyword"/>
        </xsl:for-each>
</xsl:template>

1
虽然这份代码可能回答了问题,但是提供关于它如何和/或为什么解决问题的额外上下文会增加答案的长期价值。 - thewaywewere

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