XSL - Replace pipe by another character - xslt

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.

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.

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>

How to craft an entity in XSLT

How can I create the entity ' ', if I have the part starting with the '#' in a variable?
When I try to do something like this:
concat('&', '#160;')
I get an syntax error in XMLspy.
Does it have to be an entity (actually you mean a "character reference"), or will it do just to output a non-breaking space character?
To do the latter, given that $var holds "#160", in XSLT 2.0 you can use
<xsl:value-of select="codepoints-to-string(number(substring($var, 2)))"/>
The problem with your code is that, in XML, you cannot use a standalone &, so it should be like this:
concat('&', '#160;')
which outputs &#160; if the output method is xml and   if text.
disable-output-escaping helps to force   in xml output:
<xsl:value-of select="concat('&', '#160;')" disable-output-escaping="yes"/>
Another way to replace a character by an arbitrary string is using character maps:
<xsl:output use-character-maps="foo"/>
<xsl:character-map name="foo">
<xsl:output-character character="&" string="&"/>
</xsl:character-map>
<xsl:template match="/">
<xsl:value-of select="concat('&', '#160;')"/>
</xsl:template>

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 do I convert strings starting with numbers to numeric data in XSLT?

Given the following XML:
<table>
<col width="12pt"/>
<col width="24pt"/>
<col width="12pt"/>
<col width="48pt"/>
</table>
How can I convert the width attributes to numeric values that can be used in mathematical expressions? So far, I have used substring-before to do this. Here is an example template (XSLT 2.0 only) that shows how to sum the values:
<xsl:template match="table">
<xsl:text>Col sum: </xsl:text>
<xsl:value-of select="sum(
for $w
in col/#width
return number(substring-before($w, 'pt'))
)"/>
</xsl:template>
Now my questions:
Is there a more efficient way to do the conversion than substring-before?
What if I don't know the text after the numbers? Any way to do it without using regular expressions?
This is horrible, but depending on just how much you know about the potetntial set of non-numeric characters, you could strip them with translate():
translate("12jfksjkdfjskdfj", "abcdefghijklmnopqrstuvwxyz", "")
returns
"12"
which you can then pass to number() as currently.
(I said it was horrible. Note that translate() is case sensitive, too)
I found this answer from Dimitre Novatchev that provides a very clever XPATH solution that doesn't use regex:
translate(., translate(.,'0123456789', ''), '')
It uses the nested translate to strip all the numbers from the string, which yields all other characters, which are used as the values for the wrapping translate function to strip out and return just the number characters.
Applied to your template:
<xsl:template match="table">
<xsl:text>Col sum: </xsl:text>
<xsl:value-of select="sum(
for $w
in col/#width
return number(translate($w, translate($w,'0123456789', ''), ''))
)"/>
</xsl:template>
If you are using XSLT 2.0 is there a reason why you want to avoid using regex?
The most simple solution would probably be to use the replace function with a regex pattern to match on any non-numeric character and replace with empty string.:
replace($w,'[^0-9]','')