代码之家  ›  专栏  ›  技术社区  ›  developer

XSLT的XPath结果不正确-没有遍历整个XML

  •  1
  • developer  · 技术社区  · 14 年前

    所以我手上有个很困惑的问题。。

    一些伪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时,它就停止了。

    有人能帮我修复这个代码,让它返回正确的结果吗?我很沮丧!:(

    谢谢!

    2 回复  |  直到 14 年前
        1
  •  3
  •   Dimitre Novatchev    14 年前

    只要改变 :

      <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 .

    实际上,您希望为的所有子级收集数据 宠物

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

    下面是完整的更正代码 :

    <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>
    

    :

    <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>
    
        2
  •  0
  •   Jon Hanna    14 年前

    *[generate-id()=generate-id(key('elem_key',concat(@key, .))[1])]

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