XSLT-поиск XML с использованием регулярных выражений, границ слов - PullRequest
3 голосов
/ 11 марта 2012

Можно ли использовать регулярные выражения для поиска содержимого XML с использованием XSLT? Я могу искать узлы с использованием содержимого, однако мне нужно использовать границы слов (например, /\bmy phrase\b/i) для поиска фразы, а не только отдельного слова.

При поиске «кровяного давления» с использованием следующего возвращаются все узлы с «кровью», «давлением» и «кровяным давлением».

Я хочу вернуть только узлы, содержащие «кровяное давление». Используя PHP preg_match, я могу добиться этого используя: /\b$keywords\b/i

<xsl:template match="//item">
    <xsl:choose>
        <xsl:when test="contains(translate(title, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), $keyword) or contains(translate(content, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), $keyword)">
            <item>
                <title><xsl:value-of select="title"/></title>
                <content><xsl:value-of select="content"/></content>
                <date><xsl:value-of select="date"/></date>
                <author><xsl:value-of select="author"/></author>
            </item>
        </xsl:when>
    </xsl:choose>
</xsl:template>

Ответы [ 3 ]

2 голосов
/ 11 марта 2012

I.Вы можете сделать что-то подобное в XSLT 2.0 :

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="s">
  <xsl:variable name="vWords" select=
  "tokenize(lower-case(string(.)),
            '[\s.?!,;—:\-]+'
            ) [.]
  "/>
  <xsl:sequence select=
   " for $current in .,
         $i in 1 to count($vWords)
     return
        if($vWords[$i] eq 'blood'
          and
           $vWords[$i+1] eq 'pressure'
           )
           then .
           else ()
  "/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

Когда это преобразование XSLT 2.0 применяется к следующему XML-документу (такого документа в вопросе не предусмотрено !!!):

<t>
 <s>He has high blood pressure.</s>
 <s>He has high Blood Pressure.</s>
 <s>He has high Blood
 Pressure.</s>

  <s>He was  coldblood Pressured.</s>

</t>

требуемый, правильный результат (создаются только элементы, содержащие `" кровь "и" давление "(без учета регистра и как два соседних слова) :

<s>He has high blood pressure.</s>
<s>He has high Blood Pressure.</s>
<s>He has high Blood
 Pressure.</s>

Объяснение :

  1. Использование функции tokenize() для разделения строк из nn-буквенных символов сФлаги для нечувствительности к регистру и многострочного режима.

  2. Итерация по результату tokenize() для нахождения слова "blood", за которым сразу следует слово "pressure".


II. Решение XSLT 1.0 :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vUpper" select=
 "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>

 <xsl:variable name="vLower" select=
 "'abcdefghijklmnopqrstuvwxyz'"/>

 <xsl:variable name="vSpaaaceeees" select=
 "'                                                                               '
 "/>

 <xsl:variable name="vAlpha" select="concat($vLower, $vUpper)"/>

 <xsl:template match="s">
   <xsl:variable name="vallLower" select="translate(., $vUpper, $vLower)"/>
     <xsl:copy-of select=
     "self::*
       [contains
        (concat
         (' ',
          normalize-space
           (translate($vallLower, translate($vallLower, $vAlpha, ''), $vSpaaaceeees)),
          ' '
          ),

         ' blood pressure '
         )
       ]
  "/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

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

<s>He has high blood pressure.</s>
<s>He has high Blood Pressure.</s>
<s>He has high Blood
 Pressure.</s>

Пояснение :

  1. Преобразование в нижний каскаде.

  2. Использование метода двойного перевода для замены любого не-буквенного символа на пробел.

  3. Затем с помощью normalize-space() заменить любую группу смежных пробелов одним пробелом.

  4. Затем окружить этот результат пробелами.

  5. Наконец, проверяем, еслитекущий результат содержит строку " blood pressure ".

0 голосов
/ 11 марта 2012

http://www.w3.org/TR/xslt20/#regular-expressions

Регулярные выражения , используемые в этой инструкции, и флаги, управляющие интерпретацией этих регулярных выражений, должны соответствовать определенному синтаксисув [Функции и операторы] (см. Раздел 7.6.1 Синтаксис регулярных выражений ), который сам основан на синтаксисе , определенном в [XML Schema Part 2].

Первая ссылка, указанная в цитате, показывает отсутствие \b.

То же самое для второй ссылки Побег из одного символа

Но если немного прокрутить последний документ, мы сможем найти классы символов (Category Escape).И используйте комбинацию punctuation и space классов: [\p{P}\p{Z}], чтобы добиться аналогичного эффекта.

0 голосов
/ 11 марта 2012

XSLT и XPath 2.0 имеют функцию соответствия, поддерживающую регулярные выражения, XSLT и XPath 1.0 не имеют такой функции, вам необходимо использовать функцию расширения, которую поддерживает ваш процессор XSLT: http://www.exslt.org/regexp/functions/match/index.html. Однако даже с XSLT / XPath 2.0 я думаю, что поддерживаемый язык регулярных выражений не поддерживает какой-либо шаблон «границы слова».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...