1

基本的に、ノードからルートへの絶対パスを抽出して、コンソールまたはファイルに報告したいと思います。以下は現在の解決策です:

require "rexml/document"

include REXML

def get_path(xml_doc, key)
  XPath.each(xml_doc, key) do |node|
    puts "\"#{node}\""
    XPath.each(node, '(ancestor::#node)') do |el|
      #  puts  el
    end
  end
end

test_doc = Document.new <<EOF
  <root>
   <level1 key="1" value="B">
     <level2 key="12" value="B" />
     <level2 key="13" value="B" />
   </level1>
  </root>
EOF

get_path test_doc, "//*/[@key='12']"

問題は、それが私"<level2 value='B' key='12'/>"を出力として与えるということです。必要な出力は次<root><level1><level2 value='B' key='12'/>のとおりです(形式は異なる場合があります。主な目標はフルパスを持つことです)。私はXPathの基本的な知識しか持っていないので、どこを見ればよいか、そしてこれをどのように達成するかについてのヘルプ/ガイダンスをいただければ幸いです。

4

3 に答える 3

4

これで始められるはずです:

require 'nokogiri'

test_doc = Nokogiri::XML <<EOF
  <root>
   <level1 key="1" value="B">
     <level2 key="12" value="B" />
     <level2 key="13" value="B" />
   </level1>
  </root>
EOF

node = test_doc.at('//level2')
puts [*node.ancestors.reverse, node][1..-1].map{ |n| "<#{ n.name }>" }
# >> <root>
# >> <level1>
# >> <level2>

Nokogiriは、必要に応じてXPathの代わりにCSSアクセサーを使用できるので本当に便利です。CSSは一部の人にとってより直感的であり、同等のXPathよりもクリーンになります。

node = test_doc.at('level2')
puts [*node.ancestors.reverse, node][1..-1].map{ |n| "<#{ n.name }>" }
# >> <root>
# >> <level1>
# >> <level2>
于 2010-12-30T01:22:06.563 に答える
3

まず、あなたの文書はあなたが意図したものではないと私は思います。あなたは<level1>自己閉鎖的ではなく、<level2>子供として要素を封じ込めたいと思っていたのではないかと思います。

第二に、私はREXMLではなくNokogiriを好み、支持しています。REXMLにRubyが付属しているのは素晴らしいことですが、Nokogiriの方が高速で便利です。それで:

require 'nokogiri'

test_doc = Nokogiri::XML <<EOF
  <root>
    <level1 key="1" value="B">
      <level2 key="12" value="B" />
      <level2 key="13" value="B" />
    </level1>
  </root>
EOF

def get_path(xml_doc, key)
  xml_doc.at_xpath(key).ancestors.reverse
end

path = get_path( test_doc, "//*[@key='12']" )
p path.map{ |node| node.name }.join( '/' )
#=> "document/root/level1"
于 2010-12-30T01:01:26.200 に答える
2

REXMLを使用している場合、REXMLソリューションは次のとおりです。

require 'rexml/document'

test_doc = REXML::Document.new <<EOF
  <root>
    <level1 key="1" value="B">
      <level2 key="12" value="B" />
      <level2 key="13" value="B" />
    </level1>
  </root>
EOF

def get_path(xml_doc, key)
  node = REXML::XPath.first( xml_doc, key )
  path = []
  while node.parent
    path << node
    node = node.parent
  end
  path.reverse
end

path = get_path( test_doc, "//*[@key='12']" )
p path.map{ |el| el.name }.join("/")
#=> "root/level1/level2"

または、get_path他の回答と同じ実装を使用する場合は、REXMLにモンキーパッチを適用してancestorsメソッドを追加できます。

class REXML::Child
  def ancestors
    ancestors = []

    # Presumably you don't want the node included in its list of ancestors
    # If you do, change the following line to    node = self
    node = self.parent

    # Presumably you want to stop at the root node, and not its owning document
    # If you want the document included in the ancestors, change the following
    # line to just    while node
    while node.parent
      ancestors << node
      node = node.parent
    end

    ancestors.reverse
  end
end
于 2010-12-30T02:26:29.153 に答える