How to express a string containing both apostrophes and quotes in XPath? - xslt

I'll spare you the details because they would be needlessly confusing. Long story short, I'm using XSLT 1.0 to generate XSL documents, I'm trying to compare a variable to a literal string, and that string may contain quotes and apostrophes.
For the sake of simplicity, let's say that this literal is composed of two characters: a quote followed by an apostrophe. In reality, it can be any text really. Is there a simpler way to do this:
<xsl:if test="$var = concat('"', "'")">
than this?
<xsl:variable name="str">"'</xsl:variable>
<xsl:if test="$var = $str">
I have checked XPath's specs and there doesn't seem to be a way to escape characters, so the following would not work as desired:
<xsl:if test="$var = '"&apos;'">
Thanks!

There's no way to do it neatly in XPath 1.0. In XPath 2.0, you can escape both kinds of quotes by doubling.

& quot;& amp;&(!)apos; -looks much better, but what did you want to get?
In anyway: once I have written application that deals with producing of Javascript over XSLT.
The same problem with huge number of & quot;,... we solved in 2 ways:
Declare global xsl:param, $q - looks shorter than & quot;
Use 'translate' XPath function, make assumption '!' - is a & quot;, # is a & amp; ..

Related

Acute accent character eliminate using xslt

I am trying to either eliminate or replace the acute accent character with a simple single quote character in xslt 1.0.This is what I have tried so far and none of them replace that character. What could be wrong with my translate construct?
<xsl:value-of select="translate(HeaderFields/Name,'#xb4','')"/>
<xsl:value-of select="translate(HeaderFields/Name,'0xb4','')"/>
<xsl:value-of select="translate(HeaderFields/Name,'´','\'')"/>
Try:
<xsl:value-of select='translate(HeaderFields/Name,"´","&apos;")'/>
Note the exchange of double and single quotation marks - see explanation at: https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Introduction
You can express an acute accent as '´' or as ´. Neither '#xb4' nor '0xb4' is correct. (Were you just guessing?)
Expressing the single quote is a bit trickier. In XSLT 2.0 you can write it as '''', but that doesn't work in 1.0. In 1.0 the best way is to use a variable:
<xsl:variable name="apos">'</xsl:variable>
<xsl:value-of select="translate(HeaderFields/Name,'´',$apos)"/>
Finally, you need to be aware that an acute accent might not be a free-standing Unicode character; it might be combined with the character that it modifies, so for example á could be expressed as the single code point xE1. To ensure that it is a separate character you need to convert the text to decomposed normal form, which can be done in 2.0 using the normalize-unicode() function, but this is not available in 1.0.

XSLT 2 analyze-string finding block names

I am trying to detect strings in other languages in my XML.
I thought I could use something like :
<xsl:analyze-string select="$mystring" regex="(\p{InGreek})" >
but I am unable to make this work.
Do you think this is possible in XSLT ? How would you do this ?
Thanks a lot.
Maria
(XSLT 2, Saxon-HE 9.8.0.8)
I think the right category name would be IsGreek so the regular expression would be \p{IsGreek}, however as the regex attribute of xsl:analyze-string allows attribute value templates you either need to put the expression into a string variable <xsl:param name="pattern" as="xs:string">\p{IsGreek}</xsl:param>you reference as regex="{$pattern}" or you need to duplicate the curly braces, as in regex="\p{{IsGreek}}".

What escape character for fn:replace function

I have to to change a bad char to a quotation mark but I can't escape this last one.
Doing this doesn't work
<xsl:value-of select="fn:replace(prog:intitules/prog:intitule_fr,'¿', '\'')"/>
it produces
net.sf.saxon.trans.XPathException: Unmatched quote in expression
Same error with double or triple escapes '\' or '\\'.
My editor refuses this alternative syntax:
<xsl:value-of select='fn:replace(prog:intitules/prog:intitule_fr,"¿", "'")'/>
Any idea ?
Bernard
Try it this way:
<xsl:value-of select='replace(input, "¿", "&apos;")'/>
In XPath 2.0+, you can escape an apostrophe within an apostrophe-delimited string literal by doubling it. So try:
''''
You need to think very carefully about escapes when you're using regular expressions within XPath within XSLT. Why does the character need escaping?
If it has a special meaning in regular expressions (for example '(') then use a backslash
If it isn't allowed because of XPath rules (like here), use XPath escaping (write 'O'Neil' as 'O''Neil' or "a="3"" as "a=""3""")
If it isn't allowed because of XML rules (e.g. "<"), use XML escaping (write < as <)
The reason this doesn't work:
<xsl:value-of select='fn:replace(prog:intitules/prog:intitule_fr,"¿", "'")'/>
is that the XML parser is treating the apostrophe within the string literal as marking the end of the value of the select attribute. So here you have an XML issue, and under rule 3 you therefore need to use XML escaping (&apos;)
Assuming your files are utf-8 encoded, you could you try a workaround, using the Unicode apostrophe character (hexadecimal 2BC) instead of quote (hexadecimal 27):
<xsl:value-of select="fn:replace(prog:intitules/prog:intitule_fr,'¿', 'ʼ')"/>
Edited: searching a little bit more, I discovered that switching ' and " and using the entity &apos; will get the same result, as michael.hor257k proposed meanwhile:
<xsl:value-of select='fn:replace(prog:intitules/prog:intitule_fr,"¿", "&apos;")'/>

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.

lower case the first character of a string using only xslt 1.0

I have seen patterns for translating a string into lower (or upper case) using the translate function for folks stuck using xslt 1.0.
Is there a elegant way of just making the first letter of a string lowercase?
TestCase => testCase
If your string were, for example, in an attribute called name:
<xsl:value-of select="concat(translate(substring(#name, 1, 1), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), substring(#name, 2))"/>
You should be able to combine substring and concat with translate to do it like so:
concat(translate(substring(s,1,1), $smallcase, $uppercase),substring(s,2))
Use the XPath translate function, having separated the string into first character and the rest. This will require somewhat long winded XSLT using multiple variables to hold intermediate results.
XSLT has a substring function, so you could use that pattern with the substring function to get what you want.