Browse files

SAX parser context provides line and column information at parse time

  • Loading branch information...
1 parent ebc34f0 commit f5cd9a1e6dd8e0bacc06e52e21624e7d3727d5b1 @tenderlove tenderlove committed Nov 11, 2010
View
1 CHANGELOG.rdoc
@@ -6,6 +6,7 @@
* XSLT supports function extensions. #336
* XPath bind parameter substitution. #329
* XML::Reader node type constants. #369
+ * SAX Parser context provides line and column information
* Bugfixes
View
1 Manifest.txt
@@ -113,6 +113,7 @@ lib/nokogiri/ffi/structs/xml_node_set.rb
lib/nokogiri/ffi/structs/xml_notation.rb
lib/nokogiri/ffi/structs/xml_ns.rb
lib/nokogiri/ffi/structs/xml_parser_context.rb
+lib/nokogiri/ffi/structs/xml_parser_input.rb
lib/nokogiri/ffi/structs/xml_relax_ng.rb
lib/nokogiri/ffi/structs/xml_sax_handler.rb
lib/nokogiri/ffi/structs/xml_sax_push_parser_context.rb
View
40 ext/nokogiri/xml_sax_parser_context.c
@@ -140,6 +140,44 @@ static VALUE get_replace_entities(VALUE self)
return Qtrue;
}
+/*
+ * call-seq: line
+ *
+ * Get the current line the parser context is processing.
+ */
+static VALUE line(VALUE self)
+{
+ xmlParserCtxtPtr ctxt;
+ xmlParserInputPtr io;
+
+ Data_Get_Struct(self, xmlParserCtxt, ctxt);
+
+ io = ctxt->input;
+ if(io)
+ return INT2NUM(io->line);
+
+ return Qnil;
+}
+
+/*
+ * call-seq: column
+ *
+ * Get the current column the parser context is processing.
+ */
+static VALUE column(VALUE self)
+{
+ xmlParserCtxtPtr ctxt;
+ xmlParserInputPtr io;
+
+ Data_Get_Struct(self, xmlParserCtxt, ctxt);
+
+ io = ctxt->input;
+ if(io)
+ return INT2NUM(io->col);
+
+ return Qnil;
+}
+
void init_xml_sax_parser_context()
{
VALUE nokogiri = rb_define_module("Nokogiri");
@@ -156,4 +194,6 @@ void init_xml_sax_parser_context()
rb_define_method(klass, "parse_with", parse_with, 1);
rb_define_method(klass, "replace_entities=", set_replace_entities, 1);
rb_define_method(klass, "replace_entities", get_replace_entities, 0);
+ rb_define_method(klass, "line", line, 0);
+ rb_define_method(klass, "column", column, 0);
}
View
1 lib/nokogiri/ffi/libxml.rb
@@ -376,6 +376,7 @@ def xmlNextElementSiblingHack(sibling)
"structs/xml_element",
"structs/xml_entity",
"structs/xml_element_content",
+ "structs/xml_parser_input",
"xml/node",
"xml/namespace",
"xml/dtd",
View
3 lib/nokogiri/ffi/structs/xml_parser_context.rb
@@ -11,7 +11,8 @@ class XmlParserContext < FFI::Struct
:version, :string,
:encoding, :string,
:standalone, :int,
- :html, :int
+ :html, :int,
+ :input, :pointer
)
end
end
View
19 lib/nokogiri/ffi/structs/xml_parser_input.rb
@@ -0,0 +1,19 @@
+module Nokogiri
+ # :stopdoc:
+ module LibXML
+ class XmlParserInput < FFI::Struct
+ layout(
+ :buf, :pointer,
+ :filename, :pointer,
+ :directory, :pointer,
+ :base, :pointer,
+ :cur, :pointer,
+ :end, :pointer,
+ :length, :int,
+ :line, :int,
+ :col, :int
+ )
+ end
+ end
+ # :startdoc:
+end
View
12 lib/nokogiri/ffi/xml/sax/parser_context.rb
@@ -40,6 +40,18 @@ def self.file filename
pc
end
+ def line
+ return nil if cstruct[:input].null?
+ input = LibXML::XmlParserInput.new cstruct[:input]
+ input[:line]
+ end
+
+ def column
+ return nil if cstruct[:input].null?
+ input = LibXML::XmlParserInput.new cstruct[:input]
+ input[:col]
+ end
+
def parse_with sax_handler, type = :xml
raise ArgumentError unless XML::SAX::Parser === sax_handler
sax = sax_handler.cstruct
View
50 test/xml/sax/test_parser_context.rb
@@ -6,6 +6,56 @@ module Nokogiri
module XML
module SAX
class TestParserContext < Nokogiri::SAX::TestCase
+ def setup
+ @xml = '<hello>
+
+world
+<inter>
+ <net>
+ </net>
+</inter>
+
+</hello>'
+ end
+
+ class Counter < Nokogiri::XML::SAX::Document
+ attr_accessor :context, :lines, :columns
+ def initialize
+ @context = nil
+ @lines = []
+ @columns = []
+ end
+
+ def start_element name, attrs = []
+ @lines << [name, context.line]
+ @columns << [name, context.column]
+ end
+ end
+
+ def test_line_numbers
+ sax_handler = Counter.new
+
+ parser = Nokogiri::XML::SAX::Parser.new(sax_handler)
+ parser.parse(@xml) do |ctx|
+ sax_handler.context = ctx
+ end
+
+ assert_equal [["hello", 1], ["inter", 4], ["net", 5]],
+ sax_handler.lines
+ end
+
+ def test_column_numbers
+ sax_handler = Counter.new
+
+ parser = Nokogiri::XML::SAX::Parser.new(sax_handler)
+ parser.parse(@xml) do |ctx|
+ sax_handler.context = ctx
+ end
+
+ assert_equal [["hello", 7], ["inter", 7], ["net", 9]],
+ sax_handler.columns
+ end
+
def test_replace_entities
pc = ParserContext.new StringIO.new('<root />'), 'UTF-8'
pc.replace_entities = false

0 comments on commit f5cd9a1

Please sign in to comment.