Подтвердить что ты не робот

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

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

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

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

Любые советы?

4b9b3361

Ответ 1

Да, есть способ сделать это в 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(
    substring-before(//div[@id='head']/text(), ': '),
    1, 
    number(
      ends-with(//div[@id='head']/text(), ': ')
    )
    * string-length(substring-before(//div [@id='head']/text(), ': '))
  ),
  substring(
    //div[@id='head']/text(), 
    1, 
    number(not(
      ends-with(//div[@id='head']/text(), ': ')
    ))
    * string-length(//div[@id='head']/text())
  )
)

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

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

Ответ 2

Официальная спецификация языка 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.

Ответ 3

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

В вашем случае следуйте концепции:

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

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

praba:
karan

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

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

Наконец, ваш результат будет praba, karan.

Ответ 4

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

<?xml version="1.0" encoding="UTF-8"?>
<Document>
    <Paragraph>This paragraph ends in a period.</Paragraph>
    <Paragraph>This one ends in a colon:</Paragraph>
    <Paragraph>This one has a : in the middle.</Paragraph>
</Document>

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

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions"
    version="2.0">
    <!-- identity -->
    <xsl:template match="/|@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- strip out colons at the end of paragraphs -->
    <xsl:template match="Paragraph">
        <xsl:choose>
            <!-- if it ends with a : -->
            <xsl:when test="fn:ends-with(.,':')">
                <xsl:copy>
                    <!-- copy everything but the last character -->
                    <xsl:value-of select="substring(., 1, string-length(.)-1)"></xsl:value-of>
                </xsl:copy>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:apply-templates/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet> 

Ответ 5

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

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

  <xsl:choose>
    <xsl:when test="condition1">
      condition1-statements
    </xsl:when>
    <xsl:when test="condition2">
      condition2-statements
    </xsl:when>
    <xsl:otherwise>
      otherwise-statements
    </xsl:otherwise>
  </xsl:choose>

Ответ 6

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

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

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

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

Ответ 7

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

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

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