【问题标题】:How to import XML string in a php DOMDocument如何在 php DOMDocument 中导入 XML 字符串
【发布时间】:2020-02-19 10:02:24
【问题描述】:

例如,我创建了一个 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>';

如何将其导入我的DOMDocument&lt;body&gt; 节点?

目前,我找到的唯一解决方案是这样的:

<?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实体来绕过这个问题,但是实在是太难看了……

有什么帮助吗?

提前致谢!

相关问题:

【问题讨论】:

    标签: php xml xhtml simplexml domdocument


    【解决方案1】:

    问题是 DOM 不知道它应该考虑 XHTML DTD,除非您根据它验证文档。除非您这样做,否则 DOM 不知道 DTD 中定义的任何实体,也不知道其中的任何其他规则。幸运的是,我们整理了如何进行验证 in that other question,所以有了这些知识你就可以做到

    $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();
    

    输出:

    <?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();
    

    输出:

    <?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,因为它缺少根节点。这就是你使用片段的原因。

    【讨论】:

    • 没关系,我可以在验证我的文档后导入,但这意味着如果我想使用 DOMDocument 模板而不是文本模板,我必须每次插入一些内容 / 每次都验证我提供一个页面,所以,请求一个始终相同的 DTD,因为 PHP 会处理 HTTP Stats,我将淹没 w3.org...
    • @G.然后 Qyy 将 HTTP 流上下文设置为使用缓存代理。
    • @Service 和@G。 Qyy:另一种选择可能是unregister regular HTTP stream wrapper 并将其替换为您自己的从本地副本读取 DTD 的实现。
    • @Service 您可以使用指向本地文件而不是 W3C URL 的 systemId。不过,这只适用于您在请求期间创建的文档。与 NG 和 Schema 验证不同,没有 validateSource 函数允许您在字符串中传递 DTD。您可以针对 XHTML schema 进行验证,但架构不包含实体。
    • 好的,因此,经过一些研究,如果不验证 DOMDocument 或将 XHTML 实体转换为 Unicode,就不可能导入 XML 字符串。所以我选择了最省力的方案:用pastebin.com/6ADYFLHa这个函数转换实体。非常感谢您的帮助
    【解决方案2】:

    您可以为此使用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);
    

    【讨论】:

    • 不幸,与 SimpleXmlElement 相同的问题:“警告:DOMDocumentFragment::appendXML():实体:第 1 行:解析器错误:未定义实体 'nbsp'”
    • @G。 Qyy:用另一种可能的解决方案编辑答案
    • 具有良好声明的 DTD 的 XHTML 是有效的 XML,并且您的解决方案使用 DTD 声明避开了 DOMImplementation,抱歉...非常感谢您愿意帮助我,还有什么?
    猜你喜欢
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    相关资源
    最近更新 更多