ruby – 在DocumentFragment中的文本节点上使用Nokogiri的交换

使用Hpricot,您可以这样做:

> doc = Hpricot("a")
=> #<Hpricot::Doc "a">
> doc.children.first.swap('b')
=> ["b"]
> doc.to_s
=> "b"

但如果你和Nokogiri尝试同样的事情,你会收到一个错误:

> doc = Nokogiri::HTML::DocumentFragment.parse('a')
=> #<Nokogiri::HTML::DocumentFragment:0x825bb88c name="#document-fragment" children=[#<Nokogiri::XML::Text:0x825bb580 "a">]>
> doc.children.first.swap('b')
RuntimeError: error parsing fragment (1)
 from /Library/Ruby/Gems/1.8/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:509:in `in_context'
 from /Library/Ruby/Gems/1.8/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:509:in `parse'
 from /Library/Ruby/Gems/1.8/gems/nokogiri-1.4.4/lib/nokogiri/html/document_fragment.rb:22:in `initialize'
 from /Library/Ruby/Gems/1.8/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:485:in `new'
 from /Library/Ruby/Gems/1.8/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:485:in `fragment'
 from /Library/Ruby/Gems/1.8/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:885:in `coerce'
 from /Library/Ruby/Gems/1.8/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:382:in `replace'
 from /Library/Ruby/Gems/1.8/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:407:in `swap'
 from (irb):63

如何在Nokogiri的文本节点上使用swap?

编辑:请注意,这不是ARGUMENT交换的问题,这是接收器的问题

例如:

> doc = Nokogiri::HTML::DocumentFragment.parse('<a>b</a>')
=> #<Nokogiri::HTML::DocumentFragment:0x825bb508 name="#document-fragment" children=[#<Nokogiri::XML::Element:0x825bb1fc name="a" children=[#<Nokogiri::XML::Text:0x825bab6c "b">]>]>
> doc.at("a").swap('x')
=> #<Nokogiri::XML::Element:0x825bb1fc name="a" children=[#<Nokogiri::XML::Text:0x825bab6c "b">]>
> doc.to_s
=> "x"

最佳答案 这是创建可与DocumentFragment中的swap一起使用的文本节点的一种方法:

require 'nokogiri'    
frag = Nokogiri::HTML::DocumentFragment.parse( "foo" )
foo  = frag.children.first
foo.swap( Nokogiri::XML::Text.new( "bar", foo.document ) )
puts frag
#=> bar

编辑:基于以下内容,这里肯定有一些微妙的变化.我已经为你提交了bug report.如果文本不在DocumentFragment的根目录下,或者如果这是Document而不是片段,它似乎正确解析字符串:

require 'nokogiri'

elems  = "<a1 /><a2>foo</a2><a3 /><a4>bar</a4>baz"
rooted = "<r>#{elems}</r>"
doc = Nokogiri::XML rooted
doc.at_xpath('/r/a1').swap( 'x1' )                  # Element->text
doc.at_xpath('/r/a2/text()').swap( 'jim' )          # Text->text
doc.at_xpath('/r/a3').swap( '<x3 />' )              # Element->element
doc.at_xpath('/r/a4/text()').swap( '<x4>jam</x4>' ) # Text->element
doc.xpath('/r/text()').last.swap( 'jom' )           # RootText->text
puts doc.root
#=> <r>x1<a2>jim</a2><x3/><a4><x4>jam</x4></a4>jom</r>
#=> (correct output)

frag = Nokogiri::XML::DocumentFragment.parse rooted
frag.at_xpath('./r/a1').swap( 'x1' )                  # Element->text
frag.at_xpath('./r/a2/text()').swap( 'jim' )          # Text->text
frag.at_xpath('./r/a3').swap( '<x3 />' )              # Element->element
frag.at_xpath('./r/a4/text()').swap( '<x4>jam</x4>' ) # Text->element
frag.xpath('./r/text()').last.swap( 'jom' )           # RootText->text
puts frag
#=> <r>x1<a2>jim</a2><x3/><a4><x4>jam</x4></a4>jom</r>
#=> (correct output)

frag = Nokogiri::XML::DocumentFragment.parse elems
frag.at_xpath('./a1').swap( 'x1' )                  # Element->text
frag.at_xpath('./a2/text()').swap( 'jim' )          # Text->text
frag.at_xpath('./a3').swap( '<x3 />' )              # Element->element
frag.at_xpath('./a4/text()').swap( '<x4>jam</x4>' ) # Text->element
baz = frag.children.last
begin
  baz.swap( 'jom' )                                 # RootText->text      
rescue Exception => e
  p baz
  #=> #<Nokogiri::XML::Text:0x80c66224 "baz">

  p e
  #=> #<RuntimeError: error parsing fragment (1)>

  puts e.backtrace
  #=> /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:509:in `in_context'
  #=> /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:509:in `parse'
  #=> /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.4.4/lib/nokogiri/xml/document_fragment.rb:14:in `initialize'
  #=> /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:485:in `new'
  #=> /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:485:in `fragment'
  #=> /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:885:in `coerce'
  #=> /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:382:in `replace'
  #=> /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.4.4/lib/nokogiri/xml/node.rb:407:in `swap'
  #=> /Users/phrogz/Desktop/test_swap.rb:32:in `<main>'      
end    
puts frag
#=> x1<a2>jim</a2><x3/><a4>
#=>   <x4>jam</x4>
#=> </a4>baz

编辑2:这已被Nokogiri开发团队确认为错误:

OMG! Thanks for the boog report!

I’m sure we don’t have any test coverage that runs Node#replace and #swap on text nodes, so hopefully I’ll be able to fix this for the 1.4.5 release.

点赞