Сериализация XML в JSON без чрезмерного экранирования

Как избежать экранирования солидуса и двойных кавычек XML в JSON?

Учитывая, что

  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-скрипта) этот вывод 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, saxon:single-quotes, кажется очень соблазнительной и близкой к помощи, но как использовать эту опцию с xml-to-json(), мне неясно.
  • Солидус: Опция сериализации XSLT, map{'method': 'json', 'use-character-maps': map{ '/': '/' }} как описан Мартином Хонненом, кажется соблазнительной, близкой к помощи, но, опять же, как использовать эту опцию с xml-to-json() ускользает (ха) от меня.
  • Атрибуты string/@escape и string/@escape-key, судя по моему прочтению спец. и подтвержденному экспериментально, здесь не помогут.
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
3
0
658
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Связанное предложение с картой символов можно использовать только в том случае, если вы хотите ввести шаг 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\""}]}

Мастерски! В этом ответе используется так много впечатляющих методов XSLT 3.0 JSON и сериализации, что он полностью отвечает не только на мой заданный вопрос, но и на многие незаданные вопросы. Он достоин углубленного изучения всем, кому нужно сериализовать XML в JSON.

kjhughes 31.05.2019 01:38

Другие вопросы по теме