|
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, '"',
> '\\"')"/>
> <xsl:variable name="string" select="replace($string, '''',
'\\''')"/>
> <xsl:variable name="string" select="replace($string, '	',
'\\t')"/>
> <xsl:variable name="string" select="replace($string, ' ',
'\\n')"/>
> <xsl:variable name="string" select="replace($string, ' ',
'\\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(., '\\',
>>> '\\\\'), '''', '\\'''), '"', '\\"'), '	', '\\t'),
>>> ' ', '\\n'), ' ', '\\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, '"', '\\"')"/>
>> ...
>> <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(.,
'"', '\\"') ! ....."/>
>> </xsl:variable>
>>
>> Michael Kay
>> Saxonica
>>
>>
>>
>>> <xsl:value-of
>>> select="replace(replace(replace(replace(replace(replace(., '\\',
>>> '\\\\'), '''', '\\'''), '"', '\\"'), '	', '\\t'),
>>> ' ', '\\n'), ' ', '\\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 |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| Re: [xsl] JSON-encoding strings in , Martynas Jusevičius | Thread | [xsl] exclude-result-prefixes issue, Andrew Welch |
| [xsl] [Announce] Video streaming of, G. Ken Holman | Date | RE: [xsl] XSLT... Good enough to ea, Michele R Combs |
| Month |