识别XML中节点下的标签超集

时间:2012-12-02 03:27:35

标签: xml xslt

我想转换XML,使特定名称的所有节点都包含这些节点下可用的所有元素的超集。

例如,这是输入xml。在此xml中,该组可以包含一个或多个项目节点。呼叫者只会传递该组下可用的项目。

<group>
   <item>
       <name> item1 </name>
       <value> 10 </value>
   </item>
</group>
<group>
    <item>
       <name> item2 </name>
       <value> 20 </value>
     </item>
</group>

要求是将其转换为如下所示的那个,其中来自所有组的项目节点应该是每个组的一部分。但是,如果该项目在该组下的输入中不可用,则应使用值0填充。

<group>
   <item>
       <name> item1 </name>
       <value> 10 </value>
   </item>
   <item>
       <name> item2 </name>
       <value> 0 </value>
   </item>
</group>
<group>
     <item>
       <name> item1 </name>
       <value> 0 </value>
     </item>    
    <item>
       <name> item2 </name>
       <value> 20 </value>
     </item>
</group>

您能否告诉我如何使用XSLT实现这一目标?

由于

2 个答案:

答案 0 :(得分:1)

以下是我的方法(在XSLT 2.0中,因为你没有指定)......

XML输入(包含在<groups>中,格式正确)

<groups>
    <group>
        <item>
            <name> item1 </name>
            <value> 10 </value>
        </item>
    </group>
    <group>
        <item>
            <name> item2 </name>
            <value> 20 </value>
        </item>
    </group>
</groups>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="names" select="distinct-values(/*/group/item/name)"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="group">
        <xsl:variable name="currentItems" select="item/name"/>
        <xsl:variable name="items" as="node()*">
            <xsl:apply-templates select="item"/>
            <xsl:for-each select="$names[not(. = current()/item/name)]">
                <item>
                    <name><xsl:value-of select="."/></name>
                    <value> 0 </value>
                </item>
            </xsl:for-each>         
        </xsl:variable>
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:perform-sort select="$items">
                <xsl:sort select="name"/>
            </xsl:perform-sort>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

XML输出

<groups>
   <group>
      <item>
         <name> item1 </name>
         <value> 10 </value>
      </item>
      <item>
         <name> item2 </name>
         <value> 0 </value>
      </item>
   </group>
   <group>
      <item>
         <name> item1 </name>
         <value> 0 </value>
      </item>
      <item>
         <name> item2 </name>
         <value> 20 </value>
      </item>
   </group>
</groups>

答案 1 :(得分:0)

这是XSLT 1.0和XSLT 2.0解决方案

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

 <xsl:variable name="vGroupContent" select="/*/group/node()"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="group">
  <group>
   <xsl:apply-templates select=
    "node()|@*|$vGroupContent[not(name = current()/item/name)]">
    <xsl:with-param name="pGroup" select="."/>
     <xsl:sort select="name"/>
   </xsl:apply-templates>
  </group>
 </xsl:template>

 <xsl:template match="item">
  <xsl:param name="pGroup"/>
  <item>
    <xsl:apply-templates select="name"/>
    <value> <xsl:value-of select=
    "value/text()[generate-id($pGroup) = generate-id(../../..)]"/>

    <xsl:if test=
     "value/text()[not(generate-id($pGroup) = generate-id(../../..))]"> 0 </xsl:if>
    </value>
  </item>
 </xsl:template>
</xsl:stylesheet>

对以下XML文档应用此转换时:

<t>
    <group>
        <item>
            <name> item1 </name>
            <value> 10 </value>
        </item>
    </group>
    <group>
        <item>
            <name> item2 </name>
            <value> 20 </value>
        </item>
    </group>
</t>

产生了想要的正确结果:

<t>
   <group>
      <item>
         <name> item1 </name>
         <value> 10 </value>
      </item>
      <item>
         <name> item2 </name>
         <value> 0 </value>
      </item>
   </group>
   <group>
      <item>
         <name> item1 </name>
         <value> 0 </value>
      </item>
      <item>
         <name> item2 </name>
         <value> 20 </value>
      </item>
   </group>
</t>