PHP中的PHTML解析器

时间:2015-05-30 12:13:09

标签: php html parsing

使用PHP,我试图找到一种简单的方法来解析HTML文件,这些文件也包含非HTML内容,例如自定义标签和放大器。内联PHP代码段。我需要迎合的元素的一个例子如下:

<!DOCTYPE html>
<html [[angular tag 1]]>
<head <?php echo 'php snippet 1'; ?>>
    <title {{curly tag 1}}></title>
    <link [[angular tag 2]]="{{curly tag 2}}.css" />
    <script src="<?php echo 'php snippet 2'; ?>.js"></script>
</head>

<body>
    <?php echo 'php snippet 3'; ?>
    <!-- comment 1 -->
    [[angular tag 3]]
</body>
</html>

这只是一个简单的例子,另一个需要可能是处理部分HTML片段,这些片段不一定包括html,head&amp;身体标签。你可以看到标签&amp; PHP代码段可以在整个文档中的任何位置出现,只要它们正确嵌套在相关实体中:

  • 作为html标签(顶级或嵌套);
  • 属性(有或没有值)
  • 内部属性值

我需要PHP代码片段卷曲“标签”&amp;角度“标签”要解析为令牌 - 它们不需要自己处理 - 解析后我需要这样做。我也在这个阶段没有看到需要在自己内部或在PHP代码片段内满足嵌套标签。

理想情况下,我想找到一个库或至少一组已经实现了可以做到这一点的文件;而不是自己做。

据我所知DOMDocument&amp; SimpleXML不支持格式错误的XML语法或外来元素,因此除非我删除自定义标记和放大,否则它们不能用于处理它。 php代码然后重新插入;但这可能需要与滚动我自己的解析器一样多的工作。

警告:请保留关于在视图逻辑等中不包含php代码的评论。我知道这些设计原则。

3 个答案:

答案 0 :(得分:2)

重要的是要了解仅仅存在<?php ?>格式的代码段不会使您的代码无效。

SGML和XML都支持格式为<?PITarget PIContent?>的任何标记,称为processing instructions。任何不知道如何处理处理指令的解析器都应该忽略它。例如,浏览器typically ignore any PHP code they find

处理指令在文档对象模型中显示为Node.PROCESSING_INSTRUCTION_NODE。如果您使用DOMDocument在PHP中解析文档,则此类节点具有node type XML_PI_NODE。您也可以使用DOMDocument XPath commandprocessing-instruction()找到它们。

如果您的代码是有效的HTML5但不是有效的XML,则可能需要尝试Masterminds/html5-php。我在PHPPowertools/DOM-Query的引擎盖下自己使用它。我不确定它对无效HTML5的效果如何,也不知道它对处理指令的作用。

答案 1 :(得分:1)

基于John's answer&amp;从Masterminds/html5-php给出的输出中得出的一些推论我发现使用DOMDocument时唯一真正的问题是我在html打开或关闭标签中使用PHP标签。即在<&amp;之间>个字符。事后看来,这一切都很有道理。

因此,实际阻止它正确解析的违规HTML模板的唯一部分是<head <?php echo 'php snippet 1'; ?>><script src="<?php echo 'php snippet 2'; ?>.js">,因为存在嵌套的角括号,这显然是基本上无效的HTML。

这意味着,只需更新HTML模板以在这些实例中使用自定义标记,就可以消除格式错误的输出和输出。关键的解析错误。这对我的需求来说是令人满意的。我实际上感觉更优雅,因为它不会在HTML模板中产生嵌套的尖括号 - 即使PHP解析器在处理PHP文件时处理它。

更新的可操作模板看起来像这样:

<!DOCTYPE html>
<html [[angular tag 1]]>
<head [[replaced PHP code snippet 1]]>
    <title {{curly tag 1}}></title>
    <link [[angular tag 2]]="{{curly tag 2}}.css" />
    <script src="[[replaced PHP code snippet 2]].js"></script>
</head>

<body>
    <?php echo 'php snippet 3'; ?>
    <!-- comment 1 -->
    [[angular tag 3]]
</body>
</html>

我用来测试的代码是:

switch(1) {
    case 1: {
        $log->info( 'Masterminds/html5-php' );
        $html5 = new HTML5();
        $dom = $html5->loadHTML( $szTemplate );
        echo $html5->saveHTML( $dom );
        exit;
    }
    case 2: {
        $log->info( 'DOMDocument' );
        $doc = new \DOMDocument();
        $doc->loadHTML( $szTemplate );
        echo $doc->saveHTML();
        exit;
    }
}

答案 2 :(得分:0)

如果要在PHP已经解析并发送输出后执行此操作。包含带有令牌的文件,并使用输出缓冲捕获已解析的HTML;然后解析剩余的标签。

当您在变量中捕获已解析的HTML时,您可以:

  1. preg_match_all('#{{[[:alnum:]_]}}', $HTML, $curlies_found);捕获令牌,然后替换与相应值匹配的令牌,例如通过循环匹配的令牌并替换$curly_tokens数组中的键。

  2. str_replace覆盖所有令牌变量的HTML; str_replace('{{token_foo}}', $curly_tokens['token_foo'], $HTML);

  3. 对每种类型的令牌重复此过程。如果你有很多代码需要搜索和替换,第一种方法可能会更经济,所有这些代码都可能不在给定的模板中。如果您的模板中存在少量令牌,则第二个可能更快。

    我认为你不需要一个库,几十行代码顶部足以完成令牌解析的基本实现。有关简单令牌解析的信息,请参阅my answer here

    如果您将HTML中的PHP代码段转换为代币,则可以使用file_get_contents来获取HTML模板并解析代币,而不是摆弄include并输出缓冲。但无论哪种方式最适合你,你的电话。