内部支架内的XSLT外支架节点

时间:2017-04-29 22:54:10

标签: xslt-1.0

我有以下XML:

<Root>
    <PersonSettings>
        <Type Drinks="1">A</Type>
        <Type Drinks="2">B</Type>
        <Type Drinks="3">C</Type>
        <LowestAge>20</LowestAge>
        <MaxAge>49</MaxAge>
    </PersonSettings>
    <PersonSettings>
        <Type Drinks="5">A</Type>
        <Type Drinks="8">B</Type>
        <Type Drinks="1">C</Type>
        <LowestAge>50</LowestAge>
        <MaxAge>90</MaxAge>
    </PersonSettings>
    <Person Alive="Yes">
        <Type>A</Type>
        <Age>23</Age>
    </Person>
    <Person Alive="Yes">
        <Type>B</Type>
        <Age>50</Age>
    </Person>
    <Person Alive="Yes">
        <Type>C</Type>
        <Age>51</Age>
    </Person>
    <Person Alive="Yes">
        <Type>A</Type>
        <Age>70</Age>
    </Person>
</Root>

以下XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="no"/>

<xsl:template match="/">
    <PersonsOneDrink>
        <xsl:value-of select="(count(/Root/Person[@Alive = 'Yes' and /Root/PersonSettings[**(Person/Age)** &gt;= LowestAge and **(Person/Age)** &lt;= MaxAge]/Type[. = **(Person/Type)** and @Drinks = '1']))"/>
    </PersonsOneDrink>
</xsl:template>

</xsl:stylesheet>

我想在这个例子中做的是计算一杯饮酒的人数,这些人还活着。根据人的类型和此人的年龄,我有不同的设置。例如,如果年龄在20到49岁之间,A型饮料有一种饮料,而如果在50到90岁之间,C型饮料有一种饮料。我发现的问题是当进入第二组括号时我无法引用外部节点。有没有办法动态创建变量?

P.S:带* *()* *的部分是我想引用外部节点的地方。

1 个答案:

答案 0 :(得分:0)

我不认为可以使用从根的上下文应用的单个count()表达式来完成此操作。

此处的问题是,您需要在谓词中引用Person的值,并将它们与预期PersonSettings的值进行比较。为此,您需要使用current() function - 但为了让current()函数引用Person,您必须首先使Person成为上下文节点。

这是一种建议的方法,为每个Person写一个字符,将测试传递给变量。这样就无需在计算变量之前将变量转换为节点集:

XSLT 1.0

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

<xsl:template match="/Root">
    <xsl:variable name="v1">
        <xsl:for-each select="Person">
            <xsl:if test="@Alive = 'Yes' and /Root/PersonSettings[LowestAge &lt;= current()/Age and MaxAge >= current()/Age]/Type[. = current()/Type]/@Drinks = 1">
                <xsl:text>Y</xsl:text>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <PersonsOneDrink>
        <xsl:value-of select="string-length($v1)"/>    
    </PersonsOneDrink>
</xsl:template>

</xsl:stylesheet>

<强>结果

<?xml version="1.0" encoding="UTF-8"?>
<PersonsOneDrink>2</PersonsOneDrink>

更通用的解决方案 - 如果您想对提供的数据执行多个查询,则适合 - 首先重写输入并为每个Person分配相应数量的饮料。

这里我们将构造一个包含以下内容的变量:

  <Person>
    <Type>A</Type>
    <Age>23</Age>
    <Drinks>1</Drinks>
  </Person>
  <Person>
    <Type>B</Type>
    <Age>50</Age>
    <Drinks>8</Drinks>
  </Person>
  <Person>
    <Type>C</Type>
    <Age>51</Age>
    <Drinks>1</Drinks>
  </Person>
  <Person>
    <Type>A</Type>
    <Age>70</Age>
    <Drinks>5</Drinks>
  </Person>

然后,一旦将变量转换为节点集,获得任意数量饮料的人数是微不足道的:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/Root">
    <!-- first pass -->
    <xsl:variable name="persons-rtf">
        <xsl:for-each select="Person">
            <xsl:copy>
                <xsl:copy-of select="*"/>
                <Drinks>
                    <xsl:value-of select="/Root/PersonSettings[LowestAge &lt;= current()/Age and MaxAge >= current()/Age]/Type[. = current()/Type]/@Drinks"/>
                </Drinks>
            </xsl:copy>
        </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="persons" select="exsl:node-set($persons-rtf)/Person"/>
    <!-- output --> 
    <results>
        <PersonsOneDrink>
            <xsl:value-of select="count($persons[Drinks = 1])"/>
        </PersonsOneDrink>
    </results>
</xsl:template>

</xsl:stylesheet>