简体   繁体   中英

Add node to the XML if does not exist?

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

Edit

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM