我已经将DomDocument用于GetElementById。它选择了一个div。我需要用h4标签替换该div中的所有标头标签。
答案 0 :(得分:8)
您在问题中没有明确说明您遇到的具体问题。我认为有两个部分可能会引起一些问题。
第一个是如何获取要重命名的所有元素,第二个实际上是如何重命名元素。
首先要做的事情是:要选择所有标题元素,您需要选择Heading elements (h1 to h6)的所有标记。结合条件,他们也需要是具有特定id属性的div标签的子项,这似乎是一件相当复杂的事情。但是对于xpath查询,它仍然只是直截了当。
我的代码示例的示例我选择了id“”content“,以下xpath表达式查询所有标题元素:
(
//div[@id="content"]//h1
|//div[@id="content"]//h2
|//div[@id="content"]//h3
|//div[@id="content"]//h4
|//div[@id="content"]//h5
|//div[@id="content"]//h6
)
如果我在这里运行此网站(在我回答之前),它会创建以下标签列表:
Found 8 elements:
#00: <h1>
#01: <h2>
#02: <h2>
#03: <h3>
#04: <h3>
#05: <h3>
#06: <h2>
#07: <h4>
这很好地说明了,使用xpath查询甚至可以创建不同元素的列表,并且具有特定条件,例如可以创建具有id的div的子元素。这段代码一目了然:
$url = 'http://stackoverflow.com/questions/16307103/use-domdocument-to-replace-all-header-tags-with-the-h4-tags';
$dom = new DOMDocument();
$internalErrorsState = libxml_use_internal_errors(true);
$dom->loadHTMLFile($url);
libxml_use_internal_errors($internalErrorsState);
$xpath = new DOMXPath($dom);
$expression = '
(
//div[@id="content"]//h1
|//div[@id="content"]//h2
|//div[@id="content"]//h3
|//div[@id="content"]//h4
|//div[@id="content"]//h5
|//div[@id="content"]//h6
)';
$elements = $xpath->query($expression);
echo "Found ", $elements->length, " elements:\n";
foreach ($elements as $index => $element) {
printf(" #%02d: <%s>\n", $index, $element->tagName);
}
那么关于重命名元素的第二个问题呢?
开箱即用的DOMDocumet不支持此功能。有一个方法存根(DOMDocument::renameNode()
;在当前的PHP手册中没有记录),但如果你调用它,你会得到一个警告:它没有实现:
警告:DOMDocument :: renameNode():尚未实现
相反,人们需要推出自己的版本。这就是它的工作原理:由于你不能用DOMDocument重命名一个元素,你所能做的就是创建一个带有重命名名称的新元素,并复制节点以将其所有属性和子元素重命名为它,然后将其替换为重命名浅拷贝。这可以通过以下方法完成:
/**
* Renames a node in a DOM Document.
*
* @param DOMElement $node
* @param string $name
*
* @return DOMNode
*/
function dom_rename_element(DOMElement $node, $name) {
$renamed = $node->ownerDocument->createElement($name);
foreach ($node->attributes as $attribute) {
$renamed->setAttribute($attribute->nodeName, $attribute->nodeValue);
}
while ($node->firstChild) {
$renamed->appendChild($node->firstChild);
}
return $node->parentNode->replaceChild($renamed, $node);
}
将其与上面的foreach
循环结合在一起,在输出标记名称旁边,它们也可以重命名:
$elements = $xpath->query($expression);
echo "Found ", $elements->length, " elements:\n";
foreach ($elements as $index => $element) {
printf(" #%02d: <%s>\n", $index, $element->tagName);
dom_rename_element($element, 'h4');
###################################
}
然后再次查询xpath表达式,只会产生h4标签:
$elements = $xpath->query($expression);
echo "Found ", $elements->length, " elements:\n";
foreach ($elements as $index => $element) {
printf(" #%02d: <%s>\n", $index, $element->tagName);
}
输出:
Found 8 elements:
#00: <h1>
#01: <h2>
#02: <h2>
#03: <h3>
#04: <h3>
#05: <h3>
#06: <h2>
#07: <h4>
这里完整的代码示例及其输出一目了然:
<?php
/**
* Use DomDocument to replace all header tags with the h4 tags
* @link http://stackoverflow.com/q/16307103/367456
*/
$url = 'http://stackoverflow.com/questions/16307103/use-domdocument-to-replace-all-header-tags-with-the-h4-tags';
$dom = new DOMDocument();
$internalErrorsState = libxml_use_internal_errors(true);
$dom->loadHTMLFile($url);
libxml_use_internal_errors($internalErrorsState);
$xpath = new DOMXPath($dom);
$expression = '
(
//div[@id="content"]//h1
|//div[@id="content"]//h2
|//div[@id="content"]//h3
|//div[@id="content"]//h4
|//div[@id="content"]//h5
|//div[@id="content"]//h6
)';
$elements = $xpath->query($expression);
echo "Found ", $elements->length, " elements:\n";
foreach ($elements as $index => $element) {
printf(" #%02d: <%s>\n", $index, $element->tagName);
dom_rename_element($element, 'h4');
}
$elements = $xpath->query($expression);
echo "Found ", $elements->length, " elements:\n";
foreach ($elements as $index => $element) {
printf(" #%02d: <%s>\n", $index, $element->tagName);
}
/**
* Renames a node in a DOM Document.
*
* @param DOMElement $node
* @param string $name
*
* @return DOMNode
*/
function dom_rename_element(DOMElement $node, $name) {
$renamed = $node->ownerDocument->createElement($name);
foreach ($node->attributes as $attribute) {
$renamed->setAttribute($attribute->nodeName, $attribute->nodeValue);
}
while ($node->firstChild) {
$renamed->appendChild($node->firstChild);
}
return $node->parentNode->replaceChild($renamed, $node);
}
如果您尝试一下,您可能会注意到,在我的回答之后,标题元素的数量已经改变。我希望这有用!