Skip to content
This repository

Prefixed attribute accessors #726

Closed
wants to merge 7 commits into from

2 participants

Ben Langfeld Mike Dalessio
Ben Langfeld

Fixes #712

Ben Langfeld

Of course, this now doesn't work on JRuby. I need to move the changes in Node#[] into the C extension.

Ben Langfeld

After doing bloody-battle with the C code, and a brief drop into Java, this is the best solution I have managed to come up with.

@yokolet Any thoughts?

Ben Langfeld

Can this be reviewed/merged please?

Ben Langfeld

Anything I can do?

Ben Langfeld

@flavorjones @jvshahid @yokolet: I'd really, really like to get this change in to 1.5.6. Can I get some feedback? I'd love to not have to move away from Nokogiri but this is becoming a deal-breaker for me.

Mike Dalessio
Owner

When I run the test suite on this branch under jruby-1.6.7.2 I get the following error:

  1) Error:
test_set_prefixed_attributes(Nokogiri::XML::TestNodeAttributes):
NoMethodError: undefined method `href' for nil:NilClass
    ./test/xml/test_node_attributes.rb:37:in `test_set_prefixed_attributes'
    org/jruby/RubyKernel.java:2076:in `send'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:942:in `run'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:939:in `run'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:781:in `_run_suite'
    org/jruby/RubyArray.java:2331:in `collect'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:774:in `_run_suite'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:764:in `_run_suites'
    org/jruby/RubyArray.java:2331:in `collect'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:764:in `_run_suites'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:740:in `_run_anything'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:903:in `run_tests'
    org/jruby/RubyKernel.java:2076:in `send'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:890:in `_run'
    org/jruby/RubyArray.java:1615:in `each'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:889:in `_run'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:878:in `run'
    /home/miked/.rvm/gems/jruby-1.6.7.2/gems/minitest-2.2.2/lib/minitest/unit.rb:658:in `autorun'
    org/jruby/RubyProc.java:270:in `call'
    org/jruby/RubyProc.java:224:in `call'

1159 tests, 2787 assertions, 0 failures, 1 errors, 10 skips
rake aborted!
Command failed with status (1): [/home/miked/.rvm/rubies/jruby-1.6.7.2/bin/...]
Ben Langfeld

Unfortunately I'm no longer able to run the specs on JRuby, due to this issue with racc. Any ideas?

Ben Langfeld

Disregard that last comment, merging master in solved that issue. Working on fixing the spec failure.

Ben Langfeld

So, re-familiarising myself with the situation, that bug was documented by this failing test. Unfortunately, my knowledge of the Java code is not great. What I need to do is get hold of the namespace definition for a particular prefix on the node (or its ancestors) in order to set that when doing:

node['foo:bar'] = 'baz'

Can someone help me out with how I might get hold of that namespace definition?

Ben Langfeld

Can we get this merged so the failure is at least infront of everyone? This is broken in master anyway, just hidden. There should be a failing test for it until it can be fixed.

Mike Dalessio
Owner

I've merged the failing tests onto master. I'd like to take a whack at fixing this.

Ben Langfeld

And what of the prefixed Node#[]?

Mike Dalessio
Owner

@benlangfeld - Are you referring to the behavior described by your tests? If so, as I said above, I'm going to write the code to make the tests pass. If not, can you be more specific with your question?

Ben Langfeld

You only merged the commits from this pull request which describe the current failure on jruby, but not the earlier ones which normalise the getter behaviour between jruby and the c extension, which form the bulk of this pull request (a whole bunch of C code to match JRuby, whose behaviour I consider correct as outlined in the linked issue this pull request fixes).

Mike Dalessio
Owner

Are we in agreement on these points:

  • You specifically asked to merge the test failures so that it was obvious that the behavior is wrong.
  • I cherry-picked the tests from this PR.
  • I did not merge your code changes from this PR.
  • There are currently failures on both MRI and JRuby, which accurately describe the desired behavior.

?

This pull request is messy. You have an unused private method implemented in C hanging around; you have a Ruby commit that is later reverted by your C implementation; and you're using regular expressions where they're not necessary.

I will make these tests pass by implementing a cleaner patchset. You are welcome to submit a new PR that addresses the above issues.

Ben Langfeld

Sure, we agree on those points.

As for the messy change-set:
1) The commits show progress in prototyping this functionality and then moving it down to C. Can you point me to the section in the contrib docs which states pull requests should be squashed?
2) I'd like to see your implementation that doesn't use a regex and does fewer operations on the string.
3) I asked repeatedly for a code review and admitted that my C implementation was less than perfect. This is not code I'm used to, and I threw something together hoping for feedback on how it might be improved such that it would become acceptable to merge.

I don't mean to appear ungrateful for your attention here, but your last comments are rather harshly worded considering 3 months of repeated requests for comments. One does not spend half a day preparing a pull request, despite the fact that you might be able to do a better job in 10 minutes, hoping to be berated for doing a less than perfect job.

Mike Dalessio
Owner

Ben,

I politely declined to merge the code, and you seemed to not understand why, so I explained. This should be interpreted as constructive feedback, and not "berating".

I don't mind implementing the fix. I'm not complaining, and I'm not attacking. I apologize that it took so long to get feedback; we all have day jobs and families here at Team Sparklemotion, and sometimes things fall through the cracks.

Your contribution on this issue has been extremely valuable, thank you again.

Mike Dalessio flavorjones closed this October 21, 2012
Ben Langfeld

Can we get an RC with this change?

Mike Dalessio
Owner

Yes. I'll put something together today/tonight.

Mike Dalessio
Owner

1.5.6.rc3 was released earlier this week.

Karsten Richter dc7kr referenced this pull request in Empact/roo March 02, 2013
Merged

Fixes for ODS reading with nokogiri 1.5.6 #18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
4  ext/java/nokogiri/XmlNode.java
@@ -892,9 +892,7 @@ public IRubyObject get(ThreadContext context, IRubyObject rbkey) {
892 892
             String key = rubyStringToString(rbkey);
893 893
             Element element = (Element) node;
894 894
             String value = element.getAttribute(key);
895  
-            if (value != null) {
896  
-                return context.getRuntime().newString(value);
897  
-            }
  895
+            return nonEmptyStringOrNil(context.getRuntime(), value);
898 896
         }
899 897
         return context.getRuntime().getNil();
900 898
     }
41  ext/nokogiri/xml_node.c
@@ -703,12 +703,32 @@ static VALUE get(VALUE self, VALUE attribute)
703 703
 {
704 704
   xmlNodePtr node;
705 705
   xmlChar* propstr ;
  706
+  xmlNsPtr ns;
706 707
   VALUE rval ;
  708
+  VALUE match;
  709
+  VALUE prefix;
  710
+  VALUE attribute_name;
  711
+
707 712
   Data_Get_Struct(self, xmlNode, node);
708 713
 
709 714
   if(NIL_P(attribute)) return Qnil;
710 715
 
711  
-  propstr = xmlGetProp(node, (xmlChar *)StringValuePtr(attribute));
  716
+  match = rb_funcall(attribute, rb_intern("match"), 1,
  717
+    rb_reg_new_str(rb_str_new2("([\\w]*):([\\w]*)$"), 0)
  718
+  );
  719
+
  720
+  if(RTEST(match)) {
  721
+    prefix = rb_funcall(match, rb_intern("[]"), 1, INT2NUM(1));
  722
+    attribute_name = rb_funcall(match, rb_intern("[]"), 1, INT2NUM(2));
  723
+
  724
+    ns = xmlSearchNs(node->doc, node, (const xmlChar *)(StringValuePtr(prefix)));
  725
+    if(!ns) return Qnil;
  726
+
  727
+    propstr = xmlGetNsProp(node, (xmlChar *)StringValuePtr(attribute_name), ns->href);
  728
+  } else {
  729
+    if(!key_eh(self, attribute)) return Qnil;
  730
+    propstr = xmlGetNoNsProp(node, (xmlChar *)StringValuePtr(attribute));
  731
+  }
712 732
 
713 733
   if(!propstr) return Qnil;
714 734
 
@@ -1069,6 +1089,24 @@ static VALUE line(VALUE self)
1069 1089
   return INT2NUM(xmlGetLineNo(node));
1070 1090
 }
1071 1091
 
  1092
+static VALUE namespace_with_prefix(VALUE self, VALUE prefix)
  1093
+{
  1094
+  xmlNodePtr node;
  1095
+  xmlNsPtr ns;
  1096
+
  1097
+  Data_Get_Struct(self, xmlNode, node);
  1098
+
  1099
+  ns = xmlSearchNs(
  1100
+    node->doc,
  1101
+    node,
  1102
+    (const xmlChar *)(NIL_P(prefix) ? NULL : StringValuePtr(prefix))
  1103
+  );
  1104
+
  1105
+  if (!ns) return Qnil;
  1106
+
  1107
+  return Nokogiri_wrap_xml_namespace(node->doc, ns);
  1108
+}
  1109
+
1072 1110
 /*
1073 1111
  * call-seq:
1074 1112
  *  add_namespace_definition(prefix, href)
@@ -1472,6 +1510,7 @@ void init_xml_node()
1472 1510
   rb_define_private_method(klass, "set", set, 2);
1473 1511
   rb_define_private_method(klass, "set_namespace", set_namespace, 1);
1474 1512
   rb_define_private_method(klass, "compare", compare, 1);
  1513
+  rb_define_private_method(klass, "namespace_with_prefix", namespace_with_prefix, 1);
1475 1514
 
1476 1515
   decorate      = rb_intern("decorate");
1477 1516
   decorate_bang = rb_intern("decorate!");
3  lib/nokogiri/xml/node.rb
@@ -251,8 +251,7 @@ def at_css *rules
251 251
       ###
252 252
       # Get the attribute value for the attribute +name+
253 253
       def [] name
254  
-        return nil unless key?(name.to_s)
255  
-        get(name.to_s)
  254
+        get name.to_s
256 255
       end
257 256
 
258 257
       ###
14  test/xml/test_node_attributes.rb
@@ -22,9 +22,23 @@ def test_prefixed_attributes
22 22
         node = doc.root
23 23
 
24 24
         assert_equal 'en-GB', node[:'xml:lang']
  25
+        assert_equal 'en-GB', node.attributes['lang'].value
25 26
         assert_equal nil, node[:lang]
26 27
       end
27 28
 
  29
+      def test_set_prefixed_attributes
  30
+        doc = Nokogiri::XML "<root />"
  31
+
  32
+        node = doc.root
  33
+
  34
+        node['xml:lang'] = 'en-GB'
  35
+
  36
+        assert_equal 'en-GB', node[:'xml:lang']
  37
+        assert_equal nil, node[:lang]
  38
+        assert_equal 'en-GB', node.attributes['lang'].value
  39
+        assert_equal 'http://www.w3.org/XML/1998/namespace', node.attributes['lang'].namespace.href
  40
+      end
  41
+
28 42
       def test_namespace_key?
29 43
         doc = Nokogiri::XML <<-eoxml
30 44
           <root xmlns:tlm='http://tenderlovemaking.com/'>
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.