# > doc.ch...">

Using Nokogiri sharing on text nodes inside a DocumentFragment

With Hpricot you can do this:

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

But if you try the same with Nokogiri, you will get an error message:

 > 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 

How can I use swap for text nodes in Nokogiri?

Edit: note that this is not a problem with ARGUMENT before swap , this is a problem with the recipient

For instance:

 > 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" 
+4
source share
1 answer

Here is one way to create node text that you can use with swap inside a DocumentFragment:

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

Edit: There is definitely something subtle going on here, based on the following. I submitted you a bug report report . It seems that it parses the line correctly if the text is not in the root of the DocumentFragment, or if it is a document, not a fragment:

 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"> pe #=> #<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 

Change 2 . This was confirmed as a bug by the Nokogiri development team:

OMG! Thanks for the battle report!

I am sure that we do not have test coverage that runs Node #replace and #swap on text nodes, so I hope I can fix this for release 1.4.5.

+2
source

Source: https://habr.com/ru/post/1337638/


All Articles