Posted at

XPathでいかにしてMay'nちゃんを探すのか

More than 1 year has passed since last update.

最近、Webページのオートパイロットやオートパイロットでのテストで何かとお世話になっているSelenium + Junitの環境で ' (シングルクオート)を含んだ文字列を探そうとしたら思いっきり嵌ったのでメモ

Seleniumなどでエレメントを特定する際に ' (シングルクオート)が含まれている文字列を検索したい場合には ' (シングルクオート)をエスケープしなければなりませんが、残念なことにXpath 1.0の仕様では ' (シングルクオート)をエスケープする方法が用意されていませんでした。

XPath 2.0からは、例えば ' (シングルクオート)で囲われた文字列中の ' (シングルクオート)をエスケープするには ' (シングルクオート)を2個続けて書いて '' の様にエスケープするらしいのですが、Firefoxの最新版やChromeでも未だXPath 2.0は使えないらしいです。

で、結局どうしたか?というと以下の様になりました。

例えば、以下の様な文字列が含まれたエレメントをXPathで探す場合には、

<a aria-label="アプリ May'n ちゃん &quot;Love&quot; <1>" href="#MarketListingPlace:p=tmp.03831173739257532153.1317485953465" data-column="TITLE"><img src="gwt/placeholder_icon_24.png" role="presentation"><div> <div>May'n ちゃん "Love" &lt;1&gt;</div> <div></div> </div> </a>

以下の様にします (Firefox quantamのconsoleで検索する場合)

$x("//a[@aria-label=concat('アプリ May', \"'\", 'n ちゃん \"Love\" <1>')]")

Selenium + Junitなら以下の様な感じで

Selenium + JunitのBy.xpathで検索

  searchString = "アプリ May'n ちゃん \"Love\" <1>";

xPathStringLiteral = toXPathStringLiteral(searchString);
searchXpath = "//a[@aria-label=" + xPathStringLiteral + "]";
wait.until(ExpectedConditions.elementToBeClickable(By.xpath(searchXpath))

toXPathStringLiteral

  private String toXPathStringLiteral(String string) {

if ( string.indexOf("'") == -1 ) {
return "'" + string + "'";
}
if ( string.indexOf('"') == -1 ) {
return '"' + string + '"';
}
return ("concat('" + string.replace("'", "', \"'\", '") + "')");
}

…と恐ろしく面倒でした