Сериализация XML в JSON без чрезмерного экранирования - PullRequest
3 голосов
/ 30 мая 2019

Как избежать перехода из XML в JSON через Solidus и двойные кавычки?

При условии, что

  1. символов солидуса (или косая черта , /)может, но не обязательно, экранироваться в JSON, и атрибуты
  2. XML могут использовать ' вместо ", чтобы избежать экранирования в строковых значениях JSON,

лучший способ реализовать эти потенциальные улучшения сериализации в XSLT?


Этот XML ,

<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
  <array key="o_array">
    <map>
      <string key="s/1">x/y/z</string>
    </map>
    <map>
      <string key="s2"><![CDATA[<a href="/x/y">Link</a> a/b "test"]]></string>
    </map>
  </array>
</map>

вход для этого XSLT ,

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
  <xsl:output method="text"/>  
  <xsl:template match="/">
    <xsl:value-of select="xml-to-json(.,map{'indent':true()})"/>
  </xsl:template>
</xsl:stylesheet>

выходов (через Saxon, XSLT Fiddle demo ) это JSON вывод:

{ "o_array" : 
  [ 
    { "s\/1" : "x\/y\/z" },

    { "s2" : "<a href=\"\/x\/y\">Link<\/a> a\/b \"test\"" } ] }

В целях эстетики (выше JSON этоизлишне уродливый) и минимизируя размер файла (после отключения отступа), я хотел бы создать следующее JSON вместо:

{ "o_array" : 
  [ 
    { "s/1" : "x/y/z" },

    { "s2" : "<a href='/x/y'>Link</a> a/b \"test\"" } ] }

Примечания:

  • Одиночные кавычки: Вариант сериализации, специфичный для саксонской, saxon:single-quotes, кажется дразнящим близким к помощиg, но как использовать эту опцию с xml-to-json() мне неясно.
  • Solidus: Опция сериализации XSLT, map{'method': 'json', 'use-character-maps': map{ '/': '/' }} как описанаМартином Хонненом , кажется, дразнит близость к помощи, но, опять же, как использовать эту опцию с xml-to-json(), ускользает от меня.
  • string/@escape и string/@escape-key атрибуты, согласно моим прочтениям spec и подтвержденные экспериментально, здесь не могут помочь.

1 Ответ

1 голос
/ 30 мая 2019

Связанное предложение с картой персонажа можно использовать, только если вы готовы ввести шаг parse-json() => serialize(...):

. => xml-to-json() => parse-json() => serialize(map { 'method' : 'json', 'use-character-maps' : map { '/' : '/' } })

Таким образом, с

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0">

  <xsl:output method="text"/>

  <xsl:template match="/">
      <xsl:value-of select=". => xml-to-json() => parse-json() => serialize(map { 'method' : 'json', 'use-character-maps' : map { '/' : '/' } })"/>
  </xsl:template>

</xsl:stylesheet>

в https://xsltfiddle.liberty -development.net / b4GWVd / 25 Я получаю

{"o_array":[{"s/1":"x/y/z"},{"s2":"<a href=\"/x/y\">Link</a> a/b \"test\""}]}

Вставить параметр сериализации, специфичный для Saxon, в строковые значения, которые являются фрагментами XML. Я думаю, вы можете попытаться выполнить вводсначала через режим, который просто выполняет еще один шаг разбора и сериализации, только на этот раз как

. => parse-xml-fragment() => serialize(map {
                        'method': 'xml',
                        QName('http://saxon.sf.net/', 'single-quotes'): true()
                    })

С Saxon 9,9 EE в oXygen и

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">

    <xsl:output method="text"/>

    <xsl:template match="/">
        <xsl:value-of
            select="
                $single-quotes => xml-to-json() => parse-json() => serialize(map {
                    'method': 'json',
                    'use-character-maps': map {'/': '/'}
                })"
        />
    </xsl:template>

    <xsl:variable name="single-quotes">
        <xsl:apply-templates mode="serialize-fragments"/>
    </xsl:variable>

    <xsl:mode name="serialize-fragments" on-no-match="shallow-copy"/>

    <xsl:template match="string" mode="serialize-fragments"
        xpath-default-namespace="http://www.w3.org/2005/xpath-functions">
        <xsl:copy>
            <xsl:apply-templates select="@*" mode="#current"/>
            <xsl:try
                select="
                    . => parse-xml-fragment() => serialize(map {
                        'method': 'xml',
                        QName('http://saxon.sf.net/', 'single-quotes'): true()
                    })">
                <xsl:catch select="string()"/>
            </xsl:try>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Я получаю

{"o_array":[{"s/1":"x/y/z"},{"s2":"<a href='/x/y'>Link</a> a/b \"test\""}]}
...