Escape apostrophe character in a list in XSLT - 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.

Related

XSLT - curly braces in regex

I have a text node from which I have to extract a particular sub string based on a pattern
Below is the actual string:
//Some_string,"some_string_1":"target_string"},some_other_string//
Following is the regex pattern I am trying to use:
<xsl:analyze-string select="text_node/text()" regex=",("some_string_1":.*?)"}">
<xsl:matching-substring>
<xsl:value-of select="substring-after(regex-group(1),':"')"/>
</xsl:matching-substring>
</xsl:analyze-string>
My extracted sub string should be "target_string"
But I am getting the following error
Fatal error during transformation using //my_path: Closing curly brace in attribute value template ",("some_string_1":.*?)"}" must be doubled;
I tried to use double curly braces also but didn't work
Note - I am using Ant script to run the XSLT with saxon-he-10.1.jar
Thanks in advance!
I tend to put regular expressions into an xs:string typed parameter or variable e.g.
<xsl:param name="pattern" as="xs:string">,("some_string_1":(.*?))"}</xsl:param>
then I can use
<xsl:analyze-string select="." regex="{$pattern}">
<xsl:matching-substring>
<xsl:value-of select="regex-group(2)"/>
</xsl:matching-substring>
</xsl:analyze-string>
where I have a lot less to worry about escaping things in an attribute value template like the regex attribute.
Note, that, if you use XSLT 3, it is safer to have
<xsl:param name="pattern" as="xs:string" expand-text="no">,("some_string_1":(.*?))"}</xsl:param>
to avoid any text value template setting higher up in the tree kicking in.
You need to double the curly bracket because it has special meaning in XSLT and escape it because it has special meaning in regex:
",("some_string_1":.*?)"\}}"

XSL - Replace pipe by another character

I use XSLT 2. How I can replace pipe by aonther character ?
For exemple I have an element like this :
<list items="A1|A2|A3"/>
I want to have
<list items="A1,A2,A3"/>
I tried something like this, but not working
<xsl:variable name="result" select="replace(list/#items, '|', ',')"/>
What is problem ?
The replace() function uses regex - and the pipe character is a special character in regex. Either escape the character:
<xsl:variable name="result" select="replace(list/#items, '\|', ',')"/>
or use the translate() function instead.

I would like to include apostrophe in the output attributes

I wrote a code to eradicate all the special characters with a function.
<xsl:function name="lancet:stripSpecialChars">
<xsl:param name="string" />
<xsl:variable name="AllowedSymbols"
select="'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'"/>
<xsl:value-of select="
translate(
$string,
translate($string, $AllowedSymbols, ' '),
' ')
"/>
</xsl:function>
<xsd:element xtt:fixedLength="14" xtt:required="true" xtt:severity="error" xtt:align="left">
<xsl:value-of select="lancet:stripSpecialChars(upper-case(replace(normalize-unicode(translate($emp/wd:First_Name, ',', ' '), 'NFKD'), '⁄', '/')))"/>
</xsd:element>
Now there is a requirement for me to include apostrophe ('). When I am trying to include the same in AllowedSymbols, I am getting an error.
The output Right now is D AGOSTINO. I need something like D'AGOSTINO.
Not sure how to handle this. Could someone please help me out with this. Thanks
You don't say what the error is, but you probably just need to escape the apostrophe in your variable.
This is done by doubling up the apostrophe:
<xsl:variable name="AllowedSymbols" select="'''ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'"/>
Since you're using XSLT 2.0, you should be able to use replace() instead of translate()...
<xsl:function name="lancet:stripSpecialChars">
<xsl:param name="string"/>
<xsl:value-of select="replace($string,'[^A-Z0-9'']','')"/>
</xsl:function>
I'm not replacing lowercase letters since the string you're passing is already forced to uppercase, but if you use the function elsewhere you can add a-z to the character class.
Encode it as &apos; (’ also)
Enclose the value in a CDATA section (recommended as you get rid of encoding problems.
<data><![CDATA[some stuff including D'Agostino & other reserved/problematic characters :-) ]]></data>

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

concat, quotation mark and apostrophe combination problems

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