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

发布于 2024-11-08 02:13:30 字数 3169 浏览 1 评论 0原文

我想比较两个 xml,然后合并它们。例如:

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>

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>

所需的输出:

<?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>

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

<?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>

请帮忙!

I want to compare two xmls and then merge them. For example:

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>

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>

Desired Output:

<?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>

I have a code but, it doesnot perform as per the required output.

<?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>

Please Help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

星光不落少年眉 2024-11-15 02:13:30

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


XSLT 1.0Saxon-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>

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

XSLT 1.0Saxon-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>

This solution is totally free of loops or keys. I've loaded only one document using document(), while I use the other one as source. Briefly, an element missing in the source document, it is taken on the loaded one. More elements you have less usable is this solution. See bottom for a more general one.


XSLT 1.0 tested on 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>

Here follows a more general solution. The approach is the same. For each data, an element present in myFile2 and missing in myFile1 is added to the result tree, and vice-versa.

XSLT 1.0 tested on 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文