2009-11-20 11 views
21

Ich möchte den Unterschied zwischen zwei XML-Dateien oder Knoten mit XSL/XSLT berechnen. Gibt es ein Stylesheet, das einfach verfügbar ist oder einfach?XML-Diff: Wie generiert man XML-Diff mit XSLT?

+3

+1 Gerade für den Ehrgeiz es, BTW, welche Version von XSLT waren Sie für diese Suche in Arbeit – AnthonyWJones

+0

Ziel zu diff wäre zwei Knoten in der gleichen XML-Datei, ist das machbar? – Vincent

+0

Sie müssen definieren, was gleich und verschieden in XML bedeutet. Als Referenz betrachten Sie diese Frage http://stackoverflow.com/questions/4546190/compare-two-xml-files-with-xslt –

Antwort

6

Interessante Frage! Ich habe einmal versucht, etwas ähnliches mit zwei XML-Quellen zu tun, und meine Erfahrung war, dass es einfach keinen Weg gibt.

Sie können die XSL-Funktion verwenden, um vom Benutzer erstellte Funktionen zu integrieren und etwas wirklich Schlüpfriges zu programmieren. Aber ich kann es wirklich nicht sehen.

Wenn ich so etwas tun würde, würde ich die zwei XML-Dateien parallel mit DOM4J verarbeiten, was es mir ermöglicht, den Code programmatisch zu durchsuchen und detaillierte Unterabfragen durchzuführen.

Der Versuch, dies in XSLT zu tun, wird entweder beweisen, dass Sie ein Genie sind oder Sie in den Wahnsinn treiben.

2

XSLT ist datengesteuert, dh es durchläuft von oben nach unten die XML-Datei mit den einzelnen Quellen und sucht nach Vorlagenübereinstimmungen im XSL-Stylesheet. Die Vorlagen wissen nicht wirklich, wo sie sich in den Daten befinden, sie führen ihren Code nur aus, wenn sie übereinstimmen. Sie können auf eine andere XML-Quelle verweisen, aber das Programm wird entsprechend dem Durchlauf der ursprünglichen Quelle ausgeführt.

Wenn Sie also zum nten Kindelement von <blarg> gelangen, können Sie beispielsweise das n-te Kind von <blarg> in einem zweiten XML mit der Funktion document() nachschlagen. Aber die Nützlichkeit hängt von der Struktur Ihres XML ab und von welchen Vergleichen Sie versuchen.

Dieses Verhalten ist das Gegenteil der meisten herkömmlichen Skripts, die den Programmcode von oben nach unten durchlaufen und bei Aufforderung die Datendatei aufrufen. Letzteres - Pull-Verarbeitung - ist das, was Sie wahrscheinlich benötigen, um zwei XML-Quellen zu vergleichen. XSLT wird im Vergleich ausfallen, sobald es einen Unterschied gibt.

1

Es gibt Möglichkeiten, dies zu tun, aber ich würde nicht sagen, es ist einfach.

In der Vergangenheit habe ich ein Open-Source-Dienstprogramm diffmk genannt verwendet haben, erzeugt dies eine XML-Ausgabe mit zusätzlichen Tags zeigen, was hinzugefügt/entfernt wurde ...

ich ein zusätzliches Sheet schreiben musste dann diese konvertieren in einen besser lesbaren HTML-Bericht.

Einige Diff Tools wie XMLSpy Diff Hund sind gut, aber teuer.

1

Dies ist kein Geheimnis! Hier sind die allgemeinen Schritte:

  1. @carillonator ist richtig, wie XSLT Dokumente verarbeitet. Um es einfacher zu machen, kombinieren wir die zwei Versionen Ihrer Dokumente zu einem einzigen Dokument, mit dem Sie Ihr XSLT-Diff ausführen können (Sie können dies über die Befehlszeile mit bash oder mit der von Ihnen verwendeten Programmiersprache oder sogar einer anderen tun XSLT transformieren [pipe]). Es ist nur eine Kapselung:

    <diff_container> 
        <version1> 
         ... first version here 
        </version1> 
        <version2> 
         ... second version here 
        </version2> 
    </diff_container> 
    
  2. Wir haben dann dieses Dokument durch unsere XSLT diff ausführen, hat die XSLT dann die Aufgabe, einfach den Baum durchquert und Knoten zwischen den beiden Versionen verglichen werden. Dies kann von sehr einfach (Wurde ein Element geändert? Bewegt? Entfernt?) Zu Semi-Komplexen gehen. Ein gutes Verständnis von XPath macht dies ziemlich einfach.

    Wie bereits erwähnt, arbeiten Sie in einer anderen Umgebung, so dass Sie im Vergleich zu Tools wie Diff Dog eingeschränkt sind. Der Vorteil des Algorithmus in XSLT kann jedoch auch einen echten Wert haben.

Hoffnung half dies. Prost!

2

Wenn das, was Sie von diff meine ist so etwas wie die Überprüfung, ob Elemente in einem Dokument existieren (oder Knoten), nicht aber eine andere, können Sie XPath-Taste() Funktion mit einem dritten Parameter

<?xml version="1.0"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs ="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xsl xs"> 

<xsl:param name="doc2diff" required="yes"/> 
<!-- docB is root node of the "second" document --> 
<xsl:variable name="docB" select="document($doc2diff)"/> 
<!-- docA is the root node of the first document --> 
<xsl:variable name="docA" select="/"/> 
<xsl:output method="xml" encoding="UTF-8" indent="yes"/> 
<xsl:key name="items" match="Item" use="someId"/> 

<xsl:template match="/"> 
<ListOfItems> 
    <In_A_NotIn_B> 
    <xsl:apply-templates select="Item"> 
    <xsl:with-param name="otherDocument" select="$docB"/> 
    </xsl:apply-templates> 
    </In_A_NotIn_B> 
    <In_B_NotIn_A> 
    <xsl:apply-templates select="Item"> 
    <xsl:with-param name="otherDocument" select="$docA"/> 
    </xsl:apply-templates> 
    </In_B_NotIn_A> 
</ListOfItems> 
</xsl:template> 

<xsl:template match="Item"> 
<xsl:param name="otherDocument"/> 
    <xsl:variable name="SOMEID" select="someId"/> 
    <xsl:if test="empty(key('items', $SOMEID, $otherDocument))"> 
    <xsl:copy-of select="."/> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet>` 
2

Dies ist die Verwendung Stylesheet Ich schrieb, um zwei XML-Dateien mit unterschiedlicher Reihenfolge in Knoten und Attribut zu vergleichen, es wird zwei Textdateien generieren, 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> 

1

diesen Beitrag in letzter Zeit gefunden, aber trotzdem meine Lösung für diese Art von Problem, das ich werde teilen. Ich hatte die gleichen Bedürfnisse wie @Vincent: Vergleiche 2 XML-Dateien und sehe schnell die Unterschiede zwischen ihnen. Ein schnelles Diff hatte zu viele Zeilen, da die Dateien nicht sortiert waren. Daher entschied ich, die Dateien mit XSLT zu sortieren und dann die beiden XML-Dateien manuell zu vergleichen, zum Beispiel mit WinMerge (ein einfacher Unix-Unterschied kann auch den Job erledigen).

Hier ist die XSLT, die meine XML-Datei sortieren.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:output method="xml" indent="yes" encoding="UTF-8"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
      <xsl:apply-templates select="node()|@*"> 
        <xsl:sort select="name()" /> 
        <xsl:sort select="@*" /> 
        <xsl:sort select="*" /> 
        <xsl:sort select="text()" /> 
      </xsl:apply-templates> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 
Verwandte Themen