2011-08-19 11 views
3

nokogiriを歩き、xpathで要素を選択するのはかなり簡単です。私はこれの逆を必要とし、意味する:私はする必要があります。 nokogiriノードで.to_xpathを呼び出して、要素の完全なxpathを取得してレコードに格納します。nokogiriオブジェクトから識別子(例:xpath)を取得する方法は?

誰もがこれを行う方法を知っていますか?

+0

XMLまたはHTML?すべてのノードに 'id'属性がありますか? –

+0

それはhtmlであり、IDノードはありません。これは、動的に置換され、掛け算されるカスタムhtmlタグが使用されているからです。 – pduersteler

+0

あなたはおそらくSerabe'sと一緒に行きたいと思いますが、申し訳ありませんが、私のトンネルビジョンによって、あなたは必要以上に多くの仕事をしました。とにかくあなたのdetailesソリューションのためにありがとう、私はそれが好きです –

答えて

11

最も簡単な方法は、次のようになります。

Nokogiri::CSS.xpath_for node.css_path

EDITは:あなたも試してくださいpath方法を与えることができます。

+0

ありがとうございます。 Nokogiriはあなたが考えることができるほとんどすべての方法を備えた素晴らしい図書館です。 – Serabe

+0

ちょうどそのcss_pathもトリックを行うことを見た、これは物事をスピードアップする可能性があります。ありがとう! – pduersteler

1

私は考えることができる最も簡単な方法は、その兄弟の間で、そのノードの数値指標を把握するために、各ノードで(すなわち、バック<html>に)戻ってルートへの要素パスを構築するためにparentを使用してprevious_elementことであろう。ちょうど<body><html>が1つあるので(必要に応じてNokogiriがあなたの背中の背中にこれらを追加します)、<body>ノードにヒットしたら親を歩くのを止めることができます。

アルゴリズムは次のようになります。

  1. 初期化:path = [ ]は、nはあなたが既に持っているノードです。
  2. s = nと設定し、s = s.previous_elements.nil?まで呼び出して、繰り返し回数を数えれば、これは兄弟の中でnの位置になります。ポジションをindexに入れてください。 XPathの位置は1から始まることに注意してください。
  3. 新しいパスコンポーネントを格納します。path.unshift('*[' + index.to_s + ']')
  4. 設定p = n.parentpその後<body>n = pではなく、2
  5. たちがそこにいることを知っている最後のコンポーネントの追加手順に戻る場合:path.unshift('body').unshift('html')を。
  6. XPath式のビルド:だから、このようないくつかのHTML与えxpath = '/' + path.join('/')

を:

<ul><li>a</li><li><b>b<em>c</em></b></li></ul> 

<em>c</em>の開始ノード、あなたがこのようなXPathので終わるだろう

/html/body/*[1]/*[2]/*[1]/*[1] 

かなり正確ではありませんが、少なくともプロセスはかなり単純で、結果として得られるXPathは一意になります。

DOMのほとんどのノードへのパスが必要な場合は、ルートから開始して途中のすべてのノードに番号を付けることができます。そうすれば、兄弟を何度も何度も歩くことを避けることができます。私はオフに考えることができる

+0

ありがとう、これを試してみましょう! – pduersteler

+0

@pduersteler:恐らく0/1 /多くの兄弟の番号が正しいことを確認するために、いくつかのテストを追加したいと思うかもしれません。 –

関連する問題