Groovy结合Jackson提取含重复节点XML标签值的解决方案咨询
Hey there! The core issue here is that when converting XML to JSON and then to a Map, duplicate nodes get lost or overwritten because Maps can't have duplicate keys. Instead of going through the JSON middleman, let's use tools designed specifically for XML parsing in Groovy—this will handle duplicate nodes naturally.
Using Groovy's Native XmlSlurper (Recommended)
Groovy comes with XmlSlurper out of the box, which automatically treats duplicate nodes as collections. This is lightweight, concise, and perfect for your use case.
Here's how to rewrite your script:
def xmlFile = new File("C:/xml/full_rejection_notification.xml") // Parse the XML file def slurper = new XmlSlurper() def xml = slurper.parse(xmlFile) // Get all duplicate TxInfAndSts nodes (this will be a list if duplicates exist) def txInfNodes = xml.Document.FIToFIPmtStsRpt.TxInfAndSts // If you need to process every duplicate node: def results = [] txInfNodes.each { txNode -> def state = txNode.TxSts.text() def errorCode = txNode.StsRsnInf.Rsn.Cd.text() results.add("${state} ${errorCode}") } // Or if you only need the first node (adjust index as needed): def firstState = txInfNodes[0].TxSts.text() def firstErrorCode = txInfNodes[0].StsRsnInf.Rsn.Cd.text() def singleResult = "${firstState} ${firstErrorCode}" // Return whatever fits your needs—either the list or single result return results.join("\n") // or return singleResult
Why this works:
XmlSlurperparses XML directly, no intermediate conversion steps that lose data.- Duplicate nodes are automatically wrapped in a collection, so you can iterate over them easily.
- No extra dependencies required (it's part of Groovy's standard library).
Alternative: Jackson XML Module
If you prefer working with strongly-typed objects instead of dynamic parsing, you can use Jackson's XML data format module. This lets you map XML directly to POJOs, with explicit handling for duplicate nodes.
First, add the dependency (for Groovy scripts, use @Grab):
@Grab('com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.15.2') import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper // Define POJOs that match your XML structure @JsonIgnoreProperties(ignoreUnknown = true) class DocumentWrapper { Document Document } @JsonIgnoreProperties(ignoreUnknown = true) class Document { FIToFIPmtStsRpt FIToFIPmtStsRpt } @JsonIgnoreProperties(ignoreUnknown = true) class FIToFIPmtStsRpt { // Tell Jackson to treat TxInfAndSts as a list, even if only one exists @JacksonXmlElementWrapper(useWrapping = false) List<TxInfAndSts> TxInfAndSts } @JsonIgnoreProperties(ignoreUnknown = true) class TxInfAndSts { String TxSts StsRsnInf StsRsnInf } @JsonIgnoreProperties(ignoreUnknown = true) class StsRsnInf { Rsn Rsn } @JsonIgnoreProperties(ignoreUnknown = true) class Rsn { String Cd } // Parse the XML into your POJO def xmlMapper = new XmlMapper() // Handle cases where a node might be single or multiple xmlMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) def docWrapper = xmlMapper.readValue(new File("C:/xml/full_rejection_notification.xml"), DocumentWrapper.class) // Process the nodes def results = docWrapper.Document.FIToFIPmtStsRpt.TxInfAndSts.collect { tx -> "${tx.TxSts} ${tx.StsRsnInf.Rsn.Cd}" } return results.join("\n")
Why this works:
- The
@JacksonXmlElementWrapper(useWrapping = false)annotation ensures duplicate nodes are mapped to aListinstead of being overwritten. - Strong typing makes your code more maintainable if your XML structure is stable.
Final Notes
Either approach will solve your duplicate node problem, but XmlSlurper is the most straightforward for Groovy scripts since it's native and requires no extra setup. If you need type safety, go with the Jackson XML module.
内容的提问来源于stack exchange,提问作者K Sabrine

