There are more options to obtain your desired result. With DOMDocument
you can use importNode
, or you can directly modify original XML.
I will show you a method to create a completely new XML.
First of all, you have to load existing XML in a DOMDocument
object:
$src = new DOMDocument();
libxml_use_internal_errors(1);
$src->loadXML( $xml );
Then create the destination DOMDocument
object. For this, I use a generic <root>
tag; you can replace it with your complete XML wrapping <ad>
tags:
$dom = new DOMDocument();
libxml_use_internal_errors(1);
$dom->loadXML( '<root></root>' );
$dom->formatOutput = True;
$root = $dom->getElementsByTagName( 'root' )->item(0);
Now, init a DOMXpath
object for destination XML. DOMXPath
permits to execute complex XML queries:
$xpath = new DOMXPath( $dom );
At this point, perform a foreach
through all <ad>
nodes of source XML and — for each node — retrieve <name>
and <area>
values:
foreach( $src->getElementsByTagName( 'ad' ) as $node )
{
$name = $node->getElementsByTagName( 'name' )->item(0)->nodeValue;
$area = $node->getElementsByTagName( 'area' )->item(0)->nodeValue;
Now use DOMXPath
to find if in destination XML there is already a <ad>
node with <name>
value = retrieved name:
$found = $xpath->query( '//ad[name[.="'.$name.'"]]' );
If the destination node is found, set its <units>
as $child
:
if($found->length)
{
$child = $found->item(0)->getElementsByTagName('units')->item(0);
}
Otherwise, create a new node adding base data from source, then set it as $child
:
else
{
$lat = $node->getElementsByTagName( 'latitude' )->item(0)->nodeValue;
$long = $node->getElementsByTagName( 'longitude' )->item(0)->nodeValue;
$child = $dom->createElement( 'ad' );
$child->appendChild( $dom->createElement( 'name', $name ) );
$child->appendChild( $dom->createElement( 'latitude', $lat ) );
$child->appendChild( $dom->createElement( 'longitude', $long ) );
$child->appendChild( $dom->createElement( 'units' ) );
$root->appendChild( $child );
$child = $child->getElementsByTagName('units')->item(0);
}
At this point, you have the correct $child
node to add the <unit>
:
$unit = $dom->createElement( 'unit' );
$unit->appendChild( $dom->createElement( 'area', $area ) );
$child->appendChild( $unit );
}
At the end of foreach()
loop, you can print the obtained XML:
echo $dom->saveXML();
output:
<?xml version="1.0"?>
<root>
<ad>
<name>Property 1</name>
<latitude>29.723085</latitude>
<longitude>-95.66024</longitude>
<units/>
<unit>
<area>2000</area>
</unit>
<unit>
<area>2500</area>
</unit>
</ad>
</root>
<kbd>eval.in demo</kbd>
Additional notes:
In script above, I assume that each property name has unique long/lat. If can exists properties with same name but different long/lat, you have to find node not only by name, but also by latitude/longitude.
I assume also that your structure sample is respected in each node. Otherwise, syntax like $node->getElementsByTagName( 'latitude' )->item(0)->nodeValue
can fails, and you have to replace it by:
if( $node->getElementsByTagName( 'latitude' )->length )
{
$lat = $node->getElementsByTagName( 'latitude' )->item(0)->nodeValue;
}
and so for each code line with ->item(0)
syntax.