25

I tried to substring data with single quote in XSLT:

String : DataFromXML:'12345'

expected Result: 12345

<xsl:value-of select="substring-after('$datafromxml','DataFromXML:')"/>

Result: '12345'

i tried below code

<xsl:value-of select="substring-after('$datafromxml','DataFromXML:&#39;')"/>

<xsl:value-of select="substring-after('$datafromxml','DataFromXML:&apos;')"/>

<xsl:value-of select="substring-after('$datafromxml','DataFromXML:'')"/>

Error:

String literal was not closed 'DataFromXML:'--->'<---
buttowski
  • 4,657
  • 8
  • 27
  • 33

5 Answers5

25

The general rules for escaping are:

In 1.0:

  • if you want the attribute delimiter in a string literal, use the XML escape form &quot; or &apos;
  • if you want the string delimiter in a string literal, you're hosed

In 2.0:

  • if you want the attribute delimiter in a string literal, use the XML escape form &quot; or &apos;
  • if you want the string delimiter in a string literal, double it (for example, 'I can''t')

The use of a variable $quot or $apos as shown by Vitaliy can make the code much clearer.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • 3
    Michael, It is actually possible to extract the number with a single XPath 1.0 expression even in the most complicated case when the string contains both quotes and apostrophes -- not using any variable at all. – Dimitre Novatchev Sep 13 '12 at 12:56
  • 2
    Possible, yes, but only by making such heavy use of entity references that the code becomes totally unreadable. And why are variables so bad anyway? - a good processor will inline them. – Michael Kay Sep 13 '12 at 19:04
  • 5
    I don't have anything against using variables -- just addressed your statement that "if you want the string delimiter in a string literal, you're hosed" . Sorry for trying to be precise. – Dimitre Novatchev Sep 13 '12 at 19:32
11

This should work:

<xsl:variable name="apos">'</xsl:variable>

...

<xsl:value-of select="substring-before(substring-after($datafromxml, concat('DataFromXML:', $apos)), $apos)" />
Vitaliy
  • 2,744
  • 1
  • 24
  • 39
  • Not sure about XPath 1.0 rules - probably it could also be a simpler solution without special variable – Vitaliy Sep 13 '12 at 10:37
8

You could try swapping and " and ' in your xsl:value-of

<xsl:value-of select='substring-before
   (substring-after($datafromxml,"DataFromXML:&apos;"), "&apos;")'/> 

Alternatively, you could make use of the translate function to remove the pesky apostrophes

 <xsl:value-of select='translate
    (substring-after($datafromxml,"DataFromXML:"), "&apos;", "")'/> 

Not necessarily nicer, but it does remove the need for a variable.

Tim C
  • 70,053
  • 14
  • 74
  • 93
4

Even in the most complicated case -- the string contains both a quote and an apostrophe -- the number can be extracted without resorting to variables.

Suppose we have this XML document:

<t>' "12345' "</t>

and want to extruct just the number.

In the following transformation we use a single XPath expression to do exactly that:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="text()">
     <xsl:value-of select=
     'substring-after(.,"&apos;")
     '/>
==============  
     <xsl:value-of select=
     'substring-before(
       substring-after(substring-after(.,"&apos;"), &apos;&quot;&apos;),
       "&apos;"
                       )
     '/>
 </xsl:template>
</xsl:stylesheet>

The result is:

 "12345' "
==============  
     12345

Do note: I am intentionally having two XPath expressions -- the purpose of the first one is to make it simpler to understand what is expressed in the second XPath expression. Leaving just the last xsl:value-of in the template body produces exactly the wanted result:

12345
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
1

Just a note to my future self (or anyone else) who would benefit from a reminder of the exact syntax that worked for me.

Declare this variable

<xsl:variable name="apos" select='"&apos;"'/>

And use it in a condition like this

<xsl:if test="$value = concat('G-2', $apos, 'd')">89594</xsl:if>
NickBeaugié
  • 720
  • 9
  • 17