Facing issues while calling java method from xslt which uses fop - java

I'm using fop to convert xml to pdf, so for that I have written an xslt code.
In the same xslt, I have used java code but somehow I get an error stating nosuchmethodexception : couldn't find method org.apache.xml.utils.NodeVector.input([ExpressionContext,]).
But my java code is a user defined code which is in a different package.
My xml has local_curr attribute.
My java class name is XMLData.
Package is com.pdf
Java Method is input which takes a String value and returns a String
xslt code :
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:java="com.pdf.XMLData">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<!-- Defining Page Layout -->
<fo:layout-master-set>
<fo:simple-page-master master-name="A3-portrait"
page-height="29.7cm" page-width="40.0cm" margin="2cm">
<fo:region-body margin-bottom="20mm" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A3-portrait">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" width="100%" border-width="1mm"
border-collapse="separate">
<fo:table-row>
<fo:table-cell background-color="#F79F81"
border-width="0.1mm" border-style="solid">
<fo:block wrap-option="wrap" font-size="15pt"
padding="5pt" text-align="right">
<xsl:value-of select="java:input(#local_curr)" />
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>

The problem is that #local_curr probably does not return the type your java method is expecting.
You need to parse it for example as a string
<xsl:value-of select="java:input(string(#local_curr))" />
Or as a number
<xsl:value-of select="java:input(number(#local_curr))" />
The NoSuchMethodException was thrown because no method was found with the given type as argument.

Thanks for the help.
It is resolved. Actually I have to add my jar file in the batch file of fop which resolved my problem.
Thanks...

Related

CDATA XML masking with XSLT should return same XML with few masked fields

I have a requirement of masking few fields in XML of CDATA inside XML with XSLT.
So the resultant XML should be same like the input XML but few fileds are masked with XSLT.
I followed this link which is masking as expected but producing XML is in different format.
I tried many other solutions from SO, they are almost outputing the new XML/HTML in other format which is different from the input XML.
Please check the following example for better understading.
Input XML with CDATA content.
<XML>
<LogLevel>info</LogLevel>
<Content><![CDATA[ <Msg>
<AccountNo>2701000098983</AccountNo>
<ApplName>Testing</ApplName>
</Msg>]]></Content>
<Date>20140909</Date>
</XML>
Output XML should be:
<XML>
<LogLevel>info</LogLevel>
<Content><![CDATA[ <Msg>
<AccountNo>XXXXXXXXXX983</AccountNo>
<ApplName>Testing</ApplName>
</Msg>]]></Content>
<Date>20140909</Date>
</XML>
Edit:
I used the following XSLT
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:choose>
<xsl:when test="contains(.,'<AccountNo>')">
<!-- This is the CDATA that I want to mask and write back out as CDATA -->
<xsl:variable name="tcontent">
<xsl:value-of
select="substring-after(substring-before(.,'</AccountNo>'),'<AccountNo>') " />
</xsl:variable>
<xsl:text disable-output-escaping="yes"><![CDATA[<AccountNo></xsl:text>
<xsl:call-template name="maskVariable">
<xsl:with-param name="tvar" select="$tcontent" />
</xsl:call-template>
<xsl:text disable-output-escaping="yes"></AccountNo>]]></xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:copy />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="maskVariable">
<xsl:param name="tvar" />
<xsl:variable name="length" select="string-length($tvar)" />
<xsl:choose>
<xsl:when test="$length > 3">
<xsl:value-of
select="concat ('************', substring($tvar,$length - 1, 2))" />
</xsl:when>
<xsl:when test="$length > 1">
***
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:template>
Output of using this XSLT is :
<LogLevel>info</LogLevel>
<Content><![CDATA[<AccountNo>************02</AccountNo>]]></Content>
<Date>20140909</Date>
Here in output, only masked output of is displaying.
How to make other part of the code to get displayed ?
Please give me some idea how to do it ?
Any help is highly appreciated.
Why don't you try:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Content">
<xsl:copy>
<xsl:value-of select="substring-before(.,'<AccountNo>')" />
<xsl:text><AccountNo></xsl:text>
<xsl:variable name="acct-num" select="substring-before(substring-after(.,'<AccountNo>'), '</AccountNo>')" />
<xsl:value-of select="concat('************', substring($acct-num, string-length($acct-num) - 2))" />
<xsl:text></AccountNo></xsl:text>
<xsl:value-of select="substring-after(.,'</AccountNo>')" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Applied to your input, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<XML>
<LogLevel>info</LogLevel>
<Content> <Msg>
<AccountNo>************983</AccountNo>
<ApplName>Testing</ApplName>
</Msg></Content>
<Date>20140909</Date>
</XML>
Alternatively, you could use:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" cdata-section-elements="Content"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Content">
<xsl:copy>
<xsl:variable name="content">
<xsl:value-of select="substring-before(.,'<AccountNo>')" />
<xsl:text><AccountNo></xsl:text>
<xsl:variable name="acct-num" select="substring-before(substring-after(.,'<AccountNo>'), '</AccountNo>')" />
<xsl:value-of select="concat('************', substring($acct-num, string-length($acct-num) - 2))" />
<xsl:text></AccountNo></xsl:text>
<xsl:value-of select="substring-after(.,'</AccountNo>')" />
</xsl:variable>
<xsl:value-of select="$content" disable-output-escaping="yes"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
to produce:
<?xml version="1.0" encoding="UTF-8"?>
<XML>
<LogLevel>info</LogLevel>
<Content><![CDATA[ <Msg>
<AccountNo>************983</AccountNo>
<ApplName>Testing</ApplName>
</Msg>]]></Content>
<Date>20140909</Date>
</XML>
although this might not work with every processor (tested to work with Xalan 2.7.1: http://xsltransform.net/jyH9rMk).
The stuff inside the CDATA section is XML disguised as text. XSLT is good at transforming XML, it's not so good at transforming text, especially text with a complex grammar. So my approach would be: extract the text from the outer XML document, parse it as XML, transform it using XSLT (real XSLT that works on nodes rather than on markup), serialize it back to text, then stuff the text back into the original (outer) XML document.
Raw XSLT 1.0 can't do this within a single stylesheet. You need the functions parse() and serialize() to turn lexical XML into a node tree, and back again. These are available as extensions in some processors (such as Saxon), they become available as standard functions in XPath 3.0, and they can be written as simple extension functions (e.g. in Javascript) code in most other processors.

javax.xml.transform.TransformerException: Could not find function: unparsed-text

I am using Apache FOP for PDF generation.I want to use unparsed-text() function to read non-xml document in XSL file.
After writing that function i got this error.
This is my XSL file.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:f="Functions">
<xsl:variable name="properties" select="unparsed-text('file.properties')" as="xs:string"/>
<xsl:function name="f:getProperty" as="xs:string?">
<xsl:param name="key" as="xs:string"/>
<xsl:variable name="lines" as="xs:string*" select="
for $x in
for $i in tokenize($properties, '\n')[matches(., '^[^!#]')] return
tokenize($i, '=')
return translate(normalize-space($x), '\', '')"/>
<xsl:sequence select="$lines[index-of($lines, $key)+1]"/>
</xsl:function>
<xsl:template match=" EmployeeData">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="20cm" page-width="10.5cm" margin-left="0.2cm"
margin-right="0.2cm">
<fo:region-body margin-top="0.5cm" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<xsl:variable name="lang" select="language" />
<fo:flow flow-name="xsl-region-body">
From Properties File <xsl:value-of select="f:getProperty('language')"/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
How can i remove this error? Or give me any alternative for that if possible.
Thank you.
The error suggests you are using an XSLT 1.0 processor to run the XSLT. unparsed-text is only supported by XSLT 2.0 processors like Saxon 9.

Generate PDF from a big image using Apache FOP

I would like to generate a PDF from an image, using Apache FOP and XSLT. However, if image s bigger, then PDF document page, then it only gets as much space as it is available on the page (including right and bottom margin). So, part of the image is out of page bounds.
Is this possible to setup fop so that if image can't be fitted into the page it is automatically splitted into the multiple pages?
Here is my xslt template:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:java="http://xml.apache.org/xslt/java"
xmlns:dp="http://www.dpawson.co.uk"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="Functions"
xmlns:xdt="http://www.w3.org/2005/02/xpath-datatypes"
exclude-result-prefixes="java">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes" />
<xsl:param name="image-print-path" />
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simpleA4"
page-height="29.7cm" page-width="21cm" margin-top="2cm"
margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
<fo:region-body margin-top="20pt" margin-bottom="35pt" />
<fo:region-before extent=".5in"/>
<fo:region-after extent=".5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simpleA4">
<fo:static-content flow-name="xsl-region-before" text-align="left">
<fo:block font-size="10pt">
Print
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block font-size="10pt" text-align="left">
something else
</fo:block>
<!-- TODO: add current date, page number -->
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="10pt" page-break-after="always">
<fo:external-graphic src="{$image-print-path}"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
Doesn't look like there's anything in the spec that can format in the way you need. This leaves you with a few options:
check the graphic before you inject it into your XSL workflow and cut it up into a number of images to use across multiple pages
inspect the graphic to determine it's dimensions and create a page size big enough to contain it, and leave the slicing to printers
set content-width to scale-down-to-fit to show the entire graphic on a single page

Java setParameter in XSL file

I have a problem with printing PDF file from a Java project that is adding parameters in the XLS file. The project read the XML file, then he is generate a PDF file from the XSL style sheet. See below for the content of the files.
As you see in the XLS file I want to specified at “studentNumber”, but the problem is that is specified “studentNumber” need to set in the Java project. I have tried a lot of thing and search on internet but I cannot find the answer.
Any idea want I need to change to make this project proper.
XML file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="studentResultXLS.xsl"?>
<cursus>
<enroll>
<studentnumber>s484766</studentnumber>
<cursuscode>ISDTCEX.B627</cursuscode>
<enrolldate dateformat="eejjmmdd">20111121</enrolldate>
<acquire>ja</acquire>
<grade>4</grade>
<result></result>
</enroll>
<enroll>
<studentnumber>s484766</studentnumber>
<cursuscode>ISDTSIP.T470</cursuscode>
<enrolldate dateformat="eejjmmdd">20111116</enrolldate>
<acquire>ja</acquire><grade>2</grade>
<result></result>
</enroll>
<enroll>
<studentnumber>s484767</studentnumber>
<cursuscode>ISDTSIP.T470</cursuscode>
<enrolldate dateformat="eejjmmdd">20111116</enrolldate>
<acquire>ja</acquire><grade>2</grade>
<result></result>
</enroll>
</cursus>
XLS file:
<xsl:param name="studentnumber"/>.....
<fo:table-body>
<xsl:for-each select="/cursus/enroll[studentnumber='s484766']">
<fo:table-row>
<fo:table-cell>
<fo:block> <xsl:value-of select="studentnumber"/> </fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block> <xsl:value-of select="cursuscode"/> </fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
Java code:
transformer.setParameter("studentnumber", "s484766");
For reading the parameter value, you need to prefix it with a $ sign:
<xsl:value-of select="$studentnumber"/>

I can't change my Font Family using Apache FOP

I am trying to use fop Quick Start Guide to print a simple PDF file from a simple XML file and it works fine. but when I change <name>Frank</name> to <name>امیررضا</name> (change name to other encoding) I get #### in my printed PDF. I search through the Internet and couldn't find any feasible solution. I use many config files here are some of my them:
I use this command for creating pdf:
fop -c cfg.xml -xml name.xml -xsl name2fo.xsl -pdf name.pdf
When I use this command I get below warning:
WARNING: xHeight value could not be determined. The font may not work as
Sep 15, 2011 9:15:37 AM org.apache.fop.events.LoggingEventListener proce
WARNING: Glyph "╙" (0x633, afii57427) not available in font "Helvetica".
Sep 15, 2011 9:15:37 AM org.apache.fop.events.LoggingEventListener proce
WARNING: Glyph "╘" (0x634, afii57428) not available in font "Helvetica".
1- name.xml contains:
<name>امیررضا</name>
2-name2fo.xsl contains:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="A4-portrait"
page-height="29.7cm" page-width="21.0cm" margin="2cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4-portrait">
<fo:flow flow-name="xsl-region-body">
<fo:block>
Hello, <xsl:value-of select="name"/>!
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
3- have try many different config file (cfg.xml).
3.1:
<fop version="1.0">
<renderers>
<renderer mime="application/pdf">
<fonts>
<substitutions>
<substitution>
<from font-family="Helvetica" />
<to font-family="SansSerif"/>
</substitution>
</substitutions>
<referenced-fonts>
<match font-family=".*"/>
</referenced-fonts>
<!-- register all the fonts found in a directory and all of its sub directories (use with care) -->
<directory recursive="true">G:\....\fop\fop-1.0\Core14_AFMs</directory>
<!-- automatically detect operating system installed fonts -->
<auto-detect/>
<font embed-url="C:\WINDOWS\Fonts\times.ttf">
<font-triplet name="Times New Roman" style="normal" weight="normal"/>
</font>
</fonts>
</renderer>
</renderers>
</fop>
3.2:
<fop version="1.0">
<renderers>
<renderer mime="application/pdf">
<fonts>
<substitutions>
<substitution>
<from font-family="Helvetica" />
<to font-family="SansSerif"/>
</substitution>
</substitutions>
<referenced-fonts>
<match font-family=".*"/>
</referenced-fonts>
<!-- automatically detect operating system installed fonts -->
<auto-detect/>
</fonts>
</renderer>
</renderers>
</fop>
3.3: ......
The result output is:
Hello, #######!
Can anyone help me fix this?
Support for languages written with right-to-left scripts such as Arabic & Hebrew and full bidi support was added in Apache FOP 1.1. Based on the date of this question, an older Apache FOP version was used. For more information, see http://xmlgraphics.apache.org/fop/trunk/complexscripts.html.
I have never used Apache FOP but I found this article that allows you to create multiple language PDF.
Creating Multiple Language PDFs using Apache FOP
I would recommend that you use HelveticaWorld thatcontains arabic characters too or if you create the FOP input dynamically, then you can use Velocity or Freemarker variables to store the Font name.
I solve the problem by add font-family in XSL code:
name2fo.xsl after changes contains:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="A4-portrait"
page-height="29.7cm" page-width="21.0cm" margin="2cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4-portrait">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="10pt" font-family="Tahoma">
Hello, <xsl:value-of select="name"/>!
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
But I still have problem which is my Farsi character printed in reverse order. I mean if I want to print "Hello" it was printed "oellH" (you can imagine Hello is written in Farsi character) and also have a second problem that is the character was printed separated.

Categories