Hatena::Groupjavascript

JavaScriptで遊ぶよ

 | 

2009-06-01

XPathでテキストノードが「ある1文字ならNGだけど、その文字で終わる文字列ならOK」の書き方がわからん

05:22

oAutoPagerize の SITEINFO を作っていたときの疑問。nextLink の部分の HTML は、改行無しで

<div class="pager"><a href="foo">Prev</a>&nbsp;<a href="bar">1</a>&nbsp;2&nbsp;<a href="baz">3</a>&nbsp;<a href="foobar">Next</a>&nbsp;</div>

のようになっている。

出力は↓のような感じ。

Prev 1 2 3 Next 

"Next" という文字列でマッチさせるは嫌いなので、「"何か一文字&nbsp;"で終わるテキストに続く a 要素」というふうにしたい。(出来れば「/^\\u00a0?\d+\\u00a0$/ にマッチするテキストに続く a 要素」が良いのだけど、正規表現使わないと不可能だと思う…)

とりあえず今は

//div[@class="pager"]/text()[string-length(self::text())>1]/following-sibling::a[1]

のように書いたのだけど、なんかなあと。

div class="pager" なる要素は、別のページでは pager でもなんでもないところに使われていたりするので、//div[@class="pager"] もどうかと思うのだけど、モバイル版のページだけあってクラス名などとことん省略してあって、他に手書かりが無い。。

とりあえず出来るだけ絞り込むために「"何か一文字&nbsp;"で終わるテキストに続く a 要素」は入れたいところ。


どうにか

表題の疑問とはちょっと違って、ここなんだけど、

http://m.facebook.com/stories.php

nextLink はこんな感じで

//a[@accesskey="6"]/parent::div/preceding-sibling::div[1][@class="pager"]/node()[local-name()="a" and position()=last()-1 and text(./following-sibling)=" "]

最後の " " の中に &nbsp; に相当するエスケープ表現を入れれば良さそうということがわかった。

うーん。。。


結局

よくよく考えたら、Wedata はサーバー側でエスケープしてくれるんだから、nbsp をそのままその部分にコピペしたら出来た!!

勝利の気分。

os0xos0x2009/06/02 12:32見た感じ、//div[@class="pager"]/a[last()] でもいけそうですね。
誤爆を減らすなら、 //div[@class="pager"]/a[position()=last() and contains(@href,"ac=mobile_search_actions")] とか。

「"何か一文字 "で終わるテキストに続く a 要素」のアプローチで行くなら、
//div[@class="pager"]/text()[number(substring(self::text(),1,1) ) > 0]/following-sibling::a[1]
でしょうか。
本当は
//div[@class="pager"]/text()[number(normalize-space(self::text()) ) > 0]/following-sibling::a[1]
としたいところですが、 が上手く処理できないのか、通りませんでした(なぜか、 substring-before(self::text()," ")として駄目でした… )。

edvakfedvakf2009/06/02 14:33この場合の last() は全ノード中での last() なんですね。CSS 的に要素で考えていました。そちらの方法のほうが良さそうなので変更しておきます。

最初に考えていた方法だと、何か一文字プラス「&nbps;」で終わるテキストとしないといけないので面倒なんですよ。

edvakfedvakf2009/06/02 14:40あ、でも search だけじゃなくて inbox や friend request (や未検証のページ) なんかもあるので、href 決め打ちもマズいかも。

とりあえずこうすれば inbox は対象になるけど。
//div[@class="pager"]/a[position()=last() and (contains(@href,"ac=mobile_search_actions") or contains(@href,"/inbox/"))]

edvakfedvakf2009/06/02 14:44あとこことかがものすごく厄介です…
http://m.facebook.com/stories.php

os0xos0x2009/06/02 15:24http://m.facebook.com/stories.php
は登録しただけのアカウントでは表示するものがありませんでした…

こういう場合、nextLinkは //div[@class="pager"]/a[last()] の決め打ちにしてしまって良いと思います。
urlの正規表現である程度は誤爆を回避することもできますし、そもそも実際には誤爆することはないように思えます。

edvakfedvakf2009/06/02 15:34それもそうですね。ちょっと見たところ、stories 系だけが厄介っぽかったので、url を分けて別アイテムを作ろうと思います。

トラックバック - http://javascript.g.hatena.ne.jp/edvakf/20090601
 |