Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In PHP DOM get Element/Node depth in recursive function

Tags:

dom

php

recursion

I have the following function, which reads all child elements/text nodes of a given dom element into an array, by recursively calling itself.

It works fine, but I need the depth of each node (text or element) in relation to the first(!) given DOM node before any recursion happened. I can't figure out how to do this, any ideas?

function recursively_find_text_nodes($dom_element) {

    $return = array();

    foreach ($dom_element->childNodes as $dom_child) {

        switch ($dom_child->nodeType) {

            case XML_TEXT_NODE:

                if (trim($dom_child->nodeValue) !== '') {                

                    $return[] = $dom_child->nodeValue;

                }

            break;

            case XML_ELEMENT_NODE:

                $return = array_merge($return, $this->recursively_find_text_nodes($dom_child));

            break;

        }

    }

    return $return;

}

I am parsing an XML node with this function. It can have any number of elements and subelements. The idea is that I +1 a depth variable, every time the function goes into recursion. the problem is that when I am in a node that actually does not go deeper, but up in the tree I'd have to -1 the variable. So for every node that I am currently in I would need the depth of the current element in regard to the DOM node that was passed to the function before(!) it went into recursion.

like image 944
Sebastian Avatar asked Oct 22 '25 09:10

Sebastian


1 Answers

The question would be a lot clearer if you provided the output you want. A depth parameter can be passed as follows:

function recursively_find_text_nodes($dom_element, $depth=1) {

    $return = array();

    foreach ($dom_element->childNodes as $dom_child) {

        switch ($dom_child->nodeType) {

            case XML_TEXT_NODE:
                if (trim($dom_child->nodeValue) !== '') {
                    $return[] = array (
                        'depth' => $depth, 
                        'value' => $dom_child->nodeValue
                    );
                }
                break;

            case XML_ELEMENT_NODE:
                $return[] = array (
                    'depth' => $depth,
                    'value' => $dom_child
                );

                $return = array_merge($return, $this->recursively_find_text_nodes($dom_child, $depth+1));
                break;
        }
    }

    return $return;
}

The return value probably won't be what you intended, but you'll have to be more specific for that.


Update

From what I understand, you probably mean something like this:

<?php

function recursively_find_text_nodes($dom_element, $depth=1, $predecessor_depth=0) {

    $return = array();

    foreach ($dom_element->childNodes as $dom_child) {

        switch ($dom_child->nodeType) {

            case XML_TEXT_NODE:
                if (trim($dom_child->nodeValue) !== '') {
                    $return[] = array (
                        'absolute_depth' => $depth,
                        'relative_depth' => $depth - $predecessor_depth,
                        'value' => $dom_child->nodeValue
                    );

                    $predecessor_depth = $depth;
                }
                break;

            case XML_ELEMENT_NODE:
                $return[] = array (
                    'absolute_depth' => $depth,
                    'relative_depth' => $depth - $predecessor_depth,
                    'value' => $dom_child
                );

                // Add the sub tree nodes to the result array
                $child_return_value = $this->recursively_find_text_nodes($dom_child, $depth+1, $predecessor_depth);
                $return = array_merge($return, $child_return_value);

                // Determine the depth of the last one processed
                $predecessor_depth = $return[count($return)-1]['absolute_depth'];

                break;
        }
    }

    return $return;
}

?>

If it is something else still, you should provide example input and output (always the first step when designing an algorithm.)

like image 90
wkampmann Avatar answered Oct 24 '25 00:10

wkampmann



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!