Implemented a basic SAX API.

This API is a little bit dodgy (similar to Nokogiri's API) due to the use of
separate parser and handler classes. This is done to ensure that the return
values of callback methods (e.g. on_element) aren't used by Racc for building
AST trees. This also ensures that whatever variables are set by the handler
don't conflict with any variables of the parser.

This fixes #42.
This commit is contained in:
Yorick Peterse committed 2014-09-16 14:30:46 +02:00
1 parent 9e935e5d24
commit 317b49bcf6
7 files changed
+202 -9

No files matched your search

+3
View File
@@ -37,8 +37,11 @@ require_relative 'oga/xml/attribute'
require_relative 'oga/xml/element'
require_relative 'oga/xml/node_set'
require_relative 'oga/xml/sax_parser'
require_relative 'oga/xml/pull_parser'
require_relative 'oga/html/parser'
require_relative 'oga/html/sax_parser'
require_relative 'oga/xpath/node'
require_relative 'oga/xpath/lexer'
+18
View File
@@ -0,0 +1,18 @@
module Oga
module HTML
##
# SAX parser for HTML documents. See the documentation of
# {Oga::XML::SaxParser} for more information.
#
class SaxParser < XML::SaxParser
##
# @see [Oga::XML::SaxParser#initialize]
#
def initialize(handler, data, options = {})
options = options.merge(:html => true)
super(handler, data, options)
end
end # SaxParser
end # HTML
end # Oga
+30
View File
@@ -24,4 +24,34 @@ module Oga
def self.parse_html(html)
return HTML::Parser.new(html).parse
end
##
# Parses the given XML document using the SAX parser.
#
# @example
# handler = SomeSaxHandler.new
#
# Oga.sax_parse_html(handler, '<root>Hello</root>')
#
# @param [Object] handler The SAX handler for the parser.
# @param [String|IO] xml The XML to parse.
#
def self.sax_parse_xml(handler, xml)
XML::SaxParser.new(handler, xml).parse
end
##
# Parses the given HTML document using the SAX parser.
#
# @example
# handler = SomeSaxHandler.new
#
# Oga.sax_parse_html(handler, '<script>foo()</script>')
#
# @param [Object] handler The SAX handler for the parser.
# @param [String|IO] HTML The HTML to parse.
#
def self.sax_parse_html(handler, html)
HTML::SaxParser.new(handler, html).parse
end
end # Oga
+63
View File
@@ -0,0 +1,63 @@
module Oga
module XML
##
# The SaxParser class provides the basic interface for writing custom SAX
# parsers. All callback methods defined in {Oga::XML::Parser} are delegated
# to a dedicated handler class.
#
# To write a custom handler for the SAX parser, create a class that
# implements one (or many) of the following callback methods:
#
# * `on_document`
# * `on_doctype`
# * `on_cdata`
# * `on_comment`
# * `on_proc_ins`
# * `on_xml_decl`
# * `on_text`
# * `on_element`
# * `on_element_children`
# * `after_element`
#
# For example:
#
# class SaxHandler
# def on_element(namespace, name, attrs = {})
# puts name
# end
# end
#
# You can then use it as following:
#
# handler = SaxHandler.new
# parser = Oga::XML::SaxParser.new(handler, '<foo />')
#
# parser.parse
#
# For information on the callback arguments see the documentation of the
# corresponding methods in {Oga::XML::Parser}.
#
class SaxParser < Parser
##
# @param [Object] handler The SAX handler to delegate callbacks to.
# @see [Oga::XML::Parser#initialize]
#
def initialize(handler, *args)
@handler = handler
super(*args)
end
# Delegate all callbacks to the handler object.
instance_methods.grep(/^(on_|after_)/).each do |method|
eval <<-EOF, nil, __FILE__, __LINE__ + 1
def #{method}(*args)
@handler.#{method}(*args) if @handler.respond_to?(:#{method})
return
end
EOF
end
end # SaxParser
end # XML
end # Oga