在 XSLT 中递归组合相同的兄弟元素 [英] Recursively combine identical sibling elements in XSLT

查看:31
本文介绍了在 XSLT 中递归组合相同的兄弟元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用 XSLT 将具有相同名称和相同属性的所有兄弟元素合并为一个元素?转换也应该递归地应用于正在合并的元素的子元素.这是源文件:

How can I merge all sibling elements with the same name and the same attributes into a single element using XSLT? The transformation should also be applied recursively to children of elements that are being merged. This is the source document:

<?xml version="1.0"?>
<Root>
  <Element id="UniqueId1">
    <SubElement1/>
    <SubElement2>
      <LeafElement1/>
    </SubElement2>
  </Element>
  <Element id="UniqueId1">
    <SubElement2>
      <LeafElement1/>
      <LeafElement2/>
    </SubElement2>
    <SubElement3/>
  </Element>
  <Element id="UniqueId2">
    <SubElement1/>
    <SubElement4/>
  </Element>    
</Root>

它应该转换为:

<?xml version="1.0"?>
<Root>
  <Element id="UniqueId1">
    <SubElement1/>
    <SubElement2>
      <LeafElement1/>
      <LeafElement2/>
    </SubElement2>
    <SubElement3/>
  </Element>
  <Element id="UniqueId2">
    <SubElement1/>
    <SubElement4/>
  </Element>    
</Root>

具有相同名称和属性的任何元素合并为一个元素.然后,他们的孩子接受检查.如果它们中的任何一个具有相同的名称和相同的属性,则将它们组合在一起.这种转换递归地应用于所有元素.

Any elements with the same name and attributes are combined into one element. Then, their children are inspected. If any of them have the same name and same attributes, they are combined. This transformation is applied recursively to all elements.

澄清一下,要合并的两个元素必须满足所有这些条件.

To clarify, all of these conditions must be true for two elements to be merged.

  • 它们具有相同的元素名称
  • 它们具有相同的属性
  • 每个对应属性的值都是一样的
  • 它们是兄弟元素(递归应用,因此在考虑它们的子元素之前,任何相同的父元素都会被合并和组合)

这些元素是相同的,应该合并:

These elements are identical and should be merged:

  • (名称相同,属性相同)
  • <Item Attr="foo"/>(名称相同,属性相同)
  • <Item/> and <Item/> (same name, same attributes)
  • <Item Attr="foo"/> and <Item Attr="foo"/> (same name, same attributes)

这些元素不相同,不应合并:

These elements are not identical and shouldn't be merged:

  • (不同的名字)
  • (不同的属性)
  • (不同的属性值)
  • <Item/> and <SubItem/> (different name)
  • <Item Attr="foo"/> and <Item/> (different attributes)
  • <Item Attr="foo"/> and <Item Attr="bar"/> (different attribute values)

推荐答案

这应该可以:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" indent="yes"/>
  <xsl:key name="atts-by-name" match="@*" use="name()"/>
  <xsl:template match="Root">
    <xsl:copy>
      <xsl:call-template name="merge">
        <xsl:with-param name="elements" select="*"/>
      </xsl:call-template>
    </xsl:copy>
  </xsl:template>
  <xsl:template name="merge">
    <xsl:param name="elements"/>
    <xsl:for-each select="$elements">
      <xsl:variable name="same-elements" select="$elements[name()=name(current()) and count(@*)=count(current()/@*) and count(@*[. = key('atts-by-name',name())[generate-id(..)=generate-id(current())]])=count(@*)]"/>
      <xsl:if test="generate-id($same-elements[1]) = generate-id()">
        <xsl:copy>
          <xsl:copy-of select="@*"/>
          <xsl:call-template name="merge">
            <xsl:with-param name="elements" select="$same-elements/*"/>
          </xsl:call-template>
        </xsl:copy>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

棘手的部分是相同元素的定义;按名称索引属性对于验证所有属性的平等性是强制性的.

The tricky part is the definition of same-elements; indexing attributes by name is mandatory for verifying egality of all attributes.

这篇关于在 XSLT 中递归组合相同的兄弟元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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