使用position()在xslt中的for-each循环中选择特定节点,而不返回预期结果

时间:2013-02-21 01:01:18

标签: xslt xslt-1.0

我意识到这段代码并不是最干净的,但不幸的是,正确地重构它不是一种选择。

问题是我希望第二次迭代的position()返回一个真值。但是当使用position()时,它永远不会返回true,正如第二次迭代所期望的那样。

但是如果我对选择值进行硬编码,它会返回预期的结果。这是一个例子:

<root>
  <MainProducts>
    <MainProduct>
      <Published>0</Published>
    </MainProduct>
    <MainProduct>
      <Published>1</Published>
    </MainProduct>
  </MainProducts>
  <SubProducts>
    <SubProduct>
      <IsDefault>1</IsDefault>
    </SubProduct>
    <SubProduct>
      <IsDefault>0</IsDefault>
    </SubProduct>
  </SubProducts>
</root>



XML内容:

<xsl:for-each select="/root/SubProducts/SubProduct">
  <script type="text/javascript">
    // Always returns false
    console.log("Dynamic position " + <xsl:value-of select="position()" /> + " IsDefault: " + ( <xsl:value-of select="/root/MainProducts/MainProduct[position()]/Published" /> == 1 ? "true" : "false" ));
  </script>
</xsl:for-each>

<script type="text/javascript">
  // Returns false, but expected to return true on second iteration.
  console.log("Hard coded position 1 IsDefault: " + ( <xsl:value-of select="/root/MainProducts/MainProduct[1]/Published" /> == 1 ? "true" : "false" ));

  // Returns true
  console.log("Hard coded position 2 IsDefault: " + ( <xsl:value-of select="/root/MainProducts/MainProduct[2]/Published" /> == 1 ? "true" : "false" ));
</script>



这是确切的控制台输出:

Dynamic position 1 IsDefault: false
Dynamic position 2 IsDefault: false
Hard coded position 1 IsDefault: false
Hard coded position 2 IsDefault: true

我在这里遗漏的是position()没有正确选择节点?

1 个答案:

答案 0 :(得分:5)

  <script type="text/javascript">
    // Always returns false
    console.log("Dynamic position " + 
   <xsl:value-of select="position()" /> + 
    " IsDefault: " + 
      ( <xsl:value-of select="/root/MainProducts/MainProduct[position()]/Published" /> 
        == 1 ? "true" : "false" ));
  </script>

在上面的代码中MainProduct[position()]相当于MainProduct[true()]),不要忘记position()是上下文相关的!

所以,你实际上正在评估:

<xsl:value-of select="/root/MainProducts/MainProduct/Published" />

并且它总是输出由XPath表达式选择的第一个Published元素的字符串值 - 恰好是0

更正代码

<xsl:variable name="vPos" select="position()"/>

  <script type="text/javascript">
    // Always returns false
    console.log("Dynamic position " + 
   <xsl:value-of select="position()" /> + 
    " IsDefault: " + 
      ( <xsl:value-of select=
             "/root/MainProducts/MainProduct[position()=$vPos]/Published" /> 
        == 1 ? "true" : "false" ));
  </script>

这是一个完整的转型:

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

 <xsl:template match="/">
   <xsl:for-each select="/*/SubProducts/SubProduct">
    <xsl:variable name="vPos" select="position()"/>

      <script type="text/javascript">
        console.log("Dynamic position " +
       <xsl:value-of select="position()" /> +
        " IsDefault: " +
          ( <xsl:value-of select=
             "/*/MainProducts/MainProduct
                         [position()=$vPos]/Published" />
            == 1 ? "true" : "false" ));
      </script>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<root>
    <MainProducts>
        <MainProduct>
            <Published>0</Published>
        </MainProduct>
        <MainProduct>
            <Published>1</Published>
        </MainProduct>
    </MainProducts>
    <SubProducts>
        <SubProduct>
            <IsDefault>1</IsDefault>
        </SubProduct>
        <SubProduct>
            <IsDefault>0</IsDefault>
        </SubProduct>
    </SubProducts>
</root>

产生了想要的正确结果:

<script type="text/javascript">
        console.log("Dynamic position " +
       1 +
        " IsDefault: " +
          ( 0
            == 1 ? "true" : "false" ));
      </script>
<script type="text/javascript">
        console.log("Dynamic position " +
       2 +
        " IsDefault: " +
          ( 1
            == 1 ? "true" : "false" ));
      </script>