Frage

Mit PHP versuche ich, eine HTML -Zeichenfolge zu nehmen, die von einem WYSIWYG -Editor übergeben und die Kinder eines Elements in einem vorinstallierten HTML -Dokument durch das neue HTML ersetzt.

Bisher lade ich das Dokument, das das Element identifiziert, das ich durch ID ändern möchte, aber der Prozess, um ein HTML in etwas umzuwandeln, das in einem Domelement platziert werden kann, entgeht mir.

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
}
War es hilfreich?

Lösung

Wenn die HTML -Zeichenfolge als XML analysiert werden kann, können Sie dies tun (nach dem Löschen des Elements aller untergeordneten Knoten):

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

Wenn $ html_string nicht als XML analysiert werden kann, wird es fehlschlagen. Wenn dies der Fall ist, müssen Sie LoadHTML () verwenden, was weniger streng ist - aber es fügt Elemente um das Fragment hinzu, das Sie ausziehen müssen.

Im Gegensatz zu PHP verfügt JavaScript über die Innerhtml -Eigenschaft, mit der Sie dies sehr einfach tun können. Ich brauchte so etwas für ein Projekt, also erweiterte ich den Domelement von PHP, um den javaScript-ähnlichen Innerhtml-Zugriff aufzunehmen.

Mit dieser können Sie auf die Innerhtml -Eigenschaft zugreifen und sie genauso ändern, wie Sie es in JavaScript tun würden:

echo $element->innerHTML;
$elem->innerHTML = '<a href="http://example.org">example</a>';

Quelle: http://www.keyvan.net/2012/11/php-domdocument-replace-domelement-child-with-html-string/

Andere Tipps

Sie können verwenden loadHTML() auf einem Codefragment und dann die resultierenden erstellten Knoten in den ursprünglichen DOM -Baum anhängen.

Die aktuelle akzeptierte Antwort schlägt vor, dass appendXML () verwendet wird, erkennt jedoch an, dass sie nicht komplexe HTML behandelt, z. Wie vorgeschlagen, kann Loadhtml () dies beheben. Aber noch niemand hat gezeigt, wie.

Dies ist meiner Meinung nach die beste/korrekte Antwort auf die ursprüngliche Frage, die sich mit Codierungsproblemen befassen, "Dokumentfragment ist leer" Warnungen und "falsche Dokumentenfehler", die wahrscheinlich jemand klicken wird, wenn er dies von Grund auf neu schreibt. Ich weiß, dass ich sie gefunden habe, nachdem ich die Hinweise in den vorherigen Antworten verfolgt habe.

Dies ist Code von einer Site, die ich unterstütze, die WordPress -Seitenleisteinhalte in den $ Inhalt eines Beitrags einfügt. Es wird davon ausgegangen, dass $ DOC ein gültiges Domdocument ist, ähnlich der Art und Weise, wie $ DOC in der ursprünglichen Frage definiert ist. Es wird auch davon ausgegangen, dass $ Element das Tag ist, nach dem Sie den Seitenstück (oder was auch immer) einfügen möchten.

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

Nachdem dies erledigt ist, können Sie damit die Quelle eines vollständigen HTML -Dokuments mit Body -Tags haben und was nicht, damit Sie mit diesem die lokalisierteren HTML generieren:

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

Ich weiß, dass dies ein alter Thread ist (aber darauf antworten, weil auch eine Lösung dafür gesucht wird). Ich habe eine einfache Methode erstellt, um Inhalte durch nur eine einzige Zeile zu ersetzen, wenn ich sie benutze. Um die Methode besser zu verstehen, füge ich auch einen Kontext mit dem Namen Funktionen hinzu.

Dies ist jetzt ein Teil meiner Bibliothek. Dies ist der Grund für alle Funktionsnamen hier, alle Funktionen beginnen mit dem Präfix 'Su'.

Es ist sehr einfach zu bedienen und sehr leistungsstark (und weniger Code).

Hier ist der Code:

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

Einige Kontextfunktionen:

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

Wie man es benutzt:

In den folgenden Beispielen gehe ich davon aus, dass bereits Inhalte in eine Variable genannt werden $sMyHtml und die Variable $sMyNewContent Enthält einige neue HTML. Die Variable $sMyHtml Enthält ein Element namens/mit der 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' ); 
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top