Reputation: 85
i have an xml file in a special format how can i get nested tag value out of it for example if i want opacity, Thickness, repeat, rotation tags with value 1, 0, false, 90 respectively for first dict tag and same for the others. please point me in right direction
<?xml version="1.0" encoding="UTF-8"?>
<pu version="1.0">
<dict>
<key>ID</key>
<string>C0AC8773-CEE6-4A12-9C69-320A1BDB7255</string>
<key>Items</key>
<array>
<dict>
<key>opacity</key>
<real>1</real>
<key>Thickness</key>
<real>0</real>
<key>repeat</key>
<false/>
<key>rotation</key>
<real>90</real>
</dict>
<dict>
<key>opacity</key>
<real>1</real>
<key>Thickness</key>
<real>0</real>
<key>repeat</key>
<false/>
<key>rotation</key>
<real>180</real>
</dict>
<dict>
<key>opacity</key>
<real>1</real>
<key>Thickness</key>
<real>0</real>
<key>repeat</key>
<false/>
<key>rotation</key>
<real>270</real>
</dict>
</array>
</dict>
</pu>
this is what i want
$dom = new DOMDocument;
$dom->load($path);
$array = $dom->getElementsByTagName('array');
foreach($array as $dict)
{
foreach($dict as $key->$value)
{
print_r("key = ".$key." value = ".$value);//i.e. key = opacity value = 1
}
}
what am i doing wrong and thanks in advance
Upvotes: 1
Views: 2628
Reputation: 19492
Here are two jobs. One you have to iterate the dict
elements and get all key
elements. Second get the value node for each key
element and parse it depending on its name.
DOMXpath::evaluate() or query() can take a second argument with a context node. The Xpath expression will be relative to it.
On the root level /pu/dict
fetches all dict
children of the document element.
$result = [];
$dicts = $xpath->evaluate('/pu/dict');
foreach ($dicts as $dict) {
$result[] = getList($xpath, $dict);
}
Inside the getList()
function key
is used to get the key
child elements of a dict
node.
function getList($xpath, $node) {
$items = $xpath->evaluate('key', $node);
$result = [];
foreach ($items as $item) {
$result[$item->nodeValue] = getValue($xpath, $item);
}
return $result;
}
The value node is the element following each key
element. In Xpath following-sibling::*[1]
. The value type depends on the node name. Most are just scalar values. If it is array
, fetch the dict
element children and call getList()
for each of them.
function getValue($xpath, $node) {
$valueNode = $xpath->evaluate('following-sibling::*[1]', $node)->item(0);
switch ($valueNode->nodeName) {
case 'array' :
$dicts = $xpath->evaluate('dict', $valueNode);
foreach ($dicts as $dict) {
$result[] = getList($xpath, $dict);
}
return $result;
case 'true' :
return TRUE;
case 'false' :
return FALSE;
case 'real' :
return (float)$valueNode->nodeValue;
case 'string' :
return $valueNode->nodeValue;
}
}
Put together: https://eval.in/private/b88a430a237494
$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<pu version="1.0">
<dict>
<key>ID</key>
<string>C0AC8773-CEE6-4A12-9C69-320A1BDB7255</string>
<key>Items</key>
<array>
<dict>
<key>opacity</key>
<real>1</real>
<key>Thickness</key>
<real>0</real>
<key>repeat</key>
<false/>
<key>rotation</key>
<real>90</real>
</dict>
<dict>
<key>opacity</key>
<real>1</real>
<key>Thickness</key>
<real>0</real>
<key>repeat</key>
<false/>
<key>rotation</key>
<real>180</real>
</dict>
<dict>
<key>opacity</key>
<real>1</real>
<key>Thickness</key>
<real>0</real>
<key>repeat</key>
<false/>
<key>rotation</key>
<real>270</real>
</dict>
</array>
</dict>
</pu>
XML;
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
function getValue($xpath, $node) {
$valueNode = $xpath->evaluate('following-sibling::*', $node)->item(0);
switch ($valueNode->nodeName) {
case 'array' :
$dicts = $xpath->evaluate('dict', $valueNode);
foreach ($dicts as $dict) {
$result[] = getList($xpath, $dict);
}
return $result;
case 'true' :
return TRUE;
case 'false' :
return FALSE;
case 'real' :
return (float)$valueNode->nodeValue;
case 'string' :
return $valueNode->nodeValue;
}
}
function getList($xpath, $node) {
$items = $xpath->evaluate('key', $node);
$result = [];
foreach ($items as $item) {
$result[$item->nodeValue] = getValue($xpath, $item);
}
return $result;
}
$result = [];
$dicts = $xpath->evaluate('/pu/dict');
foreach ($dicts as $dict) {
$result[] = getList($xpath, $dict);
}
var_dump($result);
Upvotes: -1
Reputation: 219814
$dom = new DOMDocument;
$dom->loadXML($xml);
$xpath = new DOMXpath($dom);
$dicts = $xpath->query("/pu/dict/array/dict");
foreach($dicts as $dict) {
$childNodes = $dict->childNodes;
foreach ($childNodes as $child) {
if ($child->nodeName !== 'key') {
continue;
}
echo $child->nodeValue . " " . getNextSibling($child) . "<br>";
}
}
function getNextSibling($node) {
return ($node->nodeType === 3) ? $node->nextSibling->nodeValue : $node->nextSibling->nextSibling->nodeValue;
}
Upvotes: 2