如何使用xslt比较和合并两个xml

Arn*_*nab 5 xml xslt merge

我想比较两个xmls然后合并它们.例如:

myFile1.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<data>
    <title>Title1</title>
    <description>Description1</description>
    <myid>1</myid>
</data>
<data>
    <title>Title2</title>
    <description>Description2</description>
    <myid>2</myid>
</data>
</catalog>
Run Code Online (Sandbox Code Playgroud)

myFile2.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<data>
    <title>Title1</title>
    <description>Description1</description>
    <author>Author1</author>
    <date>12/34/5678</date>
    <myid>1</myid>
</data>
<data>
    <author>Author2</author>
    <date>87/65/4321</date>
    <myid>2</myid>
</data>
</catalog>
Run Code Online (Sandbox Code Playgroud)

期望的输出:

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<data>
    <title>Title1</title>
    <description>Description1</description>
    <myid>1</myid>
    <author>Author1</author>
    <date>12/34/5678</date>
</data>
<data>
    <title>Title2</title>
    <description>Description2</description>
    <myid>2</myid>
    <author>Author2</author>
    <date>87/65/4321</date>
</data>
</catalog>
Run Code Online (Sandbox Code Playgroud)

我有一个代码,但它没有按照所需的输出执行.

<?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="compare" select="'myFile1.xml'"/>
<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="*">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:variable name="info1" select="document($compare)/catalog/data[myid=current()/myid]/."/>
        <xsl:variable name="info2" select="document($with)/catalog/data[myid=current()/myid]/."/>
        <xsl:for-each select="$info1/*">
            <xsl:variable name="check1" select="name(current())"/>
            <!--xsl:text>Current node1 : </xsl:text><xsl:value-of select="$check1"/-->
            <xsl:for-each select="$info2/*">
                <xsl:variable name="check2" select="name(current())"/>
                <!--xsl:text>Current node2 : </xsl:text><xsl:value-of select="$check2"/-->
                <xsl:if test="$check1!=$check2">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>
</xsl:transform>
Run Code Online (Sandbox Code Playgroud)

请帮忙!

Emi*_*ggi 1

该解决方案完全没有循环或密钥。我仅使用 加载了一份文档document(),而使用另一份文档作为源。简而言之,源文档中缺少一个元素,它会在加载的文档中获取。元素越多,可用性就越差,这就是这个解决方案。请参阅底部以获得更通用的信息。


XSLT 1.0在Saxon-HE 9.2.1.1J上测试

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="catalog2" select="document('source_test2.xml')/catalog"/>

    <xsl:template match="catalog">
        <catalog>
            <xsl:apply-templates select="data"/>
        </catalog>
    </xsl:template>

    <xsl:template match="data">
        <xsl:variable name="data2" select="$catalog2/data[myid=current()/myid]/."/>
        <data>
            <xsl:choose>
                <xsl:when test="title">
                    <xsl:copy-of select="title"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$data2/title"/>
                </xsl:otherwise>
            </xsl:choose>

            <xsl:choose>
                <xsl:when test="description">
                    <xsl:copy-of select="description"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$data2/description"/>
                </xsl:otherwise>
            </xsl:choose>

            <xsl:copy-of select="myid"/>

            <xsl:choose>
                <xsl:when test="author">
                    <xsl:copy-of select="author"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$data2/author"/>
                </xsl:otherwise>
            </xsl:choose>

            <xsl:choose>
                <xsl:when test="date">
                    <xsl:copy-of select="date"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$data2/date"/>
                </xsl:otherwise>
            </xsl:choose>

        </data>
    </xsl:template>

</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

下面是一个更通用的解决方案。方法是一样的。对于每个data, 中存在myFile2和缺失的元素myFile1将添加到结果树中,反之亦然。

XSLT 1.0在Saxon-B 9.0.0.4J上测试

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="catalog2" select="document('myFile2.xml')/catalog"/>

    <xsl:template match="catalog">
        <catalog>
            <xsl:apply-templates select="data"/>
        </catalog>
    </xsl:template>

    <xsl:template match="data">
        <xsl:variable name="data1" select="."/>
        <xsl:variable name="data2" select="$catalog2/data[myid=current()/myid]/."/>
        <data>
            <xsl:copy-of select="$data1/*"/>
            <xsl:for-each select="$data2/*">
                <xsl:variable name="element2" select="name(.)"/>
                <xsl:if test="count($data1/*[name()=$element2])=0">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </data>
    </xsl:template>

</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)