Reputation: 11435
I want to modify a XML template with a custom logic, it's similiar to XSLT but has some very own features. The XML template file is clean and ready to expand.
<user-list>
<user id="">
<forename></forename>
<lastname></lastname>
<static-information>static</static-information>
<address-list>
<address>
...
</address>
</adress-list>
</user>
</user-list>
Now I receive a JDBC result set for this template and a mapping for the datastructure with informations about repeating nodes (like "user"-node here) and mapping hints (e.g. "user/forename" to FORENAME {a SQL column}).
<user-list>
<user id="1">
<forename>stack</forename>
<lastname>overflow</lastname>
<static-information>static</static-information>
<address-list>...</adress-list>
</user>
<user id="2">
<forename>questions</forename>
<lastname>answers</lastname>
<static-information>static</static-information>
<address-list>...</adress-list>
</user>
</user-list>
The mapping has relative informations about inner nodes which shall expand (the address should be repeated if the current user has more than one address.
<query>SELECT * FROM USER</query>
<element>user/address-list/address</element>
<mapping element="street" source="STREET"></mapping>
This could be a very complex model that can contain up to 10000 entries. How can I achieve the transformation from a easy template without knowing it's structure (beside the small informations given by the mapping). What framework should I choose? How can I achieve streaming? I don't want to transform and do the mapping in memory. After each complete e.g. user block the streaming can go on.
Thank you
Upvotes: 0
Views: 647
Reputation: 80330
You can use a STaX parser like Woodstox. Then create a reading loop and embed inside it write commands that write out XML elements based on input element.
An example that reads simple elements and writes them to output, except for <address-list>
element where it creates a series of <address></address>
subelements inside it:
FileInputStream fis = new FileInputStream(file);
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader staxXmlReader = factory.createXMLStreamReader(fis);
XMLOutputFactory outFactory = XMLOutputFactory.newInstance();
XMLStreamWriter staxWriter = outFactory.createXMLStreamWriter(out);
for (int event = staxXmlReader.next(); event != XMLStreamConstants.END_DOCUMENT;
event = staxXmlReader.next()) {
switch (event) {
case XMLStreamConstants.START_DOCUMENT:
break;
case XMLStreamConstants.START_ELEMENT:
String elementName = staxXmlReader.getLocalName();
if(elementName.equals("address-list")){
staxWriter.writeStartElement(elementName);
String addressText = staxXmlReader.getElementText();
// parse element text
// and loop creating <address> elements
for (..) {
staxWriter.writeStartElement("address"); // write <address>
staxWriter.writeCharacters("address data");
staxWriter.writeEndElement(); // write </address>
}
} else {
// just copy the element
staxWriter.writeStartElement(elementName);
staxWriter.writeCharacters(staxXmlReader.getElementText());
}
break;
case XMLStreamConstants.END_ELEMENT:
staxWriter.writeEndElement();
break;
case XMLStreamConstants.END_DOCUMENT:
staxWriter.writeEndDocument();
break;
default:
break;
}
}
Upvotes: 3
Reputation: 43651
Another options would be using extension functions and elements in XSLT. Saxon is for instance very good in supporting such things.
Upvotes: 0