使用PHP我试图获取从WYSIWYG编辑器传递的HTML字符串,并用新的HTML替换预加载的HTML文档中的元素的子元素。
到目前为止,我正在加载文档,用于标识我想要通过ID更改的元素,但是将HTML转换为可放置在DOMElement中的内容的过程正在躲避我。
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML($html);
$element = $doc->getElementById($item_id);
if(isset($element)){
//Remove the old children from the element
while($element->childNodes->length){
$element->removeChild($element->firstChild);
}
//Need to build the new children from $html_string and append to $element
}
答案 0 :(得分:13)
如果HTML字符串可以解析为XML,则可以执行此操作(清除所有子节点的元素后):
$fragment = $doc->createDocumentFragment();
$fragment->appendXML($html_string);
$element->appendChild($fragment);
如果$ html_string无法解析为XML,则会失败。如果是这样,你将不得不使用loadHTML(),它不那么严格 - 但它会在片段周围添加你必须去除的元素。
与PHP不同,Javascript具有innerHTML属性,允许您非常轻松地执行此操作。我需要类似于项目的东西,所以我扩展了PHP的DOMElement以包含类似Javascript的innerHTML访问。
有了它,您可以访问innerHTML属性并像在Javascript中一样进行更改:
echo $element->innerHTML;
$elem->innerHTML = '<a href="http://example.org">example</a>';
来源:http://www.keyvan.net/2012/11/php-domdocument-replace-domelement-child-with-html-string/
答案 1 :(得分:1)
您可以在代码片段上使用loadHTML()
,然后将生成的创建节点附加到原始DOM树中。
答案 2 :(得分:1)
当前接受的答案建议使用appendXML(),但承认它不会处理复杂的html,例如原始问题中指定的从WYSISYG编辑器返回的内容。正如建议的loadHTML()可以解决这个问题。但还没有人表明如何。
我认为这是解决编码问题的原始问题的最佳/正确答案,&#34;文档片段是空的&#34;警告和&#34;错误的文档错误&#34;如果他们从头开始写这个,可能会遇到的错误。我知道在按照之前的回复中的提示后我找到了它们。
这是我支持的网站的代码,它将WordPress边栏内容插入到帖子的$ content中。它假定$ doc是一个有效的DOMDocument,类似于原始问题中$ doc的定义方式。它还假设$ element是您希望插入sidebarcontent(或其他)的标记。
// NOTE: Cannot use a document fragment here as the AMP html is too complex for the appendXML function to accept.
// Instead create it as a document element and insert that way.
$node = new DOMDocument();
// Note that we must encode it correctly or strange characters may appear.
$node->loadHTML( mb_convert_encoding( $sidebarContent, 'HTML-ENTITIES', 'UTF-8') );
// Now we need to move this document element into the scope of the content document
// created above or the insert/append will be rejected.
$node = $doc->importNode( $node->documentElement, true );
// If there is a next sibling, insert before it.
// If not, just add it at the end of the element we did find.
if ( $element->nextSibling ) {
$element->parentNode->insertBefore( $node, $element->nextSibling );
} else {
$element->parentNode->appendChild($node);
}
完成所有这些操作后,如果您不想拥有带有body标签的完整HTML文档的来源,那么您可以使用以下内容生成更加本地化的html:
// Now because we have moved the post content into a full document, we need to get rid of the
// extra elements that make it a document and not a fragment
$body = $doc->getElementsByTagName( 'body' );
$body = $body->item(0);
// If you need an element with a body tag, you can do this.
// return $doc->savehtml( $body );
// Extract the html from the body tag piece by piece to ensure valid html syntax in destination document
$bodyContent = '';
foreach( $body->childNodes as $node ) {
$bodyContent .= $body->ownerDocument->saveHTML( $node );
}
// Now return the full content with the new content added.
return $bodyContent;
答案 3 :(得分:1)
我知道这很老了,但是当前的答案都没有一个最小的工作示例,说明如何用存储在字符串中的HTML替换DOMDocument中的DOMNode。
application/json
答案 4 :(得分:0)
我知道这是一个旧线程(但回复此问题,因为也在寻找解决方案)。我在使用它时只用一行代替了内容。为了更好地理解该方法,我还添加了一些名为functions的上下文。
现在这是我的库的一部分,所以这就是所有函数名称的原因,所有函数都以前缀'su'开头。
它非常易于使用且功能非常强大(而且代码非常少)。
以下是代码:
function suSetHtmlElementById( &$oDoc, &$s, $sId, $sHtml, $bAppend = false, $bInsert = false, $bAddToOuter = false )
{
if( suIsValidString( $s ) && suIsValidString( $sId ))
{
$bCreate = true;
if( is_object( $oDoc ))
{
if( !( $oDoc instanceof DOMDocument ))
{ return false; }
$bCreate = false;
}
if( $bCreate )
{ $oDoc = new DOMDocument(); }
libxml_use_internal_errors(true);
$oDoc->loadHTML($s);
libxml_use_internal_errors(false);
$oNode = $oDoc->getElementById( $sId );
if( is_object( $oNode ))
{
$bReplaceOuter = ( !$bAppend && !$bInsert );
$sId = uniqid('SHEBI-');
$aId = array( "<!-- $sId -->", "<!--$sId-->" );
if( $bReplaceOuter )
{
if( suIsValidString( $sHtml ) )
{
$oNode->parentNode->replaceChild( $oDoc->createComment( $sId ), $oNode );
$s = $oDoc->saveHtml();
$s = str_replace( $aId, $sHtml, $oDoc->saveHtml());
}
else { $oNode->parentNode->removeChild( $oNode );
$s = $oDoc->saveHtml();
}
return true;
}
$bReplaceInner = ( $bAppend && $bInsert );
$sThis = null;
if( !$bReplaceInner )
{
$sThis = $oDoc->saveHTML( $oNode );
$sThis = ($bInsert?$sHtml:'').($bAddToOuter?$sThis:(substr($sThis,strpos($sThis,'>')+1,-(strlen($oNode->nodeName)+3)))).($bAppend?$sHtml:'');
}
if( !$bReplaceInner && $bAddToOuter )
{
$oNode->parentNode->replaceChild( $oDoc->createComment( $sId ), $oNode );
$sId = &$aId;
}
else { $oNode->nodeValue = $sId; }
$s = str_replace( $sId, $bReplaceInner?$sHtml:$sThis, $oDoc->saveHtml());
return true;
}
}
return false;
}
// A function of my library used in the function above:
function suIsValidString( &$s, &$iLen = null, $minLen = null, $maxLen = null )
{
if( !is_string( $s ) || !isset( $s{0} ))
{ return false; }
if( $iLen !== null )
{ $iLen = strlen( $s ); }
return (( $minLen===null?true:($minLen > 0 && isset( $s{$minLen-1} ))) &&
$maxLen===null?true:($maxLen >= $minLen && !isset( $s{$maxLen})));
}
某些上下文功能:
function suAppendHtmlById( &$s, $sId, $sHtml, &$oDoc = null )
{ return suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, true, false ); }
function suInsertHtmlById( &$s, $sId, $sHtml, &$oDoc = null )
{ return suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, false, true ); }
function suAddHtmlBeforeById( &$s, $sId, $sHtml, &$oDoc = null )
{ return suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, false, true, true ); }
function suAddHtmlAfterById( &$s, $sId, $sHtml, &$oDoc = null )
{ return suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, true, false, true ); }
function suSetHtmlById( &$s, $sId, $sHtml, &$oDoc = null )
{ return suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, true, true ); }
function suReplaceHtmlElementById( &$s, $sId, $sHtml, &$oDoc = null )
{ return suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, false, false ); }
function suRemoveHtmlElementById( &$s, $sId, &$oDoc = null )
{ return suSetHtmlElementById( $oDoc, $s, $sId, null, false, false ); }
如何使用
在以下示例中,我假设已将内容加载到名为$sMyHtml
的变量中,变量$sMyNewContent
包含一些新的html。变量$sMyHtml
包含一个名为/的元素,其标识为“example_id
”。
// Example 1: Append new content to the innerHTML of an element (bottom of element):
if( suAppendHtmlById( $sMyHtml, 'example_id', $sMyNewContent ))
{ echo $sMyHtml; }
else { echo 'Element not found?'; }
// Example 2: Insert new content to the innerHTML of an element (top of element):
suInsertHtmlById( $sMyHtml, 'example_id', $sMyNewContent );
// Example 3: Add new content ABOVE element:
suAddHtmlBeforeById( $sMyHtml, 'example_id', $sMyNewContent );
// Example 3: Add new content BELOW/NEXT TO element:
suAddHtmlAfterById( $sMyHtml, 'example_id', $sMyNewContent );
// Example 4: SET new innerHTML content of element:
suSetHtmlById( $sMyHtml, 'example_id', $sMyNewContent );
// Example 5: Replace entire element with new content:
suReplaceHtmlElementById( $sMyHtml, 'example_id', $sMyNewContent );
// Example 6: Remove entire element:
suSetHtmlElementById( $sMyHtml, 'example_id' );