I have a sample LEDES XML file https://codebeautify.org/xmlviewer/cbdc79e7
Generted Ledesxmlebilling21 class using JDK's xjc
as below and Ledes21.xsd schema https://codebeautify.org/xmlviewer/cb974a2e
xjc -d src ledes21.xsd
And I am converting the XML to Java object using JAX-B as below
Ledesxmlebilling21 XMLtoObject(InputStream fis) throws Exception {
JAXBContext context = JAXBContext.newInstance(Ledesxmlebilling21.class)
Unmarshaller um = context.createUnmarshaller()
Ledesxmlebilling21 ledes = (Ledesxmlebilling21) um.unmarshal(fis)
return ledes
}
And am trying to create a Map with Invoice object's invId
attribute value as Key and the Values as list of all of Invoice object's nested attribute's fileItemNbr
values as below
['Invoice 31' : [10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33]
'Invoice 32' : [50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73]
]
can someone please help me with it?
Update With The Solution
def extractFileItemNbr(input, List<Integer> extracted) {
input.properties.each { prop, val -> //LedesXmlRuleProcessor.groovy:82)
if (prop in ["metaClass", "class"]) return
if (prop == 'file_item_nbr') {
extracted << val
} else {
extractFileItemNbr(val, extracted) //LedesXmlRuleProcessor.groovy:87)
}
}
}
def extractFileItemNbr(List input, List<Integer> extracted) {
input.each {
extractFileItemNbr(it, extracted)
}
}
void testExtract(Ledesxmlebilling21 ledesxmlebilling21) {
def xmlInvoices = ledesxmlebilling21.firm.client.invoice.flatten()
Map<String, List<Integer>> extracted = [:]
println "invoices -- "+xmlInvoices
for (Invoice invoice : xmlInvoices) {
def accuList = []
extractFileItemNbr(invoice, accuList)
extracted.put(invoice.invId, accuList)
}
println("extracted file_item_nbr "+ extracted)
}
I am getting below exception with the actual Ledesxmlebilling21
object
Disconnected from the target VM, address: '127.0.0.1:59759', transport: 'socket'
2017-12-11 11:04:06 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError: null
at org.codehaus.groovy.util.AbstractConcurrentMap.getOrPut(AbstractConcurrentMap.java:37)
at org.codehaus.groovy.reflection.GroovyClassValuePreJava7.get(GroovyClassValuePreJava7.java:94)
at org.codehaus.groovy.reflection.ClassInfo.getClassInfo(ClassInfo.java:143)
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:265)
at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:879)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.createPojoMetaClassGetPropertySite(AbstractCallSite.java:351)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.createGetPropertySite(AbstractCallSite.java:327)
at org.codehaus.groovy.runtime.callsite.GetEffectivePojoPropertySite.acceptGetProperty(GetEffectivePojoPropertySite.java:56)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:296)
at com.validation.rule.processor.impl.LedesXmlRuleProcessor.extractFileItemNbr(LedesXmlRuleProcessor.groovy:82)
at sun.reflect.GeneratedMethodAccessor82.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:384)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:174)
at com.validation.rule.processor.impl.LedesXmlRuleProcessor$_extractFileItemNbr_closure2.doCall(LedesXmlRuleProcessor.groovy:87)
My guess would be that the schema will have a cyclic property. Have a look here perhaps: JAXB Mapping cyclic references to XML
I believe what you want is to recursively iterate over groovy properties.
I skip over the JAX-B parsing since you have that solved already, and use my own classes. The groovy code is not idiomatic and could be shortened
class LedesStatementTest extends GroovyTestCase {
// Recursive function adding file_item_nbr to given list
def extractFileItemNbr(input, List<Integer> extracted) {
input.properties.each { prop, val ->
if (prop in ["metaClass", "class"]) return
if (prop == 'file_item_nbr') {
// println(" $prop : $val")
extracted << val
} else {
extractFileItemNbr(val, extracted)
}
}
}
// deal with list fields
def extractFileItemNbr(List input, List<Integer> extracted) {
input.each {
extractFileItemNbr(it, extracted)
}
}
void testExtract() {
List<LedesInvoice> invoices = [new LedesInvoice([inv_id: 'Invoice 31',
file_item_nbr: 10,
statement: new LedesStatement([file_item_nbr: 11]),
summary: [new LedesTaxSummary([file_item_nbr: 12]), new LedesTaxSummary([file_item_nbr: 13])]]),
new LedesInvoice([inv_id: 'Invoice 32',
file_item_nbr: 50,
statement: new LedesStatement([file_item_nbr: 51]),
summary: [new LedesTaxSummary([file_item_nbr: 52]),
new LedesTaxSummary([file_item_nbr: 53])]])
]
Map<String, List<Integer>> extracted = [:]
for (LedesInvoice invoice : invoices) {
def accuList = []
extractFileItemNbr(invoice, accuList)
extracted.put(invoice.inv_id, accuList)
}
println(extracted)
}
// data classes, similar to Ledes XML, simplified
static class LedesInvoice {
String inv_id;
int file_item_nbr;
LedesStatement statement;
List<LedesTaxSummary> summary;
}
static class LedesStatement {
int file_item_nbr;
}
static class LedesTaxSummary {
int file_item_nbr;
}
}
Output:
[Invoice 31:[12, 13, 11, 10], Invoice 32:[52, 53, 51, 50]]
In case of cycles, don't just pass around a List<Integer> extracted
of extracted ints, but also a a Set of visited inputs, and in each extract method check if the given input is already in the list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With