0

So I have some xml....

<parentnode>
 <childnode>
  <babynode id="1">
    <parameter>goes here</parameter>
  <babynode />
 <childnode />
<parentnode />
<parentnode>
 <childnode>
  <babynode id="2">
    <parameter>goes here</parameter>
  <babynode />
 <childnode />
<parentnode />

...and, using e4x, I want to delete to delete a parent node where a babynode id is equal to something. For example where baby node id is 2, I want to delete the whole node starting from <parentnode>.

I know I can do var xml = the xml and then do delete xml.parentnode but I am not sure how I specify which parentnode to delete.

I am sure this is probably simple, and I am probably being silly, but could anyone point me in the right direction please?

Thanks

  • Btw, you might want to fix up your E4X syntax (as I did below) as far as your marking closing tags as self-closing tags--in case it may encourage someone to test your code more quickly (assuming there is a better answer to be found). – Brett Zamir Apr 20 '12 at 02:40

1 Answers1

0

First off, if your environment is the browser or even a Firefox extension, I'd advise against continuing with E4X as they have deprecated it.

That being said, here is what I could find in testing around about what works (very little) and what does not, in attempting to do what you are trying to do.

As useful as it would be, and as well as it seems it would fit into the filter/accessor syntax, deleting a parent (or grand-parent in your case) does not seem to work (at least when I try with Mozilla's E4X engine--btw, as I recall, the function:: used below might only be supported in Spidermonkey).

var a = <a>
  <b>
  <c/>
  </b>
  </a>;
delete a.b.c.parent(); // Removing parent() will delete <c/>

alert(a); // <b/> is not deleted

Thus naturally, in taking your example:

var xml = <><parentnode>
 <childnode>
  <babynode id="1">
    <parameter>goes here</parameter>
  </babynode>
 </childnode>
</parentnode>
<parentnode>
 <childnode>
  <babynode id="2">
    <parameter>goes here</parameter>
  </babynode>
 </childnode>
</parentnode></>;

...while this (using the .. descendant selector):

alert(xml..*.(function::attribute('id') == "2")[0].parent().parent()); // I'm also not sure why the formatting of the attribute cannot be obtained by `xml..*.(@id == "2")` without giving an error since id is not a reserved word, but anyways...

...does get the <parentnode> you want, deleting it like in the following does not work:

delete xml..*.(function::attribute('id') == "2")[0].parent().parent();

...even while this:

delete xml..*.(function::attribute('id') == "2")[0]; 

...will at least delete the <babynode> part you want to delete.

Theoretically, I would think that the following (i.e., without the * mark which selects the filtered elements of descendants instead of just filtering the ancestor) should work (or at least it would be nice if it did!):

delete xml..(function::attribute('id') == "2")[0]; 

...yet it does not.

Even accessing an element in this manner (of not grabbing a descedant) does not seem to work:

alert(xml..(function::attribute('id') == "2")[0]);

And even if we avoid using an XMLList (<></> being the short-hand syntax used above if you were not familiar with it) and wrap the XML in some named element, say <container>, deleting or accessing still does not work:

delete xml.container..(function::attribute('id') == "2")[0]; 

You could take a look at http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf to see if your reading should allow this, but in any case it does not work, at least as I've tried it.

So, as far as I can see, the only solution would be to iterate through the elements and track where you are manually rather than using filters.

Brett Zamir
  • 14,034
  • 6
  • 54
  • 77