Calling dateNow() with XALAN - java

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.

Related

If regEx is bad for matching XML, what is the correct way?

I was trying to do a simple string delete in XML.
I want to delete something like the following.
<A>
<B>Test Name</B>
</A>
Has to work with all possible XML, though.
<Test><A><B>Test Name</B></A></Test>
<Test ><A ><B >Test Name</B ></A ></Test >
<Test>
<A>
<B>Test Name</B>
</A>
</Test>
etc, etc.
The regularEX I got so far, is simply:
<A>\s*(\r\n|\r|\n)*\s*<B>Test Name<\/B>\s*(\r\n|\r|\n)*\s*<\/A>
Everyone always says regEx is bad for match XML, which it clearly is. So what should I use instead.
GC_
The best approach for this case would be using XSLT. And even with XSLT-1.0 this is simple (You can use the Java XSLT-processor, linux'es xsltproc or any other XSLT processor; every XSLT processor supports at least XSLT-1.0):
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<!-- identity template - matches everything except the things matched by other templates -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Removes the elements you do not want -->
<xsl:template match="A[B[normalize-space(.)='Test Name']]" />
</xsl:stylesheet>
The output of your sample case (with a hypothetical root element) would be
<Test/>
<Test/>
<Test/>
Trying to use RegEx would be error-prone and no good-practice at all.
Why would you make it complicated if it could be so easy?

How can I join 2 XML in 1 XSL

I have two .xml files which need to be joined
The first file is Song.xml as the following:
<Songs>
<Song>
<SongID>1</SongID>
<SongName>We dont talk anymore</SongName>
<Author>M-TP</Author>
<UploadBy>admin</UploadBy>
<GerneCode>1</GerneCode>
</Song>
</Songs>
and the Gerne.xml which generate from a schema
<ns2:gernes xmlns="http://www.w3.org/2001/XMLSchema/playlist" xmlns:ns2="https://xml.netbeans.org/schema/genses">
<ns2:gerne>
<GerneCode>1</GerneCode>
<GerneName>Pop</GerneName>
<Image>img-pop.jpg</Image>
</ns2:gerne>
</ns2:gerne>
I want to join these .xml files inside a XSL, to which will add the GerneName for every Song that match the GerneName inside the Gerne.xml.
The result im trying to get should be like this:
<Songs>
<Song>
<SongID>1</SongID>
<SongName>We dont talk anymore</SongName>
<Author>M-TP</Author>
<UploadBy>admin</UploadBy>
<GerneName>Pop</GerneName>
<GerneCode>1</GerneCode>
</Song>
</Songs>
Can anyone help me with this? Any e.g or keywords what should I look up for this problem?
Assuming you are limited to XSLT 1.0, you can do:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:pl="http://www.w3.org/2001/XMLSchema/playlist"
xmlns:ns2="https://xml.netbeans.org/schema/genses"
exclude-result-prefixes="pl ns2">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="lookup-path" select="'Gerne.xml'" />
<xsl:key name="genre" match="ns2:gerne" use="pl:GerneCode" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GerneCode">
<xsl:variable name="code" select="." />
<!-- switch context to the other file -->
<xsl:for-each select="document($lookup-path)">
<GerneCode>
<xsl:value-of select="key('genre', $code)/pl:GerneName" />
</GerneCode>
</xsl:for-each>
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
This is assuming you are telling your XSLT processor to process the Song.xml file, and passing the path to the Gerne.xml file as a parameter.
Note that the Gerne.xml document you have posted is not well-formed XML (no </ns2:gernes> closing tag).
BTW, the correct term is "genre" - not "gerne" or "gense".

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

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')).

Using XSLT to recursively load relative XML files and apply transformation

I have a xml file whose structure looks like this:
<root>
<includes>
<includeFile name="../other/some_xml.xml"/>
</includes>
<itemlist>
<item id="1" >
<selections>
<selection name="one" />
</selections>
</item>
</itemlist>
The xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output method="xml" indent="yes" xalan:indent-amount="4" />
<xsl:template match="/">
<xsl:element name="ItemList">
<xsl:if test="root/item">
<xsl:call-template name="templ" />
</xsl:if>
</xsl:element>
</xsl:template>
<xsl:template name="templ">
<xsl:element name="ItemList">
<xsl:for-each select="root/itemlist/item">
<xsl:element name="Item">
<xsl:element name="ItemIdentifier">
<xsl:value-of select="#id" />
</xsl:element>
<xsl:element name="Condition">
<xsl:value-of select="selections/selection[1]/#name" />
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
I created one XSLT which i am using to filter out items. The problem is that for every file, i have to check if it contains the includefile tag, which is a relative path pointing to a similar xml, and if it does, i need to collect items from that file also, recursively. For now i transformed the xml using my xslt and then i have to parse the xml to look for includefile tag. This solution doesn't look elegant and i was wondering if all of it could be done via xslt.
The XSLT document function in XSLT 1.0 and in XSLT 2.0 additionally the doc function allow you to pull in further documents, processing is then simply possible with matching templates. So consider to move your XSLT coding style to write matching templates and apply-templates, then you can easily do
<xsl:template match="includes/includeFile">
<xsl:apply-templates select="document(#name)/*"/>
<xsl:template>
and then you simply need to make sure the <xsl:template match="root">...</xsl:template> creates the output you want.

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