Как использовать шаблон замены регистра с функцией замены Xpath

У меня есть эта демонстрация регулярных выражений и шаблонов подстановки, и мне нужно использовать ее в контексте xpath с Функция fn:replace, но я не могу понять, как правильно написать строку замены Возможно ли это? мой наивный тест был

replace ("dsfjkljsdfjlsjdfABCDdfsfsdff",
             "(\p{Lu})(\p{Lu}+)",
             "$1\L$2")

но он жалуется на FORX0004: недопустимая строка замены в replace(): за символом \ должен следовать \ или $


person Mystic Tm    schedule 19.06.2020    source источник
comment
Можете объяснить на понятном языке, какую замену вы хотите выполнить? Также рассмотрите возможность включения соответствующих образцов в текст вопроса. Обратите внимание, что в XSLT 2 и более поздних версиях у вас есть пользовательские функции и xsl:analyze-string для реализации чего-либо с регулярными выражениями, которые XPath 2 replace может вам не дать, поэтому, если вы хотите применить строковую функцию к части совпадения, я думаю, вы должны посмотреть на этот вариант.   -  person Martin Honnen    schedule 20.06.2020
comment
цель состоит в том, чтобы обнаружить последовательность смежных символов ВЕРХНЕГО РЕГИСТРА в слове и преобразовать ее в верхний регистр.   -  person Mystic Tm    schedule 20.06.2020


Ответы (2)


Я думаю, вы хотите, например.

<xsl:function name="mf:lower-case-match">
  <xsl:param name="input" as="xs:string"/>
  <xsl:param name="regex" as="xs:string"/>
  <xsl:analyze-string select="$input" regex="{$regex}">
    <xsl:matching-substring>
      <xsl:value-of select="concat(regex-group(1), lower-case(regex-group(2)))"/>
    </xsl:matching-substring>
    <xsl:non-matching-substring>
      <xsl:value-of select="."/>
    </xsl:non-matching-substring>
  </xsl:analyze-string>
</xsl:function>

mf:lower-case-match("dsfjkljsdfjlsjdfABCDdfsfsdff", "(\p{Lu})(\p{Lu}+)")

или, чтобы использовать as="xs:string" в качестве объявленного типа функции:

<xsl:function name="mf:lower-case-match" as="xs:string">
  <xsl:param name="input" as="xs:string"/>
  <xsl:param name="regex" as="xs:string"/>
  <xsl:value-of>
      <xsl:analyze-string select="$input" regex="{$regex}">
        <xsl:matching-substring>
          <xsl:value-of select="concat(regex-group(1), lower-case(regex-group(2)))"/>
        </xsl:matching-substring>
        <xsl:non-matching-substring>
          <xsl:value-of select="."/>
        </xsl:non-matching-substring>
      </xsl:analyze-string>          
  </xsl:value-of>
</xsl:function>

Вам необходимо объявить пространство имен для любой определяемой пользователем функции, например. xmlns:mf="http://example.com/mf" в корне xsl:stylesheet или xsl:transform.

В XSLT 3 вы также можете просто передать результат функции analyze-string через режим, который затем выполняет любое преобразование в нужных вам группах:

<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-copy"/>

  <xsl:template match="text">
      <xsl:copy>
          <xsl:apply-templates select="analyze-string(., '(\p{Lu})(\p{Lu}+)')" mode="lower-case"/>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="*:group[@nr = 2]" mode="lower-case">
      <xsl:value-of select="lower-case(.)"/>
  </xsl:template>
  
</xsl:stylesheet>
person Martin Honnen    schedule 19.06.2020
comment
Привет Мартин. Это кажется почти хорошим, за исключением того, что когда я запускаю преобразование, оно жалуется при вызове функции со следующим сообщением: XTTE0780 Последовательность из более чем одного элемента не разрешена в результате вызова mf: нижний регистр -соответствие - person Mystic Tm; 20.06.2020
comment
Я также пытаюсь заменить xsl:value-of на xsl:sequence, но получаю то же сообщение - person Mystic Tm; 20.06.2020
comment
Для быстрого исправления удалите атрибут as из объявления функции. Позже я попытаюсь проверить, решит ли обертывание тела функции значение-of проблему с типом. - person Martin Honnen; 20.06.2020
comment
посмотрите его в прямом эфире на xsltfiddle.liberty-development.net/93dFK9t - person Mystic Tm; 20.06.2020
comment
Мне было бы очень интересно общее решение преобразования любой проблемы, ориентированной на регулярное выражение, с помощью этого метода переноса в функцию - person Mystic Tm; 20.06.2020
comment
поэтому при удалении объявления типа результата as=xs:string это действительно работает, но тогда xsl:value-of производит правильный ввод, тогда как xsl:sequence вводит пробелы между каждой подстрокой - person Mystic Tm; 20.06.2020
comment
@MysticTm, см. редактирование, в этом случае, чтобы следовать хорошей практике кодирования, чтобы объявить возвращаемый тип функции, тело должно быть немного сложнее, используя элемент-оболочку xsl:value-of вокруг xsl:analyze-string. - person Martin Honnen; 20.06.2020
comment
Я сделал новую версию xsltfiddle.liberty-development.net/93dFK9t/1, и вы можно увидеть, что даже если удалить атрибут возвращаемого типа as=xs:string для функции, она все еще терпит неудачу при попытке назначить промежуточной переменной с тем же атрибутом типа, что и = xs:string, поэтому обходной путь не полностью функционален. - person Mystic Tm; 20.06.2020
comment
решение должно состоять в том, чтобы передать вызов fm:lower-case-match с fn:string-join(.,''), чтобы он объединил все подстроки (совпадения/не совпадения) вместе, но мне это не очень нравится много: xsltfiddle.liberty-development.net/93dFK9t/2 - person Mystic Tm; 20.06.2020
comment
@MysticTm, посмотрите предложение обертки со значением или используйте свой подход с string-join, поместив xsl:analyze-string в переменную, а затем вернув вызов string-join($var) из функции (тогда вы даже можете использовать xsl:sequence). - person Martin Honnen; 20.06.2020

Я не думаю, что свойство регулярного выражения \L поддерживается XPath. Ответ @Martin Honnen, вероятно, лучший, но вот полное решение XPath 2.0:

С :

dsfjkljsdfjlsjdfABCDdfsfsdff

XPath:

replace(replace("dsfjkljsdfjlsjdfABCDdfsfsdff","(\p{Lu})(\p{Lu}+)","$1___$2___"),"_{3}.+_{3}",lower-case(substring-before(substring-after(replace("dsfjkljsdfjlsjdfABCDdfsfsdff","(\p{Lu})(\p{Lu}+)","$1___$2___"),"___"),"___")))

Описание :

P1: мы добавляем ___, чтобы идентифицировать строчную часть:

replace("dsfjkljsdfjlsjdfABCDdfsfsdff","(\p{Lu})(\p{Lu}+)","$1___$2___")

P2: мы генерируем строчную часть с помощью:

lower-case(substring-before(substring-after(resultofP1,"___"),"___"))

Мы соединяем два предыдущих выражения с помощью:

replace(resultofP1,"_{3}.+_{3}",resultofP2)

Выход :

dsfjkljsdfjlsjdfAbcddfsfsdff
person E.Wiest    schedule 20.06.2020