Skip to content

Instantly share code, notes, and snippets.

@delputnam
Created December 23, 2016 17:41
Show Gist options
  • Save delputnam/ff627bbeee157c76264970d7a1c6088d to your computer and use it in GitHub Desktop.
Save delputnam/ff627bbeee157c76264970d7a1c6088d to your computer and use it in GitHub Desktop.
Iterative post-order traversal of the DOM to remove empty nodes.
<?php
/**
* Post-order traversal of the dom starting at given node. Remove any
* nodes that have no children and no attributes. Nodes named in the
* AMP_Rule_Spec::node_types_to_allow_empty array will not be removed.
*/
private function remove_empty_descendants( $node ) {
$stack = array();
$next_traversal = 'child';
$nodes_to_remove = array();
$starting_node = $node;
while ( $node ) {
if ( 'child' == $next_traversal ) {
if ( $node->firstChild ) {
$node = $node->firstChild;
$next_traversal = 'child';
} else {
if ( XML_TEXT_NODE != $node->nodeType ) {
if ( ( ! $node->hasAttributes() ) &&
( ! in_array( $node->nodeName, AMP_Rule_Spec::node_types_to_allow_empty ) ) ) {
$nodes_to_remove[] = $node;
}
}
$next_traversal = 'sibling';
}
} elseif ( 'sibling' == $next_traversal ) {
if ( $node->nextSibling ) {
$node = $node->nextSibling;
$next_traversal = 'child';
} else {
$node = $node->parentNode;
if ( $node && $node->isSameNode( $starting_node ) ) {
$node = null;
}
$next_traversal = 'sibling';
}
}
}
foreach( $nodes_to_remove as $node ) {
if ( $node->parentNode ) {
$node->parentNode->removeChild( $node );
}
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment