如何找到具有相同子节点的节点 [英] How to find nodes with same children

查看:32
本文介绍了如何找到具有相同子节点的节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下 xml.请注意,节点 n1 和 n3 具有相同的子节点(顺序可以不同).如何编写 XSL 转换来识别此类节点?

I have following xml. Note that node n1 and n3 have same children (order can be different). How can I write an XSL transformation to identify such nodes?

<Document>
    <Node name="n1">
        <Item value="v1">
        <Item value="v2">
        <Item value="v3">
    </Node>
    <Node name="n2">
        <Item value="p1">
        <Item value="p2">
        <Item value="p3">
    </Node>
    <Node name="n3">
        <Item value="v3">
        <Item value="v1">
        <Item value="v2">
    </Node>
</Document>

推荐答案

这是一个完整的 XSLT 1.0 解决方案,它足够通用,即使 Node允许有任何名字的孩子:

Here is a complete XSLT 1.0 solution that is general enough so that it would produce correct results even when a Node is allowed to have children with any name:

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

 <xsl:key name="kNodeBySign" match="Node" use="@signature"/>

 <xsl:template match="/*">
     <xsl:variable name="vrtfPass1">
      <xsl:apply-templates/>
     </xsl:variable>

     <xsl:apply-templates mode="pass2"
          select="ext:node-set($vrtfPass1)"/>
 </xsl:template>

 <xsl:template match="Node">
  <Node name="{@name}">
   <xsl:variable name="vSignature">
    <xsl:for-each select="*">
     <xsl:sort select="name()"/>
     <xsl:sort select="@value"/>
      <xsl:value-of select="concat(name(),'+++',@value)"/>
    </xsl:for-each>
  </xsl:variable>

  <xsl:attribute name="signature">
   <xsl:value-of select="$vSignature"/>
  </xsl:attribute>
  </Node>
 </xsl:template>

 <xsl:template match="/" mode="pass2">
  <xsl:for-each select=
    "Node[generate-id()
         =
          generate-id(key('kNodeBySign',@signature)[1])
         ]
    ">

    <Node name="{@name}">
      <xsl:variable name="vNodesInGroup">
        <xsl:for-each select=
          "key('kNodeBySign',@signature)[position()>1]">
          <xsl:value-of select="concat(@name, ' ')"/>
        </xsl:for-each>
      </xsl:variable>

      <xsl:attribute name="matches">
       <xsl:value-of select="$vNodesInGroup"/>
      </xsl:attribute>
    </Node>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

应用于此 XML 文档时:

<Document>
    <Node name="n1">
        <Item value="v1"/>
        <Item value="v2"/>
        <Item value="v3"/>
    </Node>
    <Node name="n2">
        <Item value="p1"/>
        <Item value="p2"/>
        <Item value="p3"/>
    </Node>
    <Node name="n3">
        <Item value="v3"/>
        <Item value="v1"/>
        <Item value="v2"/>
    </Node>
    <Node name="n4">
        <Item value="p3"/>
        <Item value="v1"/>
        <Item value="v2"/>
    </Node>
    <Node name="n5">
        <Item value="v2"/>
        <Item value="v1"/>
        <Item value="v3"/>
    </Node>
    <Node name="n6">
        <Item value="v2"/>
        <Item value="v1"/>
        <Item value="v3"/>
        <Item value="v4"/>
    </Node>
    <Node name="n7">
        <Item value="v1"/>
        <Item value="v1"/>
        <Item value="v2"/>
        <Item value="v3"/>
        <Item value="v4"/>
    </Node>
</Document>

产生想要的、正确的结果:

<Node name="n1" matches="n3 n5 "/>
<Node name="n2" matches=""/>
<Node name="n4" matches=""/>
<Node name="n6" matches=""/>
<Node name="n7" matches=""/>

说明:

  1. 这是一个两遍的转换.

  1. This is a two-pass transformation.

第一遍的结果是一个 XML 片段,其中包含 Node 元素及其 name 属性和一个新添加的属性:signature.这是所有子项的名称和值的串联(以正常的排序形式).在这种具体情况下,pass1 的结果如下:

The result of the first pass is an XML fragment containing Node elements with their name attribute and one newly added attribute: signature. This is the concatenation of the names and values of all children (in normal, sorted form). The result of pass1 in this concrete case is the following:

在第 2 轮中,我们使用 Muenchian 方法按 signature 属性对所有 Node 元素进行分组.每个组中的第一个 Node 在输出中用一个新属性 matches 表示,其值是以下元素的 name 属性的空格分隔连接当前组中剩余的 Node 元素.

In pass 2 we use the Muenchian method for grouping all Node elements by their signature attribute. The first Node in every group is represented in the output with a new attribute matches whose value is the space-delimited concatenation of the name attributes of the remaining Node elements in the current group.

这篇关于如何找到具有相同子节点的节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆