-1

I used an XMLHttpRequest object to retrieve data from a PHP response.

Then, I created an XML file:

<?xml version="1.0" encoding="UTF-8"?>
<persons>
    <person>
        <name>Ce</name>
        <gender>male</gender>
        <age>24</age>
    </person>
    <person>
        <name>Lin</name>
        <gender>female</gender>
        <age>25</age>
    </person>
</persons>

In the PHP file, I load the XML file and try to echo tag values of "name."

$dom = new DOMDocument("1.0");
$dom -> load("test.xml");
$persons = $dom -> getElementsByTagName("person");
foreach($persons as $person){
    echo $person -> childNodes -> item(0) -> nodeValue;
}

But the nodeValue returned is null. However, when I change to item(1), the name tag values can be displayed. Why?

ndmeiri
  • 4,979
  • 12
  • 37
  • 45
CEz
  • 43
  • 1
  • 7

3 Answers3

0

Change code to

$dom = new DOMDocument("1.0");
$dom -> load("test.xml");
$persons = $dom -> getElementsByTagName("persons");
foreach($persons as $person){
echo  $person->childNodes[1]->nodeValue;
}
Anas
  • 971
  • 13
  • 28
  • I tried, didn't work. It's clear that there is only one tag of persons which is root, its first child is tag of person, not name – CEz Mar 14 '18 at 13:03
0

Anything in a DOM is a node, include texts and text with only whitespaces. So the first child of the person element node is a text node that contains the linebreak and indent before the name element node.

Here is a property that removes any whitespace node at parse time:

$document = new DOMDocument("1.0");
// do not preserve whitespace only text nodes
$document->preserveWhiteSpace = FALSE;
$document->load("test.xml");
$persons = $document->getElementsByTagName("person");
foreach ($persons as $person) {
    echo $person->firstChild->textContent;
}

However typically a better way is to use Xpath expressions.

$document = new DOMDocument("1.0");
$document->load("test.xml");
$xpath = new DOMXpath($document)
$persons = $xpath->evaluate("/persons/person");
foreach ($persons as $person) {
    echo $xpath->evaluate("string(name)", $person);
}

string(name) fetches the child element node name (position is not relevant) and casts it into a string. If here is no name element it will return an empty string.

ThW
  • 19,120
  • 3
  • 22
  • 44
-1

Using DOM you need to get the right element to pick up the name, child nodes include all sorts of things including whitespace. The node 0 your trying to use is null because of this. So for DOM...

$dom = new DOMDocument("1.0");
$dom -> load("test.xml");
$persons = $dom -> getElementsByTagName("person");
foreach($persons as $person){
   $name = $person->getElementsByTagName("name");
   echo $name->item(0)->nodeValue.PHP_EOL;
}

If your requirements are as simple as this, you could alternatively use SimpleXML...

$sxml = simplexml_load_file("test.xml");
foreach ( $sxml->person as $person )    {
    echo $person->name.PHP_EOL;
}

This allows you to access elements as though they are object properties and as you can see ->person equates to accessing <person>.

Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
  • In your code, seems like after get nodelist of person, still need to get a nodelist of name, instead of directly use childNodes property? – CEz Mar 14 '18 at 13:35
  • The problem with childNodes in DOM is that they are split down to each element. Blindly using `->childNodes->item(1)` could pick up any element, if the XML changed it could pick up another field. Specifically fetching the `name` element avoids this risk. – Nigel Ren Mar 14 '18 at 13:38