到目前为止,我已经能够非常轻松地替换节点,因为我只需要1:1替换它们,因为它们只是文本。我正在使用这样的东西:
$element->parentNode->replaceChild($element->ownerDocument->createTextNode($value),$element);
现在的问题是我需要接受可能包含或不包含某些HTML的字符串。例如,我不能再使用createTextNode()
字符串:
This is some <span style="font-weight:bold;"></span> text.
因为我在实际的html中最终会混合使用html实体。我也不能这样做:
<p>Paragraph 1</p>
<p> </p>
<p>Paragraph 3</p>
我已经将我的代码修改为以下内容,第一部分通过导入text / html mix创建一个新的dom节点,我可以使用它作为节点将其拉出来,第二部分导入新的<fubar>
DOMNode,并用它替换原始节点:
$temp = new DOMDocument('1.0','UTF-8');
$temp->loadHTML('<fubar id="replacement">'.$val.'</fubar>');
$replacement = $temp->getElementById('replacement');
$replacement = $element->ownerDocument->importNode($replacement, TRUE);
$element->parentNode->replaceChild($replacement,$element);
我无法解决的问题是,该文档现在包含所有新节点,包括 <fubar>
元素,但它&# 39; s是进行1:1替换的唯一方法,因为replaceChild()
要求参数是DOMNode,所以我不能直接使用子节点DOMNodeList。
删除<fubar>
节点但保留其子节点(我想要的实际内容)或直接用多个节点替换原始节点的最简单的解决方案是什么? < / p>
编辑:完整的意图是:
<html>
<body>
<p>Opening content....<placeholder>REPLACE_ME_FIRST</placeholder></p>
<placeholder>REPLACE_ME_SECOND</placeholder>
<p>Closing content....</p>
</body>
</html>
然后将<placeholder>REPLACE_ME_FIRST</placeholder>
替换为...
This is some <span style="font-weight:bold;"></span> text.
并将<placeholder>REPLACE_ME_SECOND</placeholder>
替换为...
<p>Paragraph 1</p>
<p> </p>
<p>Paragraph 3</p>
导致:
<html>
<body>
<p>Opening content....This is some <span style="font-weight:bold;"></span> text.</p>
<p>Paragraph 1</p>
<p> </p>
<p>Paragraph 3</p>
<p>Closing content....</p>
</body>
</html>
...在我原来的问题中,在代码示例中,$element
代表<placeholder>
节点。
答案 0 :(得分:0)
感谢OP评论中的一些对话,我能够提出以下替代策略,该策略仍然具有高效性并与我提出的所有示例兼容。
$temp = new DOMDocument('1.0', 'UTF-8');
$temp->loadHTML('<fubar id="replacement">'.$val.'</fubar>');
$replacement = $temp->getElementById('replacement');
// If element is a text node just add a new node with the value, otherwise if it's an element with child nodes, iterate over them adding them to a fragment which can be imported as a whole.
if ($replacement->nodeType === XML_TEXT_NODE || ($replacement->nodeValue && $replacement->childNodes->length === 1 && $replacement->childNodes->item(1) === NULL)) {
// Text Node
$new_node = $element->ownerDocument->createTextNode($replacement->nodeValue);
} else {
// Node List
$new_node = $element->ownerDocument->createDocumentFragment();
$children = $replacement->childNodes->length - 1;
for ($i = 0; $i <= $children; $i++) {
$child = $element->ownerDocument->importNode($replacement->childNodes->item($i), TRUE);
$new_node->appendChild($child);
}
}
$element->parentNode->replaceChild($new_node,$element);
unset($replacement);
unset($temp);
--- N.B. --- 强>
我通过对childNodes的迭代努力了很多。我能够在$replacement
中看到childNodes,但它们似乎总是空的。
直到我意识到需要在原始元素的doc而不是temp元素中创建documentFragment
,并且在导入到doc之后附加新的子元素。
根本原因是子节点($replacement->childNodes->item($i)
)无法附加到已存在的文档中。
答案 1 :(得分:0)
感谢您的输入,这就是我解决类似问题的方式,我需要剥离所有//span[@class="scayt-misspell-word"]
并将其替换为内容(可以是文本,节点或它们的任意组合)。
请注意,我使用HTML5DOMDocument
来保存自定义标记:https://github.com/ivopetkov/html5-dom-document-php
$doc = new HTML5DOMDocument('1.0', 'UTF-8');
$doc->loadHTML($oldText);
$xpath = new DOMXPath($doc);
$body = $xpath->query('//body')->item(0);
while ($span = $xpath->query('//span[@class="scayt-misspell-word"]')
->item(0)) {
$frag = $doc->createDocumentFragment();
foreach ($span->childNodes as $child) {
$frag->appendChild($child);
}
$span->parentNode->replaceChild($frag, $span);
}
$newText = $doc->saveHTML($body);