DOM解析器,允许HTML5样式的<! - in <script - >标记

时间:2010-10-27 01:33:21

标签: php dom html5

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

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

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

大多数解析器会在{4.0} </标记内找到ETAGO(<script>)时因为HTML 4.01 ends script tag parsing而过早解析。但是,</script>之前的HTML5 allows for </。到目前为止,我尝试过的所有解析器都失败了,或者它们的文档记录很差,以至于我还没弄清楚它们是否有效。

我的要求:

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

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

    输出失败的示例(无结束</td>):

    <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>
    

5 个答案:

答案 0 :(得分:10)

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

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

但当然,标记必须没有错误才能使loadXML正常工作。

答案 1 :(得分:5)

Re: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对象一样进行操作。

答案 2 :(得分:5)

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

答案 3 :(得分:4)

我在jQuery模板块中添加了注释标记(<!-- ... -->)(CDATA块也失败了),DOMDocument没有触及内部HTML。

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

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

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

答案 4 :(得分:3)

我遇到了这个问题。

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

我希望这会对某些人有所帮助: - )。