Скажем, у меня есть этот XML, и мне нужно удалить пустые элементы (элементы, которые вообще не содержат данных), такие как:
...
<date>
<!-- keep oneDay -->
<oneDay>
<startDate>1450288800000</startDate>
<endDate>1449086400000</endDate>
</oneDay>
<!-- remove range entirely -->
<range>
<startDate/>
<endDate/>
</range>
<!-- remove deadline entirely -->
<deadline>
<date/>
</deadline>
<data>
...
Вывод тогда должен быть
...
<oneDay>
<startDate>1450288800000</startDate>
<endDate>1449086400000</endDate>
</oneDay>
...
Я ищу динамическое решение, которое будет работать в любых случаях, как это, независимо от буквального имени элемента.
Оказывается, используя //*[not(normalize-space())]
возвращается все элементы без непустого текстового содержимого (нет необходимости в рекурсии).
foreach($xpath->query('//*[not(normalize-space())]') as $node ) {
$node->parentNode->removeChild($node);
}
Проверять, выписываться Решение @ har07 Больше подробностей
Подход xPath, предоставляемый @manuelbc, работает, но только для дочерних элементов (это означает, что дочерние элементы исчезнут, но их родительские узлы также останутся … пустыми).
Однако это будет работать рекурсивно, пока в XML-документе нет пустых узлов.
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->loadxml('<XML STRING GOES HERE>');
$xpath = new DOMXPath($doc);
while (($notNodes = $xpath->query('//*[not(node())]')) && ($notNodes->length)) {
foreach($notNodes as $node) {
$node->parentNode->removeChild($node);
}
}
$doc->formatOutput = true;
echo $doc->saveXML();
XPath в другом ответе только возвращает пустые элементы в том смысле, что элемент не имеет никакого дочернего узла (нет узла элемента, нет текстового узла, ничего). Чтобы получить все пустые элементы согласно вашему определению, это элемент без непустого текстового содержимого, попробуйте вместо этого использовать следующий XPath:
//*[not(normalize-space())]
выход :
<?xml version="1.0"?>
<data>
<!-- keep oneDay -->
<oneDay>
<startDate>1450288800000</startDate>
<endDate>1449086400000</endDate>
</oneDay>
<!-- remove range entirely -->
<!-- remove deadline entirely -->
</data>
Вы можете сделать это с XPath
<?php
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->loadxml('<date>
<!-- keep oneDay -->
<oneDay>
<startDate>1450288800000</startDate>
<endDate>1449086400000</endDate>
</oneDay>
<!-- remove range entirely -->
<range>
<startDate/>
<endDate/>
</range>
<!-- remove deadline entirely -->
<deadline>
<date/>
</deadline>
<data>');
$xpath = new DOMXPath($doc);
foreach( $xpath->query('//*[not(node())]') as $node ) {
$node->parentNode->removeChild($node);
}
$doc->formatOutput = true;
echo $doc->savexml();
Смотрите оригинальное решение здесь:
Удалить пустые теги из XML с помощью PHP