Чтобы просто получить все элементы P не в таблице и только до первого h1, вы можете сделать
$xp = new DOMXPath($dom);
$expression = '//p[not(preceding::h1[1]) and not(ancestor::table)]';
foreach ($xp->query($expression) as $node) {
echo $dom->saveXml($node);
}
Демонстрация на кодовой панели
В общемЕсли вам известна позиция первого h1 в документе, более целесообразно использовать прямой путь к этому элементу вместо запроса //
, который будет искать в любом месте документа.Например, в качестве альтернативы вы также можете использовать XPath, данный Alejandro в комментариях ниже:
/descendant::h1[1]/preceding::p[not(ancestor::table)]
Если вы хотите создать новый DOM-документ из узлов в исходном документе, вынеобходимо импортировать узлы в новый документ.
// src document
$dom = new DOMDocument;
$dom->loadXML($xml);
// dest document
$new = new DOMDocument;
$new->formatOutput = TRUE;
// xpath setup
$xp = new DOMXPath($dom);
$expr = '//p[not(preceding::h1[1]) and not(ancestor::table)]';
// importing nodes into dest document
foreach ($xp->query($expr) as $node) {
$new->appendChild($new->importNode($node, TRUE));
}
// output dest document
echo $new->saveXML();
Демонстрация на кодовой панели
Еще несколько дополнений
В вашем примере вы использовали оператор подавления ошибок.Это плохая практика.Если вы хотите игнорировать любые ошибки синтаксического анализа из DOM, используйте
libxml_use_internal_errors(TRUE); // catch any DOM errors with libxml
$dom = new DOMDocument; // remove the @ as it is bad practise
$dom->loadXML($xhtml); // use loadHTML if it's not valid XHTML
libxml_clear_errors(); // disregards any DOM related errors
Удаление узлов с DOM - это всегда один и тот же подход.Найдите узел, который вы хотите удалить.Доберитесь до него parentNode
и вызовите на нем removeChild
с узлом, который будет удален в качестве аргумента.
foreach ($dom->getElementsByTagName('foo') as $node) {
$node->parentNode->removeChild($node);
}
Вы также можете перейти к одноуровневым узлам (и дочерним узлам) без XPath.Вот как удалить всех следующих братьев и сестер после первого элемента h1
$firstH1 = $dom->getElementsByTagName('h1')->item(0);
while ($firstH1->nextSibling !== NULL) {
$firstH1->parentNode->removeChild($firstH1->nextSibling);
}
echo $dom->saveXml();
Удаление узлов из DOMDocument
, немедленно повлияет на DOMDocument
.В приведенном выше коде мы всегда запрашиваем первого следующего брата первого h1.Если он есть, он удаляется из DOMDocument
.nextSibling
будет указывать на брата после только что удаленного (если есть).
Получение и печать всех параграфов одинаково просты.Чтобы получить externalXML, просто передайте узел, для которого вы хотите externalXML, методу saveXML
.
foreach ($dom->getElementsByTagName('p') as $paragraph)
{
echo $dom->saveXml($paragraph);
}
В любом случае, это должно помочь вам.Я предлагаю вам ознакомиться с DOM API .Это не сложно.Вы обнаружите, что большинство вещей, которые вы будете делать, вращаются вокруг свойств и методов в DOMDocument
, DOMNode
и DOMElement
(который является подклассом DOMNode
).