2015-06-30 151 views
2

如何基於普通匹配節點(密鑰或在此示例中:<id>)通過使用php合併2個XML記錄?通過匹配節點加入或合併兩個XML文件

1.XML:

<record> 
    <id>001</id> 
    <other_nodes>...</other_nodes> 
    ... 
</record> 
<record> 
    <id>002</id> 
    ... 
</record> 

2.XML:

<record> 
    <id>001</id> 
    <description>abc</description> 
    ... 
</record> 
<record> 
    <id>002</id> 
    <description>def</description> 
    ... 
    </record> 

Merged.xml:

<record> 
    <id>001</id> 
    <other_nodes></other_nodes> 
    <description>abc</description> 
    ... 
</record> 
<record> 
    <id>002</id> 
    <description>def</description> 
    ... 
</record> 

<id>,在這兩個XML文件中的所有節點都不同(獨特)。目標是將2.xml的內容添加到1.xml中。 (只需將<description>節點添加到1.xml中也可以完成這項工作!)

我嘗試了幾個編碼(如嵌套的foreach循環),沒有任何工作。我能做的最好的(我試過多個版本):

(由Merge two xml files based on common attribute啓發):

$file = ...  
$targetDom = new DOMDocument(); 
$targetDom->load($file); 
$targetXpath = new DOMXpath($targetDom); 

$addDom = new DOMDocument(); 
$addDom->loadXml($file2); 
$addXpath = new DOMXpath($addDom); 

// copy elements depending on ProductId 
foreach ($targetXpath->evaluate('//record') as $record) { 
    $productId = $record->id->value; 
    foreach ($addXpath->evaluate('//record[id=\"'.$productId.'\"]') as $attribute) { 
    $parent_node = $attribute->evaluate('../codename'); //evaluate or xpath? 
    //$record->appendChild($targetDom->importNode($parent_node)); 
    $newValue = $attribute->description->value; 

    //$record->addChild("description", $newValue); 
    $element = $dom->createElement('codename', $newValue); 
    $record->appendChild($element); 

    //$targetDom->documentElement->appendChild(
    // $targetDom->importNode($parent_node)); 
    } 
} 

$xmlsave = $targetDom->saveXml(); 

相關問題: How to join two XML files with a matching node

+0

a)XML2是否有一個不在XML1中的記錄,並且必須包含在組合的XML3中? – michi

+0

是的,在我的情況下,XML2的所有記錄都不同於XML1('id'除外)。 – Olivier

+0

我的意思是,如果在XML2中有'id's不在XML1 – michi

回答

0

你可以做到這一點與xsl(t)

合併.xsl

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0" 
    xmlns:exsl="http://exslt.org/common" 
    extension-element-prefixes="exsl" 
> 
    <xsl:strip-space elements="*"/> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:param name="mergedoc" select="document($mergesrc)" /> 

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

    <xsl:template match="record"> 
     <xsl:variable name="idmerge" select="id" /> 
     <xsl:copy> 
      <xsl:apply-templates /> 
      <xsl:apply-templates select="$mergedoc/records/record[id=$idmerge]/*[not(name()='id')]" /> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

PHP腳本:

<?php 
$src = doc('1.xml'); 
$processor = new XSLTProcessor; 
$processor->importStylesheet(doc('merge.xsl')); 
$processor->setParameter('', 'mergesrc', '2.xml'); 

$result = $processor->transformToDoc($src); 
$result->formatOutput=true; 
echo $result->savexml(); 


function doc($srcpath) { 
    $doc = new DOMDocument; 
    $doc->load($srcpath); 
    return $doc; 
} 

交代

xmlns:exsl="http://exslt.org/common" 
extension-element-prefixes="exsl" 

到使用一個以上的文件不是XSLT 1.0規範的一部分的能力。但libxslt通過exsl支持它 - 所以我們「導入」它。


<xsl:strip-space elements="*"/> 
<xsl:output method="xml" indent="yes"/> 

只是要使輸出有點漂亮。與$result->formatOutput=true;一起工作。但是,如果你應該對這些空白有任何問題......請看看這三行。


<xsl:param name="mergedoc" select="document($mergesrc)" /> 

這裏的第二個文件是 「加載和存儲在$ mergedoc」。
$ mergesrc本身是通過$processor->setParameter('', 'mergesrc', '2.xml');


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

基本的XSL複製所有的模板設置的參數。每個沒有更具體模板的節點被深層複製到結果中。


現在爲了好玩的部分,模板匹配record元素。

<xsl:variable name="idmerge" select="id" /> 

專賣店在$ idmerge當前記錄元素的ID元素的值。

<xsl:copy> 
    <xsl:apply-templates /> 

我們希望將內容複製到結果,並與當前記錄元素的內容開始(XSL:申請模板沒有選擇屬性,複製所有的模板將做到這一點)。

<xsl:apply-templates select="$mergedoc/records/record[id=$idmerge]/*[not(name()='id')]" /> 

從mergedoc(2.XML)選擇具有相同的ID 「中的」 1.XML當前record元件的record元件 - 其被存儲在$ idmerge。
在這條記錄中選擇所有子節點 - 但不是id元素(它已經由1.xml的當前記錄元素提供) - 並將其發送到全部複製模板(因爲沒有更多特定模板) 。

+0

很好的解決方案,並很好地解釋。我得到了腳本的工作,但它只輸出原始的1.xml和2.xml的記錄似乎根本沒有被複制。看起來(通過省略)該行沒有被執行:(我的$ idmergedoc引用應該可以工作。)'' – Olivier