Измените innerHTML php DOMElement

Как изменить innerHTML php DOMElement?

Мне нужно было сделать это для проекта в последнее время и в конечном итоге с расширением для DOMElement: http://www.keyvan.net/2010/07/javascript-like-innerhtml-access-in-php/

Вот пример, показывающий, как он используется:

<?php require_once 'JSLikeHTMLElement.php'; $doc = new DOMDocument(); $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement'); $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>'); $elem = $doc->getElementsByTagName('div')->item(0); // print innerHTML echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>' // set innerHTML $elem->innerHTML = '<a href="http://fivefilters.org">FF</a>'; // print document (with our changes) echo $doc->saveXML(); ?> 

Другое решение:

1) создать новый DOMDocumentFragment из строки HTML, которую нужно вставить; 2) удалить старый контент нашего элемента, удалив его дочерние узлы; 3) добавьте DOMDocumentFragment к нашему элементу.

 function setInnerHTML($element, $html) { $fragment = $element->ownerDocument->createDocumentFragment(); $fragment->appendXML($html); while ($element->hasChildNodes()) $element->removeChild($element->firstChild); $element->appendChild($fragment); } 

Кроме того, мы можем заменить наш элемент своей чистой копией, а затем добавить DOMDocumentFragment к этому клону.

 function setInnerHTML($element, $html) { $fragment = $element->ownerDocument->createDocumentFragment(); $fragment->appendXML($html); $clone = $element->cloneNode(); // Get element copy without children $clone->appendChild($fragment); $element->parentNode->replaceChild($clone, $element); } 

Контрольная работа:

 $doc = new DOMDocument(); $doc->loadXML('<div><span style="color: green">Old HTML</span></div>'); $div = $doc->getElementsByTagName('div')->item(0); echo $doc->saveHTML(); setInnerHTML($div, '<p style="color: red">New HTML</p>'); echo $doc->saveHTML(); // Output: // <div><span style="color: green">Old HTML</span></div> // <div><p style="color: red">New HTML</p></div> 

Я думаю, что самое лучшее, что вы можете сделать, это придумать функцию, которая возьмет DOMElement, который вы хотите изменить InnerHTML, скопируйте и замените.

В очень грубом PHP:

 function replaceElement($el, $newInnerHTML) { $newElement = $myDomDocument->createElement($el->nodeName, $newInnerHTML); $el->parentNode->insertBefore($newElement, $el); $el->parentNode->removeChild($el); return $newElement; } 

Это не учитывает атрибуты и вложенные структуры, но я думаю, что это поможет вам.

Кажется, что appendXML не работает всегда – например, если вы пытаетесь добавить XML с 3 уровнями. Вот функция, которую я написал, которая всегда работает (вы хотите установить $ content как innerHTML в $ element):

 function setInnerHTML($DOM, $element, $content) { $DOMInnerHTML = new DOMDocument(); $DOMInnerHTML->loadHTML($content); $contentNode = $DOMInnerHTML->getElementsByTagName('body')->item(0)->firstChild; $contentNode = $DOM->importNode($contentNode, true); $element->appendChild($contentNode); return $elementNode; } 

Посмотрите на эту библиотеку. PHP Simple HTML DOM Parser http://simplehtmldom.sourceforge.net/

Это выглядит довольно просто. Вы можете изменить свойство innertext своих элементов. Это может помочь.

Вот функция replace by class, которую я только что написал:

Он заменит innerHtml класса. Вы также можете указать тип узла, например. div / p / a и т. д.

 function replaceInnerHtmlByClass($html, $replace=null, $class=null, $nodeType=null){ if(!$nodeType){ $nodeType = '*'; } $dom = new DOMDocument(); $dom->loadHTML($html); $xpath = new DOMXPath($dom); $nodes = $xpath->query("//{$nodeType}[contains(concat(' ', normalize-space(@class), ' '), '$class')]"); foreach($nodes as $node) { while($node->childNodes->length){ $node->removeChild($node->firstChild); } $fragment = $dom->createDocumentFragment(); $fragment->appendXML($replace); $node->appendChild($fragment); } return $dom->saveHTML($dom->documentElement); } в function replaceInnerHtmlByClass($html, $replace=null, $class=null, $nodeType=null){ if(!$nodeType){ $nodeType = '*'; } $dom = new DOMDocument(); $dom->loadHTML($html); $xpath = new DOMXPath($dom); $nodes = $xpath->query("//{$nodeType}[contains(concat(' ', normalize-space(@class), ' '), '$class')]"); foreach($nodes as $node) { while($node->childNodes->length){ $node->removeChild($node->firstChild); } $fragment = $dom->createDocumentFragment(); $fragment->appendXML($replace); $node->appendChild($fragment); } return $dom->saveHTML($dom->documentElement); } 

Вот еще одна функция, которую я написал для удаления узлов с определенным классом, но сохраняя внутренний html.

Установка replace на true приведет к отмене внутреннего html.

Установка замены на любой другой контент заменит внутренний html предоставленным контентом.

 function stripTagsByClass($html, $class=null, $nodeType=null, $replace=false){ if(!$nodeType){ $nodeType = '*'; } $dom = new DOMDocument(); $dom->loadHTML($html); $xpath = new DOMXPath($dom); $nodes = $xpath->query("//{$nodeType}[contains(concat(' ', normalize-space(@class), ' '), '$class')]"); foreach($nodes as $node) { $innerHTML = ''; $children = $node->childNodes; foreach($children as $child) { $tmp = new DOMDocument(); $tmp->appendChild($tmp->importNode($child,true)); $innerHTML .= $tmp->saveHTML(); } $fragment = $dom->createDocumentFragment(); if($replace !== null && $replace !== false){ if($replace === true){ $replace = ''; } $innerHTML = $replace; } $fragment->appendXML($innerHTML); $node->parentNode->replaceChild($fragment, $node); } return $dom->saveHTML($dom->documentElement); } 

Функции тезисов могут быть легко адаптированы для использования в качестве селектора других атрибутов.

Мне нужно было только оценить атрибут класса.

Развивая ответ от ответа Джоанны Гох, эта функция будет вставлять либо текстовый узел, либо фрагмент HTML:

 function nodeFromContent($node, $content) { //creates a text node, or dom node if content contains html $lt = strpos($content, '<'); $gt = strrpos($content, '>'); if (!($lt === false || $gt === false) && $gt > $lt) { //< followed by > means potentially contains HTML $DOMInnerHTML = new DOMDocument(); $DOMInnerHTML->loadHTML($content); $contentNode = $DOMInnerHTML->getElementsByTagName('body')->item(0); $newNode = $node->ownerDocument->importNode($contentNode, true); } else { $newNode = $node->ownerDocument->createTextNode($content); } return $newNode; } 

Применение

 $newNode = nodeFromContent($node, $content); $node->parentNode->insertBefore($newNode, $node); //or $node->appendChild($newNode) depending on what you require 
 function setInnerHTML($DOM, $element, $innerHTML) { $node = $DOM->createTextNode($innerHTML); $element->appendChild($node); } 

Я закончил тем, что эту функцию использовал несколько функций от других людей на этой странице. Я изменил одно из Джоанны Гох так, как говорит Питер Бранд , а также добавил код от гостя и из других мест.

Эта функция не использует расширение и не использует appendXML (который очень разборчив и ломается, даже если он видит один тег BR, который не закрыт) и, кажется, работает хорошо.

 function set_inner_html( $element, $content ) { $DOM_inner_HTML = new DOMDocument(); $internal_errors = libxml_use_internal_errors( true ); $DOM_inner_HTML->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) ); libxml_use_internal_errors( $internal_errors ); $content_node = $DOM_inner_HTML->getElementsByTagName('body')->item(0); $content_node = $element->ownerDocument->importNode( $content_node, true ); while ( $element->hasChildNodes() ) { $element->removeChild( $element->firstChild ); } $element->appendChild( $content_node ); } 

вот как вы это делаете:

 $doc = new DOMDocument(''); $label = $doc->createElement('label'); $label->appendChild($doc->createTextNode('test')); $li->appendChild($label); echo $doc->saveHTML();