如何在扩展DOMElement的自定义类中设置新的HTML标记(在php中使用DOMDocument)?

时间:2013-10-30 10:50:35

标签: php html-parsing domdocument

我需要一个用PHP编写的快速HTML解析器。首先,我尝试了一些现有的解析器(如Ganon或QueryPath),但它们对我的项目来说非常慢。最后我决定使用php内置的DOMDocument,这是最快的。它只有一些简单的方法。所以我不得不开始建立自己的。

我正在编写一个扩展DOMElement的类。像'addText'这样的新方法工作正常,但是当我想更改标签名称时,我遇到了问题。

要更改标记名称,必须替换该节点。这是另一个节点。在此之后,任何进一步的操作都不会再影响节点。

更新:现在,我在newTag方法中添加了return $newNode;,我正在使用它:$node = $node->newTag('h1');但为了保持一致性,我真的只想使用:{{1 }}

请参阅代码(简化):

$node->newTag('h1');

此代码将输出 <?php class my_element extends DOMElement { public function __construct() { parent::__construct();} public function newTag($newTagName) { $newNode = $this->ownerDocument->createElement($newTagName); $this->parentNode->replaceChild($newNode, $this); foreach ($this->attributes as $attribute) { $newNode->setAttribute($attribute->name, $attribute->value); } foreach (iterator_to_array($this->childNodes) as $child) { $newNode->appendChild($this->removeChild($child)); } //at this point, $newnode should become $this... How??? } //append plain text public function addText ($text = '') { $textNode = $this->ownerDocument->createTextNode($text); $this->appendChild($textNode); } //... some other methods } $html = '<div><p></p></div>'; $dom = new DOMDocument; $dom->loadHTML($html); $xPath = new DOMXPath($dom); $dom->registerNodeClass("DOMElement", "my_element"); //extend DOMElement class $nodes = $xPath->query('//p'); //select all 'p' nodes $node = $nodes->item(0); // get the first //Start to change the selected node $node->addText('123'); $node->newTag('h1'); $node->addText('345'); //This is not working because the node has changed! echo $dom->saveHTML(); 如您所见,我在更改标记名称后未添加文本<div><h1>123</h1></div>

为了继续使用所选节点,可以做些什么?是否可以将新节点设置为'newTag'方法中的当前节点?

1 个答案:

答案 0 :(得分:1)

理想的解决方案是DOMDocument::renameNode(),但它尚未在PHP中提供。

也许这会起作用,称为$node = $node->parentNode->renameChild($node, 'h1')

<?php

class MyDOMNode extends DOMNode {
    public function renameChild($node, $name) {
        $newNode = $this->ownerDocument->createElement($name);

        foreach ($node->attributes as $attribute) {
            $newNode->setAttribute($attribute->name, $attribute->value);
        }

        while ($node->firstChild) {
            $newNode->appendChild($node->firstChild);
        }

        $this->replaceChild($newNode, $node);

        return $newNode;
    }
}