【问题标题】:Merge 2 XML files with matching 'id' attribute using XSLT使用 XSLT 合并 2 个具有匹配“id”属性的 XML 文件
【发布时间】:2012-08-31 13:34:21
【问题描述】:

当有匹配的 'id' 属性时,我想使用 XSLT 合并 2 个 XML 文件。

myFile1.xml(这是第一个输入文件)

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <test>
      <node>
        <type id="a">
          <name>joe</name>
          <name>kill</name>
        </type>
      </node>
      <node>
        <type id="b">
          <name>sam</name>
        </type>
      </node>
    </test>

myFile2.xml(这是第二个输入文件)

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <test>
      <node>
        <type id="a">
        <name>jill</name>
        <name>kill</name>
        </type>
      </node>
    </test>

mergeOutput.xml(这是 id 匹配并合并 2 个文件的预期输出)

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <test>
      <node>
        <type id="a">
          <name>joe</name>
         <name>jill</name> 
          <name>Kill</name>
        </type>
      </node>
      <node>
        <type id="b">
          <name>sam</name>
        </type>
      </node>
    </test>

任何 XSLT 代码或代码链接都会有所帮助。我没有 XSLT 知识,也没有使用此合并来使事情正常进行。

【问题讨论】:

  • 同一个文件中可以有多个&lt;type&gt;元素与同一个id吗?
  • (回复 Ian Roberts)- 文件中有多个 元素,但每个元素都有唯一的 id 属性。
  • 可以在几秒钟内使用 LINQ2XML 做到这一点......但不能在 xslt 中......如果你是 c# 开发人员,你可以为此使用 LINQ2XML
  • 在一个输入文件中,id="a" 的元素有两个孩子;在另一个文件中,它有 2 个不同的孩子;但结果是这四个中的三个。我不明白其中的逻辑。
  • @MichaelKay,OP 认为“Kill”和“kill”是两个相等的字符串——可能是一个错字。

标签: xml xslt merge


【解决方案1】:

XSLT 2.0 解决方案:

<xsl:template name="main">
  <test>
    <node>
      <xsl:for-each-group select="(doc('myFile1.xml'), doc('myFile2.xml'))/test/node/type"
                          group-by="@id">
        <type id="{@id}">
          <xsl:copy-of select="current-group()/*"/>
        </type>
      </xsl:for-each-group>
    </node>
  </test>
</xsl:template>

【讨论】:

    【解决方案2】:

    您可以在LINQ2XML 中执行此操作

    XElement doc1=XElement.Load("myFile1.xml");
    XElement doc2=XElement.Load("myFile2.xml");
    XElement doc3=XElement.Load("myFile1.xml");//will contain mergeOutput
    
    var dec=doc3.Descendants().Elements("type").ToList();
    int i=0;
    foreach(XElement elm1 in doc1.Descendants().Elements("type"))
    foreach(XElement elm2 in doc2.Descendants().Elements("type"))
    if(elm1.Attribute("id").Value==elm2.Attribute("id").Value)
    dec[i++].Add(elm2.Elements());
    
    doc3;//your mergeOutput
    

    【讨论】:

    • 感谢您提供此解决方案,但出于架构方面的考虑,我需要在 XSLT 中实现此功能。
    【解决方案3】:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" encoding="ISO-8859-1" indent="yes" />
      <xsl:variable name="with" select="'myFile2.xml'" />
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="//type">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()" />
          <xsl:variable name="info" select="document($with)/test/node/type[@id=current()/@id]/." />
         <xsl:for-each select="$info/*">
              <xsl:copy-of select="." />
          </xsl:for-each>
        </xsl:copy>
      </xsl:template>
    </xsl:transform>
    

    这个变换的输出是(见kill是否重复)-

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <test>
        <node>
            <type id="a">
                <name>joe</name>
                <name>kill</name>
                <name>jill</name>
                <name>kill</name>
            </type>
        </node>
        <node>
            <type id="b">
                <name>sam</name>
            </type>
        </node>
    </test>
    

    【讨论】:

    • 我使用上面的转换来获得带有重复的中间 XML,然后我写了另一个在给定的 /type/@id 下查找和删除重复的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多