使用XSLT 2.0将多个属性的值解析为类似数组的结构

时间:2013-08-20 15:29:55

标签: xslt xslt-2.0

我希望能够选择文档中某种类型的所有属性(例如// @ arch),然后获取该节点集并将值解析为第二个节点集。当我说“解析”时,具体我的意思是我想要转换这样的节点:

arch="value1;value2;value3"
arch="value1:value4"

进入这样的节点集:

arch="value1"
arch="value2"
arch="value3"
arch="value1"
arch="value4"

或类似的东西;我想从属性中获取各个值并将其放入自己的节点中。

如果我可以进入该状态,我有很多方法可以进行排序和重复删除,之后我将使用完成的节点集进行发布任务。

作为一种方法,我并不是在寻找一个整洁的答案。我知道XSLT不能做动态数组,但这与不能做之类的动态数组或模仿功能重要部分的东西不同。

我想到的一个想法是,我可以计算第一个节点集中的节点和分隔符的数量,计算第二个节点集所需的条目数并创建它(以某种方式),并使用substring函数用于解析第一个节点集到第二个节点集。

通常有办法解决XSLT的问题;有没有人在此之前解决过这个问题?

感谢您的帮助, 杰夫。

2 个答案:

答案 0 :(得分:2)

您可以使用tokenize表达式中的for函数来获取单独值的序列,然后为每个值创建一个属性节点。但是,由于XSLT不允许您创建没有父元素的裸属性节点,因此您必须使用这样的技巧:

<xsl:variable name="archElements">
  <xsl:for-each select="for $attr in $initialNodeSet
                        return tokenize($attr, '[:;]')">
    <dummy arch="{.}" />
  </xsl:for-each>
</xsl:variable>

然后$archElements/dummy/@arch应该是您需要的一组独立的arch属性节点。

完整示例:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

  <xsl:output indent="yes" />

  <xsl:template match="/">
    <xsl:variable name="inputData">
      <a arch="value1;value2;value3" />
      <a arch="value1:value4" />
    </xsl:variable>

    <!-- create an example node set containing the two arch attribute nodes -->
    <xsl:variable name="initialNodeSet" select="$inputData/a/@arch" />

    <!-- tokenize and generate one arch attribute node for each value -->
    <xsl:variable name="archElements">
      <xsl:for-each select="for $attr in $initialNodeSet
                            return tokenize($attr, '[:;]')">
        <dummy arch="{.}" />
      </xsl:for-each>
    </xsl:variable>

    <!-- output to verify -->
    <r>
      <xsl:for-each select="$archElements/dummy/@arch">
        <c><xsl:copy-of select="."/></c>
      </xsl:for-each>
    </r>
  </xsl:template>
</xsl:stylesheet>

当在任何输入文档上运行时(内容被忽略),这会产生

<?xml version="1.0" encoding="UTF-8"?>
<r>
   <c arch="value1"/>
   <c arch="value2"/>
   <c arch="value3"/>
   <c arch="value1"/>
   <c arch="value4"/>
</r>

答案 1 :(得分:2)

我认为你要找的是一个序列。序列可以是节点或原子值(参见http://www.w3.org/TR/xslt20/#constructing-sequences)。

这是一个示例,显示序列的构造,然后迭代它。序列是来自@arch的原子值,但它也可以是节点。

XML输入

<doc>
    <foo arch="value1;value2;value3"/>
    <foo arch="value1:value4"/>
</doc>

XSLT 2.0

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

    <xsl:variable name="archSequence" as="item()*">
        <xsl:for-each select="//@arch">
            <xsl:for-each select="tokenize(.,'[;:]')">
                <xsl:value-of select="."/>                  
            </xsl:for-each>             
        </xsl:for-each>         
    </xsl:variable>

    <xsl:template match="/*">
        <sequence>
            <xsl:for-each select="$archSequence">
                <item><xsl:value-of select="."/></item>
            </xsl:for-each>
        </sequence>
    </xsl:template>

</xsl:stylesheet>

XML输出

<sequence>
   <item>value1</item>
   <item>value2</item>
   <item>value3</item>
   <item>value1</item>
   <item>value4</item>
</sequence>

元素序列的示例(相同的输出):

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

    <xsl:variable name="archSequence" as="element()*">
        <xsl:for-each select="//@arch">
            <xsl:for-each select="tokenize(.,'[;:]')">
                <item><xsl:value-of select="."/></item>         
            </xsl:for-each>             
        </xsl:for-each>         
    </xsl:variable>

    <xsl:template match="/*">
        <sequence>
            <xsl:for-each select="$archSequence">
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </sequence>
    </xsl:template>

</xsl:stylesheet>