title: Remove empty elements from XML in php
body: <p>Say I have this XML and I need to remove empty elements (elements that don't contain data at all) such as:</p>
  
  <pre><code>...
  &lt;date&gt;
      &lt;!-- keep oneDay --&gt;
      &lt;oneDay&gt;
          &lt;startDate&gt;1450288800000&lt;/startDate&gt;
          &lt;endDate&gt;1449086400000&lt;/endDate&gt;
      &lt;/oneDay&gt;
      &lt;!-- remove range entirely --&gt;
      &lt;range&gt;
          &lt;startDate/&gt;
          &lt;endDate/&gt;
      &lt;/range&gt;
      &lt;!-- remove deadline entirely --&gt;
      &lt;deadline&gt;
          &lt;date/&gt;
      &lt;/deadline&gt;
  &lt;data&gt;
  ...
  </code></pre>
  
  <p>The output then should be</p>
  
  <pre><code>...
  &lt;oneDay&gt;
      &lt;startDate&gt;1450288800000&lt;/startDate&gt;
      &lt;endDate&gt;1449086400000&lt;/endDate&gt;
  &lt;/oneDay&gt;
  ...
  </code></pre>
  
  <p>I'm looking for a dynamic solution that would work on any cases like this regardless of the literal name of the element.</p>
  
  <h2><strong>SOLUTION (UPDATED)</strong></h2>
  
  <p>It turns out that using <code>//*[not(normalize-space())]</code> returns <strong>all</strong> elements without non-empty text content (no need for recursion).</p>
  
  <pre><code>foreach($xpath-&gt;query('//*[not(normalize-space())]') as $node ) {
      $node-&gt;parentNode-&gt;removeChild($node);
  } 
  </code></pre>
  
  <p>Check out <a href="https://stackoverflow.com/a/34056793/5253103">@har07's solution</a> for more details </p>
  
  <h2><strong>SOLUTION</strong></h2>
  
  <p>The xPath approach provided by @manuelbc works but only on child elements (meaning that the children will be gone but the parent nodes of those will stay... empty as well).</p>
  
  <p>However, this will work recursively until the XML document is out of empty nodes.</p>
  
  <pre><code>$doc = new DOMDocument;
  $doc-&gt;preserveWhiteSpace = false;
  $doc-&gt;loadxml('&lt;XML STRING GOES HERE&gt;');
  
  $xpath = new DOMXPath($doc);
  
  while (($notNodes = $xpath-&gt;query('//*[not(node())]')) &amp;&amp; ($notNodes-&gt;length)) {
    foreach($notNodes as $node) {
      $node-&gt;parentNode-&gt;removeChild($node);
    }
  }
  
  $doc-&gt;formatOutput = true;
  echo $doc-&gt;saveXML();
  </code></pre>