节点计数和出现 - XSL

时间:2009-09-30 20:44:56

标签: xml xslt

我需要编写通用xsl,它将接收xml文档并输出节点数及其名称。所以,如果我有一个如下文件:

   <assets>
    <asset>
        <type>hardware</type>
        <item>
            <name>HP laptop</name>
            <value>799</value>
        </item>
        <item>
            <name>server</name>
            <value>1000</value>
        </item>
        <item>
            <name>ViewSonic Monitor</name>
            <value>399</value>
        </item>
    </asset>
    <asset>
        <type>software</type>
        <item>
            <name>Windows Vista</name>
            <value>399</value>
        </item>
        <item>
            <name>Office XP</name>
            <value>499</value>
        </item>
        <item>
            <name>Windows 7</name>
            <value>399</value>
        </item>
          <item>
            <name>MS Project Professional 2007</name>
            <value>299</value>
          </item>
       </asset>
    </assets>

输出结果为:

   <output>
    <node name="assets" count="1"/>
    <node name="asset" count="2"/>
    <node name= "type" count="??"/>
    <node name="item" count=??/>
    <node name="name" count=??/>
    <node name="value" count=??/>
    </output>

3 个答案:

答案 0 :(得分:6)

您需要使用计数功能:

<xsl:value-of select="count(assets/asset)" />

所以你的代码看起来像是:

Assets: <xsl:value-of select="count(assets)" />
Asset:  <xsl:value-of select="count(assets/asset)" />
Item:   <xsl:value-of select="count(assets/asset/item)" />

答案 1 :(得分:4)

包含具有任何名称的节点的输入的通用解决方案可以使用Muenchian方法完成:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="nodes-by-name" match="*" use="name()"/>
  <xsl:template match="/">
    <output>
      <xsl:for-each select="//*[count(.|key('nodes-by-name', name())[1]) = 1]">
        <node name="{name()}" count="{count(key('nodes-by-name', name()))}"/>
      </xsl:for-each>
    </output>
  </xsl:template>
</xsl:stylesheet>

说明:使用xsl:key,创建从名称到具有该名称的节点的映射。然后遍历所有唯一名称,并输出名称的节点计数。这里的主要技巧是如何遍历唯一的名称。有关用于确定count(.|foo)=1是否仅包含上下文节点的节点集的foo惯用语的解释,请参阅链接页面。

答案 2 :(得分:1)

这是我使用XSLT 2.0的解决方案:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">

   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/">
      <xsl:element name="output">
         <xsl:for-each-group select="//*" group-by="name()">
            <xsl:element name="node">
               <xsl:attribute name="name">
                  <xsl:value-of select="current-grouping-key()"/>
               </xsl:attribute>
               <xsl:attribute name="count">
                  <xsl:value-of select="count(current-group())"/>
               </xsl:attribute>
            </xsl:element>
         </xsl:for-each-group>
      </xsl:element>
   </xsl:template>

</xsl:stylesheet>