Merge people profiles based on email match

60
May 28, 2022, at 00:20 AM

I have an existing directory (php with xml datasource) which contains people information such as this:

MainSource.xml

<people>
    <person>
        <id></id>
        <last_name></last_name>
        <first_name></first_name>
        <email></email>
        <phone></phone>
    </person>
    ...
</people>

I need to add a new node to MainSource.xml from NewSource.xml, matching on email address, from the new datasource which contains people info like this:

NewSource.xml

<people>
    <person>
        <email></email>
        <website_url></website_url>
    </person>
    ...
</people>

I have tried a number of variations, but I think my hangup is properly comparing the two documents. Logically, it feels like I need to be iterating, as opposed to foreach? Or two foreach, one for each source? Here's a sample of what I'm thinking. Please offer any clarity or insight which can nudge me along in the right direction.

<?php
$doc1 = new DOMDocument();
$doc1->load('MainSource.xml');
$doc2 = new DOMDocument();
$doc2->load('NewSource.xml');
    
foreach ($doc1->person as $person) {
    if ($person->email === $doc2->person->email) {
        $node = $doc1->createElement("website_url", $valueFromDoc2);
        $newnode = $doc1->appendChild($node);
    }
}
$merged = $doc1->saveXML();
file_put_contents('MergedSource.xml', $merged)
?>
Answer 1

As mentioned by @waterloomatt, you need to use xpath to achieve that.

Assuming that MainSource.xml looks like this:

<people>
    <person>
        <id>1</id>
        <last_name>smith</last_name>
        <first_name>john</first_name>
        <email>js@example.com</email>
        <phone>555-123-1234</phone>
    </person>
    <person>
        <id>2</id>
        <last_name>doe</last_name>
        <first_name>jane</first_name>
        <email>jd@anotherexample.com</email>
        <phone>666-234-2345</phone>
    </person>
</people>

and NewSource.xml looks like this:

<people>
 <person>
        <email>js@example.com</email>
        <website_url>js.example.com</website_url>
    </person>
    <person>
        <email>jd@anotherexample.com</email>
        <website_url>jd.anotherexample.com</website_url>
    </person>
   </people>

you can try this:

$doc1->loadXML('MainSource.xml');    
$xpath1 = new DOMXPath($doc1);
# find each person's email address
$sources = $xpath1->query('//person//email');
$doc2->loadXML('NewSource.xml');
$xpath2 = new DOMXPath($doc2);
foreach ($sources as $source) {
    #for each email address, get the parent and use that as the destination
    #of the new web address element
    $destination = $xpath1->query('..',$source);
    #in the other doc, search for each person whose email address matches
    #that of the first doc and get the relevant web address
    $exp2 = "//person[email[text()='{$source->nodeValue}']]//website_url";
    $target = $xpath2->query($exp2);
    #import the result of the search as a node into the first doc
    $node = $doc1->importNode($target[0], true);
    #finally, append the imported node in the right location of the first doc
    $destination[0]->appendChild($node);
};
echo $doc1->saveXml();

Output:

<people>
        <person>
            <id>1</id>
            <last_name>smith</last_name>
            <first_name>john</first_name>
            <email>js@example.com</email>
            <phone>555-123-1234</phone>
        <website_url>js.example.com</website_url></person>
        <person>
            <id>2</id>
            <last_name>doe</last_name>
            <first_name>jane</first_name>
            <email>jd@anotherexample.com</email>
            <phone>666-234-2345</phone>
        <website_url>jd.anotherexample.com</website_url></person>
    </people>
READ ALSO
Writing a new and appending a file in PHP without erasing contents

Writing a new and appending a file in PHP without erasing contents

How could one write a new line to a file in php without erasing all the other contents of the file?

63
Add proc_open $pipe inputs on the go dynamically

Add proc_open $pipe inputs on the go dynamically

I am trying to create a C program compiler + executer using PHP

54