【问题标题】:DOM parser that allows HTML5-style </ in <script> tagDOM 解析器,允许 HTML5 样式的 </ 在 <script> 标记中
【发布时间】:2011-05-01 01:40:47
【问题描述】:

更新html5lib(问题的底部)似乎接近了,我只需要提高对它的使用方式的理解。

我正在尝试为 PHP 5.3 寻找与 HTML5 兼容的 DOM 解析器。特别是,我需要在脚本标签中访问以下类似 HTML 的 CDATA:

<script type="text/x-jquery-tmpl" id="foo">
    <table><tr><td>${name}</td></tr></table>
</script>

大多数解析器会提前结束解析,因为 HTML 4.01 ends script tag parsing&lt;script&gt; 标记内找到 ETGO (&lt;/) 时。但是,HTML5 allows for &lt;/&lt;/script&gt; 之前。到目前为止,我尝试过的所有解析器都失败了,或者它们的文档记录太差,以至于我不知道它们是否有效。

我的要求:

  1. 真正的解析器,而不是正则表达式破解。
  2. 能够加载整个页面或 HTML 片段。
  3. 能够拉回脚本内容,通过标签的 id 属性进行选择。

输入:

<script id="foo"><td>bar</td></script>

失败输出示例(不关闭&lt;/td&gt;):

<script id="foo"><td>bar</script>

一些解析器及其结果:


DOMDocument(失败)

来源:

<?php

header('Content-type: text/plain');
$d = new DOMDocument;
$d->loadHTML('<script id="foo"><td>bar</td></script>');
echo $d->saveHTML();

输出:

Warning: DOMDocument::loadHTML(): Unexpected end tag : td in Entity, line: 1 in /home/adam/public_html/2010/10/26/dom.php on line 5
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head><script id="foo"><td>bar</script></head></html>


FluentDOM(失败)

来源:

<?php

header('Content-type: text/plain');
require_once 'FluentDOM/src/FluentDOM.php';
$html = "<html><head></head><body><script id='foo'><td></td></script></body></html>";
echo FluentDOM($html, 'text/html');

输出:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head></head><body><script id="foo"><td></script></body></html>


phpQuery(失败)

来源:

<?php

header('Content-type: text/plain');

require_once 'phpQuery.php';

phpQuery::newDocumentHTML(<<<EOF
<script type="text/x-jquery-tmpl" id="foo">
<td>test</td>
</script>
EOF
);

echo (string)pq('#foo');

输出:

<script type="text/x-jquery-tmpl" id="foo">
<td>test
</script>


html5lib(通过)

可能很有希望。我可以得到script#foo标签的内容吗?

来源:

<?php

header('Content-type: text/plain');

include 'HTML5/Parser.php';

$html = "<!DOCTYPE html><html><head></head><body><script id='foo'><td></td></script></body></html>";
$d = HTML5_Parser::parse($html);

echo $d->saveHTML();

输出:

<html><head></head><body><script id="foo"><td></td></script></body></html>

【问题讨论】:

  • 注意:当您尝试通过 loadHTML 解析 HTML 时,基于 DOM 的库将使用 libxml 的 HTML 解析器模块。如果您使用 loadXML 加载上面的 sn-p,则不会出现错误,但是当然,页面应该是有效的 XHTML。另请参阅Best Methods to parse HTML,但基本上所有基于 DOM 的解析器都可能在这里产生相同的结果。
  • +1 提出一个好问题。我想知道是否可以使用 HTML cmets 或 CDATA 块来分隔脚本标记中的代码,就像对 Javascript 所做的那样?或者这也会包含在模板的输出中?
  • 如果 html5lib 通过不就是这个问题的答案吗?

标签: php dom html


【解决方案1】:

我只是发现(就我而言)。

尝试在DOMDocument 中使用LIBXML_SCHEMA_CREATE 更改loadHTML 的参数选项

$dom = new DOMDocument;

libxml_use_internal_errors(true);
//$dom->loadHTML($buffer, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->loadHTML($buffer, LIBXML_SCHEMA_CREATE);

【讨论】:

    【解决方案2】:

    我遇到了这个确切的问题。

    PHP Dom Document 解析脚本标签内的 html,这实际上可以导致完全不同的 dom。

    因为我不想使用 DomDocument 以外的其他库。我写了几行去掉任何脚本内容,然后你对 dom 文档做任何你需要做的事情,然后你把脚本内容放回去。

    显然脚本内容对您的 dom 对象不可用,因为它是空的。

    使用以下几行 php 代码,您可以“修复”这个问题。请注意,脚本标签中的脚本标签会导致错误。

    $scripts = array();
    // this will select all script tags non-greedy. If you have a script tag in your script tag, it will cause problems.
    preg_match_all("/((<script.*>)(.*))\/script>/sU", $html, $scripts);
    // Make content of scripts empty
    $html = str_replace($scripts[3], '', $html);
    
    // Do DOM Document stuff here
    
    // Put script contents back
    $html = str_replace($scripts[2], $scripts[1], $html);
    

    我希望这会帮助一些人:-)。

    【讨论】:

    • 这几乎是一个很好的解决方案。但是,当脚本标签没有区分它们的属性时,它就不起作用了。
    【解决方案3】:

    我遇到了同样的问题,显然你可以通过将文档加载为 XML 并将其保存为 HTML 来解决这个问题 :)

    $d = new DOMDocument;
    $d->loadXML('<script id="foo"><td>bar</td></script>');
    echo $d->saveHTML();
    

    当然,要使 loadXML 工作,标记必须没有错误。

    【讨论】:

    • 另请注意,这会破坏非自关闭的 HTML5 元素(链接、img、br 等),因为这些元素在 XML 中是非法的。
    【解决方案4】:

    我在我的 jQuery 模板块中添加了注释标签 (&lt;!-- ... --&gt;)(CDATA 块也失败了)并且 DOMDocument 没有触及内部 HTML。

    然后,在我使用 jQuery 模板之前,我编写了一个脚本来删除 cmets。

    $(function() {
        $('script[type="text/x-jquery-tmpl"]').text(function() {
            // The comment node in this context is actually a text node.
            return $.trim($(this).text()).replace(/^<!--([\s\S]*)-->$/, '$1');
        });
    });
    

    不理想,但我不确定是否有更好的解决方法。

    【讨论】:

    • 我的意思是......我正在使用 标签(用于下划线模板)并评论它不起作用。我很想阻止 XMLDocument 解析脚本内部文本/htmls
    【解决方案5】:

    FluentDOM 使用 DOMDocument 但会阻止加载通知和警告。它没有自己的解析器。您可以添加自己的加载器(例如使用 html5lib 的加载器)。

    【讨论】:

      【解决方案6】:

      回复:html5lib

      你点击下载标签和download the PHP version of the parser

      在本地文件夹中解压存档

       tar -zxvf html5lib-php-0.1.tar.gz
       x html5lib-php-0.1/
       x html5lib-php-0.1/VERSION
       x html5lib-php-0.1/docs/
       ... etc
      

      您更改目录并创建一个名为 hello.php 的文件

      cd html5lib-php-0.1
      touch hello.php 
      

      您将以下PHP代码放入hello.php

      $html = '<html><head></head><body>
      <script type="text/x-jquery-tmpl" id="foo">
      <table><tr><td>${name}</td></tr></table>
      </script> 
      </body></html>';
      $dom = HTML5_Parser::parse($html); 
      var_dump($dom->saveXml()); 
      echo "\nDone\n";
      

      你从命令行运行hello.php

      php hello.php
      

      解析器将解析文档树,并返回一个 DOMDocument 对象,该对象可以像任何其他 DOMDocument 对象一样进行操作。

      【讨论】:

      • 感谢您的指点。如何深入到脚本标签的内容,按 id 搜索?
      • 这是一个标准的 DOMDocument 对象。如果您对 DOMDocument 不满意,请调用 saveXML 方法(如上)并从中创建一个 SimpleXml 对象。如果您对 Simple XML 不满意,您应该us.php.net/manual/en/simplexml.examples-basic.php">read手册
      • 将 html5lib 添加到 Best Methods to parse HTML
      • @Alan 当我无法让$dom-&gt;getElementById() 处理生成的 DOMDocument 时,我碰壁了(好吧,有点生气)。我最终解决了这个问题,但我很想知道它为什么会失败以及它是否可以工作。
      • 因为 DOMDocument 是一堆令人困惑的过度设计的糟糕文档 XML 处理?要使 getElementById 与 DOM 文档一起工作,您需要有一个 DTD,说明哪个属性名称是 ID,或者明确设置元素上的哪个属性名称是 ID。每当我有一个 DOMDocument 时,我都会保存一个 XML 字符串以输入 SimpleXML,然后使用 xPath 函数来获得我想要的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-20
      • 2011-06-02
      • 2016-10-16
      相关资源
      最近更新 更多