DOMDocument zum Zerlegen von HTML bereitet Probleme, wenn HTML-Elemente im Fließtext

NTDY

Erfahrenes Mitglied
Hallo,
ich nutze die Klasse DOMDocument, um HTML in seine Bestandteile zu zerlegen:
  • HTML-Elementname
  • HTML-Text
  • Attribute
  • Kindelemente
Der Code funktioniert bereits gut, hat aber noch einen Fehler. Wenn ich innerhalb von HTML-Text HTML-Elemente verwende, schneidet mir der Code den vorderen Teil des HTML Textes ab:

<p>Dieser Teil wird fälschlicherweise gelöscht<a href="allesokay.html">Alles okay</a>Dieser Teil bleibt drin.</p>

Der Wunsch ist, dass auch der Teil vor dem <a>-Element erhalten bleibt.
Wo ist mein Gedankenfehler?

Die HTMLParser-Klasse
PHP:
<?php


/**

 * Class HTMLParser

 */

class HTMLParser

{

    public function __construct()

    {

        $this->setEncodeType();

    }


    /**

     * @param $sFileName

     */

    public function setEncodeType()

    {

        $this->sEncodeType = '<?xml encoding="utf-8" ?>';

    }


    /**

     * @param $sFileName

     */

    public function getEncodeType()

    {

        return $this->sEncodeType;

    }


    public function htmlToObject($sHtmlCode)

    {

        $oDOMDocumentInner = new DOMDocument();

        $oDOMDocumentInner->loadHTML($this->getEncodeType().'<div>'.$sHtmlCode.'</div>', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

        $aResult = $this->htmlElementToObject($oDOMDocumentInner->documentElement);

        return $aResult;

    }


    /**

     * Convert HTML to array

     * Saves also JS Code

     *

     * @param $oElement

     *

     * @return array|null

     */

    private function htmlElementToObject($oElement)

    {

        if (isset($oElement->tagName)) {

            $aObject = array( 'tag' => $oElement->tagName );

        }

        if (isset($oElement->attributes)) {

            foreach ($oElement->attributes as $attribute) {

                $aObject[ $attribute->name ] = $attribute->value;

            }

        }


        if (isset($oElement->childNodes)) {

            foreach ($oElement->childNodes as $oSubElement) {

                if ($oSubElement->nodeType == XML_TEXT_NODE) {

                    $aObject['html'] = $oSubElement->wholeText;

                } elseif ($oSubElement->nodeType == XML_CDATA_SECTION_NODE) {

                    $aObject['html'] = $oSubElement->data;

                } else {

                    $aObject['children'][] = $this->htmlElementToObject($oSubElement);

                }

            }

        }

        return (isset($aObject)) ? $aObject : null;

    }


    /**

     * @param $aArray

     *

     * @return array

     */

    public function arrayToHtmlElement($aArray)

    {

        $sOutput = array();

        foreach ($aArray as $iKey => $aChildren) {

            if (isset($aChildren['children']) && isset($aChildren['tag'])) {

                $sOutput[] = $this->wrapToken($aChildren, $this->arrayToHtmlElement($aChildren['children']));

            } else {

                $sOutput[] = $this->token($aChildren);

            }

        }

        return $sOutput;

    }


    /**

     * Converts the single html element to a html tag

     * There are no children elements anymore.

     *

     * @param $element

     *

     * @return string

     */

    private function token($element)

    {

        $sTagName = 'DIV';

        $sHtml = '';

        $sTagInner = '';

        foreach ($element as $sKey => $sValue) {

            switch ($sKey) {

                case 'tag': {

                    $sTagName = $sValue;

                    break;

                }

                case 'html':{

                    $sHtml = $sValue;

                    break;

                }

                default: {

                    $sTagInner .= ' '.$sKey . '="' . $sValue . '" ';

                }

            }

        }

        $sTagInner = rtrim($sTagInner);

        return '<'.$sTagName.$sTagInner.'>'.$sHtml.'</'.$sTagName.'>';

    }


    /**

     * Wrap the children element in parent

     *

     * @param $aChildren

     * @param $aChildrenElements

     *

     * @return string|string[]

     */

    private function wrapToken($aChildren, $aChildrenElements)

    {

        // Get the outer element and prepare it for the children elements

        $sInner = '';

        $sTagName = 'DIV';

        $sHtml = '';

        $sTagInner = '';

        foreach ($aChildren as $sKey => $sValue) {

            switch ($sKey) {

                case 'tag': {

                    $sTagName = $sValue;

                    break;

                }

                case 'html':{

                    $sHtml = $sValue;

                    break;

                }

                case 'children':{

                    break;

                }

                default: {

                    $sTagInner .= ' '.$sKey . '="' . $sValue . '" ';

                }

            }

            if ($sKey != 'html' && $sKey!='children' && $sKey!='tag') {

                $sInner.= $sKey.'="'.$sValue.'" ';

            }

        }

        $sTagInner = rtrim($sTagInner);


        // Inner elements collector

        $sCollector = '';

        foreach ($aChildrenElements as $iKey => $sHtmlElements) {

            $sCollector .= $sHtmlElements;

        }

        return '<'.$sTagName.$sTagInner.'>'.$sCollector.$sHtml.'</'.$sTagName.'>';

    }

}

Die index.php-Datei

PHP:
<?php
require_once ('HTMLParser.php');
$sString = '<div class="text">
    <p>Lorem ipsum <a href="italo">dolor sit amet</a>, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
    <p>Lorem ipsum <a href="dolor">dolor</a> sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut l.</p>
</div>';

$oHTMLParser = new HTMLParser();
$aResult = $oHTMLParser->htmlToObject($sString);

print_r($aResult);

Die derzeitige Ausgabe ist:
Code:
Array
(
    [tag] => div
    [children] => Array
        (
            [0] => Array
                (
                    [tag] => div
                    [class] => text
                    [html] =>

                    [children] => Array
                        (
                            [0] => Array
                                (
                                    [tag] => p
                                    [html] => , consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
                                    [children] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [tag] => a
                                                    [href] => italo
                                                    [html] => dolor sit amet
                                                )

                                        )

                                )

                            [1] => Array
                                (
                                    [tag] => p
                                    [html] =>  sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut l.
                                    [children] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [tag] => a
                                                    [href] => dolor
                                                    [html] => dolor
                                                )

                                        )

                                )

                        )

                )

        )

)

Über eine Gedankenstütze freue ich mich :)
Gruß
NTDY
 

Sempervivum

Erfahrenes Mitglied
Siehe meinen Kommentar im Code:
Code:
        if (isset($oElement->childNodes)) {

            foreach ($oElement->childNodes as $oSubElement) {

                if ($oSubElement->nodeType == XML_TEXT_NODE) {

                    // Hier überschreibst Du bei jedem Textnode den alten Text
                    // Am Schluss bleibt nur der aus dem letzten Node erhalten:
                    $aObject['html'] = $oSubElement->wholeText;

                } elseif ($oSubElement->nodeType == XML_CDATA_SECTION_NODE) {

                    $aObject['html'] = $oSubElement->data;

                } else {

                    $aObject['children'][] = $this->htmlElementToObject($oSubElement);

                }

            }

        }