Re: [xsl] JSON-encoding strings in XSLT 2.0

Subject: Re: [xsl] JSON-encoding strings in XSLT 2.0
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxx>
Date: Wed, 20 Nov 2013 09:47:46 -0500
Martynas,

What do you mean by 'fragile' exactly? It's true it's not very pretty;
if it's fragile under maintenance that's mainly due to the string
processing. This is not XSLT's strength; and it'll be better under
XSLT 3.0 (as Mike showed).

You could do a bit of further refactoring like so:

<xsl:template name="html-json">
  <xsl:for-each-group select="xhtml:div/*" group-by="true()">
    <xsl:text>{ html: '</xsl:text>
    <xsl:value-of disable-output-escaping="yes">
      <xsl:call-template name="json-escape">
        <xsl:with-param name="string">
          <xsl:apply-templates select="current-group()"
mode="xml-to-string"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:value-of>
    <xsl:text>' }</xsl:text>
</xsl:template>

Then replace your xsl:if block with a call to this template.

Note: untested.

You might also consider using a character map instead of
disable-output-escaping, which is an optional feature in XSLT 2.0
processors.

Cheers, Wendell
Wendell Piez | http://www.wendellpiez.com
XML | XSLT | electronic publishing
Eat Your Vegetables
_____oo_________o_o___ooooo____ooooooo_^


On Tue, Nov 19, 2013 at 7:42 PM, Martynas JuseviD
ius
<martynas@xxxxxxxxxxxx> wrote:
> Michael,
>
> I now realised this solution was incomplete. I have to pass a piece of
> XHTML as a string into a WYSIWYG editor constructor, so not only the
> characters inside text nodes are significant, but also the markup
> itself. For example, the quotes surrounding attributes have to be
> escaped for JSON as well. I ended up with a solution involving
> xml-to-string.xsl [1] and disable-output-escaping="yes":
>
>                 <script type="text/javascript">
>                 jQuery(function() {
>                     jQuery('#textarea').wymeditor(
>                     <xsl:if test="xhtml:div/*">
>                         <xsl:text>{ html: '</xsl:text>
>                         <xsl:variable name="escaped-xhtml">
>                             <xsl:apply-templates select="xhtml:div/*"
> mode="xml-to-string"/>
>                         </xsl:variable>
>                         <xsl:variable name="escaped-json">
>                             <xsl:call-template name="json-escape">
>                                 <xsl:with-param name="string"
> select="$escaped-xhtml"/>
>                             </xsl:call-template>
>                         </xsl:variable>
>                         <xsl:value-of disable-output-escaping="yes"
> select="$escaped-json"/>
>                         <xsl:text>' }</xsl:text>
>                     </xsl:if>)
>                 });
>                 </script>
>
>     <xsl:template name="json-escape">
>         <xsl:param name="string" as="xs:string?"/>
>         <xsl:variable name="string" select="replace($string, '\\',
'\\\\')"/>
>         <xsl:variable name="string" select="replace($string, '&quot;',
> '\\&quot;')"/>
>         <xsl:variable name="string" select="replace($string, '''',
'\\''')"/>
>         <xsl:variable name="string" select="replace($string, '&#09;',
'\\t')"/>
>         <xsl:variable name="string" select="replace($string, '&#10;',
'\\n')"/>
>         <xsl:variable name="string" select="replace($string, '&#13;',
'\\r')"/>
>
>         <xsl:value-of select="$string"/>
>     </xsl:template>
>
> It works, but seems rather fragile to me. I wonder if there is a better
way?
>
> [1] http://lenzconsulting.com/xml-to-string/
>
> Martynas
> graphityhq.com
>
> On Tue, Oct 29, 2013 at 12:46 PM, Michael Kay <mike@xxxxxxxxxxxx> wrote:
>>
>> On 29 Oct 2013, at 11:02, Martynas JuseviD
ius <martynas@xxxxxxxxxxxx>
wrote:
>>
>>> Thanks Michael. I was looking at http://json.org and here's what I came up
with:
>>>
>>>    <xsl:template match="text()" mode="json-identity">
>>>        <xsl:value-of
>>> select="replace(replace(replace(replace(replace(replace(., '\\',
>>> '\\\\'), '''', '\\'''), '&quot;', '\\&quot;'), '&#09;', '\\t'),
>>> '&#10;', '\\n'), '&#13;', '\\r')"/>
>>>    </xsl:template>
>>>
>>> Can this be improved?
>>
>> Well, I'm not going to check that the list of characters to be escaped is
complete, but you've got the right idea. I would code it like this for
readability:
>>
>>>  <xsl:template match="text()" mode="json-identity">
>>        <xsl:variable name="v" select="."/>
>>        <xsl:variable name="v" select="replace($v, '\\', '\\\\')"/>
>>        <xsl:variable name="v" select="replace($v, '&quot;', '\\&quot;')"/>
>>        ...
>>        <xsl:value-of select="$v"/>
>> </xsl:variable>
>>
>> or in 3.0 you can use the "!" operator for function chaining:
>>
>>> <xsl:template match="text()" mode="json-identity">
>>        <xsl:value-of select="replace(., '\\', '\\\\') ! replace(.,
'&quot;', '\\&quot;') ! ....."/>
>> </xsl:variable>
>>
>> Michael Kay
>> Saxonica
>>
>>
>>
>>>        <xsl:value-of
>>> select="replace(replace(replace(replace(replace(replace(., '\\',
>>> '\\\\'), '''', '\\'''), '&quot;', '\\&quot;'), '&#09;', '\\t'),
>>> '&#10;', '\\n'), '&#13;', '\\r')"/>
>>    </xsl:template>
>>
>>>
>>> On Tue, Oct 29, 2013 at 10:37 AM, Michael Kay <mike@xxxxxxxxxxxx> wrote:
>>>>
>>>> There's no built-in function for the job, but picking out the characters
=
>>>> that need special treatment (e.g. replacing newline by "\n") isn't =
>>>> difficult. Handling astral characters is a bit tricky because JSON =
>>>> requires them to be represented as a surrogate pair, but again the logic
=
>>>> for that isn't really difficult.
>>>>
>>>> Michael Kay
>>>> Saxonica
>>>>
>>>> On 29 Oct 2013, at 00:56, Martynas JuseviD
ius <martynas@xxxxxxxxxxxx>
wrote:
>>>>
>>>>> Hey,
>>>>>
>>>>> is there some way in XSLT 2.0 to encode strings for use in JSON? In my
>>>>> case, the stylesheet has to encode all text nodes in a XHTML fragment
>>>>> which then gets passed to WYSIWYM editor constructor. Could this be
>>>>> done as identity transform?
>>>>>
>>>>> I had solved this problem when I used XSLT 1.0 on PHP by calling
>>>>> json_encode() as extension function, but now I'm in the Java world.
>>>>> http://php.net/manual/en/function.json-encode.php
>>>>>
>>>>> Martynas
>>>>> graphityhq.com

Current Thread