Pass absolute file path from java code to xslt document() - java

In my xslt I'd like to look up an xml file. I need to pass the path to this file from java code.I have the followings:
...
Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
transformer.setParameter("mypath", "/home/user/repository");
xslt:
<?xml version="1.0"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="mypath"/>
...
<xsl:template match="connection[#id]">
<xsl:variable name="lookupStore" select="document('$mypath/myfile.xml')/connections"/>
<xsl:copy>
<xsl:apply-templates select="$lookupStore">
<xsl:with-param name="current" select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
...
<xsl:transform>
The problem is that I want to pass an absolute "base" path to the xsl, which I want to combine with the actual xml file name (myfile.xml). It seems to me that document considers file parameters relative to the location of the xsl.
Furthermore I remarked that the parameter is not picked up from the java code. I use JABX with the default Xalan XSLT processor (1.0)
I tried many variations of passing the parameters based on the other SO posts, but no success.

You need to construct a string then with the complete file URL: document(concat('file://', $mypath, '/myfile.xml')).

Related

Possibility of including Java code into XSLT1.0 file from web?

I'm wondering, is there any possibility to include java code into my XSLT1.0 file from other source than classpath (I dont have an acces into classpath files), like github for example or some web solution
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:xalan="http://xml.apache.org/xalan/java"
xmlns:test="http://github.com/user/test.java">
<xsl:output indent="yes"/>
<xsl:template match="/">
<out>
<xsl:value-of select="test:function()"/>
</out>
</xsl:template>
</xsl:stylesheet>

How to find a Xpath and add value to the tags in Camel

I'm trying to find an Xpath from exchange body and add a value to the tag.
<root>
<details1>
<Name>Ying</Name>
<status></status>
</details1>
<details2>
<Name>Ying</Name>
<status></status>
</details2>
</root>
I want to find xPath=root/details2/status From this exchange body and add value to the status. Since there are two occurances of status in the body String I will not be able to use String1.replace('<status></status>',<status>no</status>) Is there any way to use camel Xpath to find the correct tag and add the value?
With xpath you can find and read the correct tag. But how are you going to write it?
One solution could be to use the xpath inside an xlst tranformation.
So you can add the value you want to put in the element in a camel header "myHeader" and then use it in the xslt as an xsl:param .
Assuming the xml is in the inbox folder then
from("file:inbox?noop=true")
.setHeader("myHeader",constant("no"))
.to("xslt:mytransform.xslt")
.to("file:outbox/?fileName=out.xml");
Will put the value "no" in root/details2/status.
Where mytransform.xlst inside your /src/main/resources folder is like
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="myHeader"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/details2/status[. = '']">
<status><xsl:value-of select="$myHeader"/></status>
</xsl:template>
</xsl:stylesheet>
Xpath /root/details2/status[. = ''] matches empty status elements

Calling dateNow() with XALAN

am using XSL which is being called by JAVA method, I have tried to fix it by giving absolute path of a class but I don't think it will work because I didn't find anywhere calling a method in XSL using absolute class path so am trying by keeping in the server environment.here is my code,i have given class path and i have called method also .. but am not getting the proper output. Is this the correct way to call a method?
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xalan="http://xml.apache.org/xalan"
xmlns:datetime="java:com.ibm.date"
exclude-result-prefixes="xalan"
version="1.0">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes" indent="no" />
<xsl:strip-space elements="*" />
<xsl:template name="RootToAcknowledgeInventoryRequirement">
<xsl:param name="Root" />
<xsl:variable name="PromiseHeader" select="$Root/PromiseHeader" />
<xsl:variable name="today" select="datetime:dateNow()" />
<xsl:variable name="OrganizationCode">
<xsl:value-of select="$PromiseHeader/#OrganizationCode" />
</xsl:variable>
<_inv:AcknowledgeInventoryRequirement releaseID="">
<_wcf:ApplicationArea>
<oa:CreationDateTime xsi:type="udt:DateTimeType">
<xsl:value-of select="datetime:dateNow()" />
</oa:CreationDateTime>
</_wcf:ApplicationArea>
As you have mentioned XLAN processor, its version is XSLT 1.0.
So by default it doesn't possess any date-time function that brings it a current datetime value.
It is XSLT 2.0 that supports
<xsl:value-of select="current-dateTime()"/>
<xsl:value-of select="current-date()"/>
<xsl:value-of select="current-time()"/>
you should go with Machael Kay's Saxon latest version for that.
Now for work around, EXSLT has been into good practice:
Download code from this link, copy date.xsl to your xsl file's location. Import it in your xsl.
<xsl:stylesheet version="1.0"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="date"
...>
<xsl:import href="date.xsl" />
<xsl:template match="//root">
<xsl:value-of select="date:date-time()"/>
</xsl:template>
</xsl:stylesheet>
solution 2: Pass Datetime value as param to XSL. Use it as variable wherever required.

How to call named XSLT template from java

I have XSLT file with named templates:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template name="A">...</xsl:template>
<xsl:template name="B">...</xsl:template>
<xsl:template name="C">...</xsl:template>
</xsl:stylesheet>
How can I call named templates (A,B,C) from java code (I need this just for testing)?
XSLT 1.0 doesn't allow this. XSLT 2.0 does, but the API depends on the product you are using (JAXP never caught up with XSLT 2.0). For Saxon, use the s9api method XsltTransformer.setInitialTemplate().

Delete XSL output file generation at runtime

I am writing text output files reading an XML file using XSL.
Here i am trying to check weather a particular content is available in the source XML and write that content to a file if available.
But if the content is not available ( not fulfilling "<XSL:if>" condition), then output file would be an empty file.
So I want to add an else condition and in that else condition to avoid XSL output file being created at runtime.
Any body having any clue?
<xsl:message terminate="yes"> wont help because it does generate the output but only terminating the further processing of XSL.
Can any body help or even suggest any other approach to be taken in java code even without deleting files after they have created. [By reading them and identifying empty files]
Currently I am using java to read the created empty files and delete them explicitly. Thanks in adavance.
I will give two examples how this can be done -- the second is what I recommend:
Suppose we have this XML document:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
and we want to produce another one from it, in which the num elements with even numbers are "deleted".
One way of doing this is:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<nums>
<xsl:apply-templates/>
</nums>
</xsl:template>
<xsl:template match="num">
<xsl:choose>
<xsl:when test=". mod 2 = 1">
<num><xsl:value-of select="."/></num>
</xsl:when>
<!-- <xsl:otherwise/> -->
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The wanted result is produced:
<nums>
<num>01</num>
<num>03</num>
<num>05</num>
<num>07</num>
<num>09</num>
</nums>
Do notice: For "not doing anything" you even don't need the <xsl:otherwise> and it is commented out.
A better solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="num[. mod 2 = 0]"/>
</xsl:stylesheet>
This produces the same correct result.
Here we are overriding the identity rule with a template matching num elements with even value and with empty body -- which does the "delete".
Do notice:
Here we don't use any "if-then-else" explicit instructions at all -- just Xtemplate pattern matching, which is the most distinguishing feature of XSLT.

Categories

Resources