web-dev-qa-db-ja.com

XPathに「if -then-else」ステートメントがありますか?

Xpathの豊富な機能をすべて使用して、「if」を実行できるようです。しかし、私のエンジンは「そのような機能はありません」と主張し続けており、ウェブ上でドキュメントを見つけることはほとんどありません(疑わしいソースを見つけましたが、構文は機能しませんでした)

文字列の末尾から「:」を削除する必要がある場合(存在する場合)、これを実行したかったのです。

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

何かアドバイス?

42
Yossale

はい、XPath 1.0でそれを行う方法があります。

 concat(
 substring($ s1、1、number($ condition)* string-length($ s1))、
 substring($ s2、1、number(not( $ condition))* string-length($ s2))
)

これは、2つの相互に排他的な文字列の連結に依存しています。最初の文字列は、条件がfalseの場合は空(0 * string-length(...))で、2番目の文字列は条件がtrueの場合は空です。これは "Beckerのメソッド"と呼ばれ、 Oliver Becker に起因します。

あなたの場合:

 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']は複数のノードを返します。
注意してください— //div[@id='head'][1]はより防御的です。

61
Tomalak

W3.orgの XPath 2. の公式言語仕様は、言語が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の一部ではないと思います。

22
Noldorin

pkaratの法律によると、バージョン1.0で条件付きXPathを実現できます。

あなたの場合、概念に従ってください:

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

これは間違いなく機能します。仕組みをご覧ください。 2つの入力を与える

praba:
karan

最初の入力の場合::が含まれているため、条件が真で、:の前の文字列が出力になります。たとえば、prabaが出力になります。 2番目の条件はfalseなので問題ありません。

2番目の入力の場合::が含まれていないため条件が失敗し、2番目の条件になると文字列に:が含まれないため条件が真になります。したがって、出力karanがスローされます。

最後に、出力はprabakaranになります。

3
prabakaran

個人的には、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> 
3
james.garriss

代わりに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>
1
Jonas Elfström

残念ながら、以前の回答は私にとって選択肢ではなかったので、しばらく調査し、この解決策を見つけました:

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)
1
noreabu

Tomalek(ここに投稿)とDimitre( here )から適応した、やや単純なXPath 1.0ソリューション:

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

注:boolをintに変換するには明示的なnumber()が必要であることがわかりました。それ以外の場合、XPathエバリュエーターは型の不一致エラーをスローしました。 XPathプロセッサがどの程度厳密に型マッチングを行っているかによっては、必要ない場合があります。

0
tiritea