I have two xml files with a similar structure, and I need to merge them based on a common attribute. To be more explicit, here are two samples:
file1.xml
I use Xpath to fetch nodes and values from DOM. In your case I see two tasks.
One task to iterate all record elements in on document, fetch the attributes of the matching element from the second document and copy the attributes.
The other task to iterate all record elements in the second document and add them to the first if here is no element with that 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();
You can use the attribute() function of SimpleXML
$xml = simplexml_load_file($filename);
foreach($xml->Products->record->attributes() as $attribute => $value) {
//do something
}