I am going around in circles for a problem that seems simple.
I have an XML which contains only tags with no values (only with attributes).
I want to iterate over this XML with a StaxEventItemReader but I can't.
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE dataset>
<dataset>
<table_row id="3944552" code_a="N" code_b="232" num_abc="[NULL]" sexe="M" date_nais="1959-11-15" />
<table_row id="3944553" code_a="[NULL]" code_b="[NULL]" num_abc="[NULL]" sexe="F" date_nais="1920-05-10" />
</dataset>
And the reader :
private StaxEventItemReader<TableRow> createXmlReader(Resource source) throws Exception {
StaxEventItemReader<TableRow> reader = new StaxEventItemReader<>();
reader.setResource(source);
reader.setFragmentRootElementName("table_row");
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setClassesToBeBound(TableRow.class);
reader.setUnmarshaller(jaxb2Marshaller);
reader.afterPropertiesSet();
return reader;
}
I am indeed trying to obtain at the output of my reader (and at the input of my processor) an object in the image of this content with a MAP which contains each attribute / value
@Setter
@Getter
public class TableRow {
private Map<String, String> mapChampValeurs;
}
I try to use an adapte but I cant' see how to implement it (I use @XmlJavaTypeAdapter() but I never enter in my adapter)
Do you know how I can do this?
EDIT 1
I try to add an adapter for convert all attributes in a map
public class TableRowXmlAdapter extends XmlAdapter<Object, TableRow> {
private static final Logger LOGGER = LoggerFactory.getLogger(TableRowXmlAdapter.class);
@Override
public TableRow unmarshal(Object v) throws Exception {
LOGGER.info("***** INTO ROW ADAPTER ****");
Element element = (Element) v;
Map<String, String> properties = new LinkedHashMap<>();
NamedNodeMap attributes = element.getAttributes();
for (int i = attributes.getLength() - 1; i >= 0; i--) {
Node node = attributes.item(i);
properties.put(node.getNodeName(), node.getNodeValue());
}
TableRow tableRow = new TableRow();
tableRow.setMapChampValeurs(properties);
return tableRow;
}
I declare it in StaxEventItemReader :
private StaxEventItemReader<TableRow> createXmlReader(Resource source) throws Exception {
StaxEventItemReader reader = new StaxEventItemReader();
reader.setResource(source);
reader.setFragmentRootElementName(ROOT_ELEMENT);
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
TableRowXmlAdapter tableRowXmlAdapter = new TableRowXmlAdapter();
jaxb2Marshaller.setAdapters(tableRowXmlAdapter);
jaxb2Marshaller.setClassesToBeBound(TableRow.class);
reader.setUnmarshaller(jaxb2Marshaller);
reader.afterPropertiesSet();
return reader;
}
But when I debug this, I never enter in my adapter and there is an Exception :
Caused by: com.sun.istack.internal.SAXParseException2; lineNumber: 4; columnNumber: 94; élément inattendu (URI : "", local : "table_row"). Les éléments attendus sont (none)
Both of lineNumber and columnNumber represents the position of the last characters juste after "/>" self-closing tag
For information, I found the solution with the @XmlAnyAttribute annotation
@XmlAnyAttribute
private Map<QName, String> mapChampValeurs;
With that annotation, no need more action like Adapter