Solomon Closson
Solomon Closson

Reputation: 6217

XPath to select multiple elements at once?

I'm currently doing this to build an array called $tables, but wondering if there is an easier way to do this?

$tables = array();
$abbr = $states_xml->xpath('//StateAbbr');
$names = $states_xml->xpath('//StateName');

// State Abbreviations...
while(list($key,$table) = each($abbr)) {
    $tables[$key]['Abbr'] = (string) trim($table);
}

// State Names...
while(list($key,$name) = each($names)) {
    $tables[$key]['Name'] = (string) trim($name);
}

Is it possible to call StateAbbr and StateName elements in 1 go and have them be outputted in an array in the same format as $tables is?

So, tables array will look something like this:

array(57) {
  [0]=>
  array(2) {
    ["Abbr"]=>
    string(2) "AL"
    ["Name"]=>
    string(7) "Alabama"
  }
  [1]=>
  array(2) {
    ["Abbr"]=>
    string(2) "AK"
    ["Name"]=>
    string(6) "Alaska"
  }
  [2]=>
  array(2) {
    ["Abbr"]=>
    string(2) "AS"
    ["Name"]=>
    string(14) "American Samoa"
  }
... and so on...

Basically, the $states_xml looks like this:

<diffgr:diffgram
    xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
    xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
    <NewDataSet
        xmlns="">
        <Table diffgr:id="Table1" msdata:rowOrder="0">
            <StateAbbr>AL </StateAbbr>
            <StateName>Alabama</StateName>
        </Table>
        <Table diffgr:id="Table2" msdata:rowOrder="1">
            <StateAbbr>AK </StateAbbr>
            <StateName>Alaska</StateName>
        </Table>
        <Table diffgr:id="Table3" msdata:rowOrder="2">
            <StateAbbr>AS </StateAbbr>
            <StateName>American Samoa</StateName>
        </Table>
        <Table diffgr:id="Table4" msdata:rowOrder="3">
            <StateAbbr>AP </StateAbbr>
            <StateName>AP</StateName>
        </Table>
        ...
    </NewDataSet>
</diffgr:diffgram>

I am using $states_xml = simplexml_load_string(THE STRING ABOVE); to load up the xml into $states_xml.

Anyway to grab all StateAbbr and StateName from all Table elements in here to be outputted in an array, in one go?? Seems possible to me, but not sure how to approach this other than the way I'm currently doing it.

Upvotes: 2

Views: 1660

Answers (3)

ThW
ThW

Reputation: 19482

You should iterate their parent element node. The expressions are relative to the node the SimpleXMLElement represents, but that is not needed in your case:

$diffgram = new SimpleXMLElement($xml);

$result = [];
foreach($diffgram->xpath('.//Table') as $table) {
  $result[] = [
    'Abbr' => trim($table->StateAbbr),
    'Name' => trim($table->StateName)
  ];
}

var_dump($result);

Output:

array(4) {
  [0]=>
  array(2) {
    ["Abbr"]=>
    string(2) "AL"
    ["Name"]=>
    string(7) "Alabama"
  }
  [1]=>
  array(2) {
    ["Abbr"]=>
    string(2) "AK"
    ["Name"]=>
    string(6) "Alaska"
  }
  [2]=>
  array(2) {
    ["Abbr"]=>
    string(2) "AS"
    ["Name"]=>
    string(14) "American Samoa"
  }
  [3]=>
  array(2) {
    ["Abbr"]=>
    string(2) "AP"
    ["Name"]=>
    string(2) "AP"
  }
}

In DOM it looks nearly the same, but here you need Xpath expressions for the details.

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

$result = [];
foreach($xpath->evaluate('.//Table') as $table) {
  $result[] = [
    'Abbr' => $xpath->evaluate('normalize-space(StateAbbr)', $table),
    'Name' => $xpath->evaluate('normalize-space(StateName)', $table)  
  ];
}

var_dump($result);

Upvotes: 2

kjhughes
kjhughes

Reputation: 111491

Yes, this single XPath,

//*[self::StateAbbr or self::StateName]

will return all StateAbbr and StateName elements in an XML document.

Upvotes: 0

Vural
Vural

Reputation: 8748

please try this using array_merge_recursive :

$abbr = $states_xml->xpath('//StateAbbr');
$names = $states_xml->xpath('//StateName');
$tables = array_merge_recursive($abbr, $names);

display:

print_r($tables);

Upvotes: 0

Related Questions