В недавнем рабочем задании я использовал PHP для извлечения данных HTML в экземпляр DOMDocument и переименования некоторых элементов, таких как b в strong или i в em . Оказывается, переименование элементов с использованием расширения DOM довольно утомительно.
Версия 3 стандарта DOM представляет метод renameNode () , но расширение PHP DOM в настоящее время не поддерживает его.
$ NODENAME свойство DOMNode класса только для чтения, поэтому он не может быть изменен таким образом.
Узел может быть создан с другим именем в том же документе, но если вы укажете значение, которое будет сопровождать его, любые объекты в этом значении будут автоматически закодированы, поэтому невозможно передать предполагаемое внутреннее содержимое узла, если он содержит другие узлы.
Единственный найденный мной метод — это репликация атрибутов и дочерних узлов исходного узла. Атрибуты довольно просты, но я столкнулся с проблемой репликации дочерних элементов, когда только первый дочерний элемент любого данного узла был реплицирован в рамках его предполагаемой замены, а остальные дочерние элементы были опущены. Вот оригинальный код, демонстрирующий это поведение.
foreach ($oldNode->childNodes as $childNode) { $newNode->appendChild($childNode); }
Причиной такого поведения является то , что $ ChildNodes свойство $ oldNode не неявно изменяется при $ childNode передается от него до $ newNode, поэтому внутренний указатель $ ChildNodes к следующему ребенку в списке больше не точны.
Чтобы обойти это, я воспользовался тем, что любой узел с любыми дочерними узлами всегда будет иметь свойство $ firstChild, указывающее на первый. Модифицированный код, который использует этот подход, представлен ниже и имеет поведение, которое я изначально намеревался реализовать
while ($oldNode->firstChild) { $newNode->appendChild($oldNode->firstChild); }
Если вам интересно, ниже приведен сегмент полного кода для переименования узла.
$newNode = $oldNode->ownerDocument->createElement('new_element_name'); if ($oldNode->attributes->length) { foreach ($oldNode->attributes as $attribute) { $newNode->setAttribute($attribute->nodeName, $attribute->nodeValue); } } while ($oldNode->firstChild) { $newNode->appendChild($oldNode->firstChild); } $oldNode->ownerDocument->replaceChild($newNode, $oldNode);
Еще одна потенциальная «ошибка» — это порядок аргументов метода replaceChild () , который представляет собой новый узел, за которым следует старый узел, а не обратный, как может ожидать большинство людей. Спасибо Джошуа Мэй за то, что указал мне на это; Я никогда не мог понять , почему я получаю «не найден» DOMException иначе.