tags:

views:

42

answers:

2

I have xml, structured like this

<element>
    <x>
        <y>
            <z>Value</z>
        </y>
    </x>
</element>

I select all <z>-tags from xml by this xpath query - //*[name()='z'].

Then i work with every finding node, and if it not satisfied some demands a need to delete whole X-tag (grandparent of , if you like :)).

foreach ($x->query("//*[name()='z']") as $elm)
{

if ($elm !== good)
{

//need to delete whole X-tag here

}


}

So, how can i do this?

+1  A: 

Maybe

$elm->parentNode->parentNode->parentNode->
    removeChild($elm->parentNode->parentNode);

By the way, you could use

foreach ($x->query("//z") as $elm)

instead.

Artefacto
yes, i know about using "parentNode". It very weird, but this code `$elm->parentNode->parentNode->parentNode->removeChild($elm->parentNode->parentNode);` break the foreach. For example, i have six `$elm`'s, where 4th and 6th "not good". When foreach loop comes to 4th element, it delete the whole "X"-tag, but then, looping is break. 5th and 6th elements are ignored. It's very interesting, because this code `$elm->parentNode-> removeChild($elm);` - working perfect. In fact, that's why i wrote this post. Any ideas? Maybe it's php bug?
cru3l
huh, it worked with this code:`$temp1 = $elm->parentNode->parentNode->parentNode; $temp2 = $elm->parentNode->parentNode; $temp1->removeChild($temp2);`
cru3l
@cru You're right, I'd even say you should defer the removal until after the loop.
Artefacto
A: 

I think you are jumbling two classes' methods together.

SimpleXMLElement::removeChild does not exist (it is part of DOMNode). Unfortunately, DOMDocument::xpath also does not exist, though, so you can't use either one without modifying your code.

I chose DOMDocument because of the simplicity of your DOM selection (just needing elements by the tag name), and here are my results:

<?php

    $bad = 'Value';
    $doc = DOMDocument::load('./xpath_del.xml') or die('Failed parsing XML');
    $x   = $doc->getElementsByTagName('x');

    for ($i = 0; $i < $x->length; ++$i) {
        $z = $x->item($i)->getElementsByTagName('z');
        for ($j = 0; $j < $z->length; ++$j) {
            if ($bad === $z->item($i)->nodeValue) {
                $x->item($i)->parentNode->removeChild($x->item($j));
                break;
            }
        }
    }

?>

So, using conversion to SimpleXMLElement for debugging purposes (because I'm too lazy to write a method to traverse the DOMNodes in the DOMDocument):

var_dump(simplexml_import_dom($doc));

to output the DOMDocument structure before and after. Remember, if this is for a high traffic site, I'd absolutely recommend not leaving this debugging code in (but this might not matter to you).

Anyway, here are the results before:

object(SimpleXMLElement)#2 (1) {
  ["x"]=>
  object(SimpleXMLElement)#3 (1) {
    ["y"]=>
    object(SimpleXMLElement)#4 (1) {
      ["z"]=>
      string(5) "Value"
    }
  }
}

And after:

object(SimpleXMLElement)#5 (0) {
}

Try it out for yourself, ;)

Dan Beam
just re-read question, reformatting, hold up
Dan Beam
this also assumes you have a file named "xpath_del.xml" with the same structure you've outlined in the same directory, btw...
Dan Beam