从 php 中的 XML 中删除空元素

Remove empty elements from XML in php

假设我有这个 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())]returnsall个元素没有非空文本内容(不需要递归)

foreach($xpath->query('//*[not(normalize-space())]') as $node ) {
    $node->parentNode->removeChild($node);
} 

查看 了解更多详情

解决方案

@manuelbc 提供的 xPath 方法有效,但仅适用于子元素(这意味着子元素将消失,但这些子元素的父节点将保持......也为空)。

但是,这将递归工作,直到 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 做到这一点

<?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();

在此处查看原始解决方案: Remove empty tags from a XML with PHP

其他答案中的 XPath 只有 returns 空元素 元素没有任何类型的子节点(没有元素节点,没有文本节点) , 没有什么)。要根据您的定义获取所有 空元素 ,即没有非空文本内容的元素,请尝试改用以下 XPath:

//*[not(normalize-space())]

eval.in demo

输出:

<?xml version="1.0"?>
<data>
  <!-- keep oneDay -->
  <oneDay>
    <startDate>1450288800000</startDate>
    <endDate>1449086400000</endDate>
  </oneDay>
  <!-- remove range entirely -->
  <!-- remove deadline entirely -->
</data>