groovy

XMLParser: remove method on NodeList returns true (success). But, Node is not removed.

Details

  • Type: Improvement Improvement
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Won't Fix
  • Affects Version/s: 1.0
  • Fix Version/s: 1.1-rc-1
  • Component/s: XML Processing
  • Labels:
    None
  • Environment:
    Windows XP. Eclipse 3.2.
  • Testcase included:
    yes
  • Number of attachments :
    1

Description

Using XMLParser:

node.nodelist.remove(o) returns true. But node is not removed.

I think the node.nodelist.remove(o) syntax is preferred to o.parent().value.remove(o) which does work.

Activity

Hide
Paul King added a comment -

The issue is that node.nodeList returns a copy of the relevant nodes. The remove actually works but only in the copy.
If you go and use node.nodeList again, it generates a new list. I am not sure if this is a bug or a feature but the workaround is:

package groovy.util

class XmlParserRemoveTest extends GroovyTestCase {

    void testRemove() {
        def xml = """<config>
<server id="5"><name>server1</name></server>
<server id="12"><name>server1</name></server>
<server id="17"><name>server1</name></server>
</config>
"""
        def config = new XmlParser().parseText(xml)
        def allServers = config.server
        assert allServers.size() == 3

        def servers = allServers.findAll {it.'@id'.equals('12')}
        assert servers.size() == 1

        for (server in servers) {
            assert allServers.remove(server)
        }

        assert allServers.size() == 2
    }

}
Show
Paul King added a comment - The issue is that node.nodeList returns a copy of the relevant nodes. The remove actually works but only in the copy. If you go and use node.nodeList again, it generates a new list. I am not sure if this is a bug or a feature but the workaround is:
package groovy.util

class XmlParserRemoveTest extends GroovyTestCase {

    void testRemove() {
        def xml = """<config>
<server id="5"><name>server1</name></server>
<server id="12"><name>server1</name></server>
<server id="17"><name>server1</name></server>
</config>
"""
        def config = new XmlParser().parseText(xml)
        def allServers = config.server
        assert allServers.size() == 3

        def servers = allServers.findAll {it.'@id'.equals('12')}
        assert servers.size() == 1

        for (server in servers) {
            assert allServers.remove(server)
        }

        assert allServers.size() == 2
    }

}
Hide
Paul King added a comment -

I am going to close this. I don't think this suggested change in behaviour fits in with the current semantics of XmlParser. If I have a NodeList with a, b, a, b elements in it, then list.a produces a new NodeList with two elements in it. You can remove then one of those two elements but that doesn't affect the original 4 element list. To make that work we would have to have a 'late-evaluating' style wrapper which is what XmlSlurper gives you. Please re-open with some additional arguments and use cases if you really see some value in this behaviour. Thanks.

Show
Paul King added a comment - I am going to close this. I don't think this suggested change in behaviour fits in with the current semantics of XmlParser. If I have a NodeList with a, b, a, b elements in it, then list.a produces a new NodeList with two elements in it. You can remove then one of those two elements but that doesn't affect the original 4 element list. To make that work we would have to have a 'late-evaluating' style wrapper which is what XmlSlurper gives you. Please re-open with some additional arguments and use cases if you really see some value in this behaviour. Thanks.

People

Vote (0)
Watch (2)

Dates

  • Created:
    Updated:
    Resolved: