XSLT 根据条件合并 XML 个文件

XSLT to merge XML files based on Condition

是否可以使用 XSLT 1.0 合并两个 xml 数据文件 - Xml-01Xml-02。要使用的合并键应基于 Xml-01 中的值 SystemXml-02 中的 SystemName 映射。

最终输出应该如下所示(post 的底部)。

我正在尝试在 Mule Studio 的 Mule Data Mapper 组件中执行此操作。它没有必要的功能,所以我尝试使用 XSLT 1.0。

Xml-01

 <?xml version="1.0" encoding="UTF-8"?>
    <ns0:RetrieveMIProcessResponse xmlns:ns0="http://xmlns.jupiter.com/RetrieveMI">
      <ns0:Inquiry>
        <ns0:MIId>ID0012</ns0:MIId>
        <ns0:System>System007</ns0:System>
        <ns0:ProductsList>
          <ns0:ProductIDs>
            <ns0:ProductID/>
          </ns0:ProductIDs>
        </ns0:ProductsList>
      </ns0:Inquiry>
      <ns0:Inquiry>
        <ns0:MIId>ID0010</ns0:MIId>
        <ns0:System>System003</ns0:System>
        <ns0:ProductsList>
          <ns0:ProductIDs>
            <ns0:ProductID/>
          </ns0:ProductIDs>
        </ns0:ProductsList>
      </ns0:Inquiry>
      <ns0:Inquiry>
        <ns0:MIId>ID009</ns0:MIId>
        <ns0:System>System006</ns0:System>
        <ns0:ProductsList>
          <ns0:ProductIDs>
            <ns0:ProductID/>
          </ns0:ProductIDs>
        </ns0:ProductsList>
      </ns0:Inquiry>
     </ns0:RetrieveMIProcessResponse>

Xml-02

<ns0:ProductsResponse xmlns:ns0="http://xmlns.jupiter.com/RetrieveProducts">
  <ns0:Products>
    <ns0:ProductCode>ProductCode01</ns0:ProductCode>
    <ns0:SystemName>System007</ns0:SystemName>
  </ns0:Products>
  <ns0:Products>
    <ns0:ProductCode>ProductCode02</ns0:ProductCode>
    <ns0:SystemName>System007</ns0:SystemName>
  </ns0:Products>
  <ns0:Products>
    <ns0:ProductCode>ProductCode03</ns0:ProductCode>
    <ns0:SystemName>System003</ns0:SystemName>
  </ns0:Products>
  </ns0:ProductsResponse>

最终输出 -

 <?xml version="1.0" encoding="UTF-8"?>
<ns0:RetrieveMIProcessResponse xmlns:ns0="http://xmlns.jupiter.com/RetrieveMI">
  <ns0:Inquiry>
    <ns0:MIId>ID0012</ns0:MIId>
    <ns0:System>System007</ns0:System>
    <ns0:ProductsList>
      <ns0:ProductIDs>
        <ns0:ProductID>ProductCode01</ns0:ProductID>
      </ns0:ProductIDs>
       <ns0:ProductIDs>
        <ns0:ProductID>ProductCode02</ns0:ProductID>
      </ns0:ProductIDs>
    </ns0:ProductsList>
  </ns0:Inquiry>
  <ns0:Inquiry>
    <ns0:MIId>ID0010</ns0:MIId>
    <ns0:System>System003</ns0:System>
    <ns0:ProductsList>
      <ns0:ProductIDs>
        <ns0:ProductID>ProductCode03</ns0:ProductID>
      </ns0:ProductIDs>
    </ns0:ProductsList>
  </ns0:Inquiry>
  <ns0:Inquiry>
    <ns0:MIId>ID009</ns0:MIId>
    <ns0:System>System006</ns0:System>
    <ns0:ProductsList>
      <ns0:ProductIDs>
        <ns0:ProductID/>
      </ns0:ProductIDs>
    </ns0:ProductsList>
  </ns0:Inquiry>
 </ns0:RetrieveMIProcessResponse>

 code here

这里的一般想法是 Xml-01 将是 XSLT 的主要输入文档,您将使用 document() function 加载次要 Xml-02。

这可能是一个相当简单的查找,除了:

  1. 在 XSLT 1.0 中使用关键字跨文档查找很不方便;
  2. 您的查找文档正在使用不同的命名空间(尽管使用 相同的前缀);
  3. 查找失败时需要添加空节点(真的有必要吗?)。

考虑到这一点,请尝试:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xmlns.jupiter.com/RetrieveMI"
xmlns:ns1="http://xmlns.jupiter.com/RetrieveProducts"
exclude-result-prefixes="ns1">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="path-to-lookup" select="'02.xml'"/>

<xsl:key name="product-by-system" match="ns1:Products" use="ns1:SystemName" />

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

<xsl:template match="ns0:ProductsList">
    <xsl:variable name="system" select="../ns0:System" />
    <xsl:copy>
        <!-- switch context to lookup document in order to use key -->
        <xsl:for-each select="document($path-to-lookup)">
            <xsl:variable name="matching-products" select="key('product-by-system', $system)" />
            <xsl:for-each select="$matching-products">
                <ns0:ProductIDs>
                    <ns0:ProductID>
                        <xsl:value-of select="ns1:ProductCode"/>
                    </ns0:ProductID>
                </ns0:ProductIDs>
            </xsl:for-each>
            <!-- add empty node when there is no match -->
            <xsl:if test="not($matching-products)">
                <ns0:ProductIDs>
                    <ns0:ProductID/>
                </ns0:ProductIDs>
            </xsl:if>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>