You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Paul King (JIRA)" <ji...@apache.org> on 2019/03/22 06:56:01 UTC

[jira] [Commented] (GROOVY-9048) Replacing a Groovy XML Node causes problems in subsequents findAll calls

    [ https://issues.apache.org/jira/browse/GROOVY-9048?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16798774#comment-16798774 ] 

Paul King commented on GROOVY-9048:
-----------------------------------

Here are some samples that work:
{code}
String XML_SAMPLE = """
<ns0:root xmlns:ns0="mycompany.com">
    <ns0:firstParent>
        <ns0:item1>uppercase_me!</ns0:item1>
    </ns0:firstParent>
    <ns0:secondParent>
        <ns0:item2>uppercase_me_too!</ns0:item2>
    </ns0:secondParent>
    <ns0:thirdParent>
        <ns0:item3>also_me!</ns0:item3>
    </ns0:thirdParent>
    <ns0:fourthParent>
        <ns0:item4>join_the_crowd!</ns0:item4>
    </ns0:fourthParent>
    <ns0:fifthParent>
        <ns0:item5>last_but_not_least!</ns0:item5>
    </ns0:fifthParent>
</ns0:root>
""".trim()

def xmlRoot = new XmlParser(false, false).parseText(XML_SAMPLE)

//******* find item1 and capitalize its text ********
def nd1 = xmlRoot.'**'.findAll{ it.name().equals("ns0:item1") }[0]
nd1.setValue([nd1.text().toUpperCase()])

//******* find item2 and capitalize its text ********
def nd2 = xmlRoot.'**'.findAll{ it.name().equals("ns0:item2") }[0]
nd2.setValue([nd2.value()[0].toString().toUpperCase()])

//******* find item3 and capitalize its text ********
def nd3 = xmlRoot.'**'.findAll{ it.name().equals("ns0:item3") }[0]
def newNode = new Node(nd3.parent(), nd3.name(), [nd3.text().toUpperCase()])
nd3.replaceNode(newNode)
// current nd3 is detached during replaceNode, so search again
nd3 = xmlRoot.'**'.findAll{ it.name().equals("ns0:item3") }[0]

//******* find item4 and capitalize its text ********
def nd4 = xmlRoot.'**'.findAll{ it.name().equals("ns0:item4") }[0]
def (text4, name4) = nd4.with{ [text().toUpperCase(), name()] }
nd4.replaceNode{ "$name4"([text4]) }
// current nd4 is detached during replaceNode, so search again
nd4 = xmlRoot.'**'.findAll{ it.name().equals("ns0:item4") }[0]

//******* find item5 and capitalize its text ********
def nd5 = xmlRoot.'**'.findAll{ it.name().equals("ns0:item5") }[0]
def (text5, name5) = nd5.with{ [text().toUpperCase(), name()] }
nd5.replaceNode{ "$name5"(text5) }
// current nd5 is detached during replaceNode, so search again
nd5 = xmlRoot.'ns0:fifthParent'.'ns0:item5'[0]

assert nd1.text() == nd1.text().toUpperCase()
assert nd2.text() == nd2.text().toUpperCase()
assert nd3.text() == nd3.text().toUpperCase()
assert nd4.text() == nd4.text().toUpperCase()
assert nd5.text() == nd5.text().toUpperCase()
{code}

TL;DR: The Nodes used by {{XmlParser}} can contain lists of values or single values.
If you use single values, you need the {{instanceof}} guards. You can just replicate
the lists the parser would normally do (shown for {{nd1}} through {{nd4}}) or use {{instanceof}}
or avoid the {{findAll}} for the hetergeneous case (only shown for {{nd5}}).

> Replacing a Groovy XML Node causes problems in subsequents findAll calls
> ------------------------------------------------------------------------
>
>                 Key: GROOVY-9048
>                 URL: https://issues.apache.org/jira/browse/GROOVY-9048
>             Project: Groovy
>          Issue Type: Bug
>          Components: XML Processing
>    Affects Versions: 3.x, 2.5.x
>         Environment: Windows/JDK 8
>            Reporter: David Obber
>            Priority: Minor
>
> I use groovy to parse a XML file using XmlParser. Just to avoid the handling of namespace prefixes, I used xmlRoot.'**'.findAll() method to find some nodes. The sample code shows how it works correctly until I just read the nodes, because each item passed to the closure is a Node object. But when I change the contents of a node (in this case, just the text of the node), the next call to findAll does not iterate on Node objects. For each character I put in the text, a String object is passed to the closure. I solved it checking the type with instanceof, but it seems to be that this is a bug.
> Am I doing something wrong or it's a bug?
> {code}
> class XmlParserTest {
>     static final String XML_SAMPLE = """
>      <ns0:root xmlns:ns0="mycompany.com">
>          <ns0:firstParent>
>              <ns0:item1>uppercase_me!</ns0:item1>
>          </ns0:firstParent>
>          <ns0:secondParent>
>              <ns0:item2>uppercase_me_too!</ns0:item2>
>          </ns0:secondParent>
>      </ns0:root>
>     """
>     static void main(String[] args) {
>         def xmlRoot = new XmlParser(false, false).parseText(XML_SAMPLE)
>         //******* find item1 and capitalize its text ********
>         def nds1 = xmlRoot.'**'.findAll {
>             it.name().equals("ns0:item1")
>         }
>         Node nd1 = nds1[0]
>         //This changes the text of the node, but something strange happens to the node tree
>         nd1.setValue(nd1.value().toString().toUpperCase())
>         //The same problem happens using replaceNode() instead of setValue()
>         //Node newNode = new Node(nd1.parent(), nd1.name(), nd1.value().toString().toUpperCase())
>         //nd1.replaceNode(newNode)
>         //******* find item2 and capitalize its text ********
>         def nds2 = xmlRoot.'**'.findAll {
>             //for each character in the string "uppercase me!" a String is passed instead of Node
>             //As String doesn't have a name method, an exception is raised
>             // it.name().equals("ns0:item2")
>             //using instanceof fixes the problem, at least for this case
>             it instanceof Node && it.name().equals("ns0:item2")
>         }
>         Node nd2 = nds2[0]
>         nd2.setValue(nd2.value().toString().toUpperCase())
>         assert nd1.value().toString() == nd1.value().toString().toUpperCase()
>         assert nd2.value().toString() == nd2.value().toString().toUpperCase()
>     }
> }
> {code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)