Измените innerHTML php DOMElement

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

Ответ 1

Мне нужно было сделать это для проекта недавно и в итоге было добавлено расширение для 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();
?>

Ответ 2

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

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>

Ответ 3

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

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

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

    return $newElement;
}

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

Ответ 4

Кажется, что 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;
}

Ответ 5

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

Эта функция не использует расширение и не использует 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 );
}

Ответ 6

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

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

Ответ 7

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

Он заменит innerHtml класса. Вы также можете указать тип node, например. 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);
}

Вот еще одна функция, которую я написал для удаления узлов с определенным классом, но сохраняющий внутренний 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);
}

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

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

Ответ 8

Разработав ответ от Joanna Goch, эта функция будет вставлять либо текст node, либо фрагмент 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

Ответ 9

function setInnerHTML($DOM, $element, $innerHTML) {
  $node = $DOM->createTextNode($innerHTML);
  $element->appendChild($node);
}

Ответ 10

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

$doc = new DOMDocument('');
$label = $doc->createElement('label');

$label->appendChild($doc->createTextNode('test'));
$li->appendChild($label);

echo $doc->saveHTML();