比较两个xml文件与xslt?

时间:2023-01-14 21:16:41

I have 2 xml files. How can I compare both files are equal or not by using xslt? If not equal means where the changes havebeen occur in the second xml?

我有2个xml文件。如何使用xslt比较两个文件是否相等?如果不相等意味着在第二个xml中发生了哪些变化?

3 个解决方案

#1


4  

In XPath 2.0 you could simple use fn:deep-equal.

在XPath 2.0中,你可以简单地使用fn:deep-equal。

Following the same pattern in XSLT 1.0, this stylesheet:

在XSLT 1.0中遵循相同的模式,这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pSource2" select="'emp2.xml'"/>
    <xsl:template match="/*">
        <xsl:variable name="vDeep-equal">
            <xsl:apply-templates select="." mode="deep-equal">
                <xsl:with-param name="pTarget" select="document($pSource2)/*"/>
            </xsl:apply-templates>
        </xsl:variable>
        <xsl:choose>
            <xsl:when test="normalize-space($vDeep-equal)">
                <xsl:text>Documents are different</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>Documents are deep equal</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="*" mode="deep-equal">
        <xsl:param name="pTarget"/>
        <xsl:choose>
            <xsl:when test="$pTarget/self::* and
                            local-name()=local-name($pTarget) and
                            namespace-uri()=namespace-uri($pTarget) and
                            count(@*)=count($pTarget/@*) and
                            count(*|text()[normalize-space()]) =
                               count($pTarget/*|
                                     $pTarget/text()[normalize-space()])">
                <xsl:for-each select="@*">
                    <xsl:if test="$pTarget/@*[name()=name(current())] != .">
                        <xsl:text>false</xsl:text>
                    </xsl:if>
                </xsl:for-each>
                <xsl:for-each select="*|text()[normalize-space()]">
                    <xsl:variable name="vPosition" select="position()"/>
                    <xsl:apply-templates select="." mode="deep-equal">
                        <xsl:with-param name="pTarget"
                                        select="($pTarget/*|
                                                 $pTarget/text()
                                                    [normalize-space()])
                                                            [$vPosition]"/>
                    </xsl:apply-templates>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>false</xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="text()" mode="deep-equal">
        <xsl:param name="pTarget"/>
        <xsl:if test="not($pTarget/self::text() and
                      string() = string($pTarget))">
            <xsl:text>false</xsl:text>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Output:

输出:

Documents are different

#2


0  

XSLT is best used for transforming one XML dialect to another.

XSLT最适合用于将一种XML方言转换为另一种XML方言。

To compare XML files, I would use an XML parser on your platform and compare the documents using it.

为了比较XML文件,我将在您的平台上使用XML解析器并使用它来比较文档。

It is possible to compare the two, but I would advise against it, if you have other options.

有可能比较两者,但如果你有其他选择,我会反对它。

#3


0  

This is the stylesheet I wrote to compare two XML files with different order in nodes and attributes. It will generate two text files, containing the ordered list of all the leaf nodes path. Use any text compare tool to spot out the differences or enhance the XSLT to do what you want.

这是我编写的样式表,用于比较节点和属性中具有不同顺序的两个XML文件。它将生成两个文本文件,其中包含所有叶节点路径的有序列表。使用任何文本比较工具来发现差异或增强XSLT以执行您想要的操作。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text" indent="no" omit-xml-declaration="yes" name="output" />

<xsl:param name="OTHERFILENAME">xml_file_to_diff.xml</xsl:param>
<xsl:param name="ORIGINAL_OUTPUT_FILENAME">ORIGINAL.txt</xsl:param>
<xsl:param name="OTHER_OUTPUT_FILENAME">OTHER.txt</xsl:param>

<xsl:template match="/">
    <xsl:call-template name="convertXMLHierarchyToFullPath">
        <xsl:with-param name="node" select="*"/>
        <xsl:with-param name="filename" select="$ORIGINAL_OUTPUT_FILENAME"/>
    </xsl:call-template>
    <xsl:call-template name="convertXMLHierarchyToFullPath">
        <xsl:with-param name="node" select="document($OTHERFILENAME)/*"/>
        <xsl:with-param name="filename" select="$OTHER_OUTPUT_FILENAME"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="convertXMLHierarchyToFullPath">
    <xsl:param name="node"/>
    <xsl:param name="filename"/>

    <xsl:variable name="unorderedFullPath">
        <xsl:apply-templates select="$node"/>
    </xsl:variable>

    <xsl:result-document href="{$filename}" format="output">
        <xsl:for-each select="$unorderedFullPath/*">
            <xsl:sort select="@path" data-type="text"/>
            <xsl:value-of select="@path"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:for-each>
    </xsl:result-document>
</xsl:template>

<xsl:template match="*">
    <xsl:if test="not(*)">
        <leaf>
            <xsl:attribute name="path">
                <xsl:for-each select="ancestor-or-self::*">
                    <xsl:value-of select="name()"/>
                    <xsl:for-each select="@*">
                        <xsl:sort select="name()" data-type="text"/>
                        <xsl:text>[</xsl:text>
                        <xsl:value-of select="name()"/>
                        <xsl:text>:</xsl:text>
                        <xsl:value-of select="."/>
                        <xsl:text>]</xsl:text>
                    </xsl:for-each>
                    <xsl:text>/</xsl:text>
                </xsl:for-each>
                <xsl:value-of select="."/>
            </xsl:attribute>
        </leaf>
    </xsl:if>
    <xsl:apply-templates select="*"/>
</xsl:template>

</xsl:stylesheet>

#1


4  

In XPath 2.0 you could simple use fn:deep-equal.

在XPath 2.0中,你可以简单地使用fn:deep-equal。

Following the same pattern in XSLT 1.0, this stylesheet:

在XSLT 1.0中遵循相同的模式,这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pSource2" select="'emp2.xml'"/>
    <xsl:template match="/*">
        <xsl:variable name="vDeep-equal">
            <xsl:apply-templates select="." mode="deep-equal">
                <xsl:with-param name="pTarget" select="document($pSource2)/*"/>
            </xsl:apply-templates>
        </xsl:variable>
        <xsl:choose>
            <xsl:when test="normalize-space($vDeep-equal)">
                <xsl:text>Documents are different</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>Documents are deep equal</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="*" mode="deep-equal">
        <xsl:param name="pTarget"/>
        <xsl:choose>
            <xsl:when test="$pTarget/self::* and
                            local-name()=local-name($pTarget) and
                            namespace-uri()=namespace-uri($pTarget) and
                            count(@*)=count($pTarget/@*) and
                            count(*|text()[normalize-space()]) =
                               count($pTarget/*|
                                     $pTarget/text()[normalize-space()])">
                <xsl:for-each select="@*">
                    <xsl:if test="$pTarget/@*[name()=name(current())] != .">
                        <xsl:text>false</xsl:text>
                    </xsl:if>
                </xsl:for-each>
                <xsl:for-each select="*|text()[normalize-space()]">
                    <xsl:variable name="vPosition" select="position()"/>
                    <xsl:apply-templates select="." mode="deep-equal">
                        <xsl:with-param name="pTarget"
                                        select="($pTarget/*|
                                                 $pTarget/text()
                                                    [normalize-space()])
                                                            [$vPosition]"/>
                    </xsl:apply-templates>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>false</xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="text()" mode="deep-equal">
        <xsl:param name="pTarget"/>
        <xsl:if test="not($pTarget/self::text() and
                      string() = string($pTarget))">
            <xsl:text>false</xsl:text>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Output:

输出:

Documents are different

#2


0  

XSLT is best used for transforming one XML dialect to another.

XSLT最适合用于将一种XML方言转换为另一种XML方言。

To compare XML files, I would use an XML parser on your platform and compare the documents using it.

为了比较XML文件,我将在您的平台上使用XML解析器并使用它来比较文档。

It is possible to compare the two, but I would advise against it, if you have other options.

有可能比较两者,但如果你有其他选择,我会反对它。

#3


0  

This is the stylesheet I wrote to compare two XML files with different order in nodes and attributes. It will generate two text files, containing the ordered list of all the leaf nodes path. Use any text compare tool to spot out the differences or enhance the XSLT to do what you want.

这是我编写的样式表,用于比较节点和属性中具有不同顺序的两个XML文件。它将生成两个文本文件,其中包含所有叶节点路径的有序列表。使用任何文本比较工具来发现差异或增强XSLT以执行您想要的操作。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text" indent="no" omit-xml-declaration="yes" name="output" />

<xsl:param name="OTHERFILENAME">xml_file_to_diff.xml</xsl:param>
<xsl:param name="ORIGINAL_OUTPUT_FILENAME">ORIGINAL.txt</xsl:param>
<xsl:param name="OTHER_OUTPUT_FILENAME">OTHER.txt</xsl:param>

<xsl:template match="/">
    <xsl:call-template name="convertXMLHierarchyToFullPath">
        <xsl:with-param name="node" select="*"/>
        <xsl:with-param name="filename" select="$ORIGINAL_OUTPUT_FILENAME"/>
    </xsl:call-template>
    <xsl:call-template name="convertXMLHierarchyToFullPath">
        <xsl:with-param name="node" select="document($OTHERFILENAME)/*"/>
        <xsl:with-param name="filename" select="$OTHER_OUTPUT_FILENAME"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="convertXMLHierarchyToFullPath">
    <xsl:param name="node"/>
    <xsl:param name="filename"/>

    <xsl:variable name="unorderedFullPath">
        <xsl:apply-templates select="$node"/>
    </xsl:variable>

    <xsl:result-document href="{$filename}" format="output">
        <xsl:for-each select="$unorderedFullPath/*">
            <xsl:sort select="@path" data-type="text"/>
            <xsl:value-of select="@path"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:for-each>
    </xsl:result-document>
</xsl:template>

<xsl:template match="*">
    <xsl:if test="not(*)">
        <leaf>
            <xsl:attribute name="path">
                <xsl:for-each select="ancestor-or-self::*">
                    <xsl:value-of select="name()"/>
                    <xsl:for-each select="@*">
                        <xsl:sort select="name()" data-type="text"/>
                        <xsl:text>[</xsl:text>
                        <xsl:value-of select="name()"/>
                        <xsl:text>:</xsl:text>
                        <xsl:value-of select="."/>
                        <xsl:text>]</xsl:text>
                    </xsl:for-each>
                    <xsl:text>/</xsl:text>
                </xsl:for-each>
                <xsl:value-of select="."/>
            </xsl:attribute>
        </leaf>
    </xsl:if>
    <xsl:apply-templates select="*"/>
</xsl:template>

</xsl:stylesheet>