I am working on a project where I need to use the forEach tag to pull the information from the xml node(s). I keep run into a problem with "Expected a "java.util.Collection" for "items", got a "java.util.LinkedHashMap". Are there any ways that I can override the behavior of the <foreach> tag so that it always create a collection(put a item into the collection if the item is not a type of Collection) ?</foreach>
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Could you share more info about the XML you're parsing and how you want to use forEach to iterate over its contents? If you got a Map, you'll need to give JETT more info on what to iterate over.
It would not make sense to create a collection with one item from a HashMap and iterate over just it, because you wouln't iterate anything ; just use direct accessor to access the Map object if you know that a Map is returned, not a forEach.
Also, if your point is that you would like to use forEach to go over the XML elements, then you cannot iterate a Map like you could iterate a Collection, because you wouldn't know what to iterate on. The keys? The values? The entries? If you have some XML it may be very clear for you what you want to iterate over, but if we just consider the Map structure, it's not a call that JETT can do for you.
That being said, if there's one reproach I have for the JETT forEach tag, it's that it will only iterate a Collection and not an array[]. Having to call Arrays.asList() ourselves adds unnecessary complexity, but it's far from being a major pain :)
Cheers,
Etienne.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks, I figured out the solution. It works but I don't know if this is a good way or not.
<jt:foreach items="${if(root.get('children').getClass().getName() == 'java.util.ArrayList'){return root.children}else{var t = new(java.util.ArrayList,1); t.add(root.children); return t;}}" var="children"> {children.label}</jt:foreach>
Last edit: Hung Cu 2017-02-12
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Your XML parser will return a List if root has many children, or a single object if there's one child.
Shouldn't the type depend on your XML Schema? If you don't have a schema then your XML parser is doing its best and your code is the best way I can think to handle this case.
However, if you know your XML schema, you should bind this to a java class where the "children" element in root object is a List, so you wouldn't have a problem. It would be a List whether there's one or more child.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank,
I thought about doing that way too but I realized that it is not a good solution in our case because it would break our ${xml.child.label} syntax. We don't want to go back to every excel templates and swich ${xml.child.label} to <jt:foreach>. Therefore, I hope that there were a way that I could override the default behavior of the <jt:foreach> instead of writting a long JEXL syntax.</jt:foreach></jt:foreach>
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am working on a project where I need to use the forEach tag to pull the information from the xml node(s). I keep run into a problem with "Expected a "java.util.Collection" for "items", got a "java.util.LinkedHashMap". Are there any ways that I can override the behavior of the <foreach> tag so that it always create a collection(put a item into the collection if the item is not a type of Collection) ?</foreach>
Hi Hung Cu,
Could you share more info about the XML you're parsing and how you want to use forEach to iterate over its contents? If you got a Map, you'll need to give JETT more info on what to iterate over.
It would not make sense to create a collection with one item from a HashMap and iterate over just it, because you wouln't iterate anything ; just use direct accessor to access the Map object if you know that a Map is returned, not a forEach.
Also, if your point is that you would like to use forEach to go over the XML elements, then you cannot iterate a Map like you could iterate a Collection, because you wouldn't know what to iterate on. The keys? The values? The entries? If you have some XML it may be very clear for you what you want to iterate over, but if we just consider the Map structure, it's not a call that JETT can do for you.
That being said, if there's one reproach I have for the JETT forEach tag, it's that it will only iterate a Collection and not an array[]. Having to call Arrays.asList() ourselves adds unnecessary complexity, but it's far from being a major pain :)
Cheers,
Etienne.
Thanks, I figured out the solution. It works but I don't know if this is a good way or not.
<jt:foreach items="${if(root.get('children').getClass().getName() == 'java.util.ArrayList'){return root.children}else{var t = new(java.util.ArrayList,1); t.add(root.children); return t;}}" var="children"> {children.label}</jt:foreach>
Last edit: Hung Cu 2017-02-12
OK, now I understand what your problem is.
Your XML parser will return a List if root has many children, or a single object if there's one child.
Shouldn't the type depend on your XML Schema? If you don't have a schema then your XML parser is doing its best and your code is the best way I can think to handle this case.
However, if you know your XML schema, you should bind this to a java class where the "children" element in root object is a List, so you wouldn't have a problem. It would be a List whether there's one or more child.
Thank,
I thought about doing that way too but I realized that it is not a good solution in our case because it would break our ${xml.child.label} syntax. We don't want to go back to every excel templates and swich ${xml.child.label} to <jt:foreach>. Therefore, I hope that there were a way that I could override the default behavior of the <jt:foreach> instead of writting a long JEXL syntax.</jt:foreach></jt:foreach>