Skip to main content
Inspiring
September 22, 2006
Question

Deleting node returned from xmlSearch()

  • September 22, 2006
  • 4 replies
  • 351 views
G'day
Consider this sample XML:

<aaa id="1">
<bbb id="2">
<ccc id="3"></ccc>
<ccc id="4"></ccc>
<ccc id="5"></ccc>
</bbb>
<bbb id="6"></bbb>
</aaa>

I am using the following xpath to single out a specific node:

//ccc[@id='4']

Having located that node, I need to delete it.

The best solution I've come up with is this:

<cfset a = xmlSearch(x, "//ccc[@id='4']/preceding-sibling::ccc")>
<cfset i = xmlChildPos(a[1].xmlParent, "ccc", arrayLen(a)+1)>
<cfset arrayDeleteAt(x.aaa.bbb.xmlChildren, i)>

Now this seems like a really silly approach (I'm also not certain it's
particularly robust). I would have thought - given I have the exact node I
want to delete - I should be able to do something along the lines of:

<cfset someDeleteFunction(a[1])>

Anyone done this sort of thing before?

PS: pls resist the temptation to offer suggestions that involve a loop
going "Is it this one? No. This one? No. This one? Yes! OK, delete
it". This does not - in my mind - constitute an appropriate solution (and
I've already thought of it, and cringed even more than with my current
"solution").

Cheers.

--
Adam


This topic has been closed for replies.

4 replies

Inspiring
September 23, 2006
> But, we have found it cleaner and easier to do similar edits on the XML text
> using an REReplace. (We have no child nodes or CDATA to contend with.)

Hi Mike.
I think your opinion of CF's XML support matches mine, by the sounds of it.
It seems a bit of a superficial nod, rather than a well-considered
implementation.

I thought about the regex approach. Indeed for the situation in front of
us where we know (and are in control of) the structure of the XML and the
node we're removing is always going to be fairly simple, the regex solution
would have worked.

Cheers.

--
Adam
September 23, 2006
Given the limitations of xmlChildPos() and Adobe XPath, I believe that yours is the most concise, XML, way to delete a node by id (unless java offers something better).

But, we have found it cleaner and easier to do similar edits on the XML text using an REReplace. (We have no child nodes or CDATA to contend with.)
Inspiring
September 23, 2006
> The problem is that the xmlSearch does not return a reference to the
> node(s), but rather an array of copies of the nodes

No it doesn't. They're references to the nodes, not copies. Easy to test:
add/update/delete an attribute in the array, and it is also reflected in
the original XML object.

Along these lines, one can actually do a structClear() on the array element
which gets rid of what's there (so kinda OK), but leaves a null node in the
XML doc, rather than deleting it (which is actually OK for my immediate
requirement, but not a "complete" answer).


> I have found XSLT to be a much cleaner way to do this kind of XML
> modification.

I considered this approach. It still smacks me as a variation of the old
"loop over it until you find it" routine. Which just strikes me as
*wrong*, for a simple node deletion.

My rule of thumb is I avoid looping if I'm not performing the given action
(ie: the code in the loop) on the majority of the items being looped over.
Sure the XSLT abstracts the looping away from immediate scrutiny, but it's
still happening.

But anyway, thanks for coming back to me. It's good to know how other
people deal with these things.

--
Adam
Inspiring
September 22, 2006
The problem is that the xmlSearch does not return a reference to the
node(s), but rather an array of copies of the nodes that match the xpath
expression.

I have found XSLT to be a much cleaner way to do this kind of XML
modification.

<cfsavecontent variable="y">
<?xml version="1.0" encoding="iso-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl=" http://www.w3.org/1999/XSL/Transform">

<!-- XSL code to modify the XML in the desired manner -->

</xsl>
</cfsavecontent>


<cfset a = xmlTransform(x,y)>