我有一个奇怪的问题在这里,但它完全难倒我。最重要的是,这是因为我想不出要搜索的正确术语,所以这个问题很可能在某个地方的 StackOverflow 上得到回答,但我找不到。
我们有一个校对系统,允许我们获取页面并对其进行注释。我们可以将页面发送给我们的客户,他们可以在发回之前在上面做笔记。在大多数情况下,这工作正常。当我们尝试使用类似于 Handlebars 的 JavaScript 模板系统时,问题就来了。我们倾向于在我们的页面上有类似这样的脚本模板:
<script type="client/template" id="foo-div">
<div>#foo#</div>
</script>
我们可以在我们的脚本中使用它在模板中生成标记,替换#foo#
为正确的数据。
当我们尝试将其放入打样系统时,问题就来了。因为我们需要抓取页面以便我们可以在我们的域中呈现,所以我们使用 PHPDOMDocument
来解析 HTML,以便我们可以轻松地修改它(添加诸如target="_blank"
外部链接之类的东西)。当我们尝试通过 运行模板时DOMDocument
,它会奇怪地解析它(可能将其视为无效的 XML),这会导致页面出现问题。为了更好地说明这一点,这里有一个 PHP 示例:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$html = '<!DOCTYPE html>'.
'<html>'.
'<head></head>'.
'<body>'.
'<script type="client/template" id="foo-div"><div>#foo#</div></script>'.
'</body>'.
'</html>';
$dom = new DOMDocument();
libxml_use_internal_errors(true);
try {
$html = $dom->loadHTML($html);
} catch (Exception $e) {
throw new Exception('Invalid HTML on the page has caused a parsing error');
}
if ($html === false) {
throw new Exception('Unable to properly parse page');
}
$dom->preserveWhiteSpace = false;
$dom->formatOutput = false;
echo $dom->saveHTML();
该脚本生成的代码类似于下面的 HTML,并且似乎没有抛出任何异常。
<!DOCTYPE html>
<html>
<head></head>
<body><script type="client/template" id="foo-div"><div>#foo#</script></body>
</html>
我的问题是:有人知道我可以让 PHP单独DOMDocument
留下模板script
标签吗?是否有一个设置或插件可用于将带有属性DOMDocument
的标签的内容视为纯文本,就像浏览器一样?script
type
编辑
我最终选择了 Alf Eaton 的解决方案或将字符串解析为 XML。但是,并非所有 HTML 标记都是自关闭的,这会导致问题。我在这里发布完整的解决方案,以防有人遇到同样的问题:
/**
* Inserts a new string into an old string at the specified position.
*
* @param string $old_string Old string to modify.
* @param string $new_string New string to insert.
* @param int $position Position at which the new string should be inserted.
* @return string Old string with new string inserted.
* @see http://stackoverflow.com/questions/8251426/insert-string-at-specified-position
*/
function str_insert($old_string, $new_string, $position) {
return substr($old_string, 0, $position) . $new_string .
substr($old_string, $position);
}
/**
* Inspects a string of HTML and closes any tags that need self-closing in order
* to make the HTML valid XML.
*
* @param string $html Raw HTML (potentially invalid XML)
* @return string Original HTML with self-closing slashes added.
*/
function self_close($html) {
$fixed = $html;
$tags = array('area', 'base', 'basefont', 'br', 'col', 'frame',
'hr', 'img', 'input', 'link', 'meta', 'param');
foreach ($tags as $tag) {
$offset = 0;
while (($offset = strpos($fixed, '<' . $tag, $offset)) !== false) {
if (($close = strpos($fixed, '>', $offset)) !== false &&
$fixed[$close - 1] !== '/') {
$fixed = str_insert($fixed, '/', $close);
}
$offset += 1; // Prevent infinite loops
}
}
return $fixed;
}
// When parsing the original string:
$html = $dom->loadXML(self_close($html));