大文字と小文字を区別しないXPath contains()は可能ですか?


94

私はDOMのすべてのテキストノードを実行していて、nodeValueに特定の文字列が含まれているかどうかを確認しています。

/html/body//text()[contains(.,'test')]

これは大文字と小文字が区別されます。しかし、私もキャッチしたいTestTESTまたはTesT。XPath(JavaScript)でそれは可能ですか?

回答:


111

これはXPath 1.0用です。環境がXPath 2.0をサポートしている場合は、こちらを参照してください


はい。可能ですが、美しくありません。

/html/body//text()[
  contains(
    translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
    'test'
  )
]

これは、アルファベットが事前にわかっている検索文字列で機能します。見たいと思うアクセント付き文字を追加します。


可能であれば、興味のあるテキストを他の方法でマークしてください。 <span>、HTMLの作成中に特定のクラスを持つます。このようなものは、要素テキスト内の部分文字列よりもXPathで検索する方がはるかに簡単です。

それが選択肢でない場合は、JavaScript(またはXPathの実行に使用している他のホスト言語)に動的XPath式の作成を支援させることができます。

function xpathPrepare(xpath, searchString) {
  return xpath.replace("$u", searchString.toUpperCase())
              .replace("$l", searchString.toLowerCase())
              .replace("$s", searchString.toLowerCase());
}

xp = xpathPrepare("//text()[contains(translate(., '$u', '$l'), '$s')]", "Test");
// -> "//text()[contains(translate(., 'TEST', 'test'), 'test')]"

@KirillPolishchukの答えのヒント -もちろん、実際に検索している文字だけを翻訳する必要があります。)

このアプローチは、アルファベットの事前知識がなくても、どの検索文字列でも機能します。これは大きな利点です。

検索文字列は、物事を取得した場合には、単一引用符、含めることができたときに上記の方法の両方が失敗し、より複雑に


ありがとう!また、必要な文字だけを翻訳することもできます。パフォーマンスの勝利とは何なのか気になります。xpathPrepare()は、1回以上表示される文字を異なる方法で処理できることに注意してください(たとえば、TEEEEESTとteeeeestを取得します)。
Aron Woost 2011

@AronWoost:ええと、多少の利益があるかもしれませんが、知りたいと思っているなら、それをベンチマークしてください。translate()それ自体は、各文字を繰り返す頻度を気にしません- translate(., 'EE', 'ee')と完全に同等translate(., 'E', 'e')です。PS:@KirillPolishchukに投票することを忘れないでください。
Tomalak 2011

2
System.Xml.XmlNodeList x = mydoc.SelectNodes( "// * [contains(translate(text()、 'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜÉÈÊÀÁÂÒÓÔÙÚÛÇÅÏÕÑŒ'、 'abcdefghijklmnopqrstuvwxyzäöüéèêàáâòóôùúûçå' '' ')')") ")"
Stefan Steiger

1
いいえ。「もちろん実際に検索している文字だけを翻訳する必要がある」部分を参照してください。
Tomalak 2013年

61

より美しく:

/html/body//text()[contains(translate(., 'TES', 'tes'), 'test')]

4
+1絶対に。それは私が考えなかったものです。(私はそれを私の答えで使用します、これは私が書いた元のJavaScriptルーチンよりもはるかに優れています)
Tomalak '12 / 12/12

4
そのまま変換TESTしてtestそのままにTestしませんか?
ムハンマドアディールザヒド2013

6
@MuhammadAdeelZahid-いいえ、「T」を「t」に、「E」を「e」などに置き換えています。1対1の一致です。
Daniel Haley

行う方が明確かもしれませんtranslate(., 'TES', 'tes')。そうすれば、人々はそれが単語の翻訳ではなく、文字の翻訳であることに気付くでしょう。
mlissner 2017年

55

XPath 2.0ソリューション

  1. lower-case()を使用してください:

    /html/body//text()[contains(lower-case(.),'test')]

  2. 大文字と小文字を区別しないフラグを使用して、matches()正規表現マッチングを使用します。

    /html/body//text()[matches(.,'test', 'i')]


1
この構文はFirefoxとChromeではサポートされていませんか?コンソールで試したところ、どちらも構文エラーを返しました。
db

1
FirefoxとChromeはXPath 1.0のみを実装しています。
kjhughes

8

はい。translate次のように使用して、一致させるテキストを小文字に変換できます。

/html/body//text()[contains(translate(., 
                                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                                      'abcdefghijklmnopqrstuvwxyz'),
                   'test')]

6

XPath 2.0を使用している場合は、contains()の3番目の引数として照合順序を指定できます。ただし、照合URIは標準化されていないため、詳細は使用している製品によって異なります。

以前にtranslate()を使用して与えられたソリューションはすべて、26文字の英語のアルファベットのみを使用していることを前提としています。

更新: XPath 3.1では、大文字と小文字を区別しない照合のための標準照合URIが定義されています。


3

私がいつもこれを行う方法は、XPathの「変換」関数を使用することでした。私はそれを非常にきれいとは言いませんが、正しく動作します。

/html/body//text()[contains(translate(.,'abcdefghijklmnopqrstuvwxyz',
                                        'ABCDEFGHIJKLOMNOPQRSTUVWXYZ'),'TEST')]

お役に立てれば、

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.