Search code examples
phpxmlsimplexml

Combine XML files by unique ID with PHP


I have two XML files which I load from a third party source. Both files have different data, except a unique ID which is also provided in both files. So the files look like this (roughly sketched)

XML 1:
<cinemas>
  <cinema>
    <cinemaid>123</cinemaid>
    <addressid>456</adressid>
    <cinemaname>Best Cinema</cinemaname>
  </cinema>
</cinemas>

XML 2:
<addresses>
  <address>
    <addressid>456</adressid>
    <cinemaid>123</cinemaid>
    <street>Best Street 5</street>
    <postal>54332</postal>
    <place>Best Town</place>
  </address>
</addresses>

Each XML-File has multiple entries linked to each other by the two IDs. I don't really combine them in one file, I want to display the cinema name with the address on a website. I just thought maybe the best solution is to first combine and then iterate through one file.

I read the XML-Files from a URL with curl and then do simplexml_load_string() the curl output to have readable XML.

I iterate with a foreach-loop over the first XML-File and inside that foreach over the other and try to compare with an if-statement. But it is not showing the expected outcome. It shows each cinema multiple times because of the nested loop.

How can I just show a list of cinemas with the address from two XML-Files. Do have to combine them first? How can I do this with PHP?

Thanks in advance!


Solution

  • You could use a function to convert your xml to an associative array, and then re-order and render the data to fit your needs.

    Feed the function with an array of xml files, e.g.:

    $arr = xmlToArray(['data1.xml', 'data2.xml']);

    function xmlToArray(array $xmlFiles = []): array
    {
        $arr = [];
        foreach ($xmlFiles as $file) {
            if (file_exists($file)) {
                $xml = simplexml_load_file($file);
                $json = json_encode($xml);
                $arr[] = json_decode($json, TRUE);
            } else {
                echo 'Error: failed to open ' . $file . '!';
            }
        }
        return $arr;
    }
    

    Then merge the address data for each cinema based on cinemaid:

    $cinemaStore = [];
    foreach ($arr[0]['cinema'] as $cinema) {
        foreach ($arr[1]['address'] as $address) {
            if ($address['cinemaid'] == $cinema['cinemaid']) {
                $cinemaStore[$cinema['cinemaname']] = $address;
            }
        }
    }
    

    Based on the xml structure you provided this should give you something like this (I added two more cinemas):

    Array
    (
        [Best Cinema] => Array
            (
                [addressid] => 456
                [cinemaid] => 123
                [street] => Best Street 5
                [postal] => 54332
                [place] => Best Town
            )
    
        [Worst Cinema] => Array
            (
                [addressid] => 444
                [cinemaid] => 222
                [street] => Worst Street 5
                [postal] => 42424
                [place] => Worst Town
            )
    
        [Coolest Cinema] => Array
            (
                [addressid] => 555
                [cinemaid] => 333
                [street] => Coolest Street 5
                [postal] => 53535
                [place] => Coolest Town
            )
    
    )
    

    It should now be trivial to render the data in your view.