0

I've been trying unsuccessfully with PHP to loop through two XML files and print the result to the screen. The aim is to take a country's name and output its regions/states/provinces as the case may be.

The first block of code successfully prints all the countries but the loop through both files gives me a blank screen.

The countries file is in the format:

<row>
    <id>6</id>
    <name>Andorra</name>
    <iso2>AD</iso2>
    <phone_code>376</phone_code>
  </row> 

And the states.xml:

<row>
    <id>488</id>
    <name>Andorra la Vella</name>
    <country_id>6</country_id>
    <country_code>AD</country_code>
    <state_code>07</state_code>
  </row>

so that country_id = id.

This gives a perfect list of countries:

$xml = simplexml_load_file("countries.xml");
$xml1 = simplexml_load_file("states.xml");

foreach($xml->children() as $key => $children) {
  print((string)$children->name); echo "<br>";
}

This gives me a blank screen except for the HTML stuff on the page:

$xml = simplexml_load_file("countries.xml");
$xml1 = simplexml_load_file("states.xml");
$s = "Jamaica";
foreach($xml->children() as $child) {
  foreach($xml1->children() as $child2){ 
    if ($child->id == $child2->country_id && $child->name == $s) {
        print((string)$child2->name);
        echo "<br>";
    }
   }
}

Where have I gone wrong? Thanks.

Mark Lee
  • 163
  • 11

1 Answers1

1

I suspect your problem is not casting the name to a string before doing your comparison. But why are you starting the second loop before checking if it's needed? You're looping through every single item in states.xml needlessly.

$countries = simplexml_load_file("countries.xml");
$states = simplexml_load_file("states.xml");
$search = "Jamaica";

foreach($countries->children() as $country) {
    if ((string)$country->name !== $search) {
        continue;
    }
    foreach($states->children() as $state) { 
        if ((string)$country->id === (string)$state->country_id) {
            echo (string)$state->name . "<br/>";
        }
    }
}

Also, note that naming your variables in a descriptive manner makes it much easier to figure out what's going on with code.


You could probably get rid of the loops altogether using an XPath query to match the sibling value. I don't use SimpleXML, but here's what it would look like with DomDocument:

$search = "Jamaica";

$countries = new DomDocument();
$countries->load("countries.xml");
$xpath = new DomXPath($countries);
$country = $xpath->query("//row[name/text() = '$search']/id/text()");
$country_id = $country[0]->nodeValue;

$states = new DomDocument();
$states->load("states.xml");
$xpath = new DomXPath($states);
$states = $xpath->query("//row[country_id/text() = '$country_id']/name/text()");
foreach ($states as $state) {
    echo $state->nodeValue . "<br/>";
}
miken32
  • 42,008
  • 16
  • 111
  • 154
  • Thanks for this approach. I agree with you that the looping might be resource intensive. There are more than 30-thousand lines of states (only 239 countries). I did try looping only the countries and "comparing" the states but still no luck. But I'm a media person, not a coder, just doing enough to skimp along. Your XPath worked perfectly. Thanks. I'll have to read up on that. The first option performed like my attempts. I don't think this has to do with the problem but I've been testing from the php server running in console so I'll put it in the web root and see... – Mark Lee Nov 11 '20 at 22:55
  • Needed to add the typecast to string in the ID comparison as well. Should be working now, but XPath is much better anyway. – miken32 Nov 11 '20 at 23:06
  • Agreed. Though I'm not yet familiar with it, it seems straightforward. I assume it gets the path through the nodes. And yes, with the typecasting the loop method also works. A twofer... – Mark Lee Nov 11 '20 at 23:11