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


How to set new HTML tag in custom class that extends DOMElement (using DOMDocument in php)?

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

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

为了更改标签名称,必须替换节点。它是另一个节点。在此之后,任何进一步的操作将不再影响节点。

更新:现在,我在newTag方法中添加了一个return $newNode;,我像这样使用它:$node = $node->newTag('h1');但为了保持一致性,我真的很想只使用:$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> 如您所见,在我更改标签名称后,没有添加文本345

为了继续使用所选节点,可以执行哪些操作?是否可以在"newTag"方法中将新节点设置为当前节点?

理想的解决方案是 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;
    }
}