Условие XPath для текстового узла, разделенного пробелами

С таким элементом:

<element>one two two-and-a-half three four</element>

есть ли способ определить условие XPath 1.0 (оценивает логическое значение), которое будет проверять, содержит ли текстовый узел элемента одно или несколько значений, разделенных пробелами, таких как "two" и "three", предполагая, что значения могут отображаться в любом порядке ? Значения могут также содержать части других значений, как показано "two" и "two-and-a-half".

Этот вопрос касается шаблона кодирования XPath и не предполагает конкретного контекста языка/инструмента программирования. Ради аргумента вы можете предположить, что element уже является узлом контекста для выражения и что

. = 'one two two-and-a-half three four'

поэтому оценивается как true.


person predi    schedule 16.09.2015    source источник


Ответы (1)


В XPath 1.0, к сожалению, довольно сложно работать со строками в одном выражении, возможно, вам не очень понравится приведенное ниже решение. Если вы могли использовать XPath 2.0, это становится простым .[tokenize(., ' ')[. = ('two', 'three', 'four')]].

XPath 1.0

Без помощи основного языка, такого как XSLT, мы застряли с повторением. Однако, если мы собираемся игнорировать тот факт, что нет начального или конечного пробела, это возможное, но несколько наивное решение:

.[contains(., 'two ') and contains(., ' two')]

Основываясь на этом, мы можем добавить начальный/конечный пробел, создав несколько неудобное, но работающее решение XPath 1.0:

.[contains(concat(' ', ., ' '), ' two ')]

В этом выражении concat(...) объединяет строковое значение текущего элемента с пробелом до и после. Это гарантирует, что если мы проверим данный текст, 'two' в примере, это будет истинным только в том случае, если есть по крайней мере on с начальным пробелом и один с конечным пробелом.

Опираясь на это, мы можем расширить это, чтобы проверить несколько условий:

.[contains(concat(' ', ., ' '), ' two ') and contains(concat(' ', ., ' '), ' three ')]

Примечания

Учитывая ваше замечание в исходном вопросе о том, что фокус уже находится на element, я начал все выражения с ведущей точки. Просто замените это выражением выбора, которое выбирает element.

person Abel    schedule 16.09.2015
comment
Кстати, normalize-space() может обрабатывать любые лишние пробелы, поэтому contains(concat(' ', normalize-space(.), ' '), ' two ') будет работать. Я не упомянул возможное многократное появление пробела между моими значениями. - person predi; 16.09.2015
comment
Чтобы проверить, содержит ли строка один или несколько соответствующих терминов, используйте или, а не и между тестами contains(). - person Michael Kay; 16.09.2015
comment
@predi, точно. normalize-space() твой друг здесь. - person Abel; 16.09.2015