How can you push the sample_id
value into the array using PHP DOM, along with first
and samples
?
I've tried adding another foreach loop, but I'm getting various notices such as
Trying to get property of non-object
XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<maintable>
<group>
<first>text1</first>
<second>text2</second>
<samples a="link" b="link">
<sample_id>000555</sample_id>
</samples>
</group>
<group>
<first>text3</first>
<second>text4</second>
<samples a="link" b="link">
<sample_id>111000</sample_id>
</samples>
</group>
</maintable>
PHP
<?php
$text = file_get_contents($file);
$content = iconv('UTF-8', 'UTF-8//IGNORE', $text);
$xml = new DOMDocument('1.0', 'ISO-8859-1');
$xml->loadXML($content);
$xpath = new DOMXPath( $xml );
$query = '/maintable/group[first="text3"]';
$nodes = $xpath->query( $query );
$var = array();
foreach( $nodes as $k => $node )
{
foreach( $node->childNodes as $cnode )
{
if ($cnode->nodeName == 'first')
{
$var[$k]["first"] = (string)$cnode->textContent;
}
if ($cnode->nodeName == 'samples')
{
$var[$k]["samp_url"] = (string)$cnode->getAttribute("a");
}
if ($cnode->nextSibling->nodeName == 'sample_id')
{
$var[$k]["sample_id"] = (string)$cnode->nextSibling->textContent;
}
}
}
//print_r($cnode->childNodes);
?>
Attempt to loop thru nodeList
$var = array();
$nodes = $xpath->evaluate('/maintable/group[first="text3"]');
foreach ($nodes as $node)
{
foreach( $node->childNodes as $cnode )
{
if (is_array($cnode))
{
foreach( $cnode->childNodes as $cn )
{
$var[]["sample_id"] = (string)$cn->textContent;
}
}
}
}
var_dump($var);
DOMXpath::query()
can only return node lists, DOMXpath::evaluate()
can return scalars, too. The second argument of query()/evaluate()
is the context node. If provided, the Xpath expression will be relative to it.
So you can select the node(s) first, iterate the list and use evaluate()
again to fetch the values:
$xml = new DOMDocument();
$xml->loadXML($content);
$xpath = new DOMXPath($xml);
$results = [];
$nodes = $xpath->evaluate('/maintable/group[first="text3"]');
foreach ($nodes as $node) {
$results[] = [
'first' => $xpath->evaluate('string(first)', $node),
'sample_url' => $xpath->evaluate('string(samples/@a)', $node),
'sample_id' => $xpath->evaluate('string(samples/sample_id)', $node)
];
}
var_dump($results);
Output: https://eval.in/171656
array(1) {
[0]=>
array(3) {
["first"]=>
string(5) "text3"
["sample_url"]=>
string(4) "link"
["sample_id"]=>
string(6) "111000"
}
}
Fetching only the sample id from the document works, too:
var_dump(
$xpath->evaluate('string(/maintable/group[first="text3"]/samples/sample_id)')
);
Output:
string(6) "111000"
You can use this XPath query to select the correct element you're after:
/maintable/group/first[text()="text3"]/../samples/sample_id
Explanation:
/maintable # from the top of the document, select the maintable element
/group # select group element, child of maintable
/first[text()="text3"] # select 'first' element, child of group with text = 'text3'
/.. # move up to the parent of the 'first' element
/samples # find samples element, child of this parent
/sample_id # find sample_id element, child of this parent
Then you can push your text value (the sample id) by using $node->nodeValue
. Example:
$query = '/maintable/group/first[text()="text3"]/../samples/sample_id';
$nodes = $xpath->query($query);
$var = array();
foreach($nodes as $k => $node) {
$var[] = $node->nodeValue;
}
print_r($var);
Output:
Array
(
[0] => 111000
)
Here's a good read for learning how to use XPath selectors.