2009-11-19 58 views
11

有誰知道一個將比較兩個XML文檔的工具。 Be that,嘲笑......還有更多。我需要一些能夠確保文件1中的每個節點不管順序如何都在文件2中的東西。我認爲XML Spy可以通過忽略子節點順序選項來實現,但事實並非如此。以下將被認爲是相同的:比較XML忽略子元素的順序

<Node> 
    <Child name="Alpha"/> 
    <Child name="Beta"/> 
    <Child name="Charlie"/> 
</Node> 

<Node> 
    <Child name="Beta"/> 
    <Child name="Charlie"/> 
    <Child name="Alpha"/> 
</Node> 
+1

正是我期待的。那麼哪個比較工具可以處理這個重要的細微差別? – snahl 2013-02-19 10:33:46

回答

5

您可能希望谷歌爲「XML diff tool」,它會給你綽綽有餘結果更多。 其中之一是OxygenXml,我經常使用的工具。您也可以嘗試微軟XML Diff and Patch Tool

祝你好運。

+2

谷歌搜索沒有產生任何免費的有前途的可執行文件下載,正如我所希望的。但是,XML差異和補丁工具上的+1!它需要您有Visual Studio才能構建它以獲取.exe。對於一個很好的視覺格式化的xml差異,構建/ Samples/XmlDiffView項目,然後運行XmlDiffView [-flags] 1.xml 2.xml visual-output.html – HaterTot 2014-02-21 16:31:36

+0

OxygenXML支持功能OP請求嗎?它是如何配置的? – 2015-07-20 16:58:37

+0

OxygenXml忽略屬性順序,但它似乎不會忽略子元素順序... – thisarattr 2016-06-28 02:25:45

2

我會使用XMLUnit,因爲它可以處理不同順序的元素。

+0

我用這種方法取得了不同程度的成功(包括XmlUnit 1和2)。它經常起作用,但它有時會失敗(對於除了排序順序以外,明顯相同的XML對)。 – 2016-06-05 14:33:12

+0

如果它們確實是相同的,除了排序順序,聽起來像它可能是一個錯誤。值得檢查是否存在問題,並在可以輕鬆複製的情況下進行報告。 – 2016-06-06 15:55:34

1

我今天晚上有類似的需求,找不到符合我要求的東西。

我的解決方法是對我想要區分的兩個XML文件進行排序,按元素名稱按字母順序排序。一旦他們都是一致的順序,我可以使用常規的可視化比較工具來區分兩個排序文件。

如果這種方法聽起來別人有用的,我與他們分享的Python腳本,我寫在http://dalelane.co.uk/blog/?p=3225

0

作爲一種(非常)快速和骯髒的方法來進行排序,我在緊要關頭做到了這一點:

  1. 打開Excel
  2. 粘貼文件1到塔A中,每行一個行。命名範圍「FILE1」
  3. 將文件2粘貼到列B中,每行一行。命名範圍 「FILE2」
  4. 在C1,輸入公式:

    =IF(ISERROR(VLOOKUP(B1,FILE1,1,FALSE)),"DIFF","") 
    
  5. 在D1,輸入forumula:

    =IF(ISERROR(VLOOKUP(A1,FILE2,1,FALSE)),"DIFF","") 
    
  6. 向下填充列C和d來的底部文件。

這將突出顯示出現在一個文件中但不出現在另一個文件中的任何行。它沒有任何伸展整齊,但有時你只需要與你的工作。

0

With Beyond Compare您可以在File Formats中使用 - 設置XML Sort轉換。使用這個選項,XML子元素將在diff之前被排序。

Beyond Compare的足跡/便攜版本是available

0
/** 
    * @author sdiallo 
    * @since 2017-01-16 
    * <p> 
    * Compare the content of two XML file 
    * </p> 
    * <ul> 
    * <li>Ignore the white space</li> 
    * <li>Ignore the attribute order</li> 
    * <li>Ignore the comment</li> 
    * <li>Ignore Sequence child nodes are not the same</li> 
    * <ul> 
    * 
    * @param String XML 
    *   first Content to be compared 
    * @param String XML 
    *   second Content to be compared 
    * @return List the differences computed between the two files 
    *   <ul> 
    *   <li>null means the files are equal</li>   
    *   <li>elsewhere the files are different</li> 
    *   <ul> 
    * */ 
    public static List buildDiffXMLs(String xmlExpected, String xmlGenerated) { 
     List<?> differencesList = null; 

    XMLUnit.setIgnoreAttributeOrder(true); 
    XMLUnit.setIgnoreComments(true); 
    XMLUnit.setIgnoreWhitespace(true); 

    try { 
     DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(
       xmlExpected, xmlGenerated)); 

     // Two documents are considered to be "similar" if they contain the 
     // same elements and attributes regardless of order. 
     if (!diff.identical() && !diff.similar()) { 
      differencesList = diff.getAllDifferences(); 
     }// end if 

    } catch (SAXException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    return differencesList; 
}// buildDiffXMLs 
+1

提示:請花費1分鐘時間來正確格式化所有**代碼;並可能在那裏做一個初步的解釋。 – GhostCat 2017-01-16 12:30:13

0

我最近給這裏一個類似的答案(Open source command line tool for Linux to diff XML files ignoring element order),但我會提供更多的細節......

,如果你寫一個程序,兩棵樹一起走,你可以自定義邏輯識別樹之間的「匹配」,也用於處理不匹配的節點。這裏是xslt 2中的一個例子。0(抱歉它是如此長):

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

       xmlns:set="http://exslt.org/sets" 

       xmlns:primary="primary" 
       xmlns:control="control" 

       xmlns:util="util" 

       exclude-result-prefixes="xsl xs set primary control"> 

    <!-- xml diff tool 

     import this stylesheet from another and call the "compare" template with two args: 

      primary: the root of the primary tree to submit to comparison 
      control: the root of the control tree to compare against 

     the two trees will be walked together. the primary tree will be walked in document order, matching elements 
     and attributes from the control tree along the way, building a tree of common content, with appendages 
     containing primary and control only content. that tree will then be used to generate the diff. 

     the process of matching involves finding, for an element or attribute in the primary tree, the 
     equivalent element or attribute in the control tree, *at the same level*, and *regardless of ordering*. 

      matching logic is encoded as templates with mode="find-match", providing a hook to wire in specific 
      matching logic for particular elements or attributes. for example, an element may "match" based on an 
      @id attribute value, irrespective of element ordering; encode this in a mode="find-match" template. 

      the treatment of diffs is encoded as templates with mode="primary-only" and "control-only", providing 
      hooks for alternate behavior upon encountering differences. 

      --> 

    <xsl:output method="text"/> 

    <xsl:strip-space elements="*"/> 

    <xsl:param name="full" select="false()"/><!-- whether to render the full doc, as opposed to just diffs --> 

    <xsl:template match="/"> 
     <xsl:call-template name="compare"> 
      <xsl:with-param name="primary" select="*/*[1]"/><!-- first child of root element, for example --> 
      <xsl:with-param name="control" select="*/*[2]"/><!-- second child of root element, for example --> 
     </xsl:call-template> 
    </xsl:template> 

    <!-- OVERRIDES: templates that can be overridden to provide targeted matching logic and diff treatment --> 

    <!-- default find-match template for elements 
     (by default, for "complex" elements, name has to match, for "simple" elements, name and value do) 
     for context node (from "primary"), choose from among $candidates (from "control") which one matches 
     (override with more specific match patterns to effect alternate behavior for targeted elements) 
     --> 
    <xsl:template match="*" mode="find-match" as="element()?"> 
     <xsl:param name="candidates" as="element()*"/> 
     <xsl:choose> 
      <xsl:when test="text() and count(node()) = 1"><!-- simple content --> 
       <xsl:sequence select="$candidates[node-name(.) = node-name(current())][text() and count(node()) = 1][. = current()][1]"/> 
      </xsl:when> 
      <xsl:when test="not(node())"><!-- empty --> 
       <xsl:sequence select="$candidates[node-name(.) = node-name(current())][not(node())][1]"/> 
      </xsl:when> 
      <xsl:otherwise><!-- presumably complex content --> 
       <xsl:sequence select="$candidates[node-name(.) = node-name(current())][1]"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <!-- default find-match template for attributes 
     (by default, name and value have to match) 
     for context attr (from "primary"), choose from among $candidates (from "control") which one matches 
     (override with more specific match patterns to effect alternate behavior for targeted attributes) 
     --> 
    <xsl:template match="@*" mode="find-match" as="attribute()?"> 
     <xsl:param name="candidates" as="attribute()*"/> 
     <xsl:sequence select="$candidates[. = current()][node-name(.) = node-name(current())][1]"/> 
    </xsl:template> 

    <!-- default primary-only template (override with more specific match patterns to effect alternate behavior) --> 
    <xsl:template match="@* | *" mode="primary-only"> 
     <xsl:apply-templates select="." mode="illegal-primary-only"/> 
    </xsl:template> 

    <!-- write out a primary-only diff --> 
    <xsl:template match="@* | *" mode="illegal-primary-only"> 
     <primary:only> 
      <xsl:copy-of select="."/> 
     </primary:only> 
    </xsl:template> 

    <!-- default control-only template (override with more specific match patterns to effect alternate behavior) --> 
    <xsl:template match="@* | *" mode="control-only"> 
     <xsl:apply-templates select="." mode="illegal-control-only"/> 
    </xsl:template> 

    <!-- write out a control-only diff --> 
    <xsl:template match="@* | *" mode="illegal-control-only"> 
     <control:only> 
      <xsl:copy-of select="."/> 
     </control:only> 
    </xsl:template> 

    <!-- end OVERRIDES --> 

    <!-- MACHINERY: for walking the primary and control trees together, finding matches and recursing --> 

    <!-- compare "primary" and "control" trees (this is the root of comparison, so CALL THIS ONE !) --> 
    <xsl:template name="compare"> 
     <xsl:param name="primary"/> 
     <xsl:param name="control"/> 

     <!-- write the xml diff into a variable --> 
     <xsl:variable name="diff"> 
      <xsl:call-template name="match-children"> 
       <xsl:with-param name="primary" select="$primary"/> 
       <xsl:with-param name="control" select="$control"/> 
      </xsl:call-template> 
     </xsl:variable> 

     <!-- "print" the xml diff as textual output --> 
     <xsl:apply-templates select="$diff" mode="print"> 
      <xsl:with-param name="render" select="$full"/> 
     </xsl:apply-templates> 

    </xsl:template> 

    <!-- assume primary (context) element and control element match, so render the "common" element and recurse --> 
    <xsl:template match="*" mode="common"> 
     <xsl:param name="control"/> 

     <xsl:copy> 
      <xsl:call-template name="match-attributes"> 
       <xsl:with-param name="primary" select="@*"/> 
       <xsl:with-param name="control" select="$control/@*"/> 
      </xsl:call-template> 

      <xsl:choose> 
       <xsl:when test="text() and count(node()) = 1"> 
        <xsl:value-of select="."/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:call-template name="match-children"> 
         <xsl:with-param name="primary" select="*"/> 
         <xsl:with-param name="control" select="$control/*"/> 
        </xsl:call-template> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:copy> 

    </xsl:template> 

    <!-- find matches between collections of attributes in primary vs control --> 
    <xsl:template name="match-attributes"> 
     <xsl:param name="primary" as="attribute()*"/> 
     <xsl:param name="control" as="attribute()*"/> 
     <xsl:param name="primaryCollecting" as="attribute()*"/> 

     <xsl:choose> 
      <xsl:when test="$primary and $control"> 
       <xsl:variable name="this" select="$primary[1]"/> 
       <xsl:variable name="match" as="attribute()?"> 
        <xsl:apply-templates select="$this" mode="find-match"> 
         <xsl:with-param name="candidates" select="$control"/> 
        </xsl:apply-templates> 
       </xsl:variable> 

       <xsl:choose> 
        <xsl:when test="$match"> 
         <xsl:copy-of select="$this"/> 
         <xsl:call-template name="match-attributes"> 
          <xsl:with-param name="primary" select="subsequence($primary, 2)"/> 
          <xsl:with-param name="control" select="remove($control, 1 + count(set:leading($control, $match)))"/> 
          <xsl:with-param name="primaryCollecting" select="$primaryCollecting"/> 
         </xsl:call-template> 
        </xsl:when> 
        <xsl:otherwise> 
         <xsl:call-template name="match-attributes"> 
          <xsl:with-param name="primary" select="subsequence($primary, 2)"/> 
          <xsl:with-param name="control" select="$control"/> 
          <xsl:with-param name="primaryCollecting" select="$primaryCollecting | $this"/> 
         </xsl:call-template> 
        </xsl:otherwise> 
       </xsl:choose> 

      </xsl:when> 
      <xsl:otherwise> 
       <xsl:if test="$primaryCollecting | $primary"> 
        <xsl:apply-templates select="$primaryCollecting | $primary" mode="primary-only"/> 
       </xsl:if> 
       <xsl:if test="$control"> 
        <xsl:apply-templates select="$control" mode="control-only"/> 
       </xsl:if> 
      </xsl:otherwise> 
     </xsl:choose> 

    </xsl:template> 

    <!-- find matches between collections of elements in primary vs control --> 
    <xsl:template name="match-children"> 
     <xsl:param name="primary" as="node()*"/> 
     <xsl:param name="control" as="element()*"/> 

     <xsl:variable name="this" select="$primary[1]" as="node()?"/> 

     <xsl:choose> 
      <xsl:when test="$primary and $control"> 
       <xsl:variable name="match" as="element()?"> 
        <xsl:apply-templates select="$this" mode="find-match"> 
         <xsl:with-param name="candidates" select="$control"/> 
        </xsl:apply-templates> 
       </xsl:variable> 

       <xsl:choose> 
        <xsl:when test="$match"> 
         <xsl:apply-templates select="$this" mode="common"> 
          <xsl:with-param name="control" select="$match"/> 
         </xsl:apply-templates> 
        </xsl:when> 
        <xsl:otherwise> 
         <xsl:apply-templates select="$this" mode="primary-only"/> 
        </xsl:otherwise> 
       </xsl:choose> 
       <xsl:call-template name="match-children"> 
        <xsl:with-param name="primary" select="subsequence($primary, 2)"/> 
        <xsl:with-param name="control" select="if (not($match)) then $control else remove($control, 1 + count(set:leading($control, $match)))"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:when test="$primary"> 
       <xsl:apply-templates select="$primary" mode="primary-only"/> 
      </xsl:when> 
      <xsl:when test="$control"> 
       <xsl:apply-templates select="$control" mode="control-only"/> 
      </xsl:when> 
     </xsl:choose> 

    </xsl:template> 

    <!-- end MACHINERY --> 

    <!-- PRINTERS: print templates for writing out the diff --> 

    <xsl:template match="*" mode="print"> 
     <xsl:param name="depth" select="-1"/> 
     <xsl:param name="render" select="false()"/> 
     <xsl:param name="lineLeader" select="' '"/> 
     <xsl:param name="rest" as="element()*"/> 

     <xsl:if test="$render or descendant::primary:* or descendant::control:*"> 

      <xsl:call-template name="whitespace"> 
       <xsl:with-param name="indent" select="$depth"/> 
       <xsl:with-param name="leadChar" select="$lineLeader"/> 
      </xsl:call-template> 
      <xsl:text>&lt;</xsl:text> 
      <xsl:value-of select="name(.)"/> 

      <xsl:apply-templates select="@* | primary:*[@*] | control:*[@*]" mode="print"> 
       <xsl:with-param name="depth" select="$depth"/> 
       <xsl:with-param name="render" select="$render"/> 
       <xsl:with-param name="lineLeader" select="$lineLeader"/> 
      </xsl:apply-templates> 

      <xsl:choose> 
       <xsl:when test="text() and count(node()) = 1"><!-- field element (just textual content) --> 
        <xsl:text>&gt;</xsl:text> 
        <xsl:value-of select="."/> 
        <xsl:text>&lt;/</xsl:text> 
        <xsl:value-of select="name(.)"/> 
        <xsl:text>&gt;</xsl:text> 
       </xsl:when> 
       <xsl:when test="count(node()) = 0"><!-- empty (self-closing) element --> 
        <xsl:text>/&gt;</xsl:text> 
       </xsl:when> 
       <xsl:otherwise><!-- complex content --> 
        <xsl:text>&gt;&#10;</xsl:text> 
        <xsl:apply-templates select="*[not(self::primary:* and @*) and not(self::control:* and @*)]" mode="print"> 
         <xsl:with-param name="depth" select="$depth + 1"/> 
         <xsl:with-param name="render" select="$render"/> 
         <xsl:with-param name="lineLeader" select="$lineLeader"/> 
        </xsl:apply-templates> 
        <xsl:call-template name="whitespace"> 
         <xsl:with-param name="indent" select="$depth"/> 
         <xsl:with-param name="leadChar" select="$lineLeader"/> 
        </xsl:call-template> 
        <xsl:text>&lt;/</xsl:text> 
        <xsl:value-of select="name(.)"/> 
        <xsl:text>&gt;</xsl:text> 
       </xsl:otherwise> 
      </xsl:choose> 

      <xsl:text>&#10;</xsl:text> 

     </xsl:if> 

     <!-- write the rest of the elements, if any --> 
     <xsl:apply-templates select="$rest" mode="print"> 
      <xsl:with-param name="depth" select="$depth"/> 
      <xsl:with-param name="render" select="$render"/> 
      <xsl:with-param name="lineLeader" select="$lineLeader"/> 
      <xsl:with-param name="rest" select="()"/><!-- avoid implicit param pass to recursive call! --> 
     </xsl:apply-templates> 

    </xsl:template> 

    <xsl:template match="@*" mode="print"> 
     <xsl:param name="depth" select="0"/> 
     <xsl:param name="render" select="false()"/> 
     <xsl:param name="lineLeader" select="' '"/> 
     <xsl:param name="rest" as="attribute()*"/> 

     <xsl:if test="$render"> 

      <xsl:text>&#10;</xsl:text> 
      <xsl:call-template name="whitespace"> 
       <xsl:with-param name="indent" select="$depth + 3"/> 
       <xsl:with-param name="leadChar" select="$lineLeader"/> 
      </xsl:call-template> 
      <xsl:value-of select="name(.)"/> 
      <xsl:text>="</xsl:text> 
      <xsl:value-of select="."/> 
      <xsl:text>"</xsl:text> 
     </xsl:if> 

     <xsl:apply-templates select="$rest" mode="print"> 
      <xsl:with-param name="depth" select="$depth"/> 
      <xsl:with-param name="render" select="$render"/> 
      <xsl:with-param name="lineLeader" select="$lineLeader"/> 
      <xsl:with-param name="rest" select="()"/><!-- avoid implicit param pass to recursive call! --> 
     </xsl:apply-templates> 

    </xsl:template> 

    <xsl:template match="primary:* | control:*" mode="print"> 
     <xsl:param name="depth"/> 

     <xsl:variable name="diffType" select="util:diff-type(.)"/> 
     <xsl:variable name="primary" select="self::primary:*"/> 
     <xsl:variable name="lineLeader" select="if ($primary) then '+' else '-'"/> 

     <!-- only if this is the first in a sequence of control::* elements, since the rest are handled along with the first... --> 
     <xsl:if test="util:diff-type(preceding-sibling::*[1]) != $diffType"> 
      <xsl:if test="@*"> 
       <xsl:text>&#10;</xsl:text> 
      </xsl:if> 
      <xsl:call-template name="diffspace"> 
       <xsl:with-param name="indent" select="if (@*) then $depth + 3 else $depth"/> 
       <xsl:with-param name="primary" select="$primary"/> 
      </xsl:call-template> 
      <b><i>&lt;!-- ... --&gt;</i></b><!-- something to identify diff sections in output --> 
      <xsl:if test="node()"> 
       <xsl:text>&#10;</xsl:text> 
      </xsl:if> 
      <xsl:variable name="rest" select="set:leading(following-sibling::*, following-sibling::*[util:diff-type(.) != $diffType])"/> 
      <xsl:apply-templates select="@* | node()" mode="print"> 
       <xsl:with-param name="depth" select="$depth"/> 
       <xsl:with-param name="render" select="true()"/> 
       <xsl:with-param name="lineLeader" select="$lineLeader"/> 
       <xsl:with-param name="rest" select="$rest/@* | $rest/*"/> 
      </xsl:apply-templates> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template name="whitespace"> 
     <xsl:param name="indent" select="0" as="xs:integer"/> 
     <xsl:param name="leadChar" select="' '"/> 
     <xsl:choose> 
      <xsl:when test="$indent > 0"> 
       <xsl:value-of select="$leadChar"/> 
       <xsl:text> </xsl:text> 
       <xsl:for-each select="0 to $indent - 1"> 
        <xsl:text> </xsl:text> 
       </xsl:for-each> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:for-each select="0 to $indent"> 
        <xsl:text> </xsl:text> 
       </xsl:for-each> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template name="diffspace"> 
     <xsl:param name="indent" select="0" as="xs:integer"/> 
     <xsl:param name="primary" select="false()"/> 
     <xsl:for-each select="0 to $indent"> 
      <xsl:choose> 
       <xsl:when test="$primary"> 
        <xsl:text>++</xsl:text> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:text>--</xsl:text> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each> 
    </xsl:template> 

    <!-- just an "enum" for deciding whether to group adjacent diffs --> 
    <xsl:function name="util:diff-type" as="xs:integer"> 
     <xsl:param name="construct"/> 
     <xsl:sequence select="if ($construct/self::primary:*[@*]) then 1 else 
           if ($construct/self::control:*[@*]) then 2 else 
           if ($construct/self::primary:*) then 3 else 
           if ($construct/self::control:*) then 4 else 
           if ($construct) then 5 else 0"/> 
    </xsl:function> 

    <!-- end PRINTERS --> 

</xsl:stylesheet> 

考慮本實施例中輸入的基礎上,你的:

<test> 
    <Node> 
     <Child name="Alpha"/> 
     <Child name="Beta"/> 
     <Child name="Charlie"/> 
    </Node> 
    <Node> 
     <Child name="Beta"/> 
     <Child name="Charlie"/> 
     <Child name="Alpha"/> 
    </Node> 
</test> 

與樣式表作爲是,下面是當施加到示例的輸出:

<Node> 
    <Child 
++++++++<!-- ... --> 
+  name="Alpha" 
--------<!-- ... --> 
-  name="Beta"> 
    </Child> 
    <Child 
++++++++<!-- ... --> 
+  name="Beta" 
--------<!-- ... --> 
-  name="Charlie"> 
    </Child> 
    <Child 
++++++++<!-- ... --> 
+  name="Charlie" 
--------<!-- ... --> 
-  name="Alpha"> 
    </Child> 
</Node> 

但是,如果添加此自定義模板:

<xsl:template match="Child" mode="find-match" as="element()?"> 
    <xsl:param name="candidates" as="element()*"/> 
    <xsl:sequence select="$candidates[@name = current()/@name][1]"/> 
</xsl:template> 

它說根據@name屬性匹配Child元素,則不會得到輸出(意思是沒有差異)。

4

我寫了這一個簡單的Python工具,稱爲xmldiffs

比較兩個XML文件,忽略元素和屬性的順序。

用法:xmldiffs [OPTION] FILE1 FILE2

任何額外的選項傳遞給diff命令。

https://github.com/joh/xmldiffs

0

在這裏獲得是使用SWI-Prolog的一個diff溶液

:- use_module(library(xpath)). 
load_trees(XmlRoot1, XmlRoot2) :- 
    load_xml('./xml_source_1.xml', XmlRoot1, _), 
    load_xml('./xml_source_2.xml', XmlRoot2, _). 

find_differences(Reference, Root1, Root2) :- 
    xpath(Root1, //'Child'(@name=Name), Node), 
    not(xpath(Root2, //'Child'(@name=Name), Node)), 
    writeln([Reference, Name, Node]). 

diff :- 
    load_trees(Root1, Root2), 
    (find_differences('1', Root1, Root2) ; find_differences('2', Root2, Root1)). 

的Prolog將統一名稱變量,以在符合從文件1節點和文件2 統一Node變量執行「diff」檢測。

下面是下面的一些示例輸出:

% file 1 and file 2 have no differences 
?- diff. 
false. 

% "Alpha" was updated in file 2 
?- diff. 
[1,Alpha,element(Child,[name=Alpha],[])] 
[2,Alpha,element(Child,[name=Alpha,age=7],[])] 
false.