如何使用 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);
    }
}