Используйте 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);
}

Если вы попробуете это, вы можете заметить, что теперь, после моего ответа, количество элементов заголовка изменилось. Я надеюсь, что это полезно!

Другие вопросы по тегам