3

I have an XML schema that looks as follows:

<xml>
  <user id="1">
    <first_name>Bill</first_name>
    <last_name>Steve</last_name>
    <phone_numbers>
      <work>xxx-xxx-xxxx</work>
      <home>xxx-xxx-xxxx</home>
    </phone_numbers>
   </user>
   <user id="2">
      ........
   </user>
</xml>

Im working on parsing all of this information into PHP using DOM. Ex.

$userInfo = $doc->getElementsByTagName( "user" ); 
foreach($userInfo as $row)
{
       $first_name = $row->getElementsByTagName("first_name");
}

When I try to nest this to select the phone numbers however I get an error. I've tried using XPath to select the phone numbers with equal problems. I tried something along the lines of

$userInfo = $doc->getElementsByTagName( "user" ); 
foreach($userInfo as $row)
{
       $phoneInfo = $row->getElementsByTagName("phone_numbers");
       foreach($phoneInfo as $row2)
       {
            $work = $row2->getElementsByTagName("work");
       }
}

Im curious if Im doing something fundamentally wrong, or how to get this going. I've been tearing my hair out for a few hours now.

3
  • Works for me! Which PHP do you use? Commented Jan 24, 2011 at 21:18
  • getElementsByTagName returns a DOMNodeList. Are you sure you can iterate through it using foreach? (Just asking) Commented Jan 24, 2011 at 21:19
  • 1
    There is no XPath usage in question. Retagging Commented Jan 24, 2011 at 22:46

2 Answers 2

3

You can't get the value directly from a DOMNodeList Object, try this :

$userInfo = $doc->getElementsByTagName( "user" ); 
foreach($userInfo as $row)
{
       $phoneInfo = $row->getElementsByTagName("phone_numbers");
       foreach($phoneInfo as $row2)
       {
            // get the value from the first child
            $work = $row2->getElementsByTagName("work")->item(0)->nodeValue;
            $home = $row2->getElementsByTagName("home")->item(0)->nodeValue;
       }
}
Sign up to request clarification or add additional context in comments.

1 Comment

I want to kiss you on the mouth right now. That worked like a charm. I love/hate it when it's so easy.
1

Well, you could switch it to SimpleXml which makes this type of parsing easier:

$userInfo = $doc->getElementsByTagName( "user" ); 
foreach ($userInfo as $user) {
    $node = simplexml_import_dom($user);
    $id = (string) $node['id'];
    $first = (string) $node->first_name;
    $last = (string) $node->last_name;
    $workPhone = (string) $node->phone_numbers->work;
    $homePhone = (string) $node->phone_numbers->home;
}

Now, in DomDocument, you could do this by using DomXpath:

$userInfo = $doc->getElementsByTagName( "user" ); 
$xpath = new DomXpath($doc);
foreach ($userInfo as $user) {
    $id = $user->getAttribute('id');
    $first = $xpath->query('//first_name', $user)->item(0)->textContent;
    $last = $xpath->query('//last_name', $user)->item(0)->textContent;
    $work = $xpath->query('//phone_numbers/work', $user)->item(0)->textContent;
    $home = $xpath->query('//phone_numbers/home', $user)->item(0)->textContent;
}

Note that the above code (both parts) require that the format is exactly that. If you have conditionals, you might want to change it to something like this (the firstname conditional only):

$userInfo = $doc->getElementsByTagName( "user" ); 
$xpath = new DomXpath($doc);
foreach ($userInfo as $user) {
    $id = $user->getAttribute('id');
    $firstQuery = $xpath->query('//first_name', $user);
    if ($firstQuery->length > 0) {
        $first = $firstQuery->item(0)->textContent;
    } else {
        $first = '';
    }
}

1 Comment

I was trying to use DomXpath as you mentioned here, but the problem I was having was differentiating which user was associated with the phone number. It looks like using xpath onside the object returned from $userInfo would work, I hadn't thought of that. The other answer more closely hits what I need, but this looks really solid. Thanks for taking the time out to help and when I dig into xpath again Im sure I'll use this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.