How write in line if condition in xslt - xslt

I want to write inline if condition in xslt. I have mentioned my tried code below. I am getting an error mark when I am using it. Please note me where I am incorrect
<xsl:template match="node">
<entry type="{if (ancestor::table[#frame='all']) then 'all_rules' else 'header_single{if ($out) then concat('_',$out) else ''}'}">
<body/>
</entry>
</xsl:template>
Error :
{...hen concat('_',$out) else '...}: Unexpected token name "_" beyond end of expression
Thank you.

The use of { ... } to contain expressions is an XSLT feature, not XPath, so you can't use it within an XPath expression.
If you want to nest if-expressions like this, then you need to do so within the constructs of XPath, and I believe that means using concat() in this case:
if (ancestor::table[#frame='all'])
then 'all_rules'
else concat(
'header_single',
if ($out) then concat('_',$out) else ''
)
Of course, you need to be using a high enough version of XSLT in order for this to work. This won't work in XSLT 1.0 as that only supports XPath 1.0, which doesn't have if- expressions.

Related

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.

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

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.

Getting the value of an attribute in an XML document using XSL

I'm trying to get the value of iWantToGetThis.jpg and put it into an <img> during my XSL transformation. This is how my xml is structures:
<article>
<info>
<mediaobject>
<imageobject>
<imagedata fileref='iWantToGetThis.jpg'>
Here's what I've come up with for the XSL:
<xsl:template name="user.header.content">
<xsl:stylesheet xmlns:d='http://docbook.org/ns/docbook'>
<img><xsl:attribute name="src">../icons/<xsl:value-of select='ancestor-or-self::d:article/info/mediaobject/imageobject/imagedata/#fileref' /></xsl:attribute></img>
</xsl:stylesheet>
</xsl:template>
The image is being added to the output, but the src attribute is set to "../icons/", so I'm assuming it's not finding the fileref attribute in the XML. This looks perfectly valid to me, so I'm not sure what I'm missing.
I am not sure how you can get anything back at all, because that does not look like a valid XSLT document (I would expect the error "Keyword xsl:stylesheet may not contain img.").
However, it may be you are just showing a fragment of the code. If this is the case, your issue may be that you have only specified the namespace for the article element, when you really need to specify it for all elements in your xpath. Try this
<xsl:value-of
select="ancestor-or-self::d:article/d:info/d:mediaobject/d:imageobject/d:imagedata/#fileref"/>
Another possible problem may be because you are using the 'ancestor-or-self' xpath axis to find the attribute. This would only work if your current context was already on the article element, or one of its descendants.
As a side note, you can simplify the code by making use of Attribute Value Templates here
<img src="../icons/{ancestor-or-self::d:article/d:info/d:mediaobject/d:imageobject/d:imagedata/#fileref}" />

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,'['),']'),'-'))

XSLT; parse escaped text to a node-set and extract subelements

I've been fighting with this problem all day and am just about at my wit's end.
I have an XML file in which certain portions of data are stored as escaped text but are themselves well-formed XML. I want to convert the whole hierarchy in this text node to a node-set and extract the data therein. No combination of variables and functions I can think of works.
The way I'd expect it to work would be:
<xsl:variable name="a" select="InnerXML">
<xsl:for-each select="exsl:node-set($a)/*">
'do something
</xsl:for-each>
The input element InnerXML contains text of the form
<root><elementa>text</elementa><elementb><elementc/><elementd>text</elementd></elementb></root>
but that doesn't really matter. I just want to navigate the xml like a normal node-set.
Where am I going wrong?
In case you can use Saxon 9.x, it provides the saxon:parse() extension function exactly for solving this task.
what I've done is had a msxsl script in the xslt ( this is in a windows .NET environment):
<msxsl:script implements-prefix="cs" language="C#" >
<![CDATA[
public XPathNodeIterator parse(String strXML)
{
System.IO.StringReader rdr = new System.IO.StringReader(strXML);
XPathDocument doc = new XPathDocument(rdr);
XPathNavigator nav = doc.CreateNavigator();
XPathExpression expr;
expr = nav.Compile("/");
XPathNodeIterator iterator = nav.Select(expr);
return iterator;
}
]]>
</msxsl:script>
then you can call it like this:
<xsl:variable name="itemHtml" select="cs:parse(EscapedNode)" />
and that variable now contains xml you can iterate through