2010-12-28 15 views
5

Ich habe 2 xml-Dateien. Wie kann ich vergleichen, ob beide Dateien gleich sind oder nicht, indem Sie xslt verwenden? Wenn nicht gleich bedeutet, wo die Änderungen in der zweiten XML aufgetreten sind?zwei XML-Dateien mit xslt vergleichen?

Antwort

0

XSLT eignet sich am besten für Umwandlung einen XML-Dialekt zu einem anderen.

Um XML-Dateien zu vergleichen, würde ich einen XML-Parser auf Ihrer Plattform verwenden und die Dokumente damit vergleichen.

Es ist möglich zu vergleichen, aber ich würde davon abraten, wenn Sie andere Möglichkeiten haben.

4

In XPath 2.0 können Sie einfach fn:deep-equal verwenden.

Nach dem gleichen Muster in XSLT 1.0, dieses Sheet:

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

Ausgang:

Documents are different 
+0

@Alejandro: guter Versuch, aber Sie haben keine Knoten in einem Namespace, die nur aus Leerzeichen Knoten, Namespace-Knoten, PI-Knoten und Kommentarknoten gehören, betrachtet. Wie wir wissen, können zwei Knoten unterschiedliche Namen haben und immer noch gleichwertig sein - wie: 'h: html' und' html'. Die Leute, die nach dem Vergleich zweier XML-Dokumente für "Gleichheit" fragen, wissen normalerweise nicht, wonach genau sie fragen. –

+0

@Dimitre: Sie haben Recht mit Namen. Ich habe XPath 2.0 'node-name()' falsch übersetzt. Ich werde das korrigieren. Über den anderen Knotentyp: Da "Gleichheit" genauer definiert werden sollte, habe ich eine "Deep-Equal" -Definition verwendet, die keine Kommentare oder PI-Kinder berücksichtigt, in Geltungsbereich Namespaces oder Leerraum nur Textknoten für ** Elemente **. –

0

Dies ist das Stylesheet ich zwei XML-Dateien mit anderer Reihenfolge in Knoten vergleichen geschrieben und Attribute. Es erzeugt zwei Textdateien, die die geordnete Liste aller Blattknoten enthalten. Verwenden Sie ein beliebiges Textvergleichswerkzeug, um die Unterschiede zu erkennen oder verbessern Sie das XSLT, um das zu tun, was Sie wollen.

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