1
4

1 回答 1

1

您可能过度简化了代码,因为它只会替换开始标记,这至少会导致浏览器跳入怪癖模式。

无论如何,这绝对可以使用 DOM (尽管它会因为不支持的 HTML5 元素而引发警告,请参阅https://stackoverflow.com/a/6090728/1392379),但是您的 XPath 查询是错误的,您不能简单地将数组传递给它。即使您的查询有效,它也只会选择所有单独的文本节点,因此不会有任何东西可以替换。

无法直接更改节点的名称,您必须将节点替换为新节点。这是一个使用静态 XPath 查询的示例。它将选中的节点属性和子节点复制到一个新div节点中,然后用新节点替换原来的节点:

$dom = new DOMDocument;
$dom->loadHTML($content);

$xp = new DOMXPath($dom);
$nodes = $xp->query('//*[self::article|self::summary|self::aside][not(ancestor::pre) and not(ancestor::code)]');

foreach($nodes as $node)
{
    $newNode = $dom->createElement('div');
    while($node->childNodes->length)
    {
        $childNode = $node->childNodes->item(0);
        $newNode->appendChild($dom->importNode($childNode, true));
    }
    while($node->attributes->length)
    {
        $attributeNode = $node->attributes->item(0);
        $newNode->setAttributeNode($dom->importNode($attributeNode));
    }
    $node->parentNode->replaceChild($newNode, $node);
}

echo $dom->saveXML($dom->documentElement);

更新通过使用while而不是foreachon修复了代码示例childNodes/attributes。后者在不克隆将要附加并因此从正在迭代的节点列表中删除的节点时会导致打嗝。

使用for循环也应该可以正常工作:

for($i = 0; $i < $node->childNodes->length; $i ++)
{
    $childNode = $node->childNodes->item($i);
    $newNode->appendChild($dom->importNode($childNode, true));
}
for($i = 0; $i < $node->attributes->length; $i ++)
{
    $attributeNode = $node->attributes->item($i);
    $newNode->setAttributeNode($dom->importNode($attributeNode));
}

以及最初提到的克隆:

foreach($node->childNodes as $childNode)
{
    $newNode->appendChild($dom->importNode($childNode->cloneNode(true), true));
}
foreach($node->attributes as $attributeNode)
{
    $newNode->setAttributeNode($dom->importNode($attributeNode->cloneNode()));
}
$node->parentNode->replaceChild($newNode, $node);
于 2013-08-09T12:32:09.233 回答