如何使HTML5与DOMDocument一起使用?

Ale*_*lex 19 php html5 domdocument

我正在尝试使用DOMDocument解析HTML代码,对其进行更改,然后将其组合回我发送到输出的字符串.

但是有一些关于解析的问题,这意味着我发送给DOMDocument的内容并不总是以相同的形式返回:)

这是一个清单:

  1. 使用- > loadHTML:

    • 格式化我的文档,无论preserveWhitespaceformatOutput设置如何(在预先格式化的文本上丢失空白)
    • 给我的错误,当我有HTML5标签,如<header>,<footer>等,但它们可以supressed,这样我就可以用这个活.
    • 产生不一致的标记 - 例如,如果我添加一个<link ... />元素(带有自闭标记),解析/ saveHTML后输出将是<link .. >
  2. 使用- > loadXML:

    • 编码>来自<style><script>标签的实体:body > div变成body &gt; div
    • 所有标签都以相同的方式关闭,例如<meta ... />变为<meta...></meta>; 但这可以用正则表达式修复.

我没有尝试HTML5lib,但出于性能原因,我更喜欢DOMDocument而不是自定义解析器


更新:

就像使用CDATA提到的Honeymonster一样,修复了loadXML的主要问题.

有没有什么方法可以防止除了某个集合之外的所有空HTML标签的自动关闭,而不使用正则表达式?

现在我有:

$html = $dom->saveXML($node);

$html = preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', function($matches){

       // ignore only these tags
       $xhtml_tags = array('br', 'hr', 'input', 'frame', 'img', 'area', 'link', 'col', 'base', 'basefont', 'param' ,'meta');

       // if a element that is not in the above list is empty,
       // it should close like   `<element></element>` (for eg. empty `<title>`)
       return in_array($matches[1], $xhtml_tags) ? "<{$matches[1]}{$matches[2]} />" : "<{$matches[1]}{$matches[2]}></{$matches[1]}>";
}, $html);
Run Code Online (Sandbox Code Playgroud)

哪个有效,但它也会替换CDATA内容,我不想要......

Fra*_*ila 13

使用html5lib.它可以解析html5并生成DOMDocument.例:

require_once '/path/to/HTML5/Parser.php';
$dom = HTML5_Parser::parse('<html><body>...');
Run Code Online (Sandbox Code Playgroud)

文档

  • 但是html5lib可以保存文件并返回一个格式好的字符串吗?我没有在源代码中看到它. (2认同)

小智 13

10 年过去了,PHP DOMDocument 上的问题仍然存在,我找到了 2 种方法来解决这个问题。

解决方案1

添加LIBXML_NOERROR为 loadHTML 方法的选项,如下所示:

<?php

$dom = new DOMDocument();

$dom->loadHTML('<header data-attribute="foo">bar<', LIBXML_NOERROR);

echo $dom->saveHTML();
// outputs the html with valid closing tag without any error
?>
Run Code Online (Sandbox Code Playgroud)

解决方案2

libxml_use_internal_errors(true)在加载 HTML 之前添加

<?php

$dom = new DOMDocument();

libxml_use_internal_errors(true);

$dom->loadHTML('<header data-attribute="foo">bar<');

echo $dom->saveHTML();
// outputs the html with valid closing tag without any error
?>
Run Code Online (Sandbox Code Playgroud)


Mik*_*nen 8

如果您想支持HTML5,请不要触摸DOMDocument.

目前最好的选择似乎是https://github.com/Masterminds/html5-php

以前最好的选择是https://github.com/html5lib/html5lib-php,但正如描述所说,它"目前尚未维护".这是自2011年10月以来的状态,所以我不再屏住呼吸了.

我没有html5-php在生产中使用过,所以我无法提供任何真实世界的经验.我已经html5lib-php在生产中使用了,我会说它正确地解析了格式良好的文档但是它有一些简单的语法错误而出现意外错误.另一方面,似乎正确地实施了采用代理算法和其他一些奇怪的角落案例.如果html5lib-php仍然保持,我仍然喜欢它.但是,就目前的情况而言,我更喜欢使用html5-php并可能帮助修复那里的剩余漏洞.


Dan*_*lyn 7

不幸的是,或者可能幸运的是,domdocument旨在不尝试保留原始文档的格式.这是为了使所有元素保持相同的样式,使解析器的内部状态更容易管理.Afaik大多数解析器将在内存中创建树表示,并且在用户请求之前不用担心文本格式.这就是为什么你的自闭标签输出带有单独的结束标签.好消息是没关系.

至于风格标签和脚本标签入门<>转换为&lt;&gt;,您可以通过在周围用正是如此推荐CDATA标签问题的元素的内容,以避免转换:

<style>
  /*<![CDATA[*/
    body > div {
      width: 50%;
    }
  /*]]>*/
</style>
Run Code Online (Sandbox Code Playgroud)

关于/* */cdata声明的注释是允许不知道cdata部分的破坏客户端,而是将声明视为CSS代码.如果您仅在内部使用该文档,则可以省略/* */注释环绕并仅使用cdata声明.如果您操作文档然后将其发送到浏览器而不检查以确保/* */保留注释,则可能会遇到上述损坏客户端的问题; 我不确定domdocument是否会保留这些.