如何使用 PHP 中的 DOMNode 将 HTML 插入文本节点
How to insert HTML into a text node with DOMNode in PHP
我有一个 PHP 脚本,它使用 DOMDocument 和 DOMXPath 在 HTML 模板中查找和替换合并代码。一个简单的例子可能是:
<html>
<head>
<title>Title</title>
</head>
<body>
<p>Hello {greeting}!</p>
<table><tr>
<td>Details:</td>
<td>{details}</td>
</tr></table>
</body>
</html>
以下代码根据键与合并字段匹配的关联数组替换字段:
private function substituteFields (DOMNode $node, $fields)
{
$x = new DOMXPath ($node->ownerDocument);
foreach ($fields as $field => $value)
{
$query = $x->query (".//text()[contains(., '{" . $field . "}')]", $node);
foreach ($query as $subnode)
{
$subnode->nodeValue = str_replace ("{" . $field . "}", $value, $subnode->nodeValue);
}
}
}
效果很好。
但是,某些合并代码需要 HTML 代入其中:
$fields ['greeting'] = "Joe Soap";
$fields ['details'] = "<div class='details'>Details here</div>";
替换正在进行,但 HTML 被转义,这在大多数情况下可能是一个明智的想法。
我可以解决这个问题吗?
我有点笨拙地解决了这个问题,但它现在有效。如果有更好的解决方案,我会很乐意修改我的答案!
本质上,这会在替换文本中查找开始标记“<”字符。如果它找到一个,它会调用我从这个 question, answer and comments.
修改的 HTML 替换方法
它有一个限制,它不能替代HTML mid-node。例如,以下将不起作用:
<p>Here is a bit of {html_code}</p>
但这可以像这样工作:
<p>Here is a bit of <span>{html_code}</span></p>
修改后的代码如下:
private function substituteFields (DOMNode $node, $fields)
{
$x = new DOMXPath ($node->ownerDocument);
foreach ($fields as $field => $value)
{
$query = $x->query (".//text()[contains(., '{" . $field . "}')]", $node);
foreach ($query as $subnode)
{
$replace = str_replace ("{" . $field . "}", $value, $subnode->nodeValue);
if (substr ($replace, 0, 1) != "<")
{
$subnode->nodeValue = $replace;
}
else
{
$this->appendHTML ($subnode, $replace);
}
}
}
}
private function appendHTML (DOMNode $parent, $source)
{
$tmpDoc = new DOMDocument();
$tmpDoc->loadHTML ($source);
foreach ($tmpDoc->getElementsByTagName ('body')->item (0)->childNodes as $node)
{
$importedNode = $parent->ownerDocument->importNode ($node, true);
$parent->parentNode->replaceChild ($importedNode, $parent);
}
}
我有一个 PHP 脚本,它使用 DOMDocument 和 DOMXPath 在 HTML 模板中查找和替换合并代码。一个简单的例子可能是:
<html>
<head>
<title>Title</title>
</head>
<body>
<p>Hello {greeting}!</p>
<table><tr>
<td>Details:</td>
<td>{details}</td>
</tr></table>
</body>
</html>
以下代码根据键与合并字段匹配的关联数组替换字段:
private function substituteFields (DOMNode $node, $fields)
{
$x = new DOMXPath ($node->ownerDocument);
foreach ($fields as $field => $value)
{
$query = $x->query (".//text()[contains(., '{" . $field . "}')]", $node);
foreach ($query as $subnode)
{
$subnode->nodeValue = str_replace ("{" . $field . "}", $value, $subnode->nodeValue);
}
}
}
效果很好。
但是,某些合并代码需要 HTML 代入其中:
$fields ['greeting'] = "Joe Soap";
$fields ['details'] = "<div class='details'>Details here</div>";
替换正在进行,但 HTML 被转义,这在大多数情况下可能是一个明智的想法。
我可以解决这个问题吗?
我有点笨拙地解决了这个问题,但它现在有效。如果有更好的解决方案,我会很乐意修改我的答案!
本质上,这会在替换文本中查找开始标记“<”字符。如果它找到一个,它会调用我从这个 question, answer and comments.
修改的 HTML 替换方法它有一个限制,它不能替代HTML mid-node。例如,以下将不起作用:
<p>Here is a bit of {html_code}</p>
但这可以像这样工作:
<p>Here is a bit of <span>{html_code}</span></p>
修改后的代码如下:
private function substituteFields (DOMNode $node, $fields)
{
$x = new DOMXPath ($node->ownerDocument);
foreach ($fields as $field => $value)
{
$query = $x->query (".//text()[contains(., '{" . $field . "}')]", $node);
foreach ($query as $subnode)
{
$replace = str_replace ("{" . $field . "}", $value, $subnode->nodeValue);
if (substr ($replace, 0, 1) != "<")
{
$subnode->nodeValue = $replace;
}
else
{
$this->appendHTML ($subnode, $replace);
}
}
}
}
private function appendHTML (DOMNode $parent, $source)
{
$tmpDoc = new DOMDocument();
$tmpDoc->loadHTML ($source);
foreach ($tmpDoc->getElementsByTagName ('body')->item (0)->childNodes as $node)
{
$importedNode = $parent->ownerDocument->importNode ($node, true);
$parent->parentNode->replaceChild ($importedNode, $parent);
}
}