As a continuation in my thought patterns from this question: Saxon in Java: XSLT for CSV to XML
Per Michael Kay's answer on that question, I eventually ended up with the following code for applying an XSLT to a document:
Processor processor = new Processor(false);
StringWriter stringWriter = new StringWriter();
Serializer serializer = new Serializer(stringWriter);
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable executable = compiler.compile(new StreamSource(new File(transformLocation)));
XsltTransformer transformer = executable.load();
transformer.setInitialTemplate(new QName("main"));
transformer.setParameter(new QName("filePath"), new XdmAtomicValue("location/of/Test.csv"));
transformer.setDestination(serializer);
transformer.transform();
String transformedDocument = stringWriter.toString().trim();
This code makes use of the s9api in Saxon (I'm on version 9.4 HE). It allows me to set the initial template and dynamically inject the path to the document to be transformed, which allows me to transform non-XML files (such as CSV, in this particular case).
However, this somewhat obliterates my code-re-usability.
Let me explain: I have a transformDocument()
method. Originally, before I was trying to do crazy things like transform CSV and was working only with XML, it was called by both my marshalObjectToDocument()
and unmarshalDocumentToObject()
methods (there's the re-usability).
Here's a comparison of the two directions given a world of only XML:
unmarshalDocumentToObject()
- I start with a file that has the document inside of it.
- I do this:
new StreamSource(new File(documentLocation))
- This
StreamSource
can be passed totransformDocument
as the "source" (XsltTransformer.setSource()
).
marshalObjectToDocument()
- I start with on object of some sort.
- This gets marshaled into a giant String of the XML.
- I do this:
new StreamSource(new StringReader(giantStringOfXML))
- This
StreamSource
can be passed totransformDocument
as the "source" (XsltTransformer.setSource()
).
In case 1 (unmarshalDocumentToObject()
) I have a file path coming in, so I could just change transformDocument()
to take a file path String and pass it that so it can manually inject it into the XSLT parameter. This would work for both XML and plain text.
In case 2 (marshalObjectToDocument()
) I have NO file path. I have an object, which gets converted to a giant String containing its XML representation. I can't pass a file path String to transformDocument()
because I don't have a file. Now I can't use transformDocument()
. Code re-usability destroyed.
My goal in all of this is both to be able to somehow treat both XML and plain text documents the same way in the code and to be able to re-use my code for applying XSLTs and XSDs whether I'm marshaling or unmarshaling. Is this a quixotic goal? Am I doomed to be relegated to writing different code for each document type and direction? Or can someone see a way around this?