11

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

5 に答える 5

14

HTML文字列をXMLとして解析できる場合は、これを行うことができます(すべての子ノードの要素をクリアした後)。

$fragment = $doc->createDocumentFragment();
$fragment->appendXML($html_string);
$element->appendChild($fragment);

$ html_stringをXMLとして解析できない場合、失敗します。その場合は、それほど厳密ではないloadHTML()を使用する必要がありますが、削除する必要のあるフラグメントの周囲に要素が追加されます。

PHPとは異なり、JavascriptにはinnerHTMLプロパティがあり、これを非常に簡単に行うことができます。プロジェクトにはそのようなものが必要だったので、PHPのDOMElementを拡張して、JavascriptのようなinnerHTMLアクセスを含めました。

これを使用すると、JavaScriptの場合と同じように、innerHTMLプロパティにアクセスして変更できます。

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/

于 2010-08-23T10:15:23.527 に答える
3

現在受け入れられている回答は、appendXML()の使用を提案していますが、元の質問で指定されているWYSISYGエディターから返されるものなどの複雑なhtmlを処理しないことを認めています。提案されているように、loadHTML()はこれに対処できます。しかし、まだ誰もその方法を示していません。

これは、エンコーディングの問題、「ドキュメントフラグメントが空です」という警告、および誰かがこれを最初から作成した場合に発生する可能性のある「間違ったドキュメントエラー」エラーに対処する元の質問に対する最良/正解であると私は信じています。以前の回答のヒントに従って、それらを見つけたのはわかっています。

これは、WordPressサイドバーコンテンツを投稿の$contentに挿入する私がサポートするサイトのコードです。$ docは、元の質問で$docが定義されているのと同様の有効なDOMDocumentであると想定しています。また、$ elementが、サイドバーコンテンツ(またはその他)を挿入するタグであると想定しています。

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

これらすべてが完了した後、本文タグを含む完全な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;
于 2016-10-18T21:04:47.347 に答える
1

コードのフラグメントで使用loadHTML()して、作成されたノードを元のDOMツリーに追加できます。

于 2010-02-10T01:03:38.757 に答える
1

私はこれが古いスレッドであることを知っています(しかし、これに対する解決策も探しているので、これに返信してください)。コンテンツを使用するときに、コンテンツを1行だけに置き換える簡単な方法を作成しました。メソッドをよりよく理解するために、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には、ID' 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' ); 
于 2013-07-15T18:17:23.500 に答える
1

これは古いことは知っていますが、現在の回答のいずれも、DOMDocument内のDOMNodeを文字列に格納されたHTMLに置き換える方法の最小限の実用的な例を示していません。

// the HTML fragment we want to use as the replacement
$htmlReplace = '<div><strong>foo</strong></div>';
// the HTML of the original document
$htmlHaystack = '<p><a id="tag">bar</a></p>';

// load the HTML replacement fragment
$domDocumentReplace = new \DOMDocument;
$domDocumentReplace->loadHTML($htmlReplace, LIBXML_HTML_NOIMPLIED);

// load the HTML of the document
$domDocumentHaystack = new \DOMDocument;
$domDocumentHaystack->loadHTML($htmlHaystack, LIBXML_HTML_NOIMPLIED);

// import the replacement node into the document
$htmlReplaceNode = $domDocumentHaystack->importNode($domDocumentReplace->documentElement, true);

// find the DOMNode(s) we want to replace - in this case #tag (to keep the example simple)
$domNodeTag = $domDocumentHaystack->getElementById('tag');

// replace the node
$domNodeTag->parentNode->replaceChild($htmlReplaceNode, $domNodeTag);

// output the new HTML of the document
echo $domDocumentHaystack->saveHTML($domDocumentHaystack->documentElement);
// <p><div><strong>foo</strong></div></p>
于 2020-09-10T15:14:52.483 に答える