Как импортировать XML-строку в php DOMDocument - PullRequest
7 голосов
/ 02 ноября 2010

Например, я создаю DOMDocument вот так:

<?php

$implementation = new DOMImplementation();

$dtd =
  $implementation->createDocumentType
  (
    'html',                                     // qualifiedName
    '-//W3C//DTD XHTML 1.0 Transitional//EN',   // publicId
    'http://www.w3.org/TR/xhtml1/DTD/xhtml1-'
      .'transitional.dtd'                       // systemId
  );

$document = $implementation->createDocument('', '', $dtd);

$elementHtml     = $document->createElement('html');
$elementHead     = $document->createElement('head');
$elementBody     = $document->createElement('body');
$elementTitle    = $document->createElement('title');
$textTitre       = $document->createTextNode('My bweb page');
$attrLang        = $document->createAttribute('lang');
$attrLang->value = 'en';

$document->appendChild($elementHtml);
$elementHtml->appendChild($elementHead);
$elementHtml->appendChild($attrLang);
$elementHead->appendChild($elementTitle);
$elementTitle->appendChild($textTitre);
$elementHtml->appendChild($elementBody);

Итак, теперь, если у меня есть какая-то строка xhtml, такая:

<?php
$xhtml = '<h1>Hello</h1><p>World</p>';

Как я могу импортировать его в <body> узел моего DOMDocument?

На данный момент единственное решение, которое я нашел, это что-то вроде этого:

<?php
$simpleXmlElement = new SimpleXMLElement($xhtml);

$domElement = dom_import_simplexml($simpleXmlElement);

$domElement = $document->importNode($domElement, true);

$elementBody->appendChild($domElement);

Это решение кажется мне очень плохим и создает некоторые проблемы, например, когда я пытаюсь использовать такую ​​строку:

<?php
$xhtml = '<p>Hello&nbsp;World</p>';

Хорошо, я могу обойти эту проблему, преобразовав сущности xhtml в сущности Unicode, но это так ужасно ...

Любая помощь?

Заранее спасибо!

Похожие вопросы:

Ответы [ 2 ]

9 голосов
/ 03 ноября 2010

Проблема в том, что DOM не знает, что он должен учитывать DTD XHTML, если вы не проверили документ по нему.Если вы не сделаете этого, DOM не будет знать ни сущностей, определенных в DTD, ни каких-либо других правил в нем.К счастью, мы выяснили, как выполнить проверку в этом другом вопросе , поэтому вооружившись этими знаниями, вы можете

$document->validate(); // anywhere before importing the other DOM

и затем импортировать с помощью

$fragment = $document->createDocumentFragment();
$fragment->appendXML('<h1>Hello</h1><p>Hello&nbsp;World</p>');
$document->getElementsByTagName('body')->item(0)->appendChild($fragment);
$document->formatOutput = TRUE;
echo $document->saveXml();

output:

<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>My bweb page</title>
  </head>
  <body>
    <h1>Hello</h1>
    <p>Hello&nbsp;World</p>
  </body>
</html>

Другой способ импортировать XML в другой DOM - использовать

$one = new DOMDocument;
$two = new DOMDocument;
$one->loadXml('<root><foo>one</foo></root>');
$two->loadXml('<root><bar><sub>two</sub></bar></root>');
$bar = $two->documentElement->firstChild; // we want to import the bar tree
$one->documentElement->appendChild($one->importNode($bar, TRUE));
echo $one->saveXml();

output:

<?xml version="1.0"?>
<root><foo>one</foo><bar><sub>two</sub></bar></root>

Однако это не может работать с

<h1>Hello</h1><p>Hello&nbsp;World</p>

, поскольку при загрузке документа в DOM DOM перезаписывает все, что вы говорили об этом документе ранее.Таким образом, при использовании load libxml (и, следовательно, SimpleXml, DOM и XMLReader) не (не) знают, что вы имеете в виду XHTML.И он не знает никаких сущностей, определенных в нем, и вместо этого будет размышлять о них.Но даже если строка не будет содержать сущность, она не является допустимым XML, поскольку в ней отсутствует корневой узел.Вот почему вы используете фрагмент.

1 голос
/ 02 ноября 2010

Вы можете использовать DomDocumentFragment для этого:

$fragment = $document->createDocumentFragment();
$fragment->appendXml($xhtml);
$elementBody->appendChild($fragment);

Это все, что нужно ...

Редактировать: Что ж, если у вас должен быть xhtml (вместо действительного xml), вы можете сделать этот грязный обходной путь:

function xhtmlToDomNode($xhtml) {
    $dom = new DomDocument();
    $dom->loadHtml('<html><body>'.$xhtml.'</body></html>');
    $fragment = $dom->createDocumentFragment();
    $body = $dom->getElementByTagName('body')->item(0);
    foreach ($body->childNodes as $child) {
        $fragment->appendChild($child);
    }
    return $fragment;
}

использование:

$fragment = xhtmlToDomNode($xhtml);
$document->importNode($fragment, true);
$elementBody->appendChild($fragment);
...