3

我想转换一个 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 实现这一点?

谢谢

4

2 回答 2

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>
于 2012-12-02T04:06:49.017 回答
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>
于 2012-12-02T03:53:42.230 回答