我需要一个用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'方法中的当前节点?
答案 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;
}
}