11

Question

How can I remove empty xml tags in PHP?

Example:

 $value1 = "2";
 $value2 = "4";
 $value3 = "";

 xml = '<parentnode>
        <tag1> ' .$value1. '</tag1>
        <tag2> ' .$value2. '</tag2>
        <tag3> ' .$value3. '</tag3>
       </parentnode>';

XML Result:

<parentnode>
    <tag1>2</tag1>
    <tag2>4</tag2>
    <tag3></tag3> // <- Empty tag
</parentnode>

What I want!

    <parentnode>
            <tag1>2</tag1>
            <tag2>4</tag2> 
    </parentnode>

The XML without the empty tags like "tag3"

Thanks!

2
  • 2
    Ehm, check if the $value... variables are empty before appending them to the output? Commented Dec 22, 2011 at 11:31
  • Yes, thats a way to do it, but I want to make a very clean code with the xml responses. I'm looking for a way to do it with SimpleXMLElement or something like that. Commented Dec 22, 2011 at 11:33

5 Answers 5

17

You can use XPath with the predicate not(node()) to select all elements that do not have child nodes.

<?php
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->loadxml('<parentnode>
    <tag1>2</tag1>
    <tag2>4</tag2>
    <tag3></tag3>
    <tag2>4</tag2>
    <tag3></tag3>
    <tag2>4</tag2>
    <tag3></tag3>
</parentnode>');

$xpath = new DOMXPath($doc);

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

$doc->formatOutput = true;
echo $doc->savexml();

prints

<?xml version="1.0"?>
<parentnode>
  <tag1>2</tag1>
  <tag2>4</tag2>
  <tag2>4</tag2>
  <tag2>4</tag2>
</parentnode>
Sign up to request clarification or add additional context in comments.

2 Comments

Will it work if empty node will have comment in it? will it then remove node?
A comment node is still a node, therefore <x><!-- comment --></x> will stay in the document.
8

This works recursively and removes nodes that:

  • contain only spaces
  • do not have attributes
  • do not have child notes
// not(*) does not have children elements
// not(@*) does not have attributes
// text()[normalize-space()] nodes that include whitespace text
while (($node_list = $xpath->query('//*[not(*) and not(@*) and not(text()[normalize-space()])]')) && $node_list->length) {
    foreach ($node_list as $node) {
        $node->parentNode->removeChild($node);
    }
}

1 Comment

Have you a solution to clear nodes with just empty attributes ?
5
$dom = new DOMDocument;

$dom->loadXML($xml);

$elements = $dom->getElementsByTagName('*');

foreach($elements as $element) {

   if ( ! $element->hasChildNodes() OR $element->nodeValue == '') {
       $element->parentNode->removeChild($element);
   }

} 

echo $dom->saveXML();

CodePad.

3 Comments

Thanks, but the code changes the empty tags <tag></tag> to the format <tag />
The version by @VolkerK should be quite a bit more efficient, especially on large files, as it uses a query to eliminate anything that isn't a leaf node, whereas this one checks every node by brute force.
The above code worked for me unless I had two empty tags in succession. The foreach gets confused while iterating ad deleting. I used the xpath and not(node()) solution and it accomplished what I was looking for.
2

The solution that worked with my production PHP SimpleXMLElement object code, by using Xpath, was:

/*
 * Remove empty (no children) and blank (no text) XML element nodes, but not an empty root element (/child::*).
 * This does not work recursively; meaning after empty child elements are removed, parents are not reexamined.
 */
foreach( $this->xml->xpath('/child::*//*[not(*) and not(text()[normalize-space()])]') as $emptyElement ) {
    unset( $emptyElement[0] );
}

Note that it is not required to use PHP DOM, DOMDocument, DOMXPath, or dom_import_simplexml().

//this is a recursively option

do {
    $removed = false;
    foreach( $this->xml->xpath('/child::*//*[not(*) and not(text()[normalize-space()])]') as $emptyElement ) {
        unset( $emptyElement[0] );
        $removed = true;
    }
} while ($removed) ;

Comments

0

If you're going to be a lot of this, just do something like:

$value[] = "2";
$value[] = "4";
$value[] = "";   

$xml = '<parentnode>';
for($i=1,$m=count($value); $i<$m+1; $i++)
      $xml .= !empty($value[$i-1]) ? "<tag{$i}>{$value[$i-1]}</tag{$i}>" : null;
$xml .= '</parentnode>';
echo $xml;

Ideally though, you should probably use domdocument.

1 Comment

That will consider the string '0' empty.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.