compare two xml files with xslt?

我只是一个虾纸丫 提交于 2019-12-21 02:25:09

问题


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?


回答1:


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

Following the same pattern in XSLT 1.0, this stylesheet:

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


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

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

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




回答3:


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.

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


来源:https://stackoverflow.com/questions/4546190/compare-two-xml-files-with-xslt

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!