3ND
3ND

Reputation: 430

Php xpath iterating through parents that have same names as their children

I have an xml file that formats data like this:

<area area_id="7" countrycode="" name="Europe">
    <area area_id="9" countrycode="ALB" name="Albania"/>
    <area area_id="12" countrycode="AND" name="Andorra"/>
    <area area_id="17" countrycode="ARM" name="Armenia"/>
    <area area_id="20" countrycode="AUT" name="Austria"/>
    <area area_id="21" countrycode="AZE" name="Azerbaijan"/>
    <area area_id="26" countrycode="BLR" name="Belarus"/>
    <area area_id="27" countrycode="BEL" name="Belgium"/>
    <area area_id="33" countrycode="BIH" name="Bosnia and Herzegovina"/>
    <area area_id="38" countrycode="BGR" name="Bulgaria"/>
    <area area_id="56" countrycode="HRV" name="Croatia"/>
    <area area_id="58" countrycode="CYP" name="Cyprus"/>
    <area area_id="59" countrycode="CZE" name="Czech Republic"/>
    <area area_id="61" countrycode="DNK" name="Denmark"/>
    <area area_id="68" countrycode="ENG" name="England"/>
    <area area_id="71" countrycode="EST" name="Estonia"/>
    <area area_id="73" countrycode="FRO" name="Faroe Islands"/>
    <area area_id="75" countrycode="FIN" name="Finland"/>
    <area area_id="76" countrycode="FRA" name="France"/>
    <area area_id="79" countrycode="GEO" name="Georgia"/>
    <area area_id="80" countrycode="DEU" name="Germany"/>
    <area area_id="82" countrycode="GRC" name="Greece"/>
</area>
<area area_id="92" countrycode="OTR" name="Other"/>
    <area area_id="93" countrycode="ISL" name="Iceland"/>
    <area area_id="98" countrycode="IRL" name="Republic of Ireland"/>
    <area area_id="99" countrycode="ISR" name="Israel"/>
    <area area_id="100" countrycode="ITA" name="Italy"/>
    <area area_id="104" countrycode="KAZ" name="Kazakhstan"/>
    <area area_id="111" countrycode="LVA" name="Latvia"/>
    <area area_id="116" countrycode="LIE" name="Liechtenstein"/>
</area>

How do i iterate in php with xpath thoroug every parent area node(there can be many) and their children.

Something like

foreach parent_area
    foreach parent_area->area
        do something

Same names of parent and children are confusing me

Upvotes: 0

Views: 53

Answers (2)

ThW
ThW

Reputation: 19512

Here are two ways depending on the usage. You can nest the expression and use the node from the outer expression as an context for the inner expression.

$xml = <<<'XML'
<root>
  <area area_id="7" countrycode="" name="Europe">
    <area area_id="9" countrycode="ALB" name="Albania"/>
    <area area_id="12" countrycode="AND" name="Andorra"/>
    <area area_id="17" countrycode="ARM" name="Armenia"/>
    <area area_id="20" countrycode="AUT" name="Austria"/>
  </area>
  <area area_id="92" countrycode="OTR" name="Other">
    <area area_id="93" countrycode="ISL" name="Iceland"/>
    <area area_id="98" countrycode="IRL" name="Republic of Ireland"/>
    <area area_id="99" countrycode="ISR" name="Israel"/>
  </area>
</root>
XML;

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);

foreach ($xpath->evaluate('/*/area') as $area) {
  echo $area->getAttribute('name'), "\n";
  foreach ($xpath->evaluate('area', $area) as $subArea) {
    echo '* ', $subArea->getAttribute('name'), "\n";
  }
}

Output:

Europe
* Albania
* Andorra
* Armenia
* Austria
Other
* Iceland
* Republic of Ireland
* Israel

Or you combine several locations paths in a single expression an fetch all nodes at once. This is useful if you have several nesting levels.

foreach ($xpath->evaluate('/*/area|/*//area[parent::area]') as $area) {
  echo str_repeat('* ', $xpath->evaluate('count(ancestor::area)', $area));
  echo $area->getAttribute('name'), "\n";
}

Upvotes: 1

Miro
Miro

Reputation: 1899

If you enclose XML above with <root> element, and fix XML to be valid (please note missing '/' at the end of tag of 'Other' in my code):

<root>
    <area area_id="7" countrycode="" name="Europe">
    ...
    <area area_id="92" countrycode="OTR" name="Other">
        ...
        <area area_id="116" countrycode="LIE" name="Liechtenstein"/>
    </area>
</root>

, you can traverse the XML with Xpath using for example this code:

$str = file_get_contents(<file>);
$xml = new SimpleXMLElement($str);
$result = $xml->xpath('/root/area');
while(list( , $node) = each($result)) {
    foreach ($node->attributes() as $a => $b) {
        echo "{$a} -> {$b}<br />\n";
    }
    $result2 = $node->xpath('area');
    while(list( , $node2) = each($result2)) {
        foreach ($node2->attributes() as $a => $b) {
            echo "---> {$a} -> {$b}<br />\n";
        }
    }
}

Upvotes: 0

Related Questions