Есть ли способ вставить шаблон HTML в существующий DOMNode без кодирования содержимого?
Я попытался сделать это с помощью:
$dom->createElement('div', '<h1>Hello world</h1>'); $dom->createTextNode('<h1>Hello world</h1>');
Результат практически не изменился, и только разница в том, что первый код обернет его в div. Я попытался загрузитьHTML из строки, но я понятия не имею, как добавить его содержимое тела в другой DOMDocument.
В javascript этот процесс кажется довольно простым и очевидным.
Он работает с другим DOMDocument для анализа кода HTML. Но вам нужно импортировать узлы в основной документ, прежде чем вы сможете использовать их в нем:
$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); } }
,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>');
Вы можете использовать
DOMDocumentFragment::appendXML
– добавление необработанных данных XML Пример:
// 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, замените три строки на
$tpl = new DOMDocument; $tpl->loadXml('<h1>This is <em>my</em> template</h1>'); $body->appendChild($dom->importNode($tpl->documentElement, TRUE));
Использование TRUE
поскольку второй аргумент importNode
будет выполнять рекурсивный импорт дерева узлов.
Если вам нужно импортировать (искаженный) HTML, измените loadXml
на loadHTML
. Это вызовет анализатор HTML libxml (что внутреннее использование 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>
.
Поскольку я не хочу бороться с XML, потому что он быстрее порождает ошибки, и я не поклонник префикса @, чтобы предотвратить выход ошибки. НагрузкаHTML делает лучшую работу, на мой взгляд, и это довольно просто:
$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();
Вот простой пример, используя 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 на основе сайта.
И вот еще одно предложение, опубликованное Pian0_M4n для использования атрибута value в качестве обходного пути:
$dom = new DomDocument; // main object $object = $dom->createElement('div'); // html attribute $attr = $dom->createAttribute('value'); // ugly html string $attr->value = "<div> this is a really html string ©</div><i></i> with all the © 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
Нет идеального, но, по крайней мере, он работает.
Код Gumbo работает отлично! Просто небольшое улучшение, добавляющее параметр TRUE, чтобы он работал с вложенными фрагментами html.
$node = $parent->ownerDocument->importNode($node); $node = $parent->ownerDocument->importNode($node, **TRUE**);