Get child from node and pass into attribute - xslt

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.

Related

How to use a variable value

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.

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')"

XSLT, how to use "xsl:value-of" inside "xsl:if"?

I am new to xslt and I am wondering whether it is possible to compare the value of "#userNameKey" and the value of
<xsl:value-of select="./text()"/> in example below?
<xsl:if test="#userNameKey='??????'">
<xsl:attribute name="selected">true</xsl:attribute>
</xsl:if>
<xsl:value-of select="./text()"/>
Basically, I just want to replace the questionmarks with the following fragment: <xsl:value-of select="./text()"/> but there is an issue with the double quotes. Should I use escape characters (if yes, what are they?) or there is a better solution?
If you specifically want to compare against the value of the first text node child of the current element (which is what <xsl:value-of select="./text()"/> gives you), then use
<xsl:if test="#userNameKey=string(text())">
At first sight
<xsl:if test="#userNameKey=text()">
may seem more obvious, but this is subtly different, returning true if the userNameKey matches any one of the text node children of the current element (not necessarily the first one).
But if (as I suspect you really mean) you want to compare the userNameKey against the complete string value of the element even if that consists of more than one text node, then use
<xsl:if test="#userNameKey=.">
Remember that text() is a node set containing all the text node children of the context node, and if you're not sure you need to use it (e.g. when you want to process each separate text node individually) then you probably don't.
You should be able to do just this...
<xsl:if test="#userNameKey=./text()">
<xsl:attribute name="selected">true</xsl:attribute>
</xsl:if>
In fact, the ./ is not needed here, so you can just do this
<xsl:if test="#userNameKey=text()">
<xsl:attribute name="selected">true</xsl:attribute>
</xsl:if>

Why isn't local-name() returning anything?

I'm trying to run the following template:
<xsl:template match="*[starts-with(., 'ATTITUDE_')]/text()">
<xsl:variable name="ElementName" select="local-name()"/>
<xsl:variable name="vVal" select= "$vAttitudes[. = substring-after(current(), '_')]/#val"/>
<xsl:choose>
<xsl:when test="contains($ElementName, 'Refuse')">
<xsl:value-of select="civf:book-capitalise($vAttitudes[#val = $vVal+1])"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="civf:book-capitalise($vAttitudes[#val = $vVal])"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
So the premise is, find the name of the element, if it has the text "Refuse" in the name of it then "doTheThing"+1 otherwise just "doTheThing". However this test always fails so +1 never gets called even if the element has "Refuse" in the name. If I just output local-name then I get empty too. Why does local-name() not appear to work here?
I did previously try to start the template with:
<xsl:template match="*[contains(., 'Refuse')]/name()">
But Saxon complained that I was running too many functions in the match sequence.
I apologise in advance for not knowing too much about XSLT.
I believe that local-name() does not work because you are matching text nodes (/text() in the match attribute), and text nodes do not have local names.
I'm not sure what you are trying to do but I don't think you actually want to match /text() but instead the whole element, and obtain its text() afterwards.
Alternatively, you could try using local-name(..) to get the name of parent node but I'm not sure about that.

xsl strange behaviour using variables

I've stored a file's tree into $onto
<xsl:variable name="onto" select="document('file.xml')"/>
In some places I can use this variable as espected:
<xsl:copy-of select="$onto/rdf:RDF"/>
But I'm having trouble in other places, strange chars are written on output:
<xsl:element name="autor">
<xsl:attribute name="rdf:resource">
<xsl:text>#</xsl:text> <xsl:value-of select="$onto"/>
</xsl:attribute>
</xsl:element>
This is the beginig of the output I've got:
<autor rdf:resource="#
What I'm missing? What's wrong?
If that's to much for an attribute, what can I do?
Thank you
When <xsl:value-of> is applied to a tree fragment, it takes the text content of that tree. In your case, it looks like your XML file doesn't contain any text (other than whitespace) which isn't in an attribute value. I suspect that you mean to select the value of a particular attribute node within the document, e.g.:
<xsl:value-of select="$onto//foo/#bar"/>
(Without knowing the structure of your XML and what you're trying to select, I don't know what the real path would be.)