22

I'm iterating through a set of SimpleXML objects, and I can't figure out how to access each object's parent node. Here's what I want:

$divs = simplexml->xpath("//div");
foreach ($divs as $div)
{
   $parent_div = $div->get_parent_node(); // Sadly, there's no such function.
}

Seems like there must be a fairly easy way to do this.

thisismyname
  • 543
  • 2
  • 5
  • 10

3 Answers3

42

You could run a simple XPath query to get it:

$parent_div = $div->xpath("parent::*");

And as this is Simplexml and it only has element and attribute nodes and a parent node can only be an element and never an attribute, the abbreviated syntax can be used:

$parent_div = $div->xpath("..");

(via: Common Xpath Cheats - SimpleXML Type Cheatsheet (Feb 2013; by hakre) )

hakre
  • 193,403
  • 52
  • 435
  • 836
nickf
  • 537,072
  • 198
  • 649
  • 721
  • Will this method **always** return one parent? I'm noticing it returns an array. – mrClean Dec 21 '17 at 17:27
  • Yes, xpath returns an array, so you'd need to suffix `[0]??null` onto the end to get the actual node, or null if it doesn't exist. – Rich S Jul 08 '19 at 12:51
20

$div->get_parent_node(); // Sadly, there's no such function.

Note that you can extend SimpleXML to make it so. For example:

class my_xml extends SimpleXMLElement
{
    public function get_parent_node()
    {
        return current($this->xpath('parent::*'));
    }
}

And now all you have to do is modify the code you use to create your SimpleXMLElement in the first place:

$foo = new SimpleXMLElement('<foo/>');
// becomes
$foo = new my_xml('<foo/>');

$foo = simplexml_load_string('<foo/>');
// becomes
$foo = simplexml_load_string('<foo/>', 'my_xml');

$foo = simplexml_load_file('foo.xml');
// becomes
$foo = simplexml_load_file('foo.xml', 'my_xml');

The best part is that SimpleXML will automatically and transparently return my_xml objects for this document, so you don't have to change anything else, which makes your get_parent_node() method chainable:

// returns $grandchild's parent's parent
$grandchild->get_parent_node()->get_parent_node();
Josh Davis
  • 28,400
  • 5
  • 52
  • 67
6

If memory serves, an xpath() call returns one or more SimpleXMLElements. If that's the case, then you may be able to use something like:

$div->xpath( '..' );
# or
$div->xpath( 'parent::*' );
hakre
  • 193,403
  • 52
  • 435
  • 836
Rob Wilkerson
  • 40,476
  • 42
  • 137
  • 192