当脚本元素包含HTML时如何使用PHP DomDocument?

时间:2018-12-20 23:23:42

标签: php html dom domdocument

我正在尝试下载一个站点以供脱机查看,这需要我做一些DOM操作(相信我,wget只是没有做我需要做的事情...)。

我发现包含带有异常文本内容标签的网页正在丢弃saveHTML

对于某些网址,如果我使用curl读取页面并输出为

echo $contents;

那么一切都很好。

例如,页面的一部分包含以下来源:

<div id="area2516" class="component interaction_component float-none clear-none ">
    <div id="area2516">
        <script type="text/javascript">
            window.bm = window.bm || {};
            bm.data = bm.data || [];
            bm.data['area2516'] = {};
        </script>

        <link rel="stylesheet" type="text/css" href="/somecss.css">
        <script type="text/javascript" src="somejs.js">
        </script>

    <script class="main-template" type="text/x-handlebars-template">
            <div class="content_area">
                <div class="bg_image cf"></div>
                    {{#each rollovers}}
                <div class="rollover_content" style="left: {{x}}; top: {{y}}; display: none;" data-rollover-id="{{id}}">
                    {{{this.content}}}
                </div>
                {{/each}}
                </div>
                <div class="rollover_links">
                    <ul>
                        {{#each rollovers}}
                        <li>
                            <a class="rollover_link" href="#" data-rollover-id="{{id}}">
                                {{{link}}}
                            </a>
                        </li>
                        {{/each}}
                    </ul>
                </div>
        </script>


        <script type="text/javascript">
            bm.data['area2516'].assets = {};
            bm.data['area2516'].initial_json = '';
        </script>

从卷曲响应后的上述回声中可以看到。

现在,如果我这样做

$doc = new DOMDocument();
@$doc->loadHTML($contents);
$xpath = new DOMXpath($doc);
echo $doc->saveHTML();

HTML搞砸了,因此上面的代码变成了这样:

<div id="area2516" class="component interaction_component float-none clear-none ">
<div id="area2516">
    <script type="text/javascript">
        window.bm = window.bm || {};
        bm.data = bm.data || [];
        bm.data['area2516'] = {};
    </script>
    <link rel="stylesheet" type="text/css" href="/somecss.css"> . 
    <script type="text/javascript" src="/somejs.js"></script>
    <script class="main-template" type="text/x-handlebars-template">
        <div class="content_area">
            <div class="bg_image cf">
    </script>
            </div>
            {{#each rollovers}}
            <div class="rollover_content" style="left: {{x}}; top: {{y}}; display: none;" data-rollover-id="{{id}}">
              {{{this.content}}}
            </div>
          {{/each}}
        </div>
        <div class="rollover_links">
          <ul>
            {{#each rollovers}}
              <li>
                <a class="rollover_link" href="#" data-rollover-id="{{id}}">
                  {{{link}}}
                </a>
              </li>
            {{/each}}
          </ul></div>
<script type="text/javascript">
        bm.data['area2516'].assets = {};
        bm.data['area2516'].initial_json = '';
      </script>

很抱歉,这种格式的新编辑器很烦人。关键是,您会看到一些非常重要的区别,但我不确定saveHTML是如何导致对源代码的这种修改。我怀疑这与编码以及模板系统使用的双括号和三括号的特殊性有关,但是尽管尝试使用各种编码参数,但我得到了相同的结果。然后,我想也许与特殊字符,转义有关,但是我只是不确定需要什么函数来阻止saveHTML弄乱输出。

想法?

谢谢

2 个答案:

答案 0 :(得分:0)

根据HTML 4规范,您不能将任意文本放入<script>元素中。 (尽管这个is possible in HTML 5,PHP附带的libxml解析器并不是那么新。)

如果您正确地转义了元素的内容,则您的代码应该可以按预期工作。

$content = <<< HTML
<div id="area2516" class="component interaction_component float-none clear-none ">
    <div id="area2516">
        <script type="text/javascript">
            window.bm = window.bm || {};
            bm.data = bm.data || [];
            bm.data['area2516'] = {};
        </script>

        <link rel="stylesheet" type="text/css" href="/somecss.css">
        <script type="text/javascript" src="somejs.js">
        </script>

    <script class="main-template" type="text/x-handlebars-template">
            &lt;div class="content_area"&gt;
                &lt;div class="bg_image cf"&gt;&lt;/div&gt;
                    {{#each rollovers}}
                &lt;div class="rollover_content" style="left: {{x}}; top: {{y}}; display: none;" data-rollover-id="{{id}}"&gt;
                    {{{this.content}}}
                &lt;/div&gt;
                {{/each}}
                &lt;/div&gt;
                &lt;div class="rollover_links"&gt;
                    &lt;ul&gt;
                        {{#each rollovers}}
                        &lt;li&gt;
                            &lt;a class="rollover_link" href="#" data-rollover-id="{{id}}"&gt;
                                {{{link}}}
                            &lt;/a&gt;
                        &lt;/li&gt;
                        {{/each}}
                    &lt;/ul&gt;
                &lt;/div&gt;
        </script>


        <script type="text/javascript">
            bm.data['area2516'].assets = {};
            bm.data['area2516'].initial_json = '';
        </script>
HTML;
$doc = new DOMDocument();
$doc->loadHTML($content, LIBXML_HTML_NODEFDTD|LIBXML_HTML_NOIMPLIED);
echo $doc->saveHTML();

输出符合预期:

<div id="area2516" class="component interaction_component float-none clear-none ">
    <div id="area2516">
        <script type="text/javascript">
            window.bm = window.bm || {};
            bm.data = bm.data || [];
            bm.data['area2516'] = {};
        </script>

        <link rel="stylesheet" type="text/css" href="/somecss.css">
        <script type="text/javascript" src="somejs.js">
        </script>

    <script class="main-template" type="text/x-handlebars-template">
            &lt;div class="content_area"&gt;
                &lt;div class="bg_image cf"&gt;&lt;/div&gt;
                    {{#each rollovers}}
                &lt;div class="rollover_content" style="left: {{x}}; top: {{y}}; display: none;" data-rollover-id="{{id}}"&gt;
                    {{{this.content}}}
                &lt;/div&gt;
                {{/each}}
                &lt;/div&gt;
                &lt;div class="rollover_links"&gt;
                    &lt;ul&gt;
                        {{#each rollovers}}
                        &lt;li&gt;
                            &lt;a class="rollover_link" href="#" data-rollover-id="{{id}}"&gt;
                                {{{link}}}
                            &lt;/a&gt;
                        &lt;/li&gt;
                        {{/each}}
                    &lt;/ul&gt;
                &lt;/div&gt;
        </script>


        <script type="text/javascript">
            bm.data['area2516'].assets = {};
            bm.data['area2516'].initial_json = '';
        </script></div></div>

请注意,您的HTML在其他方面无效;重复的id属性和缺少的结束元素。

答案 1 :(得分:0)

输入甚至看起来都不像HTML,而是看起来像Twig(或类似的模板)...

需要首先通过模板引擎进行推送,以获得HTML的输出;

除非通过(array) $rollovers ...在某些情况下不会产生预期的结果。

如果这些不是您自己的模板文件,则可能是下载了错误的URL ...

,另一边的人忘记了阻止访问模板。