2011-05-18 55 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