【问题标题】:Change innerHTML of a php DOMElement [duplicate]更改php DOMElement的innerHTML [重复]
【发布时间】:2011-02-16 05:06:09
【问题描述】:

如何更改 php DOMElement 的 innerHTML ?

【问题讨论】:

  • 你不能,直接。您必须有一个中间函数来获取字符串并将其转换为 DOMElements 数组。你可以自己写,虽然我确信网络上存在类似的东西。
  • php DOMElement 类中没有 innerHTML 属性。试试看这里:php.net/manual/en/class.domelement.php 和这里:php.net/manual/en/class.domtext.php
  • 如果您路过,请随意投票 reopen,因为这不是链接问题的副本。

标签: php dom


【解决方案1】:

另一种解决方案:

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);
}

或者,我们可以用它的clean copy 替换我们的元素,然后将 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>

【讨论】:

  • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!
【解决方案2】:

我最近需要为一个项目做这件事,最终得到了 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();
?>

【讨论】:

    【解决方案3】:

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

    在非常粗略的 PHP 中:

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

    这没有考虑到属性和嵌套结构,但我认为这会让您顺利上路。

    【讨论】:

    • 对于其他尝试此代码的人 - 我必须使用 $el->parentNode->insertBefore 而不是 $el->insertBefore。
    • 这适用于设置innerText 而不是innerHTML。 createElement 的第二个参数不接受 html 格式。
    • 同意,@greg。这将对字符进行 HTML 编码。
    【解决方案4】:

    我最终使用此页面上其他人的一些功能来制作此功能。我改变了 Joanna Goch 的那个,就像 Peter Brand 所说的那样,还添加了一些来自 Guest 和其他地方的代码。

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

    【讨论】:

      【解决方案5】:

      appendXML 似乎并不总是有效 - 例如,如果您尝试附加 3 个级别的 XML。这是我编写的始终有效的函数(您想将 $content 设置为 $element 的 innerHTML):

      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;
      }
      

      【讨论】:

      • 返回的变量$elementNode 是未定义的——不应该是$contentNode 吗?您可以使用$element-&gt;ownerDocument 来简化函数,而不必传入$DOM。这仅导入 $content 包含的任何内容的第一个孩子。要导入整个片段,请删除第 4 行的 `->firstChild'。
      【解决方案6】:

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

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

      【讨论】:

      • PHP,不是 JavaScript...PHP 的 DOM 实现没有 innerHTML 属性。
      • 是的,我的错。但是 php5 HTML DOM 解析器有“innertext”。 simplehtmldom.sourceforge.net
      • 那不是 OP 所指的库。请参阅:php.net/manual/en/book.dom.php 但您可以编辑您的答案并链接到您找到的库,看看 OP 是否想要切换。
      【解决方案7】:

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

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

      这是我编写的另一个函数,用于删除具有特定类但保留内部 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 的回答进行开发,此函数将插入文本节点或 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();
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-06-07
              • 1970-01-01
              • 2011-11-01
              • 2012-09-09
              • 2013-03-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多