0

I'm working on a project where I need to parse an XML file and perform the exact same code on 100s of different XML Paths/Nodes. My code currently looks like this…

def items = parser.parseText(inputFile.text)

items.item.each { item ->
    try {
        // do stuff with item.some_node
    } catch(Exception ex) {
        //exception stuff
    }
    try {
        // do stuff with item.weight_node
    } catch(Exception ex) {
        //exception stuff
    }
    try {
        // do stuff with item.another_node[3].sub_node
    } catch(Exception ex) {
        //exception stuff
    }
    try {
        // do stuff with item.some_node
    } catch(Exception ex) {
        //exception stuff
    }
    // do this a 100 times or so with other item node paths
}

Since the 'stuff to do' and the exception 'stuff' is the exact same every time and the only thing that changes is the node I'm working with. Because of this I would rather send the node expression to a method or extend the node class like this…

def myMethod(currentNode) {
    try {
        // do stuff
    } catch(Exception ex) {
        //exception stuff
    }
}

items.item.each { item ->
    myMethod(item.some_node)
    myMethod(item.weight_node)
    myMethod(item.another_node[3].sub_node)
    myMethod(item.some_node)
}

// OR

def myProcess(NodeList n){
    try {
        // do stuff
    } catch(Exception ex) {
        //exception stuff
    }
}
NodeList.metaClass.myProcess = { -> myProcess(delegate) }

items.item.each { item ->
    item.some_node.myMethod()
    item.weight_node.myMethod()
    item.another_node[3].sub_node.myMethod()
    item.some_node.myMethod()
}

With the method attempt I can't figure out how to pass the XPath to the method and then use it. With the class extension method it works so long as the node actually exists. If it doesn't I get an error trying to invoke myProcess.

Any ideas?

dscl
  • 1,616
  • 7
  • 28
  • 48

2 Answers2

0

Since there is no xml, taking a sample xml.

You do need to write for each node like it was mentioned in initially.

In groovy, that is something which is easily achieved using find (returns single value) or findAll (multiple values). Please see the example below.

def jdbcResponse = """<Results>
    <ResultSet fetchSize="10">
        <Row rowNumber="1">
            <T1>TEXT1</T1>
            <T2>TASK1</T2>
            <T3>Value1</T3>
            <T4>xyz</T4>
      </Row>
       <Row rowNumber="2">
            <T1>TEXT2</T1>
            <T2>TASK2</T2>
            <T3>Value1a</T3>
            <T4>ABC</T4>
      </Row>
     </ResultSet>
</Results>"""

def xml = new XmlSlurper().parseText(jdbcResponse)

//Return the matching element
def getData = { elementName ->
    xml.'**'.findAll{it.name() == elementName}
}

//Coerced result to List of string as T1/2 is not complex
def t1s = getData('T1') as List<String>
def t2s = getData('T2') as List<String>
println t1s

//Here you get Rows which is complex, so not coerced
def rows = getData('Row')
//Check if first row T1 is TEXT1
assert rows[0].T1.text() == 'TEXT1'
Rao
  • 20,781
  • 11
  • 57
  • 77
0

for the second case

NodeList.metaClass.myProcess = { -> myProcess(delegate) }

items.item.each { item ->
    item.some_node.myMethod()
    item.weight_node.myMethod()
    ...
}

you can use null safe accessor to avoid exception on not-existent nodes:

items.item.each { item ->
    item?.some_node?.myMethod()
    item?.weight_node?.myMethod()
    ...
}
daggett
  • 26,404
  • 3
  • 40
  • 56