Merge XSLTs with import/include statement using Java - java

Let's say i have two xslt A, and B. In xslt A, we have a import/include statement to use some template from B. Is there a way in Java that we generate the resulting xslt (A merged with the imported template)?? Will it be possible??
SAXON has a way to export the compiled XSLT, but unfortunately the compiled XSLT has the link to the imported XSLT, which we don't want. Any input is appreciated.
Haven't explored XALAN yet on this one.

Why would you want to use Java for this, rather than XSLT?
Most of the job is easy, it can be done with a couple of template rules:
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="nested" on-no-match="shallow-copy"/>
<xsl:template match="xsl:stylesheet | xsl:transform" mode="nested">
<xsl:apply-templates mode="nested"/>
</xsl:template>
<xsl:template match="xsl:import | xsl:include" mode="#all">
<xsl:apply-templates select="document(#href)" mode="nested"/>
</xsl:template>
However, there are complications that make it difficult or impossible if certain XSLT features have been used, for example:
import precedences may not be converted correctly
xsl:apply-imports isn't going to work
attributes on xsl:stylesheet that have module scope (for example exclude-result-prefixes) will be lost.

Related

How to transform an xml file by searching for some nodes and replacing the values

This is the input xml -
<payload id="001">
<termsheet>
<format>PDF</format>
<city>New York</city>
</termsheet>
</payload>
We are using Xalan for most of our xml transformations and we are on XSLT 1.0
I want to write a XSLT template which would convert the input to the below output -
<payload id="001">
<termsheet>
<format>pdf</format>
<city>Mr. ABC</city>
</termsheet>
</payload>
I tried lot of answers on SO, but can't get around this problem.
Apologies for not being clear, toLower was an over simplification. I want to use the city name and invoke a java method which will return a business contact from that city. I have updated the original question
I think that the simplest way is to use java extension with Xalan, you can write a simple java class that implements the business logic you need, and then call it from your xslt. The stylesheet is quite simple
<xsl:stylesheet version="1.0"
xmlns:java="http://xml.apache.org/xalan/java"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="java">
<xsl:template match='node() | #*'>
<xsl:copy>
<xsl:apply-templates select ='node()|#*'></xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="termsheet/city">
<xsl:copy>
<xsl:value-of select='java:org.example.Card.getName(.)'/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
you also neeed to write the java class invoked
package org.example
public class Card {
public static String getName(String id) {
// put here your code to get what you need
return "Mr. ABC"
}
}
there are other ways to do that and you should really give an eye to the documentation about xalan extensions

How to use Parameters in xsl:apply-templates which are set from java?

I have a question on how to dynamically set the xpath expression in apply-templates select=?
<xsl:template match="CDS">
<xsl:result-document href="{$fileName}">
<xsl:copy>
<xsl:apply-templates select="$xpathCondition"/>
</xsl:copy>
</xsl:result-document>
</xsl:template>
This $xpathCondition am trying to set from java from properties file and setting to param in xsl.
transformer.setParameter("fileName", "Test.xml");
transformer.setParameter("xpathCondition", "CD[contains(Title/text(),'TEST')]");
$fileName is working as expected. But $xpathCondition is not working as expected.
There's no standard way of parsing a string as a dynamic XPath expression and executing it until you get to the xsl:evaluate instruction in XSLT 3.0. You really need to tell us which version you are using - the fact that you use xsl:result-document tells us that it's 2.0 or later, but beyond that we are guessing.
Many XSLT processors have an extension function called xx:eval() or similar.
The problem can be tackled in XSLT 3.0 using static parameters and shadow attributes. You can write:
<xsl:param name="xpathCondition" static="yes"/>
and then:
<xsl:apply-templates _select="{$xpathCondition}"/>
(Note the underscore in _select)
With 2.0 (or indeed 1.0) you can simulate this approach by doing a transformation on the stylesheet before executing it.

XSL working fine with xsltproc in unix but not when used in java code

I have an XSL as shown
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="no" indent="yes"/>
<xsl:param name="V9_XML_PATH" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="measSchedule">
<xsl:variable name="match" select="/schedule/scheduleItem[measurements/measurement=document($V9_XML_PATH)/schedule/scheduleItem/measurements/measurement]"/>
<xsl:choose>
<xsl:when test="$match">
<xsl:copy-of select="$match"/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I am using this to find the common records in 2 XML files whose records are in below format:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<schedule>
<scheduleItem scheduleId="1" startDate="2013-01-01" stopDate="2037-12-31">
<measurements>
<measurement>ADM010000</measurement>
</measurements>
<measPeriods>
<period day="0" duration="0" hour="0" interval="15" minutes="0"/>
</measPeriods>
</scheduleItem>
<!-- scheduleItem repeated n times -->
</schedule>
Here based on field /schedule/scheduleItem/measurements/measurement I am taking the intersection of 2 files.
But the problem is, when I am executing this in unix as:
xsltproc --stringparam V9_XML_PATH "/root/some/path/v9.xml" xsl.xslt v10.xml
its giving correct output, but when I started using this in my Java Program, I am getting exception java.lang.VerifyError
java.lang.VerifyError: (class: GregorSamsa$0, method: test signature: (IIIILcom/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet;Lcom/sun/org/apache/xml/internal/dtm/DTMAxisIterator;)Z) Incompatible type for getting or setting field
at GregorSamsa.template$dot$1()
at GregorSamsa.applyTemplates()
at GregorSamsa.applyTemplates()
at GregorSamsa.transform()
at com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.transform(Unknown Source)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(Unknown Source)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(Unknown Source)
at com.project.net.converter.XMLConverter.convert(XMLConverter.java:122)
Your stylesheet is obviously correct.
When you use Java to run the transformation, it uses XSLTC, the XSLT engine bundled with the JDK.
XSLTC parses your stylesheet and dynamically generates Java byte code which is then loaded and run to execute the transformation.
But somehow the generated XSLTC byte code is rejected by the Java VM, as indicated by the java.lang.VerifyError.
Therefore either XSLTC has a bug (option 1: likely), or the byte code verifier of your Java version rejects valid byte code (option 2: unlikely).
You could try to run your Java program with this JVM parameter :
java -Xverify:none ...
to turn of the byte code verifier. If it succeeds then option 2 is true.
Or you could try to use a different Java XSLT engine. For instance try Saxon; you probably only need to add the saxon jar to the classpath and your calling code should work without changes since you use the java.xml.transform interfaces. If this succeeds then option 1 was true.
This is most likely a classpath error. Check that you do not have several JAR files or directories with class files providing several times the same classes.

Escaped HTML in XML node via XSLT into XSL-FO

I have a document that has to be generated as PDF. I use Xalan and Apache FOP for processing an XML with XSLT into XSL-FO.
In my XML tree there is a node like this:
<root>
<formula>
<text>3+10*10^-6*l</text>
<html><html xmlns="http://www.w3.org/1999/xhtml">3 · + 10 · 10<sup>-6</sup> · <i>l</i></html></html>
</formula>
</root>
How can I not only get proper HTML (by using disable-output-escaping="yes") but also get a node-set (exsl:node-set?) that I can process later on? I mean, I want to get a XSL-FO representation of that HTML formula in order to integrate that into my PDF output.
Something like
<xsl:template match="xhtml:b">
<fo:inline font-weight="bold"><xsl:apply-templates/></fo:inline>
</xsl:template>
There may be a solution using saxon:parse(). However, I cannot switch to that from Xalan-J.
Is there a solution in my scenario?
You can certainly write one stylesheet to process with Xalan that does
<xsl:template match="html">
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:template>
which then creates a serialized result document with the XHTML markup.
A second stylesheet could then process the result document of the first stylesheet e.g.
<xsl:template match="xhtml:html" xmlns:xhtml="http://www.w3.org/1999/xhtml">
<xsl:apply-templates/>
</xsl:template>
But you can't do it within one stylesheet with a result tree fragment as doe (disable-output-escaping) is a serialization feature and if you work with result tree fragments converted to a node set with the help of exsl:node-set or similar within one stylesheet there is no serialization happening.
Looking closer, as your snippet seems to contain references to undeclared entities like · I think the sample does not parse as XML at all so you would need to fix that first to do any XSLT processing.

ERROR: 'The first argument to the non-static Java function 'evaluate' is not a valid object reference.' when using TrasformFactory

I am trying to transform an xsl + xml to xml (for later on transforming it into a pdf using FOP library). The JDK I am using is 1.5, and there is no way I can use another (that is what the company I work in is using). I read that the xalan jar of java 1.5 is the one responsible for the error. The text that causes the error is:
"dyn:evaluate($xpath)"/>
in:
<xsl:variable name="paramName" select="#name"/>
<xsl:variable name="xpath"
select="concat('/doc/data/',$paramName)" />
<fo:inline>
<xsl:value-of select="dyn:evaluate($xpath)"/>
</fo:inline>
</xsl:template>
is there a way arround it without changing the jar? Is there a way to write it differently? or am I using the wrong syntax?
Thanks for your help
evaluate() is an EXSLT extension function. It is non-standard, but many XSLT processors, including xalan, support it.
Have you declared the dyn namespace prefix in your stylesheet, so that it correctly references the EXSLT dynamic namespace?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="dyn">
...
</xsl:stylesheet>

Categories

Resources