disable-output-escaping="yes" is not working - xslt

I have the following code
<db:P_RECEIVED_XML>
<xsl:value-of disable-output-escaping="yes" select="oraext:get-content-as-string(/ns0:ReceivedMessage/MessageContent/*)"/>
</db:P_RECEIVED_XML>
when i test this transformation, by giving the value as
<MessageContent xmlns="">
<any_0 xmlns="##any">
<note>
<name>GENERAL</name>
<value><![CDATA[test ~<!##$%^&*()_~!##$%^&*()_+]]></value>
</note>
</any_0>
</MessageContent>
the output rendered is
<db:P_RECEIVED_XML><any_0 xmlns="##any">
<note>
<name>GENERAL</name>
<value>test ~<!##$%^&*()_~!##$%^&*()_+</value>
</note>
</any_0>
</db:P_RECEIVED_XML>
Here & is converted to & though i have used disable-output-escaping="yes".
Kindly help.

You have tagged your question as XSLT. In XSLT, using:
<xsl:value-of select="your-node-here" disable-output-escaping="yes" />
would have disabled the escaping, and not output & as &.
If you are seeing a different result, it's probably a result of your using an extension oraext:get-content-as-string() function. Try removing it and see what you get.

disable-output-escaping only works if the result tree produced by the XSLT processor is immediately serialized, and if the serialization is under the control of the the XSLT processor. That means, for example, that it doesn't work if the result is written to a DOM tree, and you then use the DOM serialization to produce lexical XML.
XSLT processors are allowed to ignore disable-output-escaping entirely.
So it basically depends on what XSLT processor you are using and how you are running it.

Related

Can I include a variable inside a src attribute of an XSL-FO block?

We have 60-odd images that we want to include, and want to insert them into a doc using a variable name in the src attribute. Here is the code that currently isn't working:
Without XSL:-
<var name="Request.Data.Communication.AddressStructured.Sender.OrgId" type="string" />
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" xmlns:svg="http://www.w3.org/2000/svg" xmlns:th="http://www.thunderhead.com/XSL/Extensions" font-family="Frutiger 45 Light">
<fo:external-graphic content-height="30mm" content-width="100mm" src="cms:///Resources/Images/Request.Data.Communication.AddressStructured.Sender.OrgId.jpg" />
</fo:block>
With XSL:-
<xsl:block xmlns:xsl="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" xmlns:svg="http://www.w3.org/2000/svg"
<xsl:var name="Request.Data.Communication.AddressStructured.Sender.OrgId" select="Request.Data.Communication.AddressStructured.Sender.OrgId"/>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Transform" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" xmlns:svg="http://www.w3.org/2000/svg" <fo:external-graphic content-height="30mm" content-width="100mm" src="cms:///Resources/Images/${Request.Data.Communication.AddressStructured.Sender.OrgId}.jpg" />
</fo:block>
</xsl:block>
You might want {$Request.Data.Communication.AddressStructured.Sender.OrgId} rather than ${Request.Data.Communication.AddressStructured.Sender.OrgId}, otherwise read on...
Getting from your source XML to PDF output is a two-step process (unless, that is, you author documents directly in the XSL-FO vocabulary). The steps are:
An XSLT transformation transforms your XML into XML in the XSL-FO vocabulary that an XSL Formatter understands
An XSL Formatter formats the XSL-FO to make pages and outputs those pages as PDF, SVG, etc.
This graphic from the XSL 1.1 Recommendation (https://www.w3.org/TR/xsl11/#d0e147) tries to illustrate the process:
The XSLT stage has variables, but the XSL-FO stage does not. (You can write expressions for the value of (most) XSL-FO properties, but the expression language (see https://www.w3.org/TR/xsl11/#d0e5032) doesn't stretch to having variables.)
So, in your XSLT stylesheet, you would have something like:
{$Request.Data.Communication.AddressStructured.Sender.OrgId}.jpg
where:
$Request.Data.Communication.AddressStructured.Sender.OrgId is a variable (or parameter) reference. We don't have enough information to know how you'd define the variable.
{...} is an Attribute Value Template (AVT) that is used when you want to evaluate an expression to generate some or all of an attribute value.
The output from the XSLT stage would include the literal string resulting from evaluating the expression, and the XSL Formatter will use the actual URL to locate the image correctly.

Passing a node as parameter to a XSL stylesheet

I need to pass a node as a parameter to an XSL stylesheet. The issue is that the parameter gets sent as a string. I have seen the several SO questions regarding this topic, and I know that the solution (in XSLT 1.0) is to use an external node-set() function to transform the string to a node set.
My issue is that I am using eXist DB I cannot seem to be able to get its XSLT processor to locate any such function. I have tried the EXSLT node-set() from the namespace http://exslt.org/common as well as both the Saxon and Xalan version (I think eXist used to use Xalan but now it might be Saxon).
Are these extensions even allowed in the XSLT processor used by eXist? If not, is there something else I can do?
To reference or transform documents from the database, you should pass the path as a parameter to the transformation, and then refer to it using a parameter and variable
(: xquery :)
let $path-to-document := "/db/test/testa.xml"
let $stylesheet :=
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="source" required="no"/>
<xsl:variable name="error"><error>doc not available</error></xsl:variable>
<xsl:variable name="theDoc" select="if (doc-available($source)) then doc($source) else $error"/>
<xsl:template match="/">
<result><xsl:value-of select="$source"/> - <xsl:value-of select="node-name($theDoc/*)"/></result>
</xsl:template>
</xsl:stylesheet>
return transform:transform(<dummy/>,$stylesheet, <parameters><param name="source" value="xmldb:exist://{$path-to-document}"/></parameters>)
As per Martin Honnen's comments I don't think it is possible to pass an XML node via the <parameters> structure of the transform:transform() function in eXist. The function seems to strip away any XML tags passed to it as a value.
As a workaround I will wrap both my input XML and my parameter XML into a root element and pass that as input to the transform function.

Dynamic Message using Barcode4J in Apache FOP XSL Document

I'm having trouble generating a dynamic message using Barcode4J ean-13 in an Apache FOP xsl document. I did get the barcode to generate using a hard coded message. However, I would like to pass the barcode number to the xsl document as a parameter. How do I go about doing that?
Also, I have referred to the barcode4J site for help page with no luck. I have tried using the technique described here but had no luck.
This is how my xsl document looks like
<fo:block-container left="1000" top="1000"
z-index="1" position="relative">
<fo:block>
<fo:instream-foreign-object>
<bc:barcode xmlns:bc="http://barcode4j.krysalis.org/ns"
message="123456789789">
<bc:ean-13 />
</bc:barcode>
</fo:instream-foreign-object>
</fo:block>
</fo:block-container>
You don't say which XSLT version you are using.
If you want to pass a parameter to your XSLT, you need to declare the parameter as a child element of your xsl:stylesheet, e.g.:
<xsl:param name="barcode" />
For XSLT 1.0, see http://www.w3.org/TR/xslt#top-level-variables. You could declare more about it if you are using XSLT 2.0.
How to pass the parameter value will depend on which XSLT processor you are using, but you can expect that to be covered in the XSLT processor's documentation.
You can then use the $barcode parameter in an 'attribute value template' in your otherwise-literal markup:
<fo:block-container left="1000" top="1000"
z-index="1" position="relative">
<fo:block>
<fo:instream-foreign-object>
<bc:barcode xmlns:bc="http://barcode4j.krysalis.org/ns"
message="{$barcode}">
<bc:ean-13 />
</bc:barcode>
</fo:instream-foreign-object>
</fo:block>
</fo:block-container>
For attribute value templates in XSLT 1.0, see http://www.w3.org/TR/xslt#dt-attribute-value-template

BizTalk HL7 send pipeline error due to line breaks in empty XML elements

I am mapping to an HL7 A31 message using the BizTalk mapper. The map has several inline XSLT scripting functoids.
When the XML is put through the HL7 send pipeline, it generates an error:
The element 'ROL_11_OfficeHomeAddress' has an invalid structure
If I look at the suspended message, I can see why this has happened. The ROL_11 element is empty, and looks like this:
<ROL_11_OfficeHomeAddress>
</ROL_11_OfficeHomeAddress>
Between the opening and closing tags, there is a line break and several spaces/tabs due to indenting. This is exactly as generated by the XSLT and I believe it is the line break that is causing the error.
I could wrap the XSLT in an <xsl:if> statement to check for a value before writing the XML. However this problem is occurring in many places and it seems overkill to wrap every single element like this.
What I really want is for BizTalk to automatically convert the element to an empty one, like this:
<ROL_11_OfficeHomeAddress />
I believe this would solve the problem. Is there any way I can tell it to do that?
Things I have already tried:
Using <xsl:strip-space> but that raised its own error. I think this is because BizTalk wraps the inline XSLT in its own code and thus strip-space was specified in the wrong place.
Changing the map's grid properties to set Indent to No in the hope the whitespace would be removed. This had no effect on the XML seen in the suspended message.
Adding the registry key for legacy whitespace handling as per this guidance. Again, this appeared to have no effect at all.
If you convert your entire map into XSLT, the below will strip out newlines and whitespace and leave you with an empty tag if there isn't anything but whitespace:
<xsl:element name="ROL_11_OfficeHomeAddress">
<xsl:if test="normalize-space(ROL_11_OfficeHomeAddress)">
<xsl:value-of select="normalize-space(ROL_11_OfficeHomeAddress)" />
</xsl:if>
</xsl:element>
Edit:
Biztalk usually generates XSLT like the following in a typical 1:1 nillable element mapping
<xsl:variable name="var:v2" select="string(ns0:ROL_11_OfficeHomeAddress/#xsi:nil) = 'true'" />
<xsl:if test="string($var:v2)='true'">
<ns0:ROL_11_OfficeHomeAddress>
<xsl:attribute name="xsi:nil">
<xsl:value-of select="'true'" />
</xsl:attribute>
</ns0:ROL_11_OfficeHomeAddress>
</xsl:if>
<xsl:if test="string($var:v2)='false'">
<ns0:ROL_11_OfficeHomeAddress>
<xsl:value-of select="ROL_11_OfficeHomeAddress/text()" />
</ns0:ROL_11_OfficeHomeAddress>
</xsl:if>
So if you did use <xsl:strip-space> it would mean that the element would map to <ROL_11_OfficeHomeAddress></ROL_11_OfficeHomeAddress> if whitespace only, unless you went through the map changing it back to <xsl:element>.
What you could try is to use a call template like the below (nodeXfrm is a node)
<xsl:template name="StripElement">
<xsl:param name="nodeXfrm"></xsl:param>
<xsl:variable name="nodeName">
<xsl:value-of select="local-name($nodeXfrm)"></xsl:value-of>
</xsl:variable>
<xsl:element name="{$nodeName}">
<xsl:if test="normalize-space($nodeXfrm)!=''">
<xsl:value-of select="$nodeXfrm/text()"/>
</xsl:if>
</xsl:element>
</xsl:template>
And then within your map you can call the template for each element you need stripped in this way
<xsl:call-template name="StripElement">
<xsl:with-param name="nodeXfrm" select="ROL_11_OfficeHomeAddress"></xsl:with-param>
</xsl:call-template>
An XSLT guru might be able to do this more elegantly
I too was recently having this problem, but in BizTalk 2013. We moved everything to custom XSLT files for mapping our HL7v2. Upon upgrading to 2013, suddenly the <xsl:strip-space> that previously worked, no longer worked.
This is because BizTalk 2013 now uses the XslCompiledTransform class rather than the now obsoleted XslTransform class and it doesn't allow the <xsl:strip-space>. So I too was faced with no global way to strip the whitespace.
However, after much searching and head scratching, I found an obscure blog post with something that worked for my solution:
http://geekswithblogs.net/peterbrouwer/archive/2012/08/17/biztalk-2010ndashlegacy-whitespace-behaviour.aspx
An option in the the Host's settings, for using legacy whitespace did it for us (so far at least).

YQL XSLT implementation limitations

For some reason, YQL's XSLT table can't parse my stylesheet. I have used the stylesheet successfully with the W3C's XSLT service. Here's an example of the problem in YQL Console. Why does this not work in YQL?
Also, I have yet to figure out how to pass the results of a YQL query to the XSLT table as the XML to be transformed while also specifying a stylesheet url. Current workaround is to abuse the W3C's service.
Your stylesheet is defined as 1.0 but you're using replace() and tokenize() which is part of the 2.0 standard. However it is a fully valid XSLT/XPath 2.0 stylesheet.
As an addition to Per T answer, change this:
<xsl:variable name="r">
<xsl:value-of select="replace(tr/td/p/a/following-sibling::text(),
'\s*-\s*(\d+)\.(\d+)\.(\d+)\s*',
'$1,$2,$3')" />
</xsl:variable>
With this:
<xsl:variable name="r"
select="translate(tr/td/p/a/following-sibling::text(),'. -',',')">
These:
tokenize($r,',')[1]
tokenize($r,',')[2]
tokenize($r,',')[3]
With these:
substring-before($r,',')
substring-before(substring-after($r,','),',')
substring-after(substring-after($r,','),',')
Note: This is just in case you don't know the amount of digit in advance, otherwise you could do:
substring($r,1,2)
substring($r,4,2)
substring($r,7)
Also, this
replace(tr/td/p[#class='t11bold']/a,'\s+',' ')
It should be just this:
normalize-space(tr/td/p[#class='t11bold']/a)
And finaly this:
replace($d,'^[^\[]*\[\s*(\d+:\d{2})?\s*-?\s*([^\]]*)\]\s*$','$2')
Could be:
normalize-space(substring-after(substring-before(substring-after($d,'['),']'),'-'))