需要XSLT来合并两个xml文件

时间:2018-11-15 16:34:35

标签: xml xslt

文件结构: File1.xml和File2.xml都具有相同的结构。

文件具有资源的列表/数组,每个资源具有代码的列表/数组。

每个代码都由“ id”属性唯一标识。

每个代码都有“ override”属性,用于指定覆盖规则。

如果override =“ true”,则可以将file1.xml中的代码元素替换为file2.xml中的代码元素。

我想使用xslt和以下规则将File1.xml与File2.xml合并

  1. 如果两个文件具有相同的资源名称(例如:“ resource1”),则可以合并其中的代码。

    在合并操作期间,如果我们具有相同的“ id”值,则只有在override =“ true”时,才能将file1代码元素替换为file2代码元素。

    <code id="1" field1="value11" field2="value12" override="true" />
    <code id="1" field1="value71" field2="value72" override="true" />
    
    For this the result should be 
    <code id="1" field1="value71" field2="value72" override="true" /> 
    

    如果override =“ false”,那么我们不会替换代码元素。

    为此,结果应该是

  2. 如果我们有不同的资源名称(例如:File1.xml中的resource2和File2.xml中的resource3),则可以将它们写在output.xml中,如下所示: 文件之间没有任何内容可以合并。

    非常感谢您对我的问题表现出兴趣!!!

File1.xml

<resources>
    <resource name="resource1">
        <codes>
            <code id="1" field1="value11" field2="value12" override="true" />
            <code id="2" field1="value21" field2="value22" override="false" />
            <code id="3" field1="value31" field2="value32" override="true" />
        </codes>
    </resource>
    <resource name="resource2">
        <codes>
            <code id="1" field1="value11" field2="value12" override="true" />
        </codes>
    </resource>
</resources>

File2.xml

<resources>
    <resource name="resource1">
        <codes>
            <code id="1" field1="value71" field2="value72" override="true" />
            <code id="2" field1="value81" field2="value82" override="true" />
            <code id="4" field1="value91" field2="value92" override="true" />
        </codes>
    </resource>
    <resource name="resource3">
        <codes>
            <code id="2" field1="value81" field2="value82" override="true" />
        </codes>
    </resource>
</resources>

output.xml

<resources>
    <resource name="resource1">
        <codes>
            <code id="1" field1="value71" field2="value72" override="true" />
            <code id="2" field1="value21" field2="value22" override="false" />
            <code id="3" field1="value31" field2="value32" override="true" />
            <code id="4" field1="value91" field2="value92" override="true" />
        </codes>
    </resource>
    <resource name="resource2">
        <codes>
            <code id="1" field1="value11" field2="value12" override="true" />
        </codes>
    </resource>
    <resource name="resource3">
        <codes>
            <code id="2" field1="value81" field2="value82" override="true" />
        </codes>
    </resource>
</resources>

1 个答案:

答案 0 :(得分:1)

当您似乎使用Java运行XSLT时,可以考虑使用Saxon 9(在Maven上的开源HE版本中可用于Java(当前最新版本的Saxon 9.9 HE位于Saxon的https://search.maven.org/artifact/net.sf.saxon/Saxon-HE/9.9.0-2/jar) 9.8 HE在https://search.maven.org/artifact/net.sf.saxon/Saxon-HE/9.8.0-14/jar和Sourceforge https://sourceforge.net/projects/saxon/files/Saxon-HE/)使用XSLT 3或2代替内置的Oracle / Apache Xalan处理器支持的20年历史的XSLT 1。

使用XSLT 3,您可以将其视为嵌套分组问题,如下所示:

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

  <xsl:param name="doc2">
<resources>
    <resource name="resource1">
        <codes>
            <code id="1" field1="value71" field2="value72" override="true" />
            <code id="2" field1="value81" field2="value82" override="true" />
            <code id="4" field1="value91" field2="value92" override="true" /> 
        </codes>
    </resource>
    <resource name="resource3">
        <codes>
            <code id="2" field1="value81" field2="value82" override="true" />
        </codes>
    </resource>
</resources>
  </xsl:param>

  <xsl:output indent="yes"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="resources">
      <xsl:copy>
          <xsl:for-each-group select="resource, $doc2/resources/resource" group-by="@name">
              <resource>
                  <xsl:apply-templates select="@*"/>
                  <codes>
                      <xsl:for-each-group select="current-group()!codes/code" group-by="@id">
                          <xsl:apply-templates
                            select="if (current-group()[2] and ./@override = 'true')
                                    then current-group()[2]
                                    else ."/>
                      </xsl:for-each-group>
                  </codes>
              </resource>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/jyH9rNn/3有一个在线示例,该示例出于紧凑性和完整性的目的而将第二个文档用作内联参数,但是您当然可以传入第二个文件的URI并使用例如改为<xsl:param name="doc2" select="doc("file2.xml")"/>

关于XSLT的介绍,可以在https://cranesoftwrights.github.io/books/ptux/index.htm上获得一本免费的书,《使用XSLT和XPath进行实用转换》。