concat, quotation mark and apostrophe combination problems - xslt

I tried different ways and also looked around but can't get this running.
I need to concat the following:
"concat(
'this is; \"a sample',
//XML_NODE,
'\"; \"using an apostrophe',
''',
'in text\"'
)"
one line version:
"concat( 'this is; \"a sample', //XML_NODE, '\"; \"using an apostrophe', ''', 'in text\"' )"
The output should be:
this is "a sample XML_NODE_VALUE"; "using an apostrophe ' in text"
The problem is the ' in the text. concat use it to end a string and expect an following ; or the end of concat. Escaping or HTML entities all seems to not work.
Any help is really appreciated.
Thanks!

In XML/XSLT you do not escape characters with a backslash.
In XML you can use entity references.
In XSLT you can use entity references and variables.
The problem with the apostrophe inside of your concat strings is that the XML parser loading the XSLT will expand it before the concat gets evaluated by the XSLT engine; so you can't use an entity reference for the apostrophe character unless it is wrapped in double quotes (or entity references for double quotes, as Dimitre Novatchev's answer demonstrates).
Use the entity reference " for the double quote ".
Create a variable for the apostrophe character and reference the variable as one of the components of the concat()
Applied in the context of an XSLT:
<xsl:variable name="apostrophe">'</xsl:variable>
<xsl:value-of select="concat(
'this is; "a sample',
//XML_NODE,
'"; "using an apostrophe ',
$apostrophe,
' in text"'
)" />
If you need a 100% XPath solution that avoids the use of XSLT variables, then Dimitre's answer would be best.
If you are concerned with how easy it is to read, understand, and maintain, then Michael Kay's suggestion to use XSLT variables for the quote and apostrophe might be best.

No variable is necessary:
Here is an example how to produce the wanted output in two ways:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:text>this is "a sample XML_NODE_VALUE"; "using an apostrophe ' in text"</xsl:text>
=============
<xsl:value-of select=
"concat('this is ',
'"a sample XML_NODE_VALUE"; "',
"using an apostrophe &apos; in text",
'"'
)
"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on any XML document (not used), the wanted output is produced:
this is "a sample XML_NODE_VALUE"; "using an apostrophe ' in text"
=============
this is "a sample XML_NODE_VALUE"; "using an apostrophe ' in text"

I find the easiest solution is to declare variables:
<xsl:variable name="apos">'</xsl:variable>
<xsl:variable name="quot">"</xsl:variable>
<xsl:value-of select="concat('This is ', $quot, "a sample using ", $apos)"/>

Related

Escape apostrophe character in a list in XSLT

How can I use the apostrophe ' character in a list? The following code fails, because the list contains an unescaped character in word "Fruit's 13". I tried escape it by backslash character and also by ', but none of them worked.
<xsl:param name="unsorted-values" as="xs:string*" select="'Apple','Banana','Fruit's 13'"/>
<xsl:param name="values" as="xs:string*">
<xsl:perform-sort select="$unsorted-values">
<xsl:sort select="string-length()" order="descending"/>
</xsl:perform-sort>
</xsl:param>
In XPath 2 and later in string literal delimited by single quotes (apostrophs) you can double '' a single quote/apostroph to have it escaped inside the string value, most attributes of XSLT like select use XPath expressions so there you can use that syntax.
Of course in the context of XSLT/XML you could also use select="'Apple', 'Banana', "Fruit's 13"".
XPath 3.1 syntax section for that is in https://www.w3.org/TR/xpath-31/#prod-xpath31-StringLiteral.

replace string in xslt 2.0 with replace function

I have a string like this
"My string"
Now I want to replace my with best so that the output will be like best string.
I have tried some thing like this
<xsl:value-of select="replace( 'my string',my,best)"/>
but probably its a wrong syntax
I have googled a lot but found nothing..every where the mechanism to do this XSLT 1.0 is explained.Can any one tell me how to do it in XSLT 2.0 ,The easy way compared to 1.0
Given:
<xsl:variable name="s1" select="'My string'"/>
Simply use:
<xsl:value-of select="replace($s1, 'My', 'best')"/>
Note that a regular expression is applied. Meaning:
<xsl:value-of select="replace('test.replace', '.', ':')"/>
Becomes:
::::::::::::
Be sure to escape the characters that have special meaning to the regular expression interpreter:
<xsl:value-of select="replace('test.replace', '\.', '::')"/>
Becomes:
test::replace
First check, if your xslt processor (saxxon) is the latest release. Then you have to set
<xsl:stylesheet version="2.0" in the head of your xslt-stylesheet. That's it.
Your code was fine, besides you forgot the apostrophs:
<xsl:value-of select="replace( 'my string',my,best)"/>
must be
<xsl:value-of select="replace('my string','my','best')"/>

apostrophe in xsl:format-number

I parse an xml with my xslt and get the result as a xml.
i need to format numbers with apostrophe as delimiter for a tousand, million, etc...
eg: 1234567 = 1'234'567
now the problem is how do i get these apostrophes in there?
<xsl:value-of select="format-number(/path/to/number, '###'###'###'###')" />
this doesn't work because the apostrophe itself is already delimiting the start of the format.
is there a simple solution to that (maybe escaping the apostrophe like in c#?
The answer depends on whether you are using 1.0 or 2.0.
In 2.0, you can escape the string delimiter by doubling it (for example 'it''s dark'), and you can escape the attribute delimiter by using an XML entity such as ". So you could write:
<xsl:value-of select="format-number(/path/to/number, '###''###''###''###')" />
In 1.0, you can escape the attribute delimiter by using an XML entity, but there is no way of escaping the string delimiter. So you could switch your delimiters and use
<xsl:value-of select='format-number(/path/to/number, "###&apos;###&apos;###&apos;###")' />
The other way - probably easier - is to put the string in a variable:
<xsl:variable name="picture">###'###'###'###</xsl:variable>
<xsl:value-of select="format-number(/path/to/number, $picture)" />
After some research we came up with this solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:decimal-format name='ch' grouping-separator="'" />
<xsl:template match="/">
<xsl:value-of select='format-number(/the/path/of/the/number, "###&apos;###&apos;###", "ch")'/>
...

How can I translate ' into an apostrophe in xslt

The relevant parts of the code:
<xsl:variable name="apos">'</xsl:variable>
<xsl:variable name="and" select='"'"' />
<xsl:value-of select="translate(products_name/node(),$and,$apos)"/>
I'm thinking this should be a simple thing and that the above code should work but it doesn't effect the output at all.
(I used variables because names cannot begin within an ampersand and using just an apostrophe brings up a compile error.)
I've tested the code to make sure the translate is working using strings and there are no errors there.
Any help would be greatly appreciated.
You are on the right track, but not yet there: Your problem is, that XSL is a language that itself is written using XML. For all XML languages, the parser automatically decodes XML entities. The XSLT engine only comes afterwards.
As a result, the XSLT engine neither does nor can distinguish whether you wrote ' or ' - it's the same. For your problem, this has two effects:
You have to use a variable containing the apostrope - this is because the apostrophe itself is reserved for string literals in expressions that may contain functions. Even for <xsl:value-of select="translate(products_name/node(),$and,''')"/>, the XML parser transforms the entity into an apostrophe, i.e. <xsl:value-of select="translate(products_name/node(),$and,''')"/>
You have to escape the ampersand used in the string you search for: for the XSL engine, the variable "and" contains the value ', i.e. you are replacing an apostrophe with an apostrophe.
Working solution:
<xsl:variable name="apos">'</xsl:variable>
<xsl:value-of select='translate(text(), "&#039;", $apos)'/>
Technically, there's no difference in any XML between &apos;, ' and ', they're different ways of representing exactly the same thing. Therefore, that translate call shouldn't do anything.
It depends on how you're transforming it, where that output is (attribute value or element?), and how the output is serialized to text, but your problem isn't with your XSLT.

Concatenate with escaped chars in xslt?

I'm writing xslt code which concatenates some string:
<xsl:attribute name='src'>
<xsl:value-of select="concat('url(&apos;', $imgSrc, '&apos;)')" />
</xsl:attribute>
For some reason I can't use it, I keep getting this error:
Unknown function - Name and number of arguments do not match any function signature in the static context - 'http://www.w3.org/2005/xpath-functions:concat'
while evaluating the expression:
select="concat('url(&apos;', $imgSrc, '&apos;)')"
Any idea?
thx
====================
EDIT
I'm trying to get:
url('some_path')
Was having trouble with the apostrophes, but now it just doesn't work.
The &apos; references are resolved by the XML parser that parses your XSLT. Your XSLT processor never sees them. What your XSLT processor sees is:
concat('url('', $imgSrc, '')')
Which is not valid because the commas don't end up in the right place to separate the arguments. However, this might work for you, depending on the serializer your XSLT processor uses:
concat("url('", $imgSrc, "')")
This surrounds the arguments in double-quotes, so that your single-quotes do not conflict. The XSLT processor should see this:
concat("url('", $imgSrc, "')")
Another option is to define a variable:
<xsl:variable name="apos" select='"&apos;"'/>
Which can be used like this:
concat('url(', $apos, $imgSrc, $apos, ')')
More here:
When you apply an XSLT stylesheet to a
document, if entities are declared and
referenced in that document, your XSLT
processor won't even know about them.
An XSLT processor leaves the job of
parsing the input document (reading it
and figuring out what's what) to an
XML parser; that's why the
installation of some XSLT processors
requires you to identify the XML
parser you want them to use. (Others
include an XML parser as part of their
installation.) An important part of an
XML parser's job is to resolve all
entity references, so that if the
input document's DTD declares a cpdate
entity as having the value "2001" and
the document has the line "copyright
&cpdate; all rights reserved", the XML
parser will pass along the text node
"copyright 2001 all rights reserved"
to put on the XSLT source tree.
From http://www.w3.org/TR/xpath/#NT-Literal
[29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
Meaning that an XPath literal string value can't have the delimiter as also part of the content.
For this you should use the host language. In XSLT:
<xsl:variable name="$vPrefix">url('</xsl:variable>
<xsl:variable name="$vSufix">')</xsl:variable>
<xsl:attribute name="src">
<xsl:value-of select="concat($vPrefix, $imgSrc, $vSufix)" />
</xsl:attribute>
Or more proper:
<xsl:attribute name="src">
<xsl:text>url('</xsl:text>
<xsl:value-of select="$imgSrc"/>
<xsl:text>')</xsl:text>
</xsl:attribute>