繁体   English   中英

如何使用 XSLT 合并 XML 元素,然后构造相同名称/类型的元素/属性?

[英]How do I use XSLT to merge XML elements and then structure elements/attributes of the same name/type?

主要问题

我有一个 XML 文件,其中包含多个相似的元素,但信息略有不同。 所以,假设我有两个 X 属性相同但 Y 属性不同的元素。 这是一个例子:

<FILE>
  <ELEMENT>
    <ATTRIBUTEX>1</ATTRIBUTEX>
    <ATTRIBUTEY>A</ATTRIBUTEY>
  </ELEMENT>
  <ELEMENT>
    <ATTRIBUTEX>1</ATTRIBUTEX>
    <ATTRIBUTEY>B</ATTRIBUTEY>
  </ELEMENT>
</FILE>

我想要做的是——基于两个元素具有相同的 X 属性这一事实——将它们合并为具有一个属性 X 和多个子元素(相同类型)的单个元素——每个元素都包含不同的属性 Y。因此,例如,我希望我的文件最终如下所示:

<FILE>
  <ELEMENT>
    <ATTRIBUTEX>1</ATTRIBUTEX>
    <NEWELEMENT>
      <ATTRIBUTEY>A</ATTRIBUTEY>
    </NEWELEMENT>
    <NEWELEMENT>
      <ATTRIBUTEY>B</ATTRIBUTEY>
    </NEWELEMENT>
  </ELEMENT>
</FILE>

可能的解决方案?

我能想到的一种可能的解决方案,但缺乏执行知识,由两个步骤组成:

  1. 首先,我可以合并所有包含 X 属性的元素,以便信息至少在一个地方。 我不知道该怎么做。
  2. 其次,一旦完成,这让我打开了大门——理论上——使用我对 XSLT 的知识来重新构造元素。

可能解决方案的问题

但是,一旦包含 X 属性的所有元素都合并在一起(第一步),我将有一个文件,其中将有同名的属性(特别是 Y 属性)。 这是一个例子:

<FILE>
  <ELEMENT>
    <ATTRIBUTEX>1</ATTRIBUTEX>
    <ATTRIBUTEY>A</ATTRIBUTEY>
    <ATTRIBUTEY>B</ATTRIBUTEY>
  </ELEMENT>
</FILE>

这意味着 - 至少据我所知 - 当我在上述 XML (第二步)上执行 XSLT 文件时,在将两个 Y 元素排序到两个新的子元素( NEWELEMENT )时,它无法区分它们。

所以,假设我在上面的 XML 上执行了下面的 XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="FILE">
  <Record>
    <xsl:for-each select = "ELEMENT">
      <ELEMENT>
        <xsl:copy-of select="ATTRIBUTEX"/>
      
        <NEWELEMENT>
          <xsl:copy-of select="ATTRIBUTEY"/>
        </NEWELEMENT>
        
        <NEWELEMENT>
          <xsl:copy-of select="ATTRIBUTEY"/>
        </NEWELEMENT>

      </ELEMENT>
    </xsl:for-each> 
  </Record>
</xsl:template>
</xsl:stylesheet>

output 是这样的:

<Record>
    <ELEMENT>
        <ATTRIBUTEX>1</ATTRIBUTEX>
        <NEWELEMENT>
            <ATTRIBUTEY>A</ATTRIBUTEY>
            <ATTRIBUTEY>B</ATTRIBUTEY>
        </NEWELEMENT>
        <NEWELEMENT>
            <ATTRIBUTEY>A</ATTRIBUTEY>
            <ATTRIBUTEY>B</ATTRIBUTEY>
        </NEWELEMENT>
    </ELEMENT>
</Record>

如您所见, NEWELEMENT已将所有和任何ATTRIBUTEY元素放入每个新元素中,而不是区分它们并将一个ATTRIBUTEY放在第一个NEWELEMENT中,将第二个ATTRIBUTEY放在第二个NEWELEMENT中。 我需要一个 XSLT 文件来执行此操作,并且如前所述,生成一个看起来像这样的 XML :

<FILE>
  <ELEMENT>
    <ATTRIBUTEX>1</ATTRIBUTEX>
    <NEWELEMENT>
      <ATTRIBUTEY>A</ATTRIBUTEY>
    </NEWELEMENT>
    <NEWELEMENT>
      <ATTRIBUTEY>B</ATTRIBUTEY>
    </NEWELEMENT>
  </ELEMENT>
</FILE>

有人能帮我解决这个问题吗? 任何从第一个示例文件生成所需 output(上图)的解决方案都将不胜感激。 如果该解决方案遵循第一步和第二步,那将是一个奖励。 谢谢!

我正在从下面的 XSLT 3.0 中获得您请求的 output。

只是事先说明几点:

  1. 您提到了属性,但实际上,一切都是您的 XML 文档中的一个元素。 XML 意义上没有属性。
  2. 我真的不认为需要创建额外的子元素。你已经可以拥有一个同名元素的列表。

尽管如此,作为样式(表)的练习,这里有一个样式表,它从您的给定输入生成您的 output:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all">

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="/FILE" >
    <FILE>
      <xsl:for-each-group select="*" group-by="name(.)" >
        <xsl:variable name="parentName" as="xs:string" select="current-grouping-key()" /> 
        
        <xsl:variable name="childNamesSameValues" as="xs:string*" >
          <xsl:for-each-group select="current-group()/*" group-by="name(.)" >
            <xsl:if test="count(distinct-values(current-group()/text())) eq 1">
              <xsl:sequence select="current-grouping-key()" />
            </xsl:if>
          </xsl:for-each-group>
        </xsl:variable>
            
        <xsl:element name="{$parentName}" >
          <xsl:for-each-group select="current-group()/*" group-by="name(.)" >
            <xsl:choose>
              <xsl:when test="current-grouping-key() = $childNamesSameValues">
                <xsl:copy-of select="current-group()[1]" />
              </xsl:when>
              <xsl:otherwise >
                <xsl:for-each select="current-group()" >
                  <xsl:element name="NEW{$parentName}" >
                    <xsl:copy-of select="." />
                  </xsl:element>
                </xsl:for-each>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each-group>
        </xsl:element>
      </xsl:for-each-group>
    </FILE>
  </xsl:template>
  
</xsl:stylesheet>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM