根据公共属性合并两个xml文件

时间:2014-02-27 22:25:00

标签: php xml xml-parsing merge

我有两个具有相似结构的xml文件,我需要根据公共属性合并它们。更明确一点,这里有两个样本:

file1.xml

 <Products>
 <record ProductId="366" ProductName="Test" ProductCategory="Categ1"></record>
 </Products>

file2.xml

 <Productprices>
 <record ProductId="366" ProductPrice="10" ProductVAT="24"></record>
 </Productprices>

两个文件中的公共属性是ProductId。我需要合并所有属性,以便组合文件看起来像这样:

 <Products>
 <record ProductId="366" ProductName="Test" ProductCategory="Categ1" ProductPrice="10" ProductVAT="24"></record>
 </Products>

不幸的是,我到目前为止所做的只是合并两个文件,合并后的文件如下所示:

 <Products>
 <record ProductId="366" ProductName="Test" ProductCategory="Categ1"></record>
 <record ProductId="366" ProductPrice="10" ProductVAT="24"></record>
 </Products>

这是我使用的PHP代码:

 $doc1 = new DOMDocument();
 $doc1->load('file1.xml');
 $doc2 = new DOMDocument();
 $doc2->load('file2.xml');
 $res1 = $doc1->getElementsByTagName('Products')->item(0);
 $items2 = $doc2->getElementsByTagName('record');
 for ($i = 0; $i < $items2->length; $i ++) {
 $item2 = $items2->item($i);
 $item1 = $doc1->importNode($item2, true);
 $res1->appendChild($item1);
 }
 $doc1->save('file1.xml');

有没有办法可以使用DomDocument基于常见的ProductId将所有属性合并到一个记录中?我宁愿不进入XSLT。

非常感谢任何帮助。

提前致谢。

2 个答案:

答案 0 :(得分:2)

我使用Xpath从DOM获取节点和值。在你的情况下,我看到两个任务。

迭代文档中所有记录元素的一项任务,从第二个文档中获取匹配元素的属性并复制属性。

另一个任务是迭代第二个文档中的所有记录元素,并将它们添加到第一个,如果这里没有该ProductId的元素。

$xmlOne = <<<'XML'
<Products>
 <record ProductId="366" ProductName="Test" ProductCategory="Categ1"></record>
</Products>
XML;

$xmlTwo = <<<'XML'
<Productprices>
 <record ProductId="366" ProductPrice="10" ProductVAT="24"></record>
 <record ProductId="444" ProductPrice="23" ProductVAT="32"></record>
</Productprices>
XML;

$targetDom = new DOMDocument();
$targetDom->loadXml($xmlOne);
$targetXpath = new DOMXpath($targetDom);

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

// merge attributes of record elements depending on ProductId
foreach ($targetXpath->evaluate('//record[@ProductId]') as $record) {
  $productId = $record->getAttribute('ProductId');
  foreach ($addXpath->evaluate('//record[@ProductId='.$productId.']/@*') as $attribute) {
    if (!$record->hasAttribute($attribute->name)) {
      $record->setAttribute($attribute->name, $attribute->value);
    }
  }
}

// copy records elements that are not in target dom
foreach ($addXpath->evaluate('//record[@ProductId]') as $record) {
  $productId = $record->getAttribute('ProductId');
  if ($targetXpath->evaluate('count(//record[@ProductId='.$productId.'])') == 0) {
    $targetDom->documentElement->appendChild(
      $targetDom->importNode($record)
    );
  }
}

echo $targetDom->saveXml();

答案 1 :(得分:0)

您可以使用SimpleXML的attribute()功能

$xml = simplexml_load_file($filename);
foreach($xml->Products->record->attributes() as $attribute => $value) {
    //do something
}