首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在一个文件中合并/合并类似的XML结构

在一个文件中合并/合并类似的XML结构
EN

Stack Overflow用户
提问于 2014-11-18 09:36:06
回答 1查看 790关注 0票数 0

我在XML文件中有以下结构:

代码语言:javascript
复制
<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="sowhat">
    </layer2>
  </layer1>
</root>
<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="justit">
    </layer2>
  </layer1>
</root>
<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="yeaha">
    </layer2>
  </layer1>
</root>
<root name="name2123">
  <layer1 name="name2">
    <layer2 attribute="itis">
    </layer2>
  </layer1>
</root>

我想要得到的结果是:

代码语言:javascript
复制
<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="sowhat"></layer2>
    <layer2 attribute="justit"></layer2>
    <layer2 attribute="yeaha"></layer2>
  </layer1>
</root>
<root name="name2123">
  <layer1 name="name2">
    <layer2 attribute="itis">
    </layer2>
  </layer1>
</root>

因此,我希望尽可能地合并和合并节点。我还没有使用XSLT,尝试过它,但是我不理解它,甚至没有一般的想法。还有其他的想法或工具吗?

谢谢

EN

回答 1

Stack Overflow用户

发布于 2014-11-18 10:38:44

值得注意的是,这里有一种在XSLT1.0中这样做的方法。

代码语言:javascript
复制
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:key name="name" match="*[@name]" use="
    concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
  " />

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

  <xsl:template match="*[@name]">
    <xsl:variable name="myKey" select="
      concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
    " />
    <xsl:variable name="myGroup" select="key('name', $myKey)" />

    <xsl:if test="generate-id() = generate-id($myGroup[1])">
      <xsl:copy>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates select="$myGroup/*" />
      </xsl:copy>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

输出

代码语言:javascript
复制
<roots>
  <root name="name1">
    <layer1 name="name2">
      <layer2 attribute="sowhat"/>
      <layer2 attribute="justit"/>
      <layer2 attribute="yeaha"/>
    </layer1>
  </root>
  <root name="name2123">
    <layer1 name="name2">
      <layer2 attribute="itis"/>
    </layer1>
  </root>
</roots>

XSLT的关键特性是能够在相对较少的代码行中表示复杂的转换。上面的转换是29行代码,您可以更多地压缩它。

我认为XSLT速成课程超出了这个答案的范围。除此之外,在Internet上有无数的XSLT速成班可供选择。

所以我要做的是对这里发生的事情做一个总体的概述。

首先,我为您的输入定义了两类元素--可合并元素和不可合并元素。我已经定义了所有具有@name属性的元素是可合并的。

  1. 所有正常节点(没有@name的节点)都按原样复制。第一个<xsl:template>这样做(它是身份模板)。
  2. 我已经定义了一个元素的“可合并组”,这些元素沿着它们的祖先共享一组公共的@name属性值。
    • 为此,我为所有拥有这些属性的元素创建了所有相关@name属性的连接。
    • 目前,这种转换可以处理3层深度的组(concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name))。
    • 在必要时以相同的方式添加更多的级别。
    • sowhat的父组名(键)是name2|name1||,这适用于逻辑组中的另一个<layer2>

  1. 现在,每当XSLT引擎遇到带有@name的元素时,它就会。
    • 计算该元素($myKey)的键。
    • 获取具有相同键($myGroup)的元素组。
    • 查找当前元素是否是组中的第一个元素,如果是,则将其复制到输出中。
    • 实际上,该方法根据元素的键对元素进行分组(这种技术称为Muenchian分组)。
    • 然后进行递归步骤:开始处理该组的子组($myGroup/*)。
    • 实际上,这使我们回到了0,算法从一开始就开始了。

在我的代码中有一些假设/限制可能不一定与您的输入相一致。

  • 元素应该由它们的@name而不是其他属性合并。
  • 具有相同@name祖先的元素没有特殊属性,因此,丢弃每个元素(某个组中的第一个元素除外)不会导致数据丢失。
  • 有有限的嵌套深度。
  • 可合并元素绝不是不可合并元素的后代(没有<layer>在没有@name<layer>中有一个@name)。
  • 可能是其他现在忘了我的人。

阅读建议

  • 模板匹配与XSLT处理器的一般工作机制
  • XSL默认规则
  • XPath
  • XSL键和Muenchian分组
  • 标识模板
  • 整个处理流程中当前节点的概念。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26990914

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档