Generate low-order non-printable characters from XLST - java

I'm trying to use XSLT text output to generate a file (in a file format that I'm not in control of), and while it is mostly text, it includes low-order non-printable characters as flags, including characters that are not valid within an XLST file (according to the XSLT specification).
I'd like for something like the below to work, but instead it isn't a valid XSLT file since it it contains characters that are not allowed in XSLT files:
<?xml version="1.0" encoding="US-ASCII" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="US-ASCII"/>
<xsl:template match="/"></xsl:template>
</xsl:stylesheet>
I get the following error:
[Fatal Error] :4:35: Character reference "&#1" is an invalid XML character.
ERROR: 'Character reference "&#1" is an invalid XML character.'
FATAL ERROR: 'Could not compile stylesheet'
I've tried with an actual character 1 too, with or without a CDATA section, xsl:text elements, xslt-2 character maps, a couple of different encodings, but I can't figure out how to get a ascii character with binary code = 1.
I've had to resort to post-processing my output, which isn't ideal.
Is there any way to generate a single low-order non-printable character output from XSLT?
Environment: Java 6, built in XSL Transformer.

You can call static methods of Java classes from XSLT. Use the following hack for example to write 0x01 to your output stream:
<?xml version="1.0" encoding="US-ASCII" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:char="java.lang.Character" version="1.0">
<xsl:output method="text" encoding="US-ASCII" />
<xsl:template match="/">
<xsl:value-of select="char:toString(1)"></xsl:value-of>
</xsl:template>
</xsl:stylesheet>

Another option that I've come up with, is to use an xsl:param which the calling environment sets to character 0x01.
This means that instead of always working within a java environment, and requiring changes anywhere else, that the stylesheet requires environmental support in all environments, but can work unchanged in them all.
I'm not yet sure which side of that trade-off is preferable for what I'm working on.

Related

ORAEXT : XPST0017: Cannot find a matching 5-argument function named

While doing XSLT transformation, I have a requirement to call Datasource inside xsl. I am using ora-ext to achieve it. But I am getting Cannot find a matching 5-argument function named and 4-argument matching function on use of the query-database function of ORAEXT.
Full stacktrace:
Static error at char 1 near {...t_code','jdbc/JDBCDataSourc...} in expression in xsl:value-of/#select on line 1 column 1575
XPST0017: Cannot find a matching 5-argument function named
{http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc}lookup-table().For diagnostics on calls to Java methods, use the -TJ command line option or set the Configuration property FeatureKeys.TRACE_EXTERNAL_FUNCTIONS
This is my XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
xmlns:sql="http://ns.saxonica.com/sql"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:java="http://saxon.sf.net/java-type"
xmlns:saxon="http://saxon.sf.net/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ora="http://schemas.oracle.com/xpath/extension"
exclude-result-prefixes="java saxon xsd xsi xsl sql"
extension-element-prefixes="saxon sql"
>
<xsl:template match="Order">
<Parameter>
<xsl:attribute name="name">ACT_CODE</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="oraext:lookup-table('ACT_CODE_MTDT', 'prdt_id','1159', 'act_code','jdbc/JDBCDataSource')"/>
</xsl:attribute>
</Parameter>
</xsl:template>
</xsl:stylesheet>
Kindly suggest, if I am missing on something. Suggest me if any jar apart from ojdbc6.jar is required.
Also, I'm not able access this URL.
Is that the namespace got changed, or there something missing in my code.
It looks to me as if you are running Saxon as your XSLT processor (we can tell from the form of the error messages) but you are trying to call an extension function that has been defined by Oracle as an vendor extension for their own XSLT processor. That ain't gonna work.

localizing xsl for different languages

I have some static xsl to translate dynamic xml into html to response to browser. The rest of the web pages use Spring MVC for view. So they can be localized by using Spring's messages.properties file written in my language. But I don't know how to localize the text nodes in the static xsl using the same method. More specific below.
In Spring's web page, I can
<title><spring:message code="title.MyTitle"/></title>
In my static xsl, I have
<xsl:stylesheet ........
<xsl:output method="html"/>
<xsl:template match="/">
.....
<title>My Title</title>
and I want something like this
<xsl:stylesheet ........
<xsl:output method="html"/>
<xsl:template match="/">
.....
<title><spring:message code="title.MyTitle"/></title>
Of course the above doesn't work. But I hope I can keep all titles and labels in messages.properties for easy changes between languages. How can I do this? Please help.
Jirka Kosek has a technique for doing l10n lookups at http://www.xml.com/pub/a/2003/11/05/xslt.html. I thought he'd made a whole system for doing l10n with XSLT, but I can't find that now.
Separately, if your properties files are text rather than the XML property file format that Java also understands, the general technique would be:
Use unparsed-text() to get the text of the properties file
Tokenize on line-ends (those not preceded by /, that is)
Make a variable that contains an element for each of those strings, where the key is in an attribute value and the text is the text content of the element
All that's done so far is mimic the XML property file format.
Make a key that matches on the elements and uses the attribute value as the lookup
Make a function that takes the string as a parameter and does a lookup on the key, using the string as the second parameter and the variable as the third

Trying to print out node values in XSLT using variable elements names

So here's a problem that's been bugging me for the last few days. It should be fairly easy, but XSLT is just such a pain to debug. We're using Xalan 1.0 on java 1.6
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<rfb2>
<rfb2_item>
<VALDATE>2011-10-23</VALDATE>
<FUND_ID>300</FUND_ID>
<SEC_ID>34567</SEC_ID>
</rfb2_item>
<rfb2_item>
<VALDATE>2011-1-09</VALDATE>
<FUND_ID>700</FUND_ID>
<SEC_ID>13587</SEC_ID>
</rfb2_item>
<rfb2_item>
<VALDATE>2011-3-09</VALDATE>
<FUND_ID>200</FUND_ID>
<SEC_ID>999334</SEC_ID>
</rfb2_item>
<rfb2>
We need to transform the XML into a comma-separated list of values for each rfb2_item, so the style sheet always iterates the rfb2_item nodes. We are using a parameter in the style sheet to control which elements of rfb2_item (valdate,fund_id,sec_id) that will be output, and in what order, for example
<xsl:param name="$outputElements" select="'VALDATE,FUND_ID'"/>
..outputs...
2011-10-23,300
2011-1-09,700
2011-3-09,200
<xsl:param name="$outputElements" select="'SEC_ID'"/>
..outputs...
34567
13587
999334
Special case where if $outputElements is '*', just output the elements in the order they appear in the input xml
<xsl:param name="$outputElements" select="'*'"/>
..outputs...
2011-10-23,300,34567
2011-1-09,700,13587
2011-3-09,200,999334
So, my question is how do we write a template to create the desired output based on the $outputElements parameter? A working example would be great...
Yup, FailedDev is right. Someone would write it for you:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:param name="outputElements" select=" 'FUND_ID,SEC_ID,VALDATE' " />
<xsl:template match="rfb2_item">
<xsl:for-each select="*[contains($outputElements, local-name()) or $outputElements = '*']">
<xsl:sort select="string-length(substring-before($outputElements, local-name(.)))" />
<xsl:value-of select="text()" />
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Bit of explanation. The xsl:for-each is gonna select each element in the current rfb2_item for which the local name is contained in the outputElements parameter, or for which the outputElements parameter is * (which would always yield true if that's the case). It's then gonna sort those based on the length of the substring that goes before that local name in outputElements. Since this value becomes higher when the name occurs later in that parameter, this results in ordering based on your parameter.
Example: element VALDATE would yield FUND_ID,SEC_ID for the substring-before function, which in turn would yield 14 as string length. This is higher than the 8 that you'd get for SEC_ID, meaning the VALDATE value is ordered after SEC_ID.
After the xsl:sort, we're simply using xsl:value-of to output the element value. You might want to trim extraneous whitespace there. Finally, we're testing if the position is not equal to that of the last node in the current context (which is that of xsl:for-each after sorting) and if so, output a comma. This avoids outputting a comma after the last value.
The line break I've inserted using xsl:text assumes the Windows/DOS convention. Remove the 
 if the file should only use new line characters for line breaks, instead of carriage return + new line.
Note that this does not escape commas in your CSV output! I'll leave that up to you. It could be interesting to look into using extension functions for delegating this task to Java if it proves too difficult in XSLT/XPath.
Sometimes in this kind of situation it's worth looking at the possibility of generating or modifying XSLT code using XSLT. You can take the parameterization a lot further that way - for example controlling which fields are output, how they are sorted, whether they are grouped, selection criteria for which rows are selected, etc etc.

Java SAX parsing: What's wrong with this XML?

I'm trying to validate an XML file, but I get the following error:
Can not find declaration of element
'xsl:stylesheet'.
This is the XML:
<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl='urn:schemas-microsoft-com:xslt' exclude-result-prefixes='msxsl' xmlns:ns='http://www.ibm.com/wsla'>
<xsl:strip-space elements='*'/>
<xsl:output method='xml' indent='yes'/>
<xsl:template match='#* | node()'>
<xsl:copy>
<xsl:apply-templates select='#* | node()'/>
</xsl:copy>
</xsl:template>
<xsl:template match="/ns:SLA/ns:ServiceDefinition/ns:WSDLSOAPOperation/ns:SLAParameter/#name[.='TotalMemoryConsumption']">
<xsl:attribute name='{name()}'>
<xsl:text>MemConsumption</xsl:text>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Where is the mistake?
EDIT: I want to parse this XML in Java with SAX, but I get the following error:
Element type "xsl:template" must be followed by either attribute specifications, ">" or "/>".
How to get rid of it?
Assuming you are actually trying to validate your XSL as an XML document, it looks like that website requires you to point to a schema or DTD in order to validate the XML against it. You can get a non-normative schema here: http://www.w3.org/TR/xslt20/#schema-for-xslt. Here's instructions on how to reference a schema from an XML file: http://www.ibm.com/developerworks/xml/library/x-tipsch.html
You could also check "Well-Formedness only," and check the document for well-formedness, if not actually validity.
Generally, any XSL engine will report any errors in your XSL document, so you don't need to validate it separately.
Your XSL is OK, don't worry. Just that there is no DTD/XSD for XSLs 1.0. no one bothers checking XSLT stylesheets (1.0) for validity. "Wellformedness" is enough.

Remove special characters from XML via XSLT only for specific tags

I am having a certian issue with special characters in my XML.
Bascially I am splitting up an xml into multiple xmls using Xalan Processor.
When splitting the documents up I am using their value of the name tag as the name of the file generated. The problem is that the name contains characters that arent recognized by the XML processor like ™ (TM) and ® (R). I want to remove those characters ONLY when naming the files.
<xsl:template match="products">
<redirect:write select="concat('..\\xml\\product\\en\\',translate(string(name),'</> ',''),'.xml')">
The above is the XSL code I have writter to split the XML into multlpe XMLs. As you can see I am using hte translate method to subtitute '/','<','>' with '' from the name. I was hoping I could do the same with ™ (TM) and ® (R) but it doesnt seem to work.
Please advice me how I would be able to do that.
Thanks for you help in advance.
I don't have Xalan, but with 8 other XSLT processors this thransformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="text()">
<xsl:value-of select="translate(., '</>™®', '')"/>
===================
<xsl:value-of select="translate(., '</>™®', '')"/>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<t>XXX™ My Trademark®</t>
produces the wanted result:
XXX My Trademark
===================
XXX My Trademark
I suggest that you try to use one of the two expressions above -- at least the second may work successfully.
Following Dimitre answer, I think that if you are not sure about wich special character could be in name, maybe you should keep what you consider legal document's name characters.
As example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="text()">
<xsl:value-of select="translate(.,
translate(.,
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ',
''),
'')"/>
</xsl:template>
</xsl:stylesheet>
With input:
<t>XXX™ My > Trademark®</t>
Result:
XXX My Trademark

Categories