XSLT按子元素数量排序

3
我正在尝试通过在xml文档上查询来创建一个html表格。我正在使用xslt。
问题是,“父”节点包含许多“子”节点。我必须输出一个包含父节点的@name和按数量排序(降序)的“子”节点计数的表格。因此我正在这样做。
 <?xml version="1.0" encoding="ISO-8859-1"?>

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

<xsl:template match="parent[count(child) &gt; 3]">

  <html>
   <table border="1">
      <xsl:for-each select=".">
      <xsl:sort select="{count(child)}" data-type="number" order="descending"/>
        <tr>
        <td><b><xsl:value-of select="@name" /></b></td>
        <td><xsl:value-of select="count(child)" /></td>
        </tr>
      </xsl:for-each> 
   </table>
   </html>

   </xsl:template>
   <xsl:template match="text()" />
  </xsl:stylesheet>

我得到了HTML,但是唯一的问题是,我没有按子元素数量排序。我怀疑我在使用 count 时出现了错误,xsl:sort 可以帮助我吗?你能帮忙吗?
输入的XML:
<outer>
<parent name="abc" attr1="22664136" attr2="647500">
<child percentage="11">aaa</child>
<child percentage="35">bbb</child>
<child percentage="50">ccc</child>
</parent>

<parent name="ggg" attr1="3249136" attr2="28750"/>

<parent name="ghi" attr1="29183032" attr2="2381740">
<child2>
<name>ppp</name>
<attr1>1507241</attr1>
</child2>
</parent>


<parent name="qwe" attr1="10342899" attr2="1246700"/>

<parent name="lkj" attr1="65647" attr2="440">
<child percentage="100">jjj</child>
</parent>

</outer>

我不确定这是否是有意为之的,但是您提供的输入文档除了文本元素外没有任何匹配的模板:您的“父”元素都没有“count(child)>3”。 - Brian
@abc Dimitre的解决方案是您问题的完整且正确的答案,请将其标记为正确答案。我只纠正了您的一个错误,甚至没有解决最初的排序问题! - Brian
3个回答

4

提供的XSLT代码中存在许多错误!

最大的问题出现在这里:

    <xsl:for-each select=".">
      <xsl:sort select="{count(child)}" data-type="number" order="descending"/>
      <tr>
        <td><b><xsl:value-of select="@name" /></b></td>
        <td><xsl:value-of select="count(child)" /></td>
      </tr>
    </xsl:for-each>
这不会进行任何有意义的排序,因为要排序的节点集只包含一个节点 - 当前节点。
下一个问题在这里:
<xsl:sort select="{count(child)}" data-type="number" order="descending"/>

在XSLT指令的任何select属性中都不应该有任何AVT - 您需要删除花括号。

第三个问题是排序指定得太晚了 - 在匹配parent的模板内部。 父元素没有任何子元素,它们自己具有child子元素。

解决方案: 修正上述所有主要问题,可以得到以下代码:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/*">
        <html>
            <table border="1">
                <xsl:for-each select="parent">
                    <xsl:sort select="count(child)" data-type="number" order="descending"/>
                    <tr>
                        <td>
                            <b>
                                <xsl:value-of select="@name" />
                            </b>
                        </td>
                        <td>
                            <xsl:value-of select="count(child)" />
                        </td>
                    </tr>
                </xsl:for-each>
            </table>
        </html>
    </xsl:template>
    <xsl:template match="text()" />
</xsl:stylesheet>

当应用于提供的 XML 文档时,此转换将发生以下变化:

<outer>
    <parent name="abc" attr1="22664136" attr2="647500">
        <child percentage="11">aaa</child>
        <child percentage="35">bbb</child>
        <child percentage="50">ccc</child>
    </parent>
    <parent name="ggg" attr1="3249136" attr2="28750"/>
    <parent name="ghi" attr1="29183032" attr2="2381740">
        <child2>
            <name>ppp</name>
            <attr1>1507241</attr1>
        </child2>
    </parent>
    <parent name="qwe" attr1="10342899" attr2="1246700"/>
    <parent name="lkj" attr1="65647" attr2="440">
        <child percentage="100">jjj</child>
    </parent>
</outer>
期望排序结果已生成:
<html>
   <table border="1">
      <tr>
         <td><b>abc</b></td>
         <td>3</td>
      </tr>
      <tr>
         <td><b>lkj</b></td>
         <td>1</td>
      </tr>
      <tr>
         <td><b>ggg</b></td>
         <td>0</td>
      </tr>
      <tr>
         <td><b>ghi</b></td>
         <td>0</td>
      </tr>
      <tr>
         <td><b>qwe</b></td>
         <td>0</td>
      </tr>
   </table>
</html>

很好,看到for-each/sort在大小为1的集合上。你的应该标记为正确! - Brian
@btlachance:谢谢。请告诉原帖作者 :) - Dimitre Novatchev
@Dimitre 在看到答案之前我已经想到了。但现在我把你的标记为正确答案了。希望你很开心 :) - Ankur Agarwal
@abc:我很高兴你感到开心 :) 对你的问题点个赞。 - Dimitre Novatchev

1

差不多了。在xsl:sort select="..."周围不需要花括号。 你的for-each看起来会像这样:

<xsl:for-each select=".">
  <xsl:sort select="count(child)" data-type="number" order="descending"/>
  <tr>
    <td><b><xsl:value-of select="@name" /></b></td>
    <td><xsl:value-of select="count(child)" /></td>
  </tr>
</xsl:for-each>

编辑:额外提供一点信息,你只在字面上、结果元素中使用花括号。来自XSLT2.0规范的属性值模板

The following example creates an img result element from a photograph element in the source; the value of the src and width attributes are computed using XPath expressions enclosed in attribute value templates:

<xsl:variable name="image-dir" select="'/images'"/>
<xsl:template match="photograph">
  <img src="{$image-dir}/{href}" width="{size/@width}"/>
</xsl:template>

0

已经有一段时间了,所以我可能记错了,但我相信 count(child) 应该是 count(child::node())。


出现错误:"XPath 语法错误,第 10 行第 6 个字符处 {count(child::node}: 未知的轴名称:" - Ankur Agarwal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接