web-dev-qa-db-ja.com

HTMLをPHP DOMNodeに挿入する方法は?

コンテンツをエンコードせずにHTMLテンプレートを既存のDOMNodeに挿入する方法はありますか?

私はそれをやってみました:

$dom->createElement('div', '<h1>Hello world</h1>');
$dom->createTextNode('<h1>Hello world</h1>');

出力はほとんど同じですが、最初のコードがそれをdivでラップする点のみが異なります。文字列からHTMLをロードしようとしましたが、本文のコンテンツを別のDOMDocumentに追加する方法がわかりません。

JavaScriptでは、このプロセスは非常に単純で明白なようです。

31
Nazariy

HTMLコードを解析するための別のDOMDocumentと連携します。しかし、メインのドキュメントでそれらを使用する前に、メインのドキュメントに ノードをインポートする する必要があります。

$newDiv = $dom->createElement('div');
$tmpDoc = new DOMDocument();
$tmpDoc->loadHTML($str);
foreach ($tmpDoc->getElementsByTagName('body')->item(0)->childNodes as $node) {
    $node = $dom->importNode($node, true);
    $newDiv->appendChild($node);
}

そして便利な機能として:

function appendHTML(DOMNode $parent, $source) {
    $tmpDoc = new DOMDocument();
    $tmpDoc->loadHTML($source);
    foreach ($tmpDoc->getElementsByTagName('body')->item(0)->childNodes as $node) {
        $node = $parent->ownerDocument->importNode($node, true);
        $parent->appendChild($node);
    }
}

次に、これを簡単に実行できます。

$elem = $dom->createElement('div');
appendHTML($elem, '<h1>Hello world</h1>');
27
Gumbo

使用できます

例:

// just some setup
$dom = new DOMDocument;
$dom->loadXml('<html><body/></html>');
$body = $dom->documentElement->firstChild;

// this is the part you are looking for    
$template = $dom->createDocumentFragment();
$template->appendXML('<h1>This is <em>my</em> template</h1>');
$body->appendChild($template);

// output
echo $dom->saveXml();

出力:

<?xml version="1.0"?>
<html><body><h1>This is <em>my</em> template</h1></body></html>

別のDOMDocumentからインポートする場合は、3行を次のように置き換えます。

$tpl = new DOMDocument;
$tpl->loadXml('<h1>This is <em>my</em> template</h1>');
$body->appendChild($dom->importNode($tpl->documentElement, TRUE));

TRUE の2番目の引数としてimportNodeを使用すると、ノードツリーが再帰的にインポートされます。


(不正な)HTMLをインポートする必要がある場合は、loadXmlloadHTMLに変更します。これはlibxmlのHTMLパーサーをトリガーします(ext/DOMが内部で使用するもの):

libxml_use_internal_errors(true);
$tpl = new DOMDocument;
$tpl->loadHtml('<h1>This is <em>malformed</em> template</h2>');
$body->appendChild($dom->importNode($tpl->documentElement, TRUE));
libxml_use_internal_errors(false);

Libxmlはマークアップを修正しようとすることに注意してください。間違った終了を変更します</h2>から</h1>

40
Gordon

私はXMLと格闘したくないので、エラーをより速くスローし、エラー出力を防ぐために@を前に付けるのは好きではありません。 loadHTMLは私の意見ではより良い仕事をし、それはそのように非常に簡単です:

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

// use a helper to load the HTML into a string
$helper = new DOMDocument();
$helper->loadHTML('<a href="#">This is my HTML Link.</a>');

// now the magic!
// import the document node of the $helper object deeply (true)
// into the $div and append as child.
$div->appendChild($doc->importNode($helper->documentElement, true));

// add the div to the $doc
$doc->appendChild($div);

// final output
echo $doc->saveHTML();
5
Markus Zeller

DOMDocumentFragment を使用した簡単な例を次に示します。

$doc = new DOMDocument();
$doc->loadXML("<root/>");
$f = $doc->createDocumentFragment();
$f->appendXML("<foo>text</foo><bar>text2</bar>");
$doc->documentElement->appendChild($f);
echo $doc->saveXML();

DOMNodeを置き換えるためのヘルパー関数を次に示します。

/** 
 * Helper function for replacing $node (DOMNode) 
 * with an XML code (string) 
 * 
 * @var DOMNode $node 
 * @var string $xml 
 */ 
public function replaceNodeXML(&$node, $xml) { 
  $f = $this->dom->createDocumentFragment(); 
  $f->appendXML($xml); 
  $node->parentNode->replaceChild($f,$node); 
}

出典:「PHP5 Dom Based Template」の古い記事。

そして、回避策としてvalue属性を使用するために Pian0_M4n によって投稿された別の提案を次に示します。

$dom = new DomDocument;

// main object
$object = $dom->createElement('div');

// html attribute
$attr = $dom->createAttribute('value');
// ugly html string
$attr->value = "<div>&nbsp; this is a really html string &copy;</div><i></i> with all the &copy; that XML hates!";
$object->appendChild($attr);

// jquery fix (or javascript as well)
$('div').html($(this).attr('value')); // and it works! 
$('div').removeAttr('value'); // to clean-up

理想的ではありませんが、少なくともそれは機能します。

0
kenorb