1

我有问题。我想用DOMDocument.

<div class="something-first">
    <div class="something-child something-good another something-great">
        <my:text value="huhu">
    </div>
</div>

但我不知道如何保留命名空间。我尝试加载它,loadHTML()但 HTML 没有名称空间,因此它们被剥离。

我尝试加载它,loadXML()但这不起作用,因为<my:text value="huhu">XML 不正确。

我需要的是一种loadHTML()不剥离命名空间的loadXML()方法或一种不验证标记的方法。所以这两种方法的结合。

到目前为止我的代码:

$html = '<div class="something-first">
    <div class="something-child something-good another something-great">
        <my:text value="huhu">
    </div>
</div>';

libxml_use_internal_errors(true);

$domDoc = new DOMDocument();
$domDoc->formatOutput = false;
$domDoc->resolveExternals = false;
$domDoc->substituteEntities = false;
$domDoc->strictErrorChecking = false;
$domDoc->validateOnParse = false;

$domDoc->loadHTML($html/*, LIBXML_NOERROR | LIBXML_NOWARNING*/);
$xpath = new DOMXPath($domDoc);
$xpath->registerNamespace ( 'my', 'http://www.example.com/' );

// -----> This results in zero nodes cause namespace gets stripped by loadHTML()
$nodes = $xpath->query('//my:*');
var_dump($nodes);

有没有办法实现我想要的?我会很高兴任何建议。

编辑我打开了对 libxml2 的增强请求,以提供在 HTML 中保留命名空间的选项:https ://bugzilla.gnome.org/show_bug.cgi?id=711670

4

2 回答 2

2

首先,名称空间只允许在 XML(或 XHTML)中使用。HTML 不支持命名空间。


鉴于它是 XHTML 并且 xmlns 声明存在于代码段中,那么您可以使用命名空间访问元素DOMDocument::getElementsByTagNameNS()

$html = <<<EOF
<div xmlns:my="http://www.example.com/" class="something-first">
    <div class="something-child something-good another something-great">
        <my:text value="huhu" />
    </div>
</div>
EOF;

$domDoc = new DOMDocument();
$domDoc->loadXML($html);
var_dump(
  // it is possible to use wildcard `*` here
  $domDoc->getElementsByTagNameNS('http://www.example.com/', '*')
);

然而,由于命名空间声明通常是在根元素<html>而不是子节点中定义的,所以上面的代码在大多数情况下都不起作用。

所以解决方案的第二部分是检查声明是否存在,如果不注入它......(正在处理这个问题)


正如我所说,上面的代码仅适用于 XML / XHTML。它仍然是开放的如何用 HTML 做到这一点。(检查下面的讨论)

于 2013-11-08T09:53:13.520 回答
2

从技术上讲,它既不是有效的 XML 也不是 HTML(或 XHTML),因为 HTML 不允许命名空间元素,而有效的 XML 要求空元素是自关闭的并且命名空间必须注册。所以你基本上问“我怎么能让 DOMDocument 将这个无效的 HTML 视为有效的 XML,即使它也不是有效的 XML?” 这将被证明是困难的,有人可能会问为什么要更新 libxml 以允许这样做?如果我将您的代码段更新为:

$html = <<<XML
<div xmlns:my="http://www.example.com/" class="something-first">
    <div class="something-child something-good another something-great">
        <my:text value="huhu" />
    </div>
</div>
XML;

添加 NS 注册并关闭my:text,它适用于:

$domDoc = new DOMDocument();
$domDoc->loadXML($html);
echo $domDoc->saveXML();

请注意,命名空间没有被剥离。据我了解,命名空间已被删除,因为它不是有效的 XML 或 HTML。XPath 无法通过命名空间查询,因为命名空间不是通过 xmlns 定义的,因此被删除了。

所以我想问题是:你为什么请求无效的 XML 支持而不是添加结束斜线?是因为数据来自外部来源,还是因为在某些情况下空的非结束标签有效?

于 2013-11-08T17:15:55.323 回答