i have following problem. I need to add a Node, if its not available. For example
Input:
<DataTable>
<DataRow>
<Field1>1</Field1>
</DataRow>
<DataRow>
<Field1>1</Field1>
<Field2>1</Field2>
</DataRow>
<DataRow>
<Field1>1</Field1>
<Field2>1</Field2>
<Field3>1</Field3>
</DataRow>
</DataTable>
Expected output:
<DataTable>
<DataRow>
<Field1>1</Field1>
<Field2/>
<Field3/>
</DataRow>
<DataRow>
<Field1>1</Field1>
<Field2>1</Field2>
<Field3/>
</DataRow>
<DataRow>
<Field1>1</Field1>
<Field2>1</Field2>
<Field3>1</Field3>
</DataRow>
</DataTable>
So if the three nodes in a row are not available, than they should be added to the result XML.
This the code I tried, it works only with a flat xml.
import com.sap.gateway.ip.core.customdev.util.Message
import groovy.xml.XmlUtil
Message processData(Message message) {
def fields = ['Field1', 'Field2', 'Field3']
def payload = new XmlParser().parse(message.getBody(Reader))
(fields - (payload.children() as List<Node>)*.name()).each { payload.appendNode(it) }
message.setBody(XmlUtil.serialize(payload))
return message
}
I want to add Tag to the output file. Thank you
So, for the conversion we can write a function that takes a string (the input xml) and a list of required fields, and returns the new xml
import groovy.xml.XmlParser
import groovy.xml.XmlNodePrinter
String extendFields(String xmlInput, List<String> fields) {
def xml = new XmlParser().parseText(xmlInput)
xml.findAll { it.name() == 'DataRow' }.each { row ->
fields.each { field ->
if (!row."$field") {
row.appendNode(field)
}
}
}
new StringWriter().with { out ->
new XmlNodePrinter(new PrintWriter(out)).with { writer ->
writer.preserveWhitespace = true
writer.print(xml)
}
out.toString()
}
}
Calling this with your input XML:
def input = '''<DataTable>
<DataRow>
<Field1>1</Field1>
</DataRow>
<DataRow>
<Field1>1</Field1>
<Field2>1</Field2>
</DataRow>
<DataRow>
<Field1>1</Field1>
<Field2>1</Field2>
<Field3>1</Field3>
</DataRow>
</DataTable>'''
println extendFields(input, ['Field1', 'Field2', 'Field3'])
prints
<DataTable>
<DataRow>
<Field1>1</Field1>
<Field2/>
<Field3/>
</DataRow>
<DataRow>
<Field1>1</Field1>
<Field2>1</Field2>
<Field3/>
</DataRow>
<DataRow>
<Field1>1</Field1>
<Field2>1</Field2>
<Field3>1</Field3>
</DataRow>
</DataTable>
So then, you can change your method in the question to call this new method:
Message processData(Message message) {
def fields = ['Field1', 'Field2', 'Field3']
def payload = extendFields(message.getBody(Reader), fields)
message.setBody(payload)
return message
}
Pulling this out into a separate method also has the advantage of making it more easily testable 😀
If you want to sort the nodes in the order of the fields you provide, you can add a sort
on the children
like so:
String extendFields(String xmlInput, List<String> fields) {
def xml = new XmlParser().parseText(xmlInput)
xml.findAll { it.name() == 'DataRow' }.each { row ->
fields.each { field ->
if (!row."$field") {
row.appendNode(field)
}
}
row.children().sort { fields.indexOf(it.name()) }
}
new StringWriter().with { out ->
new XmlNodePrinter(new PrintWriter(out)).with { writer ->
writer.preserveWhitespace = true
writer.print(xml)
}
out.toString()
}
}
Then calling this with the fields in the order we want:
println extendFields(input, ['Field3', 'Field1', 'Field2'])
Prints:
<DataTable>
<DataRow>
<Field3/>
<Field1>1</Field1>
<Field2/>
</DataRow>
<DataRow>
<Field3/>
<Field1>1</Field1>
<Field2>1</Field2>
</DataRow>
<DataRow>
<Field3>1</Field3>
<Field1>1</Field1>
<Field2>1</Field2>
</DataRow>
</DataTable>