How to use a variable value - xslt

The variable behaviour here does not work as expected.
I have a variable named fonttag with a value that is an HTML line with both start and end tags and a divider.
<xsl:variable name="fonttag">
<font face="ANGSANA NEW" size="12">|</font>
</xsl:variable>
When I try to use it, to get part of the string back, I get an empty string:
<xsl:value-of select="substring-before($fonttag ,'|')"/>
Where I expected the substring :
<font face="ANGSANA NEW" size="12">
Similarly the
<xsl:value-of select="$fonttag"/>
returns nothing, although
<xsl:copy-of select="$fonttag"/>
return the whole string. Is there another way to achieve the expected result ?
A derived-question: Is it possible to nest xsl select tags like this (cannot get it to work either)
<xsl:copy-of select="substring-before( <xsl:copy-of select="$fonttag"/>,'|')"/>
?
thanks

I am afraid you misunderstand how XSLT works. Your variable does not contain the string "<font face="ANGSANA NEW" size="12">|</font>". It contains the element font, with two attributes, and the string value of "|". The xsl:value-of instruction, as well as any string function such as substring(), only address the string value of the given expression.

Related

Substring before throwing error

I've the below XML
<?xml version="1.0" encoding="UTF-8"?>
<body>
<p>Industrial drawing: Any creative composition</p>
<p>Industrial drawing: Any creative<fn>
<fnn>4</fnn>
<fnt>
<p>ftn1"</p>
</fnt>
</fn> composition
</p>
</body>
and the below XSL.
<xsl:template match="p">
<xsl:choose>
<xsl:when test="contains(substring-before(./text(),' '),'Article')">
<xsl:text>sect3</xsl:text>
<xsl:value-of select="./text()"/>
</xsl:when>
<xsl:when test="contains(substring-before(./b/text(),' '),'Section')">
<xsl:text> Sect 2</xsl:text>
<xsl:value-of select="./text()"/>
</xsl:when>
<xsl:when test="contains(substring-before(./b/text(),' '),'Chapter')">
<xsl:text> Sect 1</xsl:text>
<xsl:value-of select="./text()"/>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Here my XSL is working fine for <p>Industrial drawing: Any creative composition</p> but for the below Case
<p>Industrial drawing: Any creative<fn>
<fnn>4</fnn>
<fnt>
<p>ftn1"</p>
</fnt>
</fn> composition
</p>
it is throwing me the below error.
XSLT 2.0 Debugging Error: Error: file:///C:/Users/u0138039/Desktop/Proview/ASAK/DIFC/XSLT/tabel.xslt:38: Wrong occurrence to match required sequence type - Details: - XPTY0004: The supplied sequence ('2' item(s)) has the wrong occurrence to match the sequence type xs:string ('zero or one')
please let me know how can i fix this and grab the text required.
Thanks
The second p element in your example XML has two child text nodes, one containing "Industrial drawing: Any creative" and the other containing a space, "composition", a newline and another six spaces. In XSLT 1.0 it is legal to apply a function that expects a string to an argument that is a set of more than one node, the behaviour is to take the value of the first node and ignore all the others. But in 2.0 it is a type mismatch error to pass two nodes to a function that expected a single value for its parameter.
But in this case I doubt that you really need to use text() at all - if all you care about is seeing whether the string "Article" occurs anywhere within the first word under the p (including when this is nested inside another element) then you can simply use .:
<xsl:when test="contains(substring-before(.,' '),'Article')">
(or better still, use predicates to separate the different conditions into their own templates, with one template matching "Article" paragraphs, another matching "Section" paragraphs, etc.)
The p element in your example has several text nodes, so the expression ./text() creates a sequence. You cannot apply a string function to a sequence; you must convert it to a string first. Instead of:
test="contains(substring-before(./text(),' '),'Article')"
try:
test="contains(substring-before(string-join(text(), ''), ' '), 'Article')"

Get child from node and pass into attribute

sorry for this rivial question but at the moment i can not figure it out.
I have an node in there are childs, i want these child and "print" these directly in an attribute. Please take a look at the code:
<fo:declarations>
<xsl:for-each select="//lb">
<xsl:for-each select="./dv-group/dv/download">
<xsl:value-of select="." />
<pdf:embedded-file filename="<xsl:value-of select="." />" src="url(test:///C:/Users/muster/Desktop/template_test/data/Mappe1.xlsx)"/>
</xsl:for-each>
</xsl:for-each>
</fo:declarations>
I have try it with a variable but that doesn't work too.
Any suggestions?
Thanks.
The concept you're looking for is called an attribute value template: in attribute values on a literal result element (and in certain attributes of some xsl: instructions too) you can enclose XPath expressions in braces and they will be evaluated and their result substituted in the output:
<pdf:embedded-file filename="{.}" src="url(test:///C:/Users/muster/Desktop/template_test/data/Mappe1.xlsx)"/>
If you want a literal brace character in an attribute that is interpreted as an AVT you must double it.

XSLT - Check if pattern exists in an element string

I have the following element as part of a larger XML
<MT N="NonEnglishAbstract" V="[DE] Deutsch Abstract text [FR] French Abstract text"/>
I need to do some formatting of the value in #V attribute, only if it contains anything like [DE], [FR] or any two capital letters representing a country code within square brackets.
If no such pattern exist, I need to simply write the value of #V without any formatting.
I can use an XSLT 2.0 solution
I was hoping that I could use the matches() function something like
<xsl:choose>
<xsl:when test="matches(#V,'\[([A-Z]{{2}})\]([^\[]+'">
//Do something
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="#V"/>
</xsl:otherwise>
</xsl:choose>
I think all you need is:
matches(#V,'\[[A-Z][A-Z]\]')
You don't have to match the entire string to get a true() ... I tell my students to write as short a reg-ex as possible.
You have not posted anything about what you have tried. How about looking up translate function and translating the strings capital letters to something like "X". Then test that string result for the existence of [XX]. That alone would tell you whether you need to process it.
<xsl:variable name="result">
<xsl:value-of select="translate(#V,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','XXXXXXXXXXXXXXXXXXXXXXXXX')"/>
</xsl:variable>
Then use that result and then test:
contains($result, "[XX]")
No regex required, pure XSL 1.1

xsl copy-of with substring

i have this function in xsl i took from this post
to replace "cr" with "line-break"
this is how i call it:
<xsl:variable name="breakText">
<xsl:call-template name="insertBreaks">
<xsl:with-param name="subject" select="PublicProfile/AboutMe"/>
</xsl:call-template>
</xsl:variable>
im doing like an article link to "read more" on text click
the first div of the short start of the article (550 chars of the long article)
display the text like i didnt use the "insertBreaks" function
<xsl:copy-of select="substring($breakText,0,550)"/>
but this line of the long description is working fine:
<xsl:copy-of select="$breakText"/>
where i was wrong?
You want to use xsl:value-of not xsl:copy-of. xsl:copy-of returns the elements and all their values of the selected tag. xsl:value-of returns the text associated with the selected tag. Since you're trying to get a substring, you want the text.
The solution used referred to in the question happens to be mine.
It replaces a newline character not with "line-break" but with a <br /> element. An element is a node -- not a string.
Thus, the $breakText as defined in this question is a temporary tree (in XSLT 2.0) or an RTF (Result Tree Fragment) in XSLT 1.0 -- not a string.
The problem is that (regardless of an accompanying minor error of using zero as index):
substring($breakText,0,550)
is a string (calculated from the string value of $breakText) and as such cannot include any <br/> element or any node at all
Remember: The string value of an element or of a tree is the concatenation of the values of all of its text-node descendents.
On the other side:
<xsl:copy-of select="$breakText"/>
copies the temporary tree (in XSLT 2.0) or produces the serialization of the RTF (in XSLT 1.0).
To put it more simply, xsl:copy-of preserves structure, string() or any conversion to string produces just a string -- and a string doesn't have structure (all nodes are gone).

Storing html tags within an xsl variable

Sorry if this is a dumb question, but it is possible to store, and retrieve, a HTML snippet within an xsl 1.0 variable? EG:
<xsl:variable name="something"><p>Hi there</p><p>How are you today?</p></xsl:variable>
<xsl:value-of disable-output-escaping="yes" select="$something"/>
It just when I try, it seems to strip the HTML tags out. Thanks.
You need to use <xsl:copy-of select="$something"/> instead of xsl:value-of.
I'll add some explanation of what's happening :)
The reason you're not getting the html tags is that the $something variable contains a dom fragment, not a string: the value-of element extracts the content of the node(s) the same way as the string() function does, so does not serialize the nodes.
This would provide, instead, a string representation of the html string you have and you can then print it out with value-of and disable-output-escaping:
<xsl:variable name="something"><![CDATA[<p>Hi there</p><p>How are you today?</p>]]></xsl:variable>
(see https://msdn.microsoft.com/en-us/library/ms256181(v=vs.110).aspx "The results are converted to a string, as by a call to the string() function")