From 57fcbbd0fc85fdd9f1448a3910497c8b05dffecf Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 4 Aug 2014 10:00:32 +0200 Subject: [PATCH] Allow Document#each_node to skip child nodes. Child nodes can be skipped by throwing :skip_children. --- lib/oga/xml/document.rb | 23 ++++++++++++++++++----- spec/oga/xml/document_spec.rb | 16 ++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/lib/oga/xml/document.rb b/lib/oga/xml/document.rb index d3fd57a..2f223a4 100644 --- a/lib/oga/xml/document.rb +++ b/lib/oga/xml/document.rb @@ -53,14 +53,25 @@ module Oga # Traverses through the document and yields every node to the supplied # block. # + # The block's body can also determine whether or not to traverse child + # nodes. Preventing a node's children from being traversed can be done by + # using `throw :skip_children` + # + # This method uses a combination of breadth-first and depth-first + # traversal to traverse the entire XML tree in document order. See + # http://en.wikipedia.org/wiki/Breadth-first_search for more information. + # # @example # document.each_node do |node| # p node.class # end # - # This method uses a combination of breadth-first and depth-first - # traversal to traverse the entire XML tree in document order. See - # http://en.wikipedia.org/wiki/Breadth-first_search for more information. + # @example Skipping the children of a certain node + # document.each_node do |node| + # if node.is_a?(Oga::XML::Element) and node.name == 'book' + # throw :skip_children + # end + # end # # @yieldparam [Oga::XML::Node] The current node. # @@ -70,9 +81,11 @@ module Oga until visit.empty? current = visit.shift - yield current + catch :skip_children do + yield current - visit = current.children.to_a + visit + visit = current.children.to_a + visit + end end end diff --git a/spec/oga/xml/document_spec.rb b/spec/oga/xml/document_spec.rb index 3130300..18efebd 100644 --- a/spec/oga/xml/document_spec.rb +++ b/spec/oga/xml/document_spec.rb @@ -53,6 +53,22 @@ describe Oga::XML::Document do names.should == %w{books book1 title1 Foo book2 title2 Bar} end + + example 'skip child nodes when skip_children is thrown' do + names = [] + + @document.each_node do |node| + if node.is_a?(Oga::XML::Element) + if node.name == 'book1' + throw :skip_children + else + names << node.name + end + end + end + + names.should == %w{books book2 title2} + end end context '#to_xml' do