Transform XML using XSLT in JAVA
If you want to use StreamSource(String systemId)
then a valid local absolute file URI would look something like: new StreamSource("file:///C:/test2/xsltFilePersonnes.xsl")
.
But I think running your Java code in a certain folder (e.g. C:\test2
) and then using relative URIs like new StreamSource("xsltFilePersonnes.xsl")
should work as well.
Saxonica also has JAXP samples for 9.8 online here.
How to pass a XML document to XSL file using Javax.xml.transformer API?
I think your issue is in the XSLT. Change
<xsl:variable name="lookup" select="('documentFile')/> .
to
<xsl:variable name="lookup" select="document('lookup')/>
this will cause the transformer to make the DOM
of your document accessible in the variable lookup
. The key lookup
comes from docs.put("lookup", documentFile);
Dynamically Pass Multiple XML Sources to XSL Transformation via URIResolver.
Full Working Example:
Be there three XML files: repo.xml
, books.xml
and articles.xml
. The repo.xml
contains status information about books and articles. The files articles.xml
and books.xml
contain title information about each item. The goal is to print status information of all books and articles together with the title information. The entries in all files are connected via id
keys.
Find complete example at github or copy/paste the listings below.
repo.xml
<repository>
<book>
<id>1</id>
<status>available</status>
</book>
<book>
<id>2</id>
<status>lost</status>
</book>
<article>
<id>1</id>
<status>in transit</status>
</article>
</repository>
books.xml
<books>
<book id="1">
<title>Book One</title>
</book>
<book id="2">
<title>Book Two</title>
</book>
<book id="3">
<title>Book Three</title>
</book>
</books>
articles.xml
<articles>
<article id="1">
<title>Article One</title>
</article>
<article id="2">
<title>Article Two</title>
</article>
<article id="3">
<title>Article Three</title>
</article>
</articles>
join.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<titleStatusJoin>
<xsl:for-each select="//book">
<xsl:variable name="myId" select="id" />
<book>
<status>
<xsl:value-of select="status" />
</status>
<title>
<xsl:for-each select="document('bookFile')//book">
<xsl:variable name="bookId" select="@id" />
<xsl:choose>
<xsl:when test="$myId = $bookId">
<xsl:value-of select="title" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</title>
</book>
</xsl:for-each>
<xsl:for-each select="//article">
<xsl:variable name="myId" select="id" />
<article>
<status>
<xsl:value-of select="status" />
</status>
<title>
<xsl:for-each select="document('articleFile')//article">
<xsl:variable name="bookId" select="@id" />
<xsl:choose>
<xsl:when test="$myId = $bookId">
<xsl:value-of select="title" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</title>
</article>
</xsl:for-each>
</titleStatusJoin>
</xsl:template>
</xsl:stylesheet>
Use this Java code...
@Test
public void useMultipleXmlSourcesInOneXsl3() {
InputStream xml = Thread.currentThread().getContextClassLoader().getResourceAsStream("stack54335576/repo.xml");
InputStream xsl = Thread.currentThread().getContextClassLoader().getResourceAsStream("stack54335576/join3.xsl");
InputStream booksXml = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("stack54335576/books.xml");
InputStream articlesXml = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("stack54335576/articles.xml");
Document booksDom = readXml(booksXml);
Document articlesDom = readXml(articlesXml);
Map<String, Document> parameters = new HashMap<>();
parameters.put("bookFile", booksDom);
parameters.put("articleFile", articlesDom);
xslt(xml, xsl, parameters);
}
public final void xslt(InputStream xml, InputStream xsl, Map<String, Document> parameters) {
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xsl));
transformer.setURIResolver((href, base) -> new DOMSource(parameters.get(href)));
transformer.transform(new StreamSource(xml), new StreamResult(System.out));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Document readXml(InputStream xmlin) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(xmlin);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
...to produce this output
<?xml version="1.0" encoding="UTF-8"?>
<titleStatusJoin>
<book>
<status>available</status>
<title>Book One</title>
</book>
<book>
<status>lost</status>
<title>Book Two</title>
</book>
<article>
<status>in transit</status>
<title>Article One</title>
</article>
</titleStatusJoin>
different results of xsl transformation using java transformer and command line processor
Make sure you explicitly use a namespace aware DocumentBuilderFactory if you want to process XML and XSLT with Java as otherwise you won't get a meaningful result, XSLT itself is XML depending on namespaces and any XML input it uses is also better processed with namespace support.
Of course to simply use XML from a file as the input you don't need a DocumentBuilder and a DOMSource, you can use a StreamSource as well where then the XSLT processor takes care of processing the input in a namespace aware mode.
How to transform each xml node with Saxon XSLT?
The XSLT template can be modified as below. The elements can be selected according to the required sequence.
<xsl:template match="employee">
<xsl:value-of select="ancestor::employees/@stage, details/name, details/age, address/street, address/nr" separator=", " />
<xsl:text>
</xsl:text>
</xsl:template>
After replacing the ...
with some dummy values in the <address>
element the following output is generated using the above template.
test, Joe, 34, test, 12
test, Sam, 24, test1, 123
For transforming the XML (using XSLT) in Java, I use the following code snippet most of the time. This method returns the transformed XML as a String
. The required library is saxon9he.jar
. You may have to upgrade the library version for using with XSLT 3.0
public static String transformXML(String xml, InputStream xslFile) {
String outputXML = null;
try {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xslFile));
Source xmlStream = new StreamSource(new StringReader(xml));
StringWriter writer = new StringWriter();
Result result = new StreamResult(writer);
transformer.transform(xmlStream, result);
outputXML = writer.getBuffer().toString();
} catch (TransformerConfigurationException tce) {
tce.printStackTrace();
} catch (TransformerException te) {
te.printStackTrace();
}
return outputXML;
}
How to run saxon xslt transformation in java
The documentation is here: http://www.saxonica.com/documentation/index.html#!using-xsl/embedding
Saxon offers two APIs for running XSLT transformations from a Java application: the JAXP API, and the s9api API. JAXP is a standard interface offered by almost all Java XSLT processors, so you want to use this one if you want your application to be portable; its disadvantage is that (a) it's very oriented to XSLT 1.0 and that makes it hard to take advantage of new capabilities in XSLT 2.0 and XSLT 3.0, and (b) it doesn't integrate especially well with APIs for related tasks such as schema processing and XPath evaluation.
The s9api API is much more closely matched to Saxon's capabilities across a variety of tasks including XSLT, XQuery, XPath, and XSD validation, but isn't portable.
It's your choice.
Related Topics
Composing Swing Components: How to Add the Ability to Add Actionlisteners
Java: How to Access a Class's Field by a Name Stored in a Variable
How to Tell Jackson to Ignore a Property for Which I Don't Have Control Over the Source Code
How to Read Xml Response from a Url in Java
Are There Best Practices for (Java) Package Organization
Can Constructor Return a Null Object
Difference Between Shutdown and Shutdownnow of Executor Service
Please Explain About Insertable=False and Updatable=False in Reference to the JPA @Column Annotation
Making Distinctions Between Different Kinds of Jsf Managed-Beans
Java Lib or App to Convert CSV to Xml File
Calling a @Bean Annotated Method in Spring Java Configuration
Stack with Find-Min/Find-Max More Efficient Than O(N)
Do Any Jvm's Jit Compilers Generate Code That Uses Vectorized Floating Point Instructions
How to Insert a Character in a String at a Certain Position
Checked VS Unchecked Exception
How to Convert a Java Object (Bean) to Key-Value Pairs (And Vice Versa)