【问题标题】:Parsing HTML to XML将 HTML 解析为 XML
【发布时间】:2018-06-14 16:29:12
【问题描述】:

我正在使用在其核心中使用 XML 的文本/HTML 差异引擎,但我们正在输入 HTML5 数据,我想知道如何处理不需要在 HTML5 中关闭但必须关闭的标签在 XML 中。例如:

<img alt="" height="239" src="http://example.com/image.png" width="272">

我是否需要手动转换每个标签(就像this example)?

有没有工具可以为我做到这一点?并省去逃避所有自闭合 HTML 标记的麻烦?

例如,xml_parse() 运行以下代码,就像它有错误一样,但 body 有一个有效的 HTML,它是无效的 XML:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html [<!ENTITY Aacute "&#193;">]>
<body>
    <div>
        <figure class="table ">
            <figcaption>
                <p class="table_number"></p>
                <p class="table_title" epub:type="title"></p>
            </figcaption>
            <table class="code ">
                <tr>
                    <td width="50">
                        <img alt="" height="239" src="http://example.com/image.png" width="272">
                    </td>
                </tr>
            </table>
        </figure>
    </div>
</body>

【问题讨论】:

  • 它们应该在 HTML 中关闭,仅仅因为“现代”浏览器足够聪明,可以关闭它们并不意味着不关闭它们很酷。这是我的意见。
  • @ArtisticPhoenix,感谢您的评论,但在我的情况下这是不可能的。我们的数据已经在数据库中,无法更新。有很多遗留的 html 垃圾。
  • @ArtisticPhoenix — 它们不应该有 / 字符。仅仅因为规范要求现代浏览器忽略它们,并不意味着浪费字节存储和发送它们很酷。
  • 问题中的代码不是有效的 HTML。
  • 确实,您在其中显示的代码是 XML 和 HTML5 的奇怪混合。如果是 HTML,则没有 &lt;?xml... 行,而 doctype 行将 exactly &lt;!DOCTYPE html&gt;。 OTOH 如果它是 XML,它将有一个正确关闭的 &lt;img /&gt; 标记。你所拥有的是一种奇怪的混合物,没有标准工具可能解析。

标签: php html xml validation parsing


【解决方案1】:

解析 HTML(包括 HTML5)并将其格式化为 XML 的正确方法是使用 SGML,即 HTML 和 XML 的超集。您可以使用专门为此目的设计的osx 程序(OpenSP/OpenJade 包的一部分)。在 Ubuntu/Debian 上通过 sudo apt-get install opensp 安装它。

在 SGML 中,您使用包含标记声明的 DTD 文件来告诉 SGML 可以省略哪些开始和结束元素标记等。为此,您可以在http://sgmljs.net/docs/w3c-html51-dtd.html 使用我的HTML 5.1 DTD(只需将该页面上的DTD 代码文本复制到一个名为html51.dtd 的文件中)。然后,要解析的 HTML 文件需要引用 .dtd 文件,因此其第一行应如下所示

<!DOCTYPE html SYSTEM "html51.dtd">

假设html51.dtd 与要解析的文件位于同一目录中。如果您想知道,SGML 是许多 HTML 文档开头的 DOCTYPE 声明的来源,尽管浏览器滥用它来检测 HTML 版本和其他内容。无论如何,您的 HTML 不得包含两个或多个 DOCTYPE 声明。因此,如果它已经包含诸如

之类的行
<!DOCTYPE html>

你用我上面写的那一行替换那行。

现在你只需调用

osx your-file.html > your-file.xml

(其中your-file.html 是您要解析的文件,并且您已经编辑以使用正确的 DOCTYPE 声明开始)并且您有正确的 XML 文件 your-file.xml,否则会看到详细的错误消息。

如果您想了解有关我的 HTML DTD 的更多信息,我在一年前的 XML 布拉格会议上发表了一篇关于它的演讲。幻灯片和全文链接自http://sgmljs.net/blog.html

【讨论】:

    【解决方案2】:

    一般来说,您可以使用 PHP 内置的 DOM 处理例程来解析 HTML 并输出 XML:

    $html = <<< HEREDOC
    <!DOCTYPE html>
    <body>
        <div>
            <figure class="table ">
                <figcaption>
                    <p class="table_number"></p>
                    <p class="table_title" epub:type="title"></p>
                </figcaption>
                <table class="code ">
                    <tr>
                        <td width="50">
                            <img alt="" height="239" src="http://example.com/image.png" width="272">
                        </td>
                    </tr>
                </table>
            </figure>
        </div>
    </body>
    HEREDOC;
    
    $dom = new DOMDocument;
    $dom->loadHTML($html);
    echo $dom->saveXml($dom), PHP_EOL;
    

    不幸的是,您使用 XML 序言并尝试将 HTML 5 Doctype 扩展为 XML/SGML Doctype 会阻止 DOM 库成功解析它。

    【讨论】:

    • DOMDocument::saveHTML() 剥离自闭合标签相比,DOMDocument::saveXML() 在缺失时放置自闭合标签?
    • @HelpNeeder — saveHTML 在没有“自闭合标签”之类的情况下保存为 HTML。只是开始和/或结束标签是可选和/或禁止的元素。 saveXML 保存为 XML,其中所有标签都必须是显式的,并且开始和结束标签可以组合成一个自闭合标签。
    【解决方案3】:

    我会用这样的东西更新旧标签,

    $field = preg_replace('/\<img([^>]+)(?<!\/)>/', '<img\1/>', $field);
    

    你可以看到here

    使用否定的lookbehind,我们可以匹配所有未封闭的img标签,捕捉每个标签中的“胆量”,然后用封闭标签替换它。

    • \&lt;img 文字匹配
    • ([^&gt;]+) 捕获不是&gt; 的任何内容
    • (?&lt;!\/)&gt; 否定后视,如果前面没有 /,则匹配结尾 &gt;,即。匹配 &gt; 不匹配 /&gt;

    所以给定一个这样的标签

    它将捕获\1,({}显示已捕获间距)

     { alt="" height="239" src="http://example.com/image.png" width="272"}
    

    然后我们只需将&lt;img&gt; 替换为/&gt; 并将“胆量”放回\1

    我们的标签现在关闭了

    <img alt="" height="239" src="http://example.com/image.png" width="272"/>
    

    这可以用另一个捕获组和这样的标签列表进行扩展:

    $field = preg_replace('/\<(img|br)([^>]*)(?<!\/)>/', '<\1\2/>', $field);
    

    现在它将匹配 &lt;br&gt; 并将其替换为 &lt;br/&gt; 以及 img 标记。一直忽略这样的封闭标签:

    <img alt="" height="239" src="http://example.com/image2.png" width="272"/>
    

    看到这个here

    所以,这并非不可能。

    我觉得有必要提一下,在进行此类范围的任何更改之前,您应该始终导出表的备份。这样你就可以确定如果有问题你有一个安全网。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-05
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-24
      • 1970-01-01
      • 2016-02-18
      相关资源
      最近更新 更多