使用 PHP 缩进 HTML(5) 时出现问题

2024-02-20

免责声明:请坦白这个问题的长度。这是我见过的现实世界问题中反复出现的问题 数百次都没有明确的、可行的解决方案 呈现。

我有数百个 HTML 文件,我想使用 PHP 进行批量缩进。起初我想到使用 Tidy,但你应该知道,它默认与 HTML5 标签和属性不兼容,经过一些研究和更多测试,我想出了以下“伪造”HTML 5 支持的实现:

function Tidy5($string, $options = null, $encoding = 'utf8')
{
    $tags = array();
    $default = array
    (
        'anchor-as-name' => false,
        'break-before-br' => true,
        'char-encoding' => $encoding,
        'decorate-inferred-ul' => false,
        'doctype' => 'omit',
        'drop-empty-paras' => false,
        'drop-font-tags' => true,
        'drop-proprietary-attributes' => false,
        'force-output' => true,
        'hide-comments' => false,
        'indent' => true,
        'indent-attributes' => false,
        'indent-spaces' => 2,
        'input-encoding' => $encoding,
        'join-styles' => false,
        'logical-emphasis' => false,
        'merge-divs' => false,
        'merge-spans' => false,
        'new-blocklevel-tags' => ' article aside audio details dialog figcaption figure footer header hgroup menutidy nav section source summary track video',
        'new-empty-tags' => 'command embed keygen source track wbr',
        'new-inline-tags' => 'btidy canvas command data datalist embed itidy keygen mark meter output progress time wbr',
        'newline' => 0,
        'numeric-entities' => false,
        'output-bom' => false,
        'output-encoding' => $encoding,
        'output-html' => true,
        'preserve-entities' => true,
        'quiet' => true,
        'quote-ampersand' => true,
        'quote-marks' => false,
        'repeated-attributes' => 1,
        'show-body-only' => true,
        'show-warnings' => false,
        'sort-attributes' => 1,
        'tab-size' => 4,
        'tidy-mark' => false,
        'vertical-space' => true,
        'wrap' => 0,
    );

    $doctype = $menu = null;

    if ((strncasecmp($string, '<!DOCTYPE', 9) === 0) || (strncasecmp($string, '<html', 5) === 0))
    {
        $doctype = '<!DOCTYPE html>'; $options['show-body-only'] = false;
    }

    $options = (is_array($options) === true) ? array_merge($default, $options) : $default;

    foreach (array('b', 'i', 'menu') as $tag)
    {
        if (strpos($string, '<' . $tag . ' ') !== false)
        {
            $tags[$tag] = array
            (
                '<' . $tag . ' ' => '<' . $tag . 'tidy ',
                '</' . $tag . '>' => '</' . $tag . 'tidy>',
            );

            $string = str_replace(array_keys($tags[$tag]), $tags[$tag], $string);
        }
    }

    $string = tidy_repair_string($string, $options, $encoding);

    if (empty($string) !== true)
    {
        foreach ($tags as $tag)
        {
            $string = str_replace($tag, array_keys($tag), $string);
        }

        if (isset($doctype) === true)
        {
            $string = $doctype . "\n" . $string;
        }

        return $string;
    }

    return false;
}

它可以工作,但有 2 个缺陷:HTML 注释,script and style标签没有正确缩进:

<link href="/_/style/form.css" rel="stylesheet" type="text/css"><!--[if lt IE 9]>
    <script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!--<script type="text/javascript" src="//raw.github.com/kevinburke/tecate/master/tecate.js"></script>-->

</script><script charset="UTF-8" src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.0.0/js/locales/bootstrap-datepicker.pt.js" type="text/javascript">
</script><!--<script src="/3rd/parsley/i18n/messages.pt_br.js"></script>-->
    <!--<script src="//cdnjs.cloudflare.com/ajax/libs/parsley.js/1.1.10/parsley.min.js"></script>-->
    <script src="/3rd/select2/locales/select2_locale_pt-PT.js" type="text/javascript">
</script><script src="/3rd/tcrosen/bootstrap-typeahead.js" type="text/javascript">

还有另一个更严重的缺陷:Tidy 转换了所有menu标签到ul并坚持放弃任何empty内联标签,迫使我绕过它。为了完全清楚地说明这一点,这里有一些例子:

  • <br>空标签
  • <i>text</i>内联标签
  • <i class="icon-home"></i> empty内联标签(示例来自 Font Awesome)

如果您检查代码,您会发现我已经考虑了b, i and menu标签使用不完美 str_replacehack - 我可以使用更强大的正则表达式,甚至str_ireplace完成同样的事情,但为了我的目的str_replace更快而且足够好。然而,这仍然留下了任何其他empty内联标签我没有考虑到这一点,这很糟糕。

所以我转向DOMDocument,但我很快发现为了formatOutput为了工作我必须:

  1. 去除标签之间的所有空格(当然使用正则表达式:'~>[[:space:]]++<~m' > ><)
  2. 将所有换行符组合转换为\n所以它不编码\r as &#23;例如
  3. 将输入字符串加载为 HTML,输出为 XML

令我惊讶的是,DOMDocument 也存在空内联标签的问题,基本上,每当它看到<i class="icon-home"></i><someOtherTag>text</someOtherTag>或类似的,它会将其变成<i class="icon-home"><someOtherTag>text</someOtherTag></i>这将完全扰乱浏览器对页面的渲染。为了克服这个问题,我发现使用LIBXML_NOEMPTYTAG随着DOMDocument::saveXML()将打开任何没有内容的标签(包括真正的空标签,例如<br />) 到内联结束标记中,例如:

  • <i class="icon-home"></i>保持不变(应该如此)
  • <br>变成<br></br>搞乱浏览器渲染(再次)

为了解决这个问题,我必须使用一个正则表达式来查找~></(?:area|base(?:font)?|br|col|command|embed|frame|hr|img|input|keygen|link|meta|param|source|track|wbr)>~并将匹配的字符串替换为简单的/>。另一个主要问题是saveXML()是它添加了<![CDATA[ .. ]]>我周围的街区script and style内部 HTML,这使得它们的内容无效,我必须返回并preg_replace再次那些令牌。这个“有效”:

function DOM5($html)
{
    $dom = new \DOMDocument();

    if (libxml_use_internal_errors(true) === true)
    {
        libxml_clear_errors();
    }

    $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
    $html = preg_replace(array('~\R~u', '~>[[:space:]]++<~m'), array("\n", '><'), $html);

    if ((empty($html) !== true) && ($dom->loadHTML($html) === true))
    {
        $dom->formatOutput = true;

        if (($html = $dom->saveXML($dom->documentElement, LIBXML_NOEMPTYTAG)) !== false)
        {
            $regex = array
            (
                '~' . preg_quote('<![CDATA[', '~') . '~' => '',
                '~' . preg_quote(']]>', '~') . '~' => '',
                '~></(?:area|base(?:font)?|br|col|command|embed|frame|hr|img|input|keygen|link|meta|param|source|track|wbr)>~' => ' />',
            );

            return '<!DOCTYPE html>' . "\n" . preg_replace(array_keys($regex), $regex, $html);
        }
    }

    return false;
}

似乎是two 最推荐和经过验证的 HTML 缩进方法 https://stackoverflow.com/a/3577662/89771无法在野外为 HTML5 生成正确或可靠的结果,我不得不屈服于黑暗之神克苏鲁 http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html.

我确实尝试过其他库,例如:

  • html5lib http://code.google.com/p/html5lib/- 无法得到DOMDocument::$formatOutput to work
  • 整洁的html5 https://github.com/w3c/tidy-html5- 与正常情况相同的问题tidy,除了它支持 HTML5 标签/属性

此时,如果不存在更好的解决方案,我正在考虑编写一些仅适用于正则表达式的东西。但我想也许DOMDocument可能被迫使用 HTML5 和script / style使用自定义 XSLT 进行标记。我以前从未使用过 XSLT,所以我不知道这是否现实,也许你们中的一位 XML 专家可以告诉我,也许可以提供一个起点。


您没有提到您的意图是为了生产目的还是为了开发而转换页面,例如调试 HTML 输出时。

如果是后者,并且既然您已经提到编写基于正则表达式的解决方案,我已经写了Dindent https://github.com/gajus/dindent为了这个目的。

您尚未包含输入和预期输出的样本。您可以使用以下命令测试我的实现sandbox http://gajus.com/dindent/sandbox/.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 PHP 缩进 HTML(5) 时出现问题 的相关文章

  • count 和 groupby 在一个查询中一起使用

    以下查询正在获取页面上的一些产品信息 这很好 但我也想以文本形式显示它出现的产品编号 但是 我使用了groupby但我也想用count on pro id SELECT FROM cart WHERE session id SESSION
  • 如何重定向(标头位置)到 html 文件?

    所以我正在 php 中运行一个注册 登录系统 包括 MySQL 出于测试目的 成功登录后 我将用户重定向到 index php 该文件声明用户已登录 并为他提供注销选项 同时 我制作了一个计划使用的实际 html 页面 因此我只是添加了 i
  • 在 iOS 上不显示数字键盘

    根据苹果的文档 http developer apple com library safari documentation AppleApplications Reference SafariHTMLRef Articles InputTy
  • JavaScript 原型继承和 html canvas

    我是一名 Ruby 开发人员 最终决定认真学习 JavaScript 所以我买了一些书 开始深入研究 但当我试图理解原型继承时 我很快就陷入了困境 这本书的例子之一如下 给定一个 Shape 其原型有一个绘制方法 以及两个子形状 一个 Tr
  • Zend Framework 2 在视图中显示视图

    我有两个模块管理和登录 我想在管理视图 index html 中显示登录视图 login phtml 我在管理模块indexAction控制器中有以下内容 public function indexAction login new Logi
  • 如何在没有数据库的情况下创建AJAX分页?

    是否可以在没有 MySQL 帮助的情况下获取 AJAX 分页页面 难道我不能只添加一个包含我需要显示的文本和标记的 PHP 文件 然后通过单击页码将该内容提供给用户吗 那么可以用纯 jQuery 和 PHP 来实现吗 您会使用什么代码方法来
  • 如何使用 PHP 中的 jQuery/AJAX 调用迭代 JSON 数组? [复制]

    这个问题在这里已经有答案了 可能的重复 循环Json对象 https stackoverflow com questions 684672 loop through json object 我有一个 PHP 函数 data php 它从外部
  • php循环中的ajax在按钮单击时执行操作

    所以我有一个 php 循环 我使用 jquery 滑动切换来隐藏 显示带有 sql 结果的表 目前该表仅使用 php 加载 但由于发生了很多事情 导致了一些加载问题 我需要使用滑动切换 btn 来触发 ajax 因此它仅在按下按钮时请求当前
  • 有效地获取下拉列表中的选定选项(XHTML Select 元素)

    背景 使用 XHTML Select 元素的下拉列表中有大量选项 数十个 我需要使用 JavaScript 检索所选选项 Problem 目前我正在使用 jQuery selectedCSS 选择器并且它按预期工作 但这种方法效率不高 因为
  • Laravel 中的支付网关回调时会话会自动销毁

    我正在尝试将 CCavenue com 支付网关集成到我的 Laravel 7 项目中 我面临的唯一问题是在回调 url 中 从支付网关获取发布数据后 活动会话会自动销毁 我还向中间件添加了 CSRF 例外 PayController 生成
  • 为 foreach() 提供的参数无效..Wordpress

    突然开始出现以下代码的错误 img src title 有时分类 贷款俱乐部 是空的 这可能是问题所在吗 如果是这样 有人可以指出我正确的代码吗 Add if之前的情况foreach
  • PHP filesize() 适用于除一个文件之外的所有文件,给出 stat failed 错误

    我正在编写一个 PHP 页面 该页面通过抓取现有 HTML 页面来生成播客提要 一切正常 但我的 mp3 文件之一出现 filesize stat failed 错误 据我所知 该文件没有损坏 并且播放得很好 我还将文件重新上传到服务器 它
  • 在 PHP 中创建关联数组

    我有一个多维数组 shop array array appn1 pub1 pub2 pub3 array appn2 pub1 array appn3 pub1 pub2 每个数组中的第一项是申请编号每个数组中的其余部分是出版号 我得到每个
  • 向上/向下滚动到带有固定按钮的部分

    我想构建一个用于向上 向下滚动到页面部分标签的脚本 我的源代码如下所示 HTML div class move div class previous UP div div class next DOWN div div section Fi
  • PHP + FTP删除文件夹中的文件

    我刚刚编写了一个 PHP 脚本 它应该连接到 FTP 并删除特殊文件夹中的所有文件 它看起来像这样 但我不知道需要什么命令来删除文件夹日志中的所有文件 任何想法
  • 从字符串中的链接中删除基本 URL

    我有一个带有图像链接的字符串 image link raw http website com files 2012 10 image001 png 现在我想删除http website com然后就得到 files 2012 10 imag
  • 可以在 IE 中的表格行上添加渐变吗?

    当我将鼠标悬停在表格特定部分的表格行上时 我希望背景更改为线性渐变 CSS 很简单 tbody row links tr hover background typical multi browser linear gradient code
  • 检测 HTML5 视频何时结束

    如何检测 HTML5
  • 如何确定函数是否不返回任何内容?

    有没有办法在 PHP 中使用反射或其他方法来做到这一点 function a return null function b a a null b b null 如果您没有显式返回某些内容 则函数将返回null默认情况下 这就是 PHP 中函
  • 复选标记的 HTML 实体[重​​复]

    这个问题在这里已经有答案了 是否有用于复选标记的 HTML 实体 我在各种 html 实体备忘单中搜索过它 但没有找到 像这样的东西吗 如果是这样 请输入 HTML 10004 And 10003 给出一个更轻的

随机推荐