Используйте DomDocument, чтобы заменить все теги заголовка на теги h4
Я использовал DomDocument для GetElementById. Он выбрал div. Мне нужно заменить все теги заголовка в этом div с тегом h4.
1 ответ
Вы не дали понять в своем вопросе, с какой конкретной проблемой вы сталкиваетесь. Я предполагаю, что есть две части, которые могут вызвать у вас некоторые вопросы.
Первый из них - как получить доступ ко всем элементам, которые вы хотите переименовать, а второй - как переименовать элемент.
Получить заголовочные элементы DOMDocument
Итак, обо всем по порядку: чтобы выбрать все элементы заголовка, вам нужно выбрать все теги, которые являются элементами заголовка (от h1 до h6). В сочетании с условием, что они также должны быть потомками тега div с определенным атрибутом id, это кажется довольно сложной задачей. Однако с запросом xpath это все еще просто.
В качестве примера для моих примеров кода я выбрал идентификатор "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 можно создать даже список различных элементов и с определенными условиями, такими как быть дочерним элементом для div с id. Этот код с первого взгляда:
$url = 'http://stackru.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);
}
Переименование DOMElement
Так что насчет второй проблемы, о переименовании элементов?
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://stackru.com/q/16307103/367456
*/
$url = 'http://stackru.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);
}
Если вы попробуете это, вы можете заметить, что теперь, после моего ответа, количество элементов заголовка изменилось. Я надеюсь, что это полезно!