Функция XSLT replace () не работает

Я использую XSLT для преобразования схемы xml в формат JSON, где есть фасет шаблона, как показано ниже:

                <simpleType>
                <restriction base="string">
                    <pattern value="[A-Z0-9a-z_]+(@\{UUID\}|@\{TIMEMILLIS\})?[A-Z0-9a-z]*"/>
                </restriction>
            </simpleType>

Хотя символы '\' необходимы для экранирования регулярных выражений, при преобразовании в JSON их необходимо дополнительно экранировать.

Я использую XSLT 3.0 с Saxon следующим образом:

<if test="child::xsi:simpleType/child::xsi:restriction/child::xsi:pattern">
    <text>,"pattern":"</text><value-of select="replace(attribute::value,'\\','\\')"/><text>"</text>
</if>

Результат по-прежнему оказывается

"pattern": "[A-Z0-9a-z_]+(@\{UUID\}|@\{TIMEMILLIS\})?[A-Z0-9a-z]*"

в формате JSON. Я пробовал много комбинаций, функция replace () здесь не работает.

Я, наверное, что-то упускаю. Я имею в виду определение функции из здесь.

Любая помощь будет оценена.


person Ironluca    schedule 22.01.2019    source источник
comment
Если вы хотите создать JSON с помощью XSLT 3, я думаю, вам следует использовать output method="json" соответственно сериализацию JSON, которая позаботится о любом экранировании внутри строковых значений JSON, если это проблема, которую вы пытаетесь решить. Поэтому не пытайтесь создать JSON вручную, просто создайте XML, который xml-to-json может использовать, или создайте карты XPath 3.1 и сериализуйте их как JSON.   -  person Martin Honnen    schedule 22.01.2019
comment
@MartinHonnen, разве нет возможности заставить функцию замены работать в этом случае?   -  person Ironluca    schedule 22.01.2019
comment
Я уверен, что функция replace работает как указано w3.org/TR/xpath- functions / # func-replace, если вы хотите заменить единственный _2 _ \\\ `в третьем аргументе. Я не понимаю, почему вы хотите создавать JSON вручную и выполнять замену здесь и там, где, по вашему мнению, он вам нужен, вместо того, чтобы полагаться на существующую сериализацию JSON, встроенную в XSLT / XPath 3.   -  person Martin Honnen    schedule 22.01.2019
comment
Кроме того, еще одна причина, по которой функция replace не работает, заключается в том, что вы не находитесь в элементе xsl:pattern, когда делаете это. Вам следует сделать replace(xsi:simpleType/xsi:restriction/xsi:pattern/@value,'\\','\\\\')"   -  person Tim C    schedule 22.01.2019


Ответы (2)


Чтобы заменить \ на \\, нужно написать

replace($x, '\\', '\\\\')

Это из-за правил экранирования в строке замены. (Правила были выбраны неудачно, мы пытались быть совместимыми с другими языками, но другие языки оказались совершенно несовместимыми в этой области.)

Есть другой вариант: используйте флаг q:

replace($x, '\', '\\', 'q')
person Michael Kay    schedule 22.01.2019
comment
Следует отметить, что подход replace ($ x, '\', '\\', 'q') не работал, он не заменял строку. Замена ($ x, '\\', '\\\\') сработала, спасибо - person Ironluca; 23.01.2019

Используйте поддержку XSLT и XPath 3 для создания и сериализации JSON, например. создание карт и сериализация как JSON

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-skip"/>

  <xsl:output method="json" indent="yes"/>

  <xsl:template match="pattern">
      <xsl:sequence select="map { local-name() : data(@value) }"/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/pPzifoX

или создание формата XML, который ожидает функция xml-to-json:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.w3.org/2005/xpath-functions"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">

  <xsl:mode on-no-match="shallow-skip"/>
  <xsl:strip-space elements="*"/>

  <xsl:output method="text" indent="yes"/>

  <xsl:variable name="json-xml">
      <xsl:apply-templates/>
  </xsl:variable>

  <xsl:template match="/">
      <xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
  </xsl:template>

  <xsl:template match="pattern">
      <map>
          <string key="{local-name()}">{@value}</string>
      </map>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/pPzifoX/1

person Martin Honnen    schedule 22.01.2019
comment
Я согласен с тем, что приведенное выше было бы правильным подходом к решению. Спасибо - person Ironluca; 23.01.2019