2011-05-18 80 views
5

我想比較兩個xmls然後合併它們。例如:如何比較和合並兩個xml使用xslt

myFile1.xml

<?xml version="1.0" encoding="ISO-8859-1"?> 
<catalog> 
<data> 
    <title>Title1</title> 
    <description>Description1</description> 
    <myid>1</myid> 
</data> 
<data> 
    <title>Title2</title> 
    <description>Description2</description> 
    <myid>2</myid> 
</data> 
</catalog> 

myFile2.xml

<?xml version="1.0" encoding="ISO-8859-1"?> 
<catalog> 
<data> 
    <title>Title1</title> 
    <description>Description1</description> 
    <author>Author1</author> 
    <date>12/34/5678</date> 
    <myid>1</myid> 
</data> 
<data> 
    <author>Author2</author> 
    <date>87/65/4321</date> 
    <myid>2</myid> 
</data> 
</catalog> 

所需的輸出:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<catalog> 
<data> 
    <title>Title1</title> 
    <description>Description1</description> 
    <myid>1</myid> 
    <author>Author1</author> 
    <date>12/34/5678</date> 
</data> 
<data> 
    <title>Title2</title> 
    <description>Description2</description> 
    <myid>2</myid> 
    <author>Author2</author> 
    <date>87/65/4321</date> 
</data> 
</catalog> 

我有一個代碼,但,它不列入執行按照需要的輸出。

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="ISO-8859-1" indent="yes"/> 
<xsl:variable name="compare" select="'myFile1.xml'"/> 
<xsl:variable name="with" select="'myFile2.xml'"/> 
<xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 
<xsl:template match="*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     <xsl:variable name="info1" select="document($compare)/catalog/data[myid=current()/myid]/."/> 
     <xsl:variable name="info2" select="document($with)/catalog/data[myid=current()/myid]/."/> 
     <xsl:for-each select="$info1/*"> 
      <xsl:variable name="check1" select="name(current())"/> 
      <!--xsl:text>Current node1 : </xsl:text><xsl:value-of select="$check1"/--> 
      <xsl:for-each select="$info2/*"> 
       <xsl:variable name="check2" select="name(current())"/> 
       <!--xsl:text>Current node2 : </xsl:text><xsl:value-of select="$check2"/--> 
       <xsl:if test="$check1!=$check2"> 
        <xsl:copy-of select="."/> 
       </xsl:if> 
      </xsl:for-each> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 
</xsl:transform> 

請幫忙!

+0

你如何搭配兩個文件之間的節點測試?就在他們的位置?我的意思是doc1上的第一個節點必須與doc2上的第一個節點合併?或通過'myid'? – 2011-05-18 20:15:54

+0

不,它與「myid」匹配,而不是它們的位置。如果您只是更改「」字段的順序,則會相應地從第二個文檔複製字段。 – Arnab 2011-05-19 08:36:06

+0

我明白了,我正在嘗試與您不同的方法。可能你會看到我的答案。 – 2011-05-19 09:59:08

回答

1

該解決方案完全沒有循環或鍵。我只用document()加載了一個文檔,而我使用另一個作爲源文件。簡而言之,源文檔中缺少一個元素,它將在加載的元素上進行。這個解決方案中有更多元素可用性較差。請參閱底部以獲取更爲一般的內容。


XSLT 1.0撒克遜-HE 9.2.1.1J

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:variable name="catalog2" select="document('source_test2.xml')/catalog"/> 

    <xsl:template match="catalog"> 
     <catalog> 
      <xsl:apply-templates select="data"/> 
     </catalog> 
    </xsl:template> 

    <xsl:template match="data"> 
     <xsl:variable name="data2" select="$catalog2/data[myid=current()/myid]/."/> 
     <data> 
      <xsl:choose> 
       <xsl:when test="title"> 
        <xsl:copy-of select="title"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:copy-of select="$data2/title"/> 
       </xsl:otherwise> 
      </xsl:choose> 

      <xsl:choose> 
       <xsl:when test="description"> 
        <xsl:copy-of select="description"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:copy-of select="$data2/description"/> 
       </xsl:otherwise> 
      </xsl:choose> 

      <xsl:copy-of select="myid"/> 

      <xsl:choose> 
       <xsl:when test="author"> 
        <xsl:copy-of select="author"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:copy-of select="$data2/author"/> 
       </xsl:otherwise> 
      </xsl:choose> 

      <xsl:choose> 
       <xsl:when test="date"> 
        <xsl:copy-of select="date"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:copy-of select="$data2/date"/> 
       </xsl:otherwise> 
      </xsl:choose> 

     </data> 
    </xsl:template> 

</xsl:stylesheet> 

測試以下是更通用的解決方案。方法是一樣的。對於每個datamyFile2中存在且在myFile1中丟失的元素被添加到結果樹中,反之亦然。

XSLT 1.0撒克遜-B 9.0.0.4J

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:variable name="catalog2" select="document('myFile2.xml')/catalog"/> 

    <xsl:template match="catalog"> 
     <catalog> 
      <xsl:apply-templates select="data"/> 
     </catalog> 
    </xsl:template> 

    <xsl:template match="data"> 
     <xsl:variable name="data1" select="."/> 
     <xsl:variable name="data2" select="$catalog2/data[myid=current()/myid]/."/> 
     <data> 
      <xsl:copy-of select="$data1/*"/> 
      <xsl:for-each select="$data2/*"> 
       <xsl:variable name="element2" select="name(.)"/> 
       <xsl:if test="count($data1/*[name()=$element2])=0"> 
        <xsl:copy-of select="."/> 
       </xsl:if> 
      </xsl:for-each> 
     </data> 
    </xsl:template> 

</xsl:stylesheet> 
+0

感謝您的快速響應,但這將是一個特定的架構,對不對?如果我有一個擁有超過1000個元素的大型模式,該怎麼辦?那麼這將不是一個可行的方法。糾正我,如果我錯了。 – Arnab 2011-05-19 15:37:28

+0

是的,你有更多的元素,並且這種方法的可用性較差。但我無法找出另一種方法。可能在接下來的幾天。如果你找到一個解決方案,請在這裏回答。 – 2011-05-19 15:43:02

+0

我已經添加了更通用的解決方案。請注意,在某些情況下,元素順序可能會受到影響。這很難解決,因爲您的假設並不知道源模式。無論如何希望這個幫助。 – 2011-05-19 19:49:35