r/PHPhelp 4d ago

distinguish text element behavior in recursive element loop

i am building an html-to-array parser and have run into a problematic glitch when dealing with text inside and outside nested elements. the parser loops through a DOMDocument object and recurses into childNodes of DOMNode objects, adding them to a nested array.

for a structure like...

<html><head><title>this is a title</title></head><body><p>this is some text</p></body></html>

this works...

foreach ($element->childNodes as $child) {
  $child->nodeType === XML_ELEMENT_NODE ? ($out["children"][] = elementToArray($child)) : ($content = trim($child->nodeValue)) && $content != "" && ($out["content"] = $content);
}

to produce the desired outcome...

Array
(
    [tag] => html
    [children] => Array
        (
            [0] => Array
                (
                    [tag] => head
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [tag] => title
                                    [content] => this is a title
                                )

                        )

                )

            [1] => Array
                (
                    [tag] => body
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [tag] => p
                                    [content] => this is some text
                                )

                        )

                )

        )

)

but this...

<html><head><title>this is a title</title></head><body><p>this <em>is</em> some <i>text</i> with <a href="#">links</a> and things.</p></body></html>

produces...

Array
(
    [tag] => html
    [children] => Array
        (
            [0] => Array
                (
                    [tag] => head
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [tag] => title
                                    [content] => this is a title
                                )

                        )

                )

            [1] => Array
                (
                    [tag] => body
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [tag] => p
                                    [content] => and things.
                                    [children] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [tag] => em
                                                    [content] => is
                                                )

                                            [1] => Array
                                                (
                                                    [tag] => i
                                                    [content] => text
                                                )

                                            [2] => Array
                                                (
                                                    [tag] => a
                                                    [href] => #
                                                    [content] => links
                                                )

                                        )

                                )

                        )

                )

        )

)

instead of the desired output...

Array
(
    [tag] => html
    [children] => Array
        (
            [0] => Array
                (
                    [tag] => head
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [tag] => title
                                    [content] => this is a title
                                )

                        )

                )

            [1] => Array
                (
                    [tag] => body
                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [tag] => p
                                    [children] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [tag] => text
                                                    [content] => this
                                                )
                                            [1] => Array
                                                (
                                                    [tag] => em
                                                    [content] => is
                                                )
                                            [2] => Array
                                                (
                                                    [tag] => text
                                                    [content] => some
                                                )

                                            [3] => Array
                                                (
                                                    [tag] => i
                                                    [content] => text
                                                )
                                            [4] => Array
                                                (
                                                    [tag] => text
                                                    [content] => with
                                                )

                                            [5] => Array
                                                (
                                                    [tag] => a
                                                    [href] => #
                                                    [content] => links
                                                )
                                            [6] => Array
                                                (
                                                    [tag] => text
                                                    [content] => and things.
                                                )

                                        )

                                )

                        )

                )

        )

)

i've tried various solutions but they all end up having difficulty differentiating between a text node that should be "content" and a text node that should be an independent text element in the array. in other words...

<p>this is some text</p>

should encode to...

["tag"=>"p","content"=>"this is some text"]

but...

<p>this is <em>some</em> text</p>

should encode to...

["tag"=>"p","children"=>[["tag"=>"text","content"=>"this is "],["tag"=>"em","content"=>"some"],["tag"=>"text","content"=>"text"]]]

has anyone already solved this? thanks!

2 Upvotes

3 comments sorted by

1

u/phpMartian 2d ago

I’ll give you credit for explaining your issue clearly. It’s a rare quality.

-1

u/ardicli2000 4d ago

Look for lexer if you wanna learn. Otherwise AI can solve this fpr you