XSLT的XPath结果不正确 - 不通过整个XML

时间:2010-08-10 16:46:16

标签: xml xslt xpath

所以我的手上有一个非常令人困惑的问题..

在XSL中使用XPath表达式时似乎没有搜索整个XML数据层次结构。

一些虚拟XML数据:

<pets name="myPets" NUM="2">
    <dog name="allMyDogs" NUM="5">
        <dog name="Frank"  NUM="3"/>
        <dog name="Spot"  NUM="4"/>
        <dog name="Rover"  NUM="1"/>
        <dog name="Rupert" NUM="6"/>
        <cat name="Lucy"  NUM="4"/>
    </dog>
    <cat name="allMyCats" NUM="4">
        <cat name="Simba" NUM="4"/>
        <cat name="Princess"  NUM="5"/>
        <cat name="Fluffy" NUM="1"/>
        <cat name="Lucy"  NUM="3"/>
        <cat name="Lucy"  NUM="35"/>
        <cat name="Lucy"  NUM="6"/>
        <cat name="Lucy" NUM="1"/>
    </cat>
    <cat name="Lucy" NUM="9"/>
</pets>

以下是我认为导致问题的XSLT代码部分:

 <xsl:key name="elem_key" match="elem" use="concat(@key, .)" />

  <xsl:variable name="all_data">
    <xsl:apply-templates select="*">
      <xsl:sort select="name()" />
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:template match="//*[@NUM&lt;=4]">
    <elem key="{name()}">
      <xsl:copy-of select="@*" />
      <xsl:for-each select="@*">
        <xsl:sort select="name()" />
        <attribute>|<xsl:value-of select="name()" />|</attribute>
      </xsl:for-each>
    </elem>
  </xsl:template>

  <xsl:template match="/">
    <html>
      <body>
        <xsl:for-each select="msxsl:node-set($all_data)">
              <xsl:for-each select="*[generate-id()=generate-id(key('elem_key',concat(@key, .))[1])]">
                <table >
                  <tr>
                    <td>Element Name</td>
                    <xsl:for-each select="*">
                      <td>
                        <xsl:value-of select="translate(.,'|','')" />
                      </td>
                    </xsl:for-each>
                  </tr>
                  <xsl:for-each select="key('elem_key', concat(@key, .))">
                    <xsl:variable name="curr_elem" select="." />
                    <tr>
                      <td>
                        <xsl:value-of select="@key" />
                      </td>
                      <xsl:for-each select="*">
                        <td >
                          <xsl:value-of select="$curr_elem/@*[name()=translate(current(),'|','')]" />
                        </td>
                      </xsl:for-each>
                    </tr>
                  </xsl:for-each>
                </table>
                <p />
              </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

使用的XPath表达式:

//*[@NUM&lt;=4]

(上面应该会产生很多结果)

我得到的结果不正确:

Element Name    name     NUM
pets            myPets   2

正如你所看到的那样,它似乎停留在根源上。

如果我将XPath更改为:

//*[@NUM=4]

我得到了这些不正确的结果:

Element Name  name    NUM
dog        Spot      4


Element Name  name      NUM
cat        Lucy      4


Element Name  name      NUM
cat        allMyCats   4

似乎发生的事情是,一旦找到匹配,它将停止搜索层次结构。前两个(Spot和Lucy)是正确的,但是当allMyCats(Simba)的子节点的NUM为4时,它在allMyCats处停止。

任何人都可以帮我修复此代码,以便返回正确的结果吗?我很沮丧! :(

谢谢!

2 个答案:

答案 0 :(得分:3)

只需更改

  <xsl:variable name="all_data">
    <xsl:apply-templates select="*">
      <xsl:sort select="name()" />
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:variable name="all_data">
    <xsl:apply-templates select="*/*">
      <xsl:sort select="name()" />
    </xsl:apply-templates>
  </xsl:variable>

第一个(很多)问题是

<xsl:apply-templates select="*">

选择当前节点的所有子元素。当前节点为/,并且只有一个子节点 - 顶部元素pets

您实际上想收集pets所有孩子的数据。

还有其他问题,但我没有空间和时间来解决这些问题。

完整更正的代码低于

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
version="1.0">

 <xsl:key name="elem_key" match="elem" 
      use="concat(@key, .)" />

  <xsl:variable name="all_data">
    <xsl:apply-templates select="*//*">
      <xsl:sort select="name()" />
    </xsl:apply-templates>
  </xsl:variable>

  <xsl:template match="*[@NUM&lt;=4]">
    <elem key="{name()}">
      <xsl:copy-of select="@*" />
      <xsl:for-each select="@*">
        <xsl:sort select="name()" />
        <attribute>|<xsl:value-of 
             select="concat(name(),'=',.)" />|</attribute>
      </xsl:for-each>
    </elem>
  </xsl:template>

  <xsl:template match="/">
    <html>
      <body>
        <xsl:for-each select="msxsl:node-set($all_data)">
              <xsl:for-each select=
               "*[generate-id()
                 =
                  generate-id(key('elem_key',concat(@key, .))[1])
                 ]">
                <table >
                  <tr>
                    <td>Element Name</td>
                    <xsl:for-each select="*">
                      <td>
                        <xsl:value-of select=
                          "substring-before(translate(.,'|',''),'=')" />
                      </td>
                    </xsl:for-each>
                  </tr>
                    <tr>
                      <td>
                        <xsl:value-of select="@key" />
                      </td>
                      <xsl:for-each select="*">
                        <td>
                          <xsl:value-of select=
                          "substring-after
                              (translate(current(),'|',''),
                               '='
                               )"/>
                        </td>
                      </xsl:for-each>
                    </tr>
                </table>
                <p />
              </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<pets name="myPets" NUM="2">
    <dog name="allMyDogs" NUM="5">
        <dog name="Frank"  NUM="3"/>
        <dog name="Spot"  NUM="4"/>
        <dog name="Rover"  NUM="1"/>
        <dog name="Rupert" NUM="6"/>
        <cat name="Lucy"  NUM="4"/>
    </dog>
    <cat name="allMyCats" NUM="4">
        <cat name="Simba" NUM="4"/>
        <cat name="Princess"  NUM="5"/>
        <cat name="Fluffy" NUM="1"/>
        <cat name="Lucy"  NUM="3"/>
        <cat name="Lucy"  NUM="35"/>
        <cat name="Lucy"  NUM="6"/>
        <cat name="Lucy" NUM="1"/>
    </cat>
    <cat name="Lucy" NUM="9"/>
</pets>

生成想要的结果(多个动物)

<html xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <body>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Lucy</td>
                <td>4</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>allMyCats</td>
                <td>4</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Simba</td>
                <td>4</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Fluffy</td>
                <td>1</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Lucy</td>
                <td>3</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>cat</td>
                <td>Lucy</td>
                <td>1</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>dog</td>
                <td>Frank</td>
                <td>3</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>dog</td>
                <td>Spot</td>
                <td>4</td>
            </tr>
        </table>
        <p></p>
        <table>
            <tr>
                <td>Element Name</td>
                <td>name</td>
                <td>NUM</td>
            </tr>
            <tr>
                <td>dog</td>
                <td>Rover</td>
                <td>1</td>
            </tr>
        </table>
        <p></p>
    </body>
</html>

答案 1 :(得分:0)

*[generate-id()=generate-id(key('elem_key',concat(@key, .))[1])]你做了一个与一些案例匹配的选择的密钥,然后你要求第一个[1]

我不清楚你想要什么样的布局作为正确的结果来进一步建议。