Will a Single XSLT file solve this issue..or...? - java

Below is my XML File -
<CVs>
<CV>
<Name>ABC</Name>
<Address></Address>
<Introduction></Introduction>
<CompSkills>Java, XSLT, XPATH, XML, Oracle, VB.NET</CompSkills>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<CV>
<CV>
<Name>XYZ</Name>
<Address></Address>
<Introduction></Introduction>
<CompSkills>Java, XSLT, XPATH, XML, JSP, HTML</CompSkills>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<CV>
</CVs>
below is the XSLT file - a short version to get an idea
<xsl:template match="Name">
<table align='center' width='800' style="font-family:tahoma; font-size:13pt;">
<tr><td>
<xsl:apply-templates/>
</td></tr>
</table>
</xsl:template>
<xsl:template match="Experience">
<table align='center' width='800' style="font-family:tahoma; font-size:13pt;">
<tr><td>
<xsl:apply-templates/>
</td></tr>
</table>
</xsl:template>
I am using Java as front-end. To display the output in HTML format I have an XSLT file. This XSLT file is a standard one ie; it displays all the CVs.
Now what I have to do is use a ListBox with Names of all candidates and when clicked on a particular name ONLY his CV should get displayed. I have coded the Java part to display the names of the candidates into the ListBox. Now have some trouble with displaying the CV of the selected candidate in HTML format.
The current XSLT file is displaying all the CVs. So Will I need another XSLT file which use parameter passed from the program and display its details..? If yes then some help on how to do this... ??
Thanks in advance - John

What you can do is add an xsl:param to your XSLT and give it a default value; 'All' for example. That way by default it will display all CVs.
If you need to display a single CV based on a Name, you can pass that value (from your ListBox) in your xsl:param to display only that CV.
Here's an example xsl:param and the xsl:template needed to display the CVs:
<xsl:param name="pName" select="'All'"/>
<xsl:template match="CV">
<xsl:if test="$pName = 'All' or Name = $pName">
<xsl:apply-templates/>
</xsl:if>
</xsl:template>
If you wanted to display only the XYZ CV, you would just use the value XYZ for the pName param when you called the XSLT.

To give you an idea how this can be done, here is a complete solution that extracts all or just the wanted CV element (no HTML formatting is done as this isn't relevant to the question):
<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="pName" select="'XYZ'"/>
<xsl:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="CV">
<xsl:if test="$pName = Name or $pName='*'">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied to the provided XML document (corrected to a well-formed one):
<CVs>
<CV>
<Name>ABC</Name>
<Address></Address>
<Introduction></Introduction>
<CompSkills>Java, XSLT, XPATH, XML, Oracle, VB.NET</CompSkills>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
</CV>
<CV>
<Name>XYZ</Name>
<Address></Address>
<Introduction></Introduction>
<CompSkills>Java, XSLT, XPATH, XML, JSP, HTML</CompSkills>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
<Experience>
<Profile></Profile>
<Duration></Duration>
<Info></Info>
</Experience>
</CV>
</CVs>
the wanted, correct (just the CV with Name XYZ is extracted) is produced:
<CVs>
<CV>
<Name>XYZ</Name>
<Address/>
<Introduction/>
<CompSkills>Java, XSLT, XPATH, XML, JSP, HTML</CompSkills>
<Experience>
<Profile/>
<Duration/>
<Info/>
</Experience>
<Experience>
<Profile/>
<Duration/>
<Info/>
</Experience>
<Experience>
<Profile/>
<Duration/>
<Info/>
</Experience>
</CV>
</CVs>
Explanation:
The wanted name or "*" must be passed externally as a global parameter (in this case named pName) to the transformation. Read your XSLT processor documentation how this must be done, as this is implementation-dependent.

Related

Setting secure processing in TransformerFactory leads to Problems in XSL

I am generating a PDF document with XML file as input using Apache FOP 2.4.
To prevent XXE-Attacks I need to set the secure processing feature (FEATURE_SECURE_PROCESSING) in TransformerFactory:
InputStream xslTransformer = getClass().getClassLoader().getResourceAsStream("foo.xsl");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setFeature(FEATURE_SECURE_PROCESSING, true);
Transformer transformer = transformerFactory.newTransformer(new StreamSource(xslTransformer));
transformer.transform(new DOMSource(), new SAXResult(fop.getDefaultHandler()));
After setting this feature I can't generate any PDF document and I'm getting warnings:
SystemId Unknown; Line #49; Column #99; "master-name" attribute is not allowed on the fo:simple-page-master element!
SystemId Unknown; Line #49; Column #99; "initial-page-number" attribute is not allowed on the fo:simple-page-master element!
SystemId Unknown; Line #49; Column #99; "page-height" attribute is not allowed on the fo:simple-page-master element!
SystemId Unknown; Line #49; Column #99; "page-width" attribute is not allowed on the fo:simple-page-master element!
etc ...
Here is a section of XSL file (foo.xsl):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf">
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="A4-portrait" initial-page-number="1"
page-height="29.7cm" page-width="21.0cm" margin-top="0cm"
margin-left="1cm" margin-right="1.3cm" margin-bottom="0cm">
<fo:region-body margin-top="2.2cm" margin-bottom="1.2cm" margin-left="1.3cm"/>
<fo:region-before region-name="xsl-region-before" extent="2.2cm"/>
<fo:region-after region-name="xsl-region-after" extent="1.2cm"/>
<fo:region-start region-name="xsl-region-start" extent="1.3cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4-portrait" font-family="Consolas" font-size="11">
<fo:flow flow-name="xsl-region-body">
<fo:block linefeed-treatment="preserve" font-weight="bold">
foo
</fo:block>
<fo:block linefeed-treatment="preserve">
bar
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
How should I use this feature and make it work? Java version is 8.
This is due to xalan-2.7.2.
Here is the bug in Xalan-J
Switching to xalan-2.7.1 or earlier will solve your problem.
You may have to force exclusions for xalan on an Apache-FO dependency.
You can also overwrite with 2.7.2_3, which patches this problem.
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<artifactId>org.apache.servicemix.bundles.xalan</artifactId>
<version>2.7.2_3</version><!--$NO-MVN-MAN-VER$-->
</dependency>
Use of <!--$NO-MVN-MAN-VER$--> prevents overrides.

Most performative way to go through an XML transformation - Java

I'm new with java, and I want an opinion for the community.
I Have a huge XML, that contains a lot of information. Actually, this XML has approximately 140Mb of information.
In this XML I have a lot of information that is no more valid, so I need to do filter and use only the valid one, to check this I need to cross information between node, to check if deletion is needed or not. In some cases, the entire father(main) node needs to be deleted.
I'm already doing it with dom parse, using loops, inside the loops I save in variables and cross the information to check, and delete the actual node or the entire father node.
Basically, the structure is like this:
<source>
<main>
<id>98567</id>
<block_information>
<name>Block A</name>
<start_date>20120210</start_date>
<end_date>20150210</end_date>
</block_information>
<block_information>
<name>Block A.01</name>
<start_date>20150210</start_date>
<end_date>20251005</end_date>
</block_information>
<city_information>
<name>Manchester</name>
<start_date>20150210</start_date>
<end_date>20150212</end_date>
</city_information>
<city_information>
<name>New Manchester</name>
<start_date>20150212</start_date>
<end_date>20251005</end_date>
</city_information>
<phone>
<type>C</type>
<number>987466321</number>
<name></name>
</phone>
<phone>
<type>P</type>
<number>36547821</number>
<name></name>
</phone>
</main>
<main>
<id>19587</id>
<block_information>
<name>Che</name>
<start_date>20090210</start_date>
<end_date>20100210</end_date>
</block_information>
<block_information>
<name></name>
<start_date>20100210</start_date>
<end_date>20351005</end_date>
</block_information>
<city_information>
<name></name>
<start_date>20150210</start_date>
<end_date>20150212</end_date>
</city_information>
<city_information>
<name>No Name</name>
<start_date>20150212</start_date>
<end_date>20191005</end_date>
</city_information>
<phone>
<type>C</type>
<number>987466321</number>
<name>Mom</name>
</phone>
<phone>
<type>P</type>
<number>36547821</number>
<name></name>
</phone>
</main>
</source>
The output is like this:
<result>
<main>
<id>98567</id>
<block_name>Block A.01</block_name>
<city_name>New Manchester</city_name>
<cellphone></cellphone>
<phone>36547821</phone>
<contact_phone></contact_phone>
<contact_phone_name></contact_phone_name>
</main>
</result>
For the information go out in result, is mandatory that there is one <block_information> and <city_information> valid (<start_date> less than actual date and <end_date> bigger than actual date), and the <name...> is needed for both.
If there is none, or more than one valid, the <main> will be deleted.
For the phone number, <type> ['C' is for contact, 'P' for personal phone, 'M' for mobile]. So if the <type> is 'C' but there is no value in <name> the phone do not go to result. 'P' go to <phone> and 'M' go to <cellphone>.
I want your considerations on what is the best way to do that in the most performative way, and to anyone can do adjustment before in an easy way if it's needed.
thanks in advance for the inputs!
as asked by #kjhughes, I put some values on the sample XML, and some filters that I need to do. Thanks!
ps.: the XML structure used as an example is TOO simple compared to the actual one, there are a lot more complex types.
I would go with the following approach:
find a library that lets you stream the xml (file or inputsream) and produce a Stream<Main>
process the Stream<Main> and filter each Main node according to your validation logic
depending if you are I/O or CPU bottlenecked use a .parallel() stream to process the stream (read: test if .parallel() helps you in any way)
This will suffice for any sane performance requirements in the context of XML parsing (I guess?). Google for Java XML Stream and go from there (or maybe this stackoverflow question can give some pointers)
XSLT is a transformation language existing since 1999 which has now three versions, 1.0, 2.0, and 3.0, the latest version published as W3C recommendation in 2017 and supported on the Java platform by Saxon 9.8 and later, available in the open-source HE edition on Sourceforge and Maven. The use of XSLT 1 is supported in the Oracle/Sun Java JRE by incorporating Apache Xalan.
So instead of using DOM you have the option to use XSLT, here is an example using XSLT 3 (online at https://xsltfiddle.liberty-development.net/bFN1yab/0):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:function name="mf:date" as="xs:date">
<xsl:param name="input-date" as="xs:string"/>
<xsl:sequence
select="xs:date(replace($input-date, '([0-9]{4})([0-9]{2})([0-9]{2})', '$1-$2-$3'))"/>
</xsl:function>
<xsl:function name="mf:select-valid-info" as="element()*">
<xsl:param name="infos" as="element()*"/>
<xsl:sequence
select="$infos[name/normalize-space()
and mf:date(start_date) lt current-date()
and mf:date(end_date) gt current-date()]"/>
</xsl:function>
<xsl:function name="mf:valid-main" as="xs:boolean">
<xsl:param name="main" as="element(main)"/>
<xsl:sequence
select="let $valid-blocks := mf:select-valid-info($main/block_information),
$valid-cities := mf:select-valid-info($main/city_information)
return count($valid-blocks) eq 1 and count($valid-cities) eq 1"/>
</xsl:function>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="main[not(mf:valid-main(.))]"/>
<xsl:template match="main[mf:valid-main(.)]">
<xsl:copy>
<xsl:apply-templates
select="id,
mf:select-valid-info(block_information)/name,
mf:select-valid-info(city_information)/name,
phone"/>
</xsl:copy>
</xsl:template>
<xsl:template match="block_information/name | city_information/name">
<xsl:element name="{substring-before(local-name(..), '_')}_name">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="main/phone[type = 'C']">
<contact_phone>
<xsl:value-of select="number[current()/normalize-space(name)]"/>
</contact_phone>
<contact_name>
<xsl:value-of select="name"/>
</contact_name>
</xsl:template>
<xsl:template match="main/phone[type = 'P']">
<phone>
<xsl:value-of select="number"/>
</phone>
</xsl:template>
<xsl:template match="main/phone[type = 'M']">
<cellphone>
<xsl:value-of select="number"/>
</cellphone>
</xsl:template>
</xsl:stylesheet>
I hope I have grasped the conditions for the main elements, I have not been able to quite understand the rules for the various phone data, but the code is meant as an example anyway.
Of course performance depends very much on the implementation but I think that XSLT is a more structured and maintainable way than doing DOM coding.
If you can afford it you can also look into Saxon 9.8 or 9.9 EE which supports streaming XSLT 3 where, with some rewrites of above code, you could have an XSLT based approach to stream forwards only through the huge document, materializing main elements as element nodes you transform while keeping the memory footprint low as that approach, in comparison to DOM or normal XSLT processing, doesn't parse the whole XML document first into a complete in-memory tree structure:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode streamable="yes" on-no-match="shallow-copy"/>
<xsl:template match="source">
<xsl:copy>
<xsl:apply-templates select="main!copy-of()" mode="main"/>
</xsl:copy>
</xsl:template>
<xsl:output indent="yes"/>
<xsl:function name="mf:date" as="xs:date">
<xsl:param name="input-date" as="xs:string"/>
<xsl:sequence
select="xs:date(replace($input-date, '([0-9]{4})([0-9]{2})([0-9]{2})', '$1-$2-$3'))"/>
</xsl:function>
<xsl:function name="mf:select-valid-info" as="element()*">
<xsl:param name="infos" as="element()*"/>
<xsl:sequence
select="$infos[name/normalize-space()
and mf:date(start_date) lt current-date()
and mf:date(end_date) gt current-date()]"/>
</xsl:function>
<xsl:function name="mf:valid-main" as="xs:boolean">
<xsl:param name="main" as="element(main)"/>
<xsl:sequence
select="let $valid-blocks := mf:select-valid-info($main/block_information),
$valid-cities := mf:select-valid-info($main/city_information)
return count($valid-blocks) eq 1 and count($valid-cities) eq 1"/>
</xsl:function>
<xsl:mode name="main" on-no-match="shallow-copy"/>
<xsl:template match="main[not(mf:valid-main(.))]" mode="main"/>
<xsl:template match="main[mf:valid-main(.)]" mode="main">
<xsl:copy>
<xsl:apply-templates
select="id,
mf:select-valid-info(block_information)/name,
mf:select-valid-info(city_information)/name,
phone" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="block_information/name | city_information/name" mode="main">
<xsl:element name="{substring-before(local-name(..), '_')}_name">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="main/phone[type = 'C']" mode="main">
<contact_phone>
<xsl:value-of select="number[current()/normalize-space(name)]"/>
</contact_phone>
<contact_name>
<xsl:value-of select="name"/>
</contact_name>
</xsl:template>
<xsl:template match="main/phone[type = 'P']" mode="main">
<phone>
<xsl:value-of select="number"/>
</phone>
</xsl:template>
<xsl:template match="main/phone[type = 'M']" mode="main">
<cellphone>
<xsl:value-of select="number"/>
</cellphone>
</xsl:template>
</xsl:stylesheet>

How to modify the attribute values in XML file using Java

I need to modifies the XML, I have a parent tag parts which contain child tag part and Child tag sub child tags, They are Item,
brand, Manufacturer, Model, Cost. And it have a Brands tag and it contain Tag name called Brand. I need to change the brand attribute
(identifier) value. If the Brand child tag Contain (textcontent) text (Geforce_GT) is equal to the text in part tag : brand child tag : text
(Geforce_GT). Then Id attribute value of brand tag in part tag should assign to the Identifeir attribute in Brand tag child of Brands Parent tag.
<?xml version="1.0" ?>
<!DOCTYPE PARTS SYSTEM "parts.dtd">
<?xml-stylesheet type="text/css" href="xmlpartsstyle.css" ?>
<PARTS>
<TITLE>Computer Parts</TITLE>
<PART>
<ITEM id="CP1809_E1">Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST>123.00</COST>
</PART>
<PART>
<ITEM id="CP1809_E2">Video Card</ITEM>
<BRAND id="CP1809_B1">Geforce_GT</BRAND>
<MANUFACTURER>ATI</MANUFACTURER>
<MODEL>All-in-Wonder Pro</MODEL>
<BRAND id="CP1809_B2">730_64-BIT</BRAND>
<COST>160.00</COST>
</PART>
<PART>
<ITEM id="CP1809_E3">Sound Card</ITEM>
<MANUFACTURER>Creative Labs</MANUFACTURER>
<MODEL>Sound Blaster Live</MODEL>
<COST>80.00</COST>
</PART>
<PART>
<ITEM id="CP1809_E3">inch Monitor</ITEM>
<MANUFACTURER>LG Electronics</MANUFACTURER>
<MODEL>995E</MODEL>
<COST>290.00</COST>
</PART>
<BRANDS>
<BRAND identifier="CP1809_E2">
<TEXTCONTENT>Geforce_GT</TEXTCONTENT>
</BRAND>
<BRAND identifier="CP1809_E2">
<TEXTOVERVIEW>730_64-BIT</TEXTOVERVIEW>
</BRAND>
<BRAND identifier="B1809_E3">
<TEXT>Empty</TEXT>
</BRAND>
<BRAND identifier="B1809_E4">
<TEXT>Empty</TEXT>
</BRAND>
</BRANDS>
</PARTS>
I need to make modifications such as:
<BRANDS>
<BRAND identifier = "CP1809_B1">
<TEXTCONTENT>Geforce_GT<TEXTCONTENT>
</BRAND>
<BRAND identifier = "CP1809_B2">
<TEXTCONTENT>730_64-BIT<TEXTCONTENT>
</BRAND>
<!-- ... -->
<BRANDS>
XSLT can do that (see example at http://xsltransform.net/ej9EGda):
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:key name="desc" match="PART/BRAND" use="."/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BRANDS/BRAND[key('desc', TEXTCONTENT)]/#identifier">
<xsl:attribute name="{name()}">
<xsl:value-of select="key('desc', ../TEXTCONTENT)/#id"/>
</xsl:attribute>
</xsl:template>
</xsl:transform>
On the Java platform you have a choice of XSLT processors like Saxon 9 for XSLT 2.0 or Xalan or Saxon 6 for XSLT 1.0 and the built-in version of Xalan in the JRE.

Convert xml to csv with xsl java

i am following this link
i want to convert an xml to csv
i have an xml and written and xsl for it
openning xml with href to the xsl work on internet explorer
but runing the code from this link return an error
Can not resolve namespace prefix: xmlns
what should fix it ?
i have a working xml & xsl
xml
<?xml version='1.0' encoding='utf-8'?>
<?xml-stylesheet type="text/xsl" href="student2.xsl"?>
<rankings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ign="http://api.DomainName.com/2.0" count="438" total="438" offset="0" xsi:schemaLocation="http://api.DomainName.com/2.0 http://api.DomainName.com/2.0/api.xsd" >
<ranking keyword="80s fancy dress">
<ranks>
<rank week="201526" country="uk" searchengine="google_uk_en">NR</rank>
<rank week="201527" country="uk" searchengine="google_uk_en">NR</rank>
<rank week="201528" country="uk" searchengine="google_uk_en">NR</rank>
<rank week="201529" country="uk" searchengine="google_uk_en">NR</rank>
<rank week="201530" country="uk" searchengine="google_uk_en">NR</rank>
<rank week="201531" country="uk" searchengine="google_uk_en">NR</rank>
</ranks>
</ranking>
</rankings>
xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://api.DomainName.com/2.0" exclude-result-prefixes=xmlns>
<xsl:output method="text" encoding="UTF-8" omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr bgcolor="#9acd32">
</tr>
<xsl:for-each select="rankings/ranking/ranks/rank">
<tr>
<keyword><xsl:value-of select="../../#keyword"/></keyword>
<xsl:text>,</xsl:text>
<week><xsl:value-of select="#week"/></week>
<xsl:text>,</xsl:text>
<country><xsl:value-of select="#country"/></country>
<xsl:text>,</xsl:text>
<searchengine><xsl:value-of select="#searchengine"/></searchengine>
<xsl:text>,</xsl:text>
<rank><xsl:value-of select="../rank"/></rank>
<xsl:value-of select="." />
<xsl:text>
</xsl:text>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
java code
after running the java code from the above link
i get an error
(Location of error unknown)org.xml.sax.SAXException: Can not resolve namespace prefix: xmlns
Exception in thread "main" java.lang.NullPointerException
at org.apache.xalan.transformer.TransformerImpl.createSerializationHandler(TransformerImpl.java:1171)
at org.apache.xalan.transformer.TransformerImpl.createSerializationHandler(TransformerImpl.java:1060)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1268)
at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1251)
what should fix it ?
To eliminate the error, you need to remove this:
exclude-result-prefixes=xmlns
from your xsl:stylesheet tag. You also need to remove the default namespace declaration:
xmlns="http://api.DomainName.com/2.0"
otherwise all your output will be placed in that namespace, which you most certainly don't want to happen if - as it seems - you want it to be HTML.
There are other changes you need to make - for example, if you want to output an HTML table, set the output method to "html" instead of "text", and make sure your table structure is valid.
Note:
Your XML declares a namespace: xmlns:ign="http://api.DomainName.com/2.0" but this namespace declaration isn't used anywhere. Therefore your stylesheet can ignore it. Provided you are showing us a representative sample of the real XML.

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