xsl-list
[Top] [All Lists]

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

2013-11-20 08:48:07
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 Jusevičius
<martynas(_at_)graphity(_dot_)org> 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(_at_)saxonica(_dot_)com> 
wrote:

On 29 Oct 2013, at 11:02, Martynas Jusevičius 
<martynas(_at_)graphity(_dot_)org> 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(_at_)saxonica(_dot_)com> 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 Jusevičius 
<martynas(_at_)graphity(_dot_)org> 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

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


<Prev in Thread] Current Thread [Next in Thread>