更改 php DOMElement 的innerHTML

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2778110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 07:39:18  来源:igfitidea点击:

Change innerHTML of a php DOMElement

phpdom

提问by iavian

How to Change innerHTML of a php DOMElement ?

如何更改 php DOMElement 的innerHTML?

回答by Keyvan

I needed to do this for a project recently and ended up with an extension to DOMElement: http://www.keyvan.net/2010/07/javascript-like-innerhtml-access-in-php/

我最近需要为一个项目执行此操作并最终扩展到 DOMElement:http://www.keyvan.net/2010/07/javascript-like-innerhtml-access-in-php/

Here's an example showing how it's used:

下面是一个示例,展示了它是如何使用的:

<?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();
?>

回答by Guest

Another solution:

另一种解决方案:

1) create new DOMDocumentFragmentfrom the HTML string to be inserted; 2) remove old content of our element by deleting its child nodes; 3) append DOMDocumentFragment to our element.

1)从要插入的 HTML 字符串创建新的DOMDocumentFragment;2)通过删除其子节点来删除我们元素的旧内容;3) 将 DOMDocumentFragment 附加到我们的元素。

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

Alternatively, we can replace our element with its clean copyand then append DOMDocumentFragment to this clone.

或者,我们可以用它的干净副本替换我们的元素,然后将 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);
}

Test:

测试:

$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>

回答by Nikolay

I ended up making this function using a few functions from other people on this page. I changed the one from Joanna Gochthe way that Peter Brandsays mostly, and also added some code from Guestand from other places.

我最终使用此页面上其他人的一些功能制作了此功能。我按照Peter Brand所说的方式更改了Joanna Goch的代码,并添加了一些来自Guest和其他地方的代码。

This function does not use an extension, and does not use appendXML (which is very picky and breaks even if it sees one BR tag that is not closed) and seems to be working good.

该函数不使用扩展,也不使用 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 );
}

回答by Michael T. Smith

I think the best thing you can do is come up with a function that will take the DOMElement that you want to change the InnerHTML of, copy it, and replace it.

我认为你能做的最好的事情就是想出一个函数来获取你想要更改 InnerHTML 的 DOMElement,复制并替换它。

In very rough PHP:

在非常粗略的 PHP 中:

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

    return $newElement;
}

This doesn't take into account attributes and nested structures, but I think this will get you on your way.

这不考虑属性和嵌套结构,但我认为这会让你上路。

回答by Joanna Goch

It seems that appendXML doesn't work always - for example if you try to append XML with 3 levels. Here is the function I wrote that always work (you want to set $content as innerHTML to $element):

似乎 appendXML 并不总是有效 - 例如,如果您尝试附加 3 个级别的 XML。这是我编写的始终有效的函数(您想将 $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;
}

回答by Peter Brand

Developing on from Joanna Goch's answer, this function will insert either a text node or an HTML fragment:

根据 Joanna Goch 的回答,此函数将插入文本节点或 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;
}

usage

用法

$newNode = nodeFromContent($node, $content);
$node->parentNode->insertBefore($newNode, $node);
//or $node->appendChild($newNode) depending on what you require

回答by Tobi

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

回答by Dieter Gribnitz

Here is a replace by class function I just wrote:

这是我刚刚写的类函数替换:

It will replace the innerHtml of a class. You can also specify the node type eg. div/p/a etc.

它将替换一个类的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);
}


Here is another function I wrote to remove nodes with a specific class but preserving the inner html.

这是我编写的另一个函数,用于删除具有特定类的节点但保留内部 html。

Setting replace to true will discard the inner html.

将 replace 设置为 true 将丢弃内部 html。

Setting replace to any other content will replace the inner html with the provided content.

将替换设置为任何其他内容将使用提供的内容替换内部 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);
}

Theses functions can easily be adapted to use other attributes as the selector.

这些函数可以很容易地适应使用其他属性作为选择器。

I only needed it to evaluate the class attribute.

我只需要它来评估类属性。

回答by Jull

Have a look at this library PHP Simple HTML DOM Parser http://simplehtmldom.sourceforge.net/

看看这个库 PHP Simple HTML DOM Parser http://simplehtmldom.sourceforge.net/

It looks pretty straightforward. You can change innertextproperty of your elements. It might help.

它看起来很简单。您可以更改innertext元素的属性。它可能会有所帮助。

回答by Christopher Pelayo

here is how you do it:

这是你如何做到的:

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

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

echo $doc->saveHTML();