<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -113,6 +113,120 @@ static void end_element(void * ctx, const xmlChar *name)
   );
 }
 
+/**
+ * start_element_ns was borrowed heavily from libxml-ruby. 
+ */
+static void
+start_element_ns (
+  void * ctx,
+  const xmlChar * localname,
+  const xmlChar * prefix,
+  const xmlChar * URI,
+  int nb_namespaces,
+  const xmlChar ** namespaces,
+  int nb_attributes,
+  int nb_defaulted,
+  const xmlChar ** attributes)
+{
+  VALUE self = (VALUE)ctx;
+  VALUE doc = rb_funcall(self, rb_intern(&quot;document&quot;), 0);
+  VALUE MAYBE_UNUSED(enc) = rb_iv_get(self, &quot;@encoding&quot;);
+
+  VALUE attrHash = rb_hash_new();
+  VALUE nsHash = rb_hash_new();
+
+  if (attributes)
+  {
+    /* Each attribute is an array of [localname, prefix, URI, value, end] */
+    int i;
+    for (i = 0; i &lt; nb_attributes * 5; i += 5)
+    {
+      rb_hash_aset( attrHash,
+                    NOKOGIRI_STR_NEW2((const char*)attributes[i+0], RTEST(enc) ? StringValuePtr(enc) : NULL),
+                    NOKOGIRI_STR_NEW((const char*)attributes[i+3], (attributes[i+4] - attributes[i+3]), RTEST(enc) ? StringValuePtr(enc) : NULL));
+    }
+  }
+
+  if (namespaces)
+  {
+    int i;
+    for (i = 0; i &lt; nb_namespaces * 2; i += 2)
+    {
+      rb_hash_aset( nsHash,
+                    namespaces[i+0] ? NOKOGIRI_STR_NEW2((const char*)namespaces[i+0], RTEST(enc) ? StringValuePtr(enc) : NULL) : Qnil,
+                    namespaces[i+1] ? NOKOGIRI_STR_NEW2((const char*)namespaces[i+1], RTEST(enc) ? StringValuePtr(enc) : NULL) : Qnil);
+    }
+  }
+
+  rb_funcall( doc,
+              rb_intern(&quot;start_element_ns&quot;),
+              5,
+              NOKOGIRI_STR_NEW2(localname, RTEST(enc) ? StringValuePtr(enc) : NULL),
+              attrHash,
+              prefix ? NOKOGIRI_STR_NEW2(prefix, RTEST(enc) ? StringValuePtr(enc) : NULL) : Qnil,
+              URI ? NOKOGIRI_STR_NEW2(URI, RTEST(enc) ? StringValuePtr(enc) : NULL) : Qnil,
+              nsHash
+  );
+
+  /* Call start element if it's there' */
+  if (rb_respond_to(doc, rb_intern(&quot;start_element&quot;)))
+  {
+    VALUE name;
+    if (prefix)
+    {
+      name = NOKOGIRI_STR_NEW2(prefix, RTEST(enc) ? StringValuePtr(enc) : NULL);
+      rb_funcall(name, rb_intern(&quot;&lt;&lt;&quot;), 1, NOKOGIRI_STR_NEW2(&quot;:&quot;, RTEST(enc) ? StringValuePtr(enc) : NULL));
+      rb_funcall(name, rb_intern(&quot;&lt;&lt;&quot;), 1, NOKOGIRI_STR_NEW2(localname, RTEST(enc) ? StringValuePtr(enc) : NULL));
+    }
+    else
+    {
+      name = NOKOGIRI_STR_NEW2(localname, RTEST(enc) ? StringValuePtr(enc) : NULL);
+    }
+    VALUE attrArray = rb_funcall(attrHash, rb_intern(&quot;to_a&quot;), 0);
+    attrArray = rb_funcall(attrArray, rb_intern(&quot;flatten&quot;), 0);
+    rb_funcall(doc, rb_intern(&quot;start_element&quot;), 2, name, attrArray);
+  }
+
+}
+
+/**
+ * end_element_ns was borrowed heavily from libxml-ruby. 
+ */
+static void
+end_element_ns (
+  void * ctx,
+  const xmlChar * localname,
+  const xmlChar * prefix,
+  const xmlChar * URI)
+{
+  VALUE self = (VALUE)ctx;
+  VALUE doc = rb_funcall(self, rb_intern(&quot;document&quot;), 0);
+
+  rb_funcall(doc, rb_intern(&quot;end_element_ns&quot;), 3, 
+             NOKOGIRI_STR_NEW2(localname, RTEST(enc) ? StringValuePtr(enc) : NULL),
+             prefix ? NOKOGIRI_STR_NEW2(prefix, RTEST(enc) ? StringValuePtr(enc) : NULL) : Qnil,
+             URI ? NOKOGIRI_STR_NEW2(URI, RTEST(enc) ? StringValuePtr(enc) : NULL) : Qnil
+  );
+
+  /* Call end element for old-times sake */
+  if (rb_respond_to(doc, rb_intern(&quot;end_element&quot;)))
+  {
+    VALUE name;
+    if (prefix)
+    {
+      name = NOKOGIRI_STR_NEW2(prefix, RTEST(enc) ? StringValuePtr(enc) : NULL);
+      rb_funcall(name, rb_intern(&quot;&lt;&lt;&quot;), 1, NOKOGIRI_STR_NEW2(&quot;:&quot;, RTEST(enc) ? StringValuePtr(enc) : NULL));
+      rb_funcall(name, rb_intern(&quot;&lt;&lt;&quot;), 1, NOKOGIRI_STR_NEW2(localname, RTEST(enc) ? StringValuePtr(enc) : NULL));
+    }
+    else
+    {
+      name = NOKOGIRI_STR_NEW2(localname, RTEST(enc) ? StringValuePtr(enc) : NULL);
+    }
+    rb_funcall(doc, rb_intern(&quot;end_element&quot;), 1, name);
+  }
+
+}
+
 static void characters_func(void * ctx, const xmlChar * ch, int len)
 {
   VALUE self = (VALUE)ctx;
@@ -192,11 +306,14 @@ static VALUE allocate(VALUE klass)
   handler-&gt;endDocument = end_document;
   handler-&gt;startElement = start_element;
   handler-&gt;endElement = end_element;
+  handler-&gt;startElementNs = start_element_ns;
+  handler-&gt;endElementNs = end_element_ns;
   handler-&gt;characters = characters_func;
   handler-&gt;comment = comment_func;
   handler-&gt;warning = warning_func;
   handler-&gt;error = error_func;
   handler-&gt;cdataBlock = cdata_block;
+  handler-&gt;initialized = XML_SAX2_MAGIC;
 
   return Data_Wrap_Struct(klass, NULL, deallocate, handler);
 }</diff>
      <filename>ext/nokogiri/xml_sax_parser.c</filename>
    </modified>
    <modified>
      <diff>@@ -65,6 +65,7 @@ static VALUE initialize_native(VALUE self, VALUE _xml_sax, VALUE _filename)
   if(ctx == NULL)
     rb_raise(rb_eRuntimeError, &quot;Could not create a parser context&quot;);
 
+  ctx-&gt;sax2 = 1;
   DATA_PTR(self) = ctx;
   return self;
 }</diff>
      <filename>ext/nokogiri/xml_sax_push_parser.c</filename>
    </modified>
    <modified>
      <diff>@@ -91,6 +91,24 @@ module Nokogiri
         end
 
         ###
+        # Called at the beginning of an element
+        # +name+ is the element name
+        # +attrs+ is a hash of attributes
+        # +prefix+ is the namespace prefix for the element
+        # +uri+ is the associated namespace URI
+        # +namespaces+ is a hash of namespace prefix:urls associated with the element
+        def start_element_ns(name, attrs = {}, prefix = nil, uri = nil, namespaces = {})
+        end
+
+        ###
+        # Called at the end of an element
+        # +name+ is the element's name
+        # +prefix+ is the namespace prefix associated with the element
+        # +uri+ is the associated namespace URI
+        def end_element_ns(name, prefix = nil, uri = nil)
+        end
+
+        ###
         # Characters read between a tag
         # +string+ contains the character data
         def characters string</diff>
      <filename>lib/nokogiri/xml/sax/document.rb</filename>
    </modified>
    <modified>
      <diff>@@ -54,8 +54,8 @@ module Nokogiri
   module SAX
     class TestCase &lt; Nokogiri::TestCase
       class Doc &lt; XML::SAX::Document
-        attr_reader :start_elements, :start_document_called
-        attr_reader :end_elements, :end_document_called
+        attr_reader :start_elements, :start_elements_ns, :start_document_called
+        attr_reader :end_elements, :end_elements_ns, :end_document_called
         attr_reader :data, :comments, :cdata_blocks
         attr_reader :errors, :warnings
 
@@ -84,11 +84,21 @@ module Nokogiri
           super
         end
 
+        def start_element_ns *args
+          (@start_elements_ns ||= []) &lt;&lt; args
+          super
+        end
+
         def end_element *args
           (@end_elements ||= []) &lt;&lt; args
           super
         end
 
+        def end_element_ns *args
+          (@end_elements_ns ||= []) &lt;&lt; args
+          super
+        end
+
         def characters string
           @data ||= []
           @data += [string]</diff>
      <filename>test/helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -38,6 +38,30 @@ module Nokogiri
           @parser.finish
         end
 
+        def test_start_element_ns
+          @parser.&lt;&lt;(&lt;&lt;-eoxml)
+            &lt;stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'&gt;&lt;/stream:stream&gt;
+          eoxml
+
+          assert_equal [[ 'stream',
+                          {'version' =&gt; '1.0'},
+                          'stream',
+                          'http://etherx.jabber.org/streams',
+                          {nil =&gt; 'jabber:client', 'stream' =&gt; 'http://etherx.jabber.org/streams'}]],
+            @parser.document.start_elements_ns
+          @parser.finish
+        end
+
+        def test_end_element_ns
+          @parser.&lt;&lt;(&lt;&lt;-eoxml)
+            &lt;stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'&gt;&lt;/stream:stream&gt;
+          eoxml
+
+          assert_equal [['stream', 'stream', 'http://etherx.jabber.org/streams']],
+            @parser.document.end_elements_ns
+          @parser.finish
+        end
+
         def test_chevron_partial_xml
           @parser.&lt;&lt;(&lt;&lt;-eoxml)
             &lt;p id=&quot;asdfasdf&quot;&gt;</diff>
      <filename>test/xml/sax/test_push_parser.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>e5a79545f4ee4d40ac073a30e266c9eace30b313</id>
    </parent>
  </parents>
  <author>
    <name>Jeff Smick</name>
    <email>sprsquish@gmail.com</email>
  </author>
  <url>http://github.com/sprsquish/nokogiri/commit/660362805ff06cd36465d08bf6dda67af6867c4f</url>
  <id>660362805ff06cd36465d08bf6dda67af6867c4f</id>
  <committed-date>2009-05-19T09:58:38-07:00</committed-date>
  <authored-date>2009-05-18T17:16:45-07:00</authored-date>
  <message>add support for SAX2 start_element_ns and end_element_ns (code was heavily borrowed from libxml-ruby)</message>
  <tree>f1cd130d5d19d18cf6ae0061ab34a0844f21d905</tree>
  <committer>
    <name>Jeff Smick</name>
    <email>sprsquish@gmail.com</email>
  </committer>
</commit>
