2009-11-20 50 views
21

我想計算使用XSL/XSLT的兩個XML文件或節點之間的差異。是否有任何樣式表可用或者簡單的方法?XML Diff:如何使用XSLT生成XML差異?

+3

+1只是爲了它的野心,BTW這XSLT的版本是你找這工作 – AnthonyWJones 2009-11-20 15:50:53

+0

的目標將是差異兩個節點在同一個XML文件中,那更可行嗎? – Vincent 2009-11-23 15:32:59

+0

您必須用XML術語定義相同和不同的含義。作爲參考看看這個問題http://stackoverflow.com/questions/4546190/compare-two-xml-files-with-xslt – 2011-02-03 00:00:46

回答

6

有趣的問題!我曾經嘗試過做類似的事情,涉及到兩個XML源,而我的經驗是,沒有辦法。

您可以使用XSL的工具來包含用戶構建的函數,並編寫一些非常流暢的代碼。但我真的看不到它。

如果我要做這樣的事情,我會使用DOM4J並行處理這兩個XML文件,這使我可以通過編程方式輕鬆遍歷代碼並執行詳細的子查詢。

試圖在XSLT中做到這一點將證明你是一個天才或驅使你陷入瘋狂。

2

XSLT是數據驅動的,也就是說,它通過單個源XML文件自上而下地查找XSL樣式表中的模板匹配。模板並不知道它們在數據中的位置,只是在匹配時才運行它們的代碼。您可以引用另一個XML源,但該程序將根據原始源的遍歷運行。

因此,例如,當您到達第<blarg>的第n個子元素時,可以使用document()函數在第二個XML中查找<blarg>的第n個子元素。但是這種有用性取決於你的XML的結構以及你想要做的比較。

這種行爲與大多數傳統腳本相反,它們通過程序代碼自上而下運行,在指示時調用數據文件。後者 - 拉處理 - 是您可能需要比較兩個XML源的東西。一旦出現差異,XSLT將進行比較分析。

1

有辦法做到這一點,但我不會說這很簡單。

在我使用所謂diffmk一個開源工具過去,這將產生一個輸出XML有額外的標籤,以顯示什麼已添加/刪除...

我不得不寫一個額外的樣式表,然後將其轉換這個轉換成更可讀的HTML報告。

XMLSpy Diff Dog等一些diff工具不錯,但成本很高。

1

這不是一個謎!以下是一般步驟:

  1. @carillonator對XSLT如何處理文檔是正確的。因此,爲了使它更容易,我們將文檔的兩個版本合併到一個文檔中,您可以使用它來運行XSLT diff(您可以通過命令行使用bash,或者使用您正在使用的任何編程語言,甚至另一種語言XSLT轉換[管道])。這只是一個封裝:

    <diff_container> 
        <version1> 
         ... first version here 
        </version1> 
        <version2> 
         ... second version here 
        </version2> 
    </diff_container> 
    
  2. 然後我們通過我們的XSLT DIFF運行此文件中,然後XSLT有簡單遍歷樹,並比較兩個版本之間的節點的工作。這可以從非常簡單(是一個元素改變?移動?刪除?)到半複雜。對XPath的很好理解使得這非常簡單。

    就像之前說的一樣,你在不同的環境中工作,所以與Diff Dog這樣的工具相比,你受到的限制。然而,在XSLT中使用算法的好處也可能具有實際價值。

希望這對我有所幫助。乾杯!

2

如果你的意思是差異什麼是一樣的東西檢查一個文件(或節點)是否存在的項目而不是另一個,你可以使用XPath鍵()函數有第三個參數

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

這是我寫的樣式表是爲了比較在節點和屬性中具有不同順序的兩個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> 

1

發現這個職位最近,但無論如何,我會分享我對這類問題的解決方案。我有和@Vincent一樣的需求:比較2個不同的XML文件,並快速查看它們之間的差異。快速差異有太多的行匹配,因爲文件沒有排序,所以我決定使用XSLT對文件進行排序,然後使用WinMerge手動比較這兩個xml文件(一個簡單的unix diff也可以完成這項工作)。

這裏是那種我的XML文件中的XSLT:

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