XSLT 根据条件合并 XML 个文件
XSLT to merge XML files based on Condition
是否可以使用 XSLT 1.0 合并两个 xml 数据文件 - Xml-01
和 Xml-02
。要使用的合并键应基于 Xml-01
中的值 System
与 Xml-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。
这可能是一个相当简单的查找,除了:
- 在 XSLT 1.0 中使用关键字跨文档查找很不方便;
- 您的查找文档正在使用不同的命名空间(尽管使用
相同的前缀);
- 查找失败时需要添加空节点(真的有必要吗?)。
考虑到这一点,请尝试:
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>
是否可以使用 XSLT 1.0 合并两个 xml 数据文件 - Xml-01
和 Xml-02
。要使用的合并键应基于 Xml-01
中的值 System
与 Xml-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。
这可能是一个相当简单的查找,除了:
- 在 XSLT 1.0 中使用关键字跨文档查找很不方便;
- 您的查找文档正在使用不同的命名空间(尽管使用 相同的前缀);
- 查找失败时需要添加空节点(真的有必要吗?)。
考虑到这一点,请尝试:
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>