PHP DomDocument HTML манипуляция
У меня есть следующий HTML.
<div id="container">
<div id="current">Current Div</div>
</div>
Используя DomDocument в PHP, я пытаюсь добавить дополнительный div в HTML перед div с идентификатором "current".
<div id="container">
<div id="new">New Div</div>
<div id="current">Current Div</div>
</div>
Когда я использую следующий код, он, по-видимому, добавляет div внутри div с идентификатором "current", но перед содержимым этого div.Может ли кто-нибудь сказать мне, почему это так и как я могу получить результаты, подобные HTML выше? (Смотрите вопрос HTML ниже)
Текущий PHP
$doc = new DOMDocument();
$doc->formatOutput = true;
$doc->loadHTMLFile('index.html');
$head = $doc->getElementById('current');
$base = $doc->createElement('div', 'New Div');
$base->setAttribute('id', 'new');
echo $doc->saveHTML();
HTML Выпуск
<div id="container">
<div id="current">
<div id="new">New Div</div>
Current Div
</div>
</div>
Редактировать:
PHP
$doc = new DOMDocument();
$doc->formatOutput = true;
$doc->loadHTMLFile('index.html');
$container = $doc->getElementById('container');
$current = $doc->getElementById('username');
$new = $doc->createElement('div', 'New Div');
$new->setAttribute('id', 'new');
$container->insertBefore($new, $current);
echo $doc->saveHTML();
HTML
<div id="container">
<form method="post" action="">
<input type="text" name="username" id="username" />
</form>
</div>
Ошибка:
Fatal error: Uncaught exception 'DOMException' with message 'Not Found Error'
in index.php:55 Stack trace: #0 index.php(55):
DOMNode->insertBefore(Object(DOMElement), Object(DOMElement))
1 ответ:
Вы можете использовать
DOMNode::insertBefore()
:<?php $doc = new DOMDocument(); $doc->formatOutput = true; $doc->loadHTMLFile('index.html'); $container = $doc->getElementById('container'); $current = $doc->getElementById('current'); $new = $doc->createElement('div', 'New Div'); $new->setAttribute('id', 'new'); $container->insertBefore($new, $current); var_dump($doc->saveHTML());
Это дает:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <html> <body> <div id="container"> <div id="new">New Div</div> <div id="current">Current Div</div> </div> </body> </html>
Надеюсь, это поможет :)
EDIT
Ссылаясь на вашу сообщенную проблему... Я вижу проблему:
input#username
не является непосредственным потомкомdiv#container
, это непосредственный ребенокform
. Таким образом, вам нужно получить элементform
как объектDOMNode
, а не его родительdiv#container
. Самый простой способ сделать это-добавить идентификатор кform
и сделать что-то вроде этого:$form = $doc->getElementById('form'); $username = $doc->getElementById('username'); $username->setAttribute('value', 'Enter username!'); var_dump($doc->saveHTML());
Это основано на следующем: HTML. Обратите внимание, что элемент
form
имеет идентификатор:<div id="container"> <form id="form" method="post" action=""> <input type="text" name="username" id="username"> </form> </div>
Если по какой-то причине вы не можете добавить идентификатор к элементу формы, вы можете перейти из
div#container
следующим образом:// find div#container element $container = $doc->getElementBy('id'); // find all form elements that are children of div#container $forms = $container->getElementsByTagName('form'); if (0 !== $forms->length) { $form = $forms->item(0); } // etc.
Править #2
Я почти забыл XPath... Если вы хотите получить более лаконичный / авантюрный вы можете использовать
DOMXPath::query()
чтобы найти узлы DOM:$xpath = new DOMXPath($doc); $form = $xpath->query('body/div[@id="container"]/form')->item(0); $input = $xpath->query('body//input[@id="username"]')->item(0);
Синтаксис запроса XPath довольно загадочный, но мощный, я не могу сказать, что я эксперт в любом случае, поэтому я не могу говорить за эффективность этих запросы. Кроме того, вы можете добавить проверку ошибок-метод
Наконец, стоит отметить, чтоquery
возвращаетDOMNodeList
, который имеет свойствоlength
.DOMDocument
украшает ваш HTML-фрагмент тегамиDOCTYPE
иhtml
иbody
; Именно поэтому запрос XPath проходит отbody
.