Есть ли в XPath инструкция if if-else?

Кажется, что у вас есть все богатое количество функций в xpath, что вы можете сделать «если». Тем не менее, мой движок продолжает настаивать «нет такой функции», и я вряд ли найду какую-либо документацию в Интернете (я нашел некоторые сомнительные источники, но синтаксис, который у них был, не работал)

Мне нужно удалить ‘:’ из конца строки (если существует), поэтому я хотел сделать это:

if (fn:ends-with(//div [@id='head']/text(),': ')) then (fn:substring-before(//div [@id='head']/text(),': ') ) else (//div [@id='head']/text()) 

Любой совет?

Да, есть способ сделать это в XPath 1.0:

 CONCAT (
   substring ($ s1, 1, number ($ condition) * string-length ($ s1)),
   substring ($ s2, 1, number (not ($ condition)) * string-length ($ s2))
 )

Это зависит от конкатенации двух взаимоисключающих строк, первая из которых пуста, если условие ложно ( 0 * string-length(...) ), вторая пустая, если условие истинно. Это называется «метод Беккера» , приписываемый Оливеру Беккеру .

В твоем случае:

 CONCAT (
   подстрока (
     substring-before (// div [@ id = 'head'] / text (), ':'),
     1, 
     номер(
       end-with (// div [@ id = 'head'] / text (), ':')
     )
     * string-length (substring-before (// div [@ id = 'head'] / text (), ':'))
   ),
   подстрока (
     // DIV [@ ид = 'головы'] / текст (), 
     1, 
     номер (не (
       end-with (// div [@ id = 'head'] / text (), ':')
     ))
     * string-length (// div [@ id = 'head'] / text ())
   )
 )

Хотя я бы попытался избавиться от всех "//" раньше.

Кроме того, существует вероятность того, что //div[@id='head'] возвращает более одного узла.
Просто имейте в виду, что использование //div[@id='head'][1] является более защитным.

Официальная спецификация языка XPath 2.0 на W3.org указывает, что язык действительно поддерживает операторы if . См. Раздел 3.8 Условные выражения , в частности. Наряду с форматом синтаксиса и объяснением он дает следующий пример:

 if ($widget1/unit-cost < $widget2/unit-cost) then $widget1 else $widget2 

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

 if (fn:ends-with(//div [@id='head']/text(),': ')) then fn:substring-before(//div [@id='head']/text(),': ') else //div [@id='head']/text() 

Я действительно подозреваю, что это может исправить, однако, поскольку тот факт, что ваш движок XPath, похоже, пытается интерпретировать, if как функция, где он фактически является специальной конструкцией языка.

Наконец, чтобы указать на очевидное, убедитесь, что ваш движок XPath фактически поддерживает XPath 2.0 (в отличие от более ранней версии)! Я не считаю, что условные выражения являются частью предыдущих версий XPath.

Лично я бы использовал XSLT для преобразования XML и удаления хвостовых двоеточий. Например, предположим, что у меня есть этот вход:

   This paragraph ends in a period. This one ends in a colon: This one has a : in the middle.  

Если бы я хотел разделить задние двоеточия в моих параграфах, я бы использовал этот XSLT:

                           в                           в                           

согласно закону pkarat, вы можете достичь условного XPath в версии 1.0.

Для вашего случая следуйте концепции:

 concat(substring-before(your-xpath[contains(.,':')],':'),your-xpath[not(contains(.,':'))]) 

Это определенно сработает. Посмотри, как это работает. Дайте два входа

 praba: karan 

Для 1-го ввода: он содержит : so condition true, string before : будет выход, скажем, praba – ваш выход. Второе условие будет ложным, поэтому никаких проблем.

Для 2-го ввода: он не содержит : поэтому условие не работает, придя к 2-му условию, строка не содержит : так что условие true … поэтому выводят karan .

Наконец, ваш выход будет praba , praba .

Как насчет использования fn: replace (string, pattern, replace) вместо этого?

XPATH очень часто используется в XSLT, и если вы находитесь в этой ситуации и не имеете XPATH 2.0, вы можете использовать:

    condition1-statements   condition2-statements   otherwise-statements   в    condition1-statements   condition2-statements   otherwise-statements   в    condition1-statements   condition2-statements   otherwise-statements   в    condition1-statements   condition2-statements   otherwise-statements   

К сожалению, предыдущие ответы не были для меня вариантом, поэтому я некоторое время искал и нашел это решение:

http://blog.alessio.marchetti.name/post/2011/02/12/the-Oliver-Becker-s-XPath-method

Я использую его для вывода текста, если существует определенный узел. 4 – длина текста foo. Поэтому я думаю, что более элегантным решением будет использование переменной.

 substring('foo',number(not(normalize-space(/elements/the/element/)))*4) 

Совсем простое решение XPath 1.0, адаптированное из Tomalek’s (размещено здесь) и Dimitre’s ( здесь ):

 concat(substring($s1, 1 div number($cond)), substring($s2, 1 div number(not($cond)))) 

Примечание. Я обнаружил, что для преобразования bool в int требуется явное число (), в противном случае некоторые оценщики XPath выбрали ошибку несоответствия типа. В зависимости от того, насколько строго ваш процессор XPath соответствует типу, вам может и не понадобиться.

  • как игнорировать пространства имен с XPath
  • XPath: выберите текстовый узел
  • Существует ли XSLT-элемент?
  • Как передать параметр переменной в выражение XPath?
  • Как преобразовать строку в верхний или нижний регистр с помощью XSLT?
  • Как предотвратить внедрение XPath / XML в .NET.
  • Функция замены XSLT не найдена
  • Специальный символ в запросе XPATH
  • XPath: выберите всех следующих братьев и сестер, пока другой брат
  • XPath для выбора элемента на основе дочернего значения childs
  • XPath: выберите первый элемент с определенным атрибутом
  • Давайте будем гением компьютера.