nokogiri 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (200) hide show
  1. data/.autotest +14 -2
  2. data/CHANGELOG.ja.rdoc +38 -0
  3. data/CHANGELOG.rdoc +43 -0
  4. data/Manifest.txt +80 -5
  5. data/README.ja.rdoc +12 -11
  6. data/README.rdoc +4 -2
  7. data/Rakefile +103 -173
  8. data/bin/nokogiri +47 -0
  9. data/ext/nokogiri/extconf.rb +19 -13
  10. data/ext/nokogiri/html_document.c +39 -3
  11. data/ext/nokogiri/html_document.h +1 -1
  12. data/ext/nokogiri/html_element_description.c +272 -0
  13. data/ext/nokogiri/html_element_description.h +10 -0
  14. data/ext/nokogiri/html_entity_lookup.h +1 -1
  15. data/ext/nokogiri/html_sax_parser.h +1 -1
  16. data/ext/nokogiri/{native.c → nokogiri.c} +11 -3
  17. data/ext/nokogiri/{native.h → nokogiri.h} +18 -4
  18. data/ext/nokogiri/xml_attr.c +14 -5
  19. data/ext/nokogiri/xml_attr.h +1 -1
  20. data/ext/nokogiri/xml_cdata.c +15 -6
  21. data/ext/nokogiri/xml_cdata.h +1 -1
  22. data/ext/nokogiri/xml_comment.c +13 -4
  23. data/ext/nokogiri/xml_comment.h +1 -1
  24. data/ext/nokogiri/xml_document.c +50 -41
  25. data/ext/nokogiri/xml_document.h +1 -1
  26. data/ext/nokogiri/xml_document_fragment.c +12 -4
  27. data/ext/nokogiri/xml_document_fragment.h +1 -1
  28. data/ext/nokogiri/xml_dtd.c +1 -1
  29. data/ext/nokogiri/xml_dtd.h +1 -1
  30. data/ext/nokogiri/xml_entity_reference.c +13 -4
  31. data/ext/nokogiri/xml_entity_reference.h +1 -1
  32. data/ext/nokogiri/xml_io.h +1 -1
  33. data/ext/nokogiri/xml_namespace.c +69 -0
  34. data/ext/nokogiri/xml_namespace.h +12 -0
  35. data/ext/nokogiri/xml_node.c +232 -124
  36. data/ext/nokogiri/xml_node.h +3 -4
  37. data/ext/nokogiri/xml_node_set.c +206 -19
  38. data/ext/nokogiri/xml_node_set.h +1 -1
  39. data/ext/nokogiri/xml_processing_instruction.c +14 -4
  40. data/ext/nokogiri/xml_processing_instruction.h +1 -1
  41. data/ext/nokogiri/xml_reader.c +87 -7
  42. data/ext/nokogiri/xml_reader.h +1 -1
  43. data/ext/nokogiri/xml_relax_ng.c +106 -0
  44. data/ext/nokogiri/xml_relax_ng.h +9 -0
  45. data/ext/nokogiri/xml_sax_parser.c +122 -2
  46. data/ext/nokogiri/xml_sax_parser.h +1 -1
  47. data/ext/nokogiri/xml_sax_push_parser.c +1 -0
  48. data/ext/nokogiri/xml_sax_push_parser.h +1 -1
  49. data/ext/nokogiri/xml_schema.c +107 -0
  50. data/ext/nokogiri/xml_schema.h +9 -0
  51. data/ext/nokogiri/xml_syntax_error.h +1 -1
  52. data/ext/nokogiri/xml_text.c +10 -3
  53. data/ext/nokogiri/xml_text.h +1 -1
  54. data/ext/nokogiri/xml_xpath.h +1 -1
  55. data/ext/nokogiri/xml_xpath_context.h +1 -1
  56. data/ext/nokogiri/xslt_stylesheet.c +29 -16
  57. data/ext/nokogiri/xslt_stylesheet.h +1 -1
  58. data/lib/action-nokogiri.rb +7 -1
  59. data/lib/nokogiri.rb +21 -5
  60. data/lib/nokogiri/css/generated_parser.rb +49 -14
  61. data/lib/nokogiri/css/generated_tokenizer.rb +2 -2
  62. data/lib/nokogiri/css/node.rb +13 -3
  63. data/lib/nokogiri/css/parser.rb +8 -0
  64. data/lib/nokogiri/css/parser.y +7 -7
  65. data/lib/nokogiri/css/tokenizer.rb +2 -0
  66. data/lib/nokogiri/css/xpath_visitor.rb +10 -6
  67. data/lib/nokogiri/decorators/hpricot/node.rb +1 -1
  68. data/lib/nokogiri/decorators/hpricot/node_set.rb +2 -2
  69. data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +2 -0
  70. data/lib/nokogiri/decorators/slop.rb +3 -1
  71. data/lib/nokogiri/ffi/html/document.rb +37 -0
  72. data/lib/nokogiri/ffi/html/element_description.rb +85 -0
  73. data/lib/nokogiri/ffi/html/entity_lookup.rb +16 -0
  74. data/lib/nokogiri/ffi/html/sax/parser.rb +21 -0
  75. data/lib/nokogiri/ffi/io_callbacks.rb +32 -0
  76. data/lib/nokogiri/ffi/libxml.rb +314 -0
  77. data/lib/nokogiri/ffi/structs/common_node.rb +26 -0
  78. data/lib/nokogiri/ffi/structs/html_elem_desc.rb +24 -0
  79. data/lib/nokogiri/ffi/structs/html_entity_desc.rb +13 -0
  80. data/lib/nokogiri/ffi/structs/xml_alloc.rb +16 -0
  81. data/lib/nokogiri/ffi/structs/xml_attr.rb +19 -0
  82. data/lib/nokogiri/ffi/structs/xml_buffer.rb +16 -0
  83. data/lib/nokogiri/ffi/structs/xml_document.rb +108 -0
  84. data/lib/nokogiri/ffi/structs/xml_dtd.rb +26 -0
  85. data/lib/nokogiri/ffi/structs/xml_node.rb +28 -0
  86. data/lib/nokogiri/ffi/structs/xml_node_set.rb +53 -0
  87. data/lib/nokogiri/ffi/structs/xml_notation.rb +11 -0
  88. data/lib/nokogiri/ffi/structs/xml_ns.rb +15 -0
  89. data/lib/nokogiri/ffi/structs/xml_relax_ng.rb +14 -0
  90. data/lib/nokogiri/ffi/structs/xml_sax_handler.rb +51 -0
  91. data/lib/nokogiri/ffi/structs/xml_sax_push_parser_context.rb +14 -0
  92. data/lib/nokogiri/ffi/structs/xml_schema.rb +13 -0
  93. data/lib/nokogiri/ffi/structs/xml_syntax_error.rb +31 -0
  94. data/lib/nokogiri/ffi/structs/xml_text_reader.rb +12 -0
  95. data/lib/nokogiri/ffi/structs/xml_xpath_context.rb +37 -0
  96. data/lib/nokogiri/ffi/structs/xml_xpath_object.rb +35 -0
  97. data/lib/nokogiri/ffi/structs/xml_xpath_parser_context.rb +20 -0
  98. data/lib/nokogiri/ffi/structs/xslt_stylesheet.rb +13 -0
  99. data/lib/nokogiri/ffi/xml/attr.rb +41 -0
  100. data/lib/nokogiri/ffi/xml/cdata.rb +19 -0
  101. data/lib/nokogiri/ffi/xml/comment.rb +18 -0
  102. data/lib/nokogiri/ffi/xml/document.rb +107 -0
  103. data/lib/nokogiri/ffi/xml/document_fragment.rb +26 -0
  104. data/lib/nokogiri/ffi/xml/dtd.rb +42 -0
  105. data/lib/nokogiri/ffi/xml/entity_reference.rb +19 -0
  106. data/lib/nokogiri/ffi/xml/namespace.rb +38 -0
  107. data/lib/nokogiri/ffi/xml/node.rb +380 -0
  108. data/lib/nokogiri/ffi/xml/node_set.rb +130 -0
  109. data/lib/nokogiri/ffi/xml/processing_instruction.rb +20 -0
  110. data/lib/nokogiri/ffi/xml/reader.rb +217 -0
  111. data/lib/nokogiri/ffi/xml/relax_ng.rb +51 -0
  112. data/lib/nokogiri/ffi/xml/sax/parser.rb +148 -0
  113. data/lib/nokogiri/ffi/xml/sax/push_parser.rb +38 -0
  114. data/lib/nokogiri/ffi/xml/schema.rb +55 -0
  115. data/lib/nokogiri/ffi/xml/syntax_error.rb +76 -0
  116. data/lib/nokogiri/ffi/xml/text.rb +18 -0
  117. data/lib/nokogiri/ffi/xml/xpath.rb +19 -0
  118. data/lib/nokogiri/ffi/xml/xpath_context.rb +135 -0
  119. data/lib/nokogiri/ffi/xslt/stylesheet.rb +47 -0
  120. data/lib/nokogiri/hpricot.rb +14 -3
  121. data/lib/nokogiri/html.rb +11 -46
  122. data/lib/nokogiri/html/builder.rb +27 -1
  123. data/lib/nokogiri/html/document.rb +62 -6
  124. data/lib/nokogiri/html/document_fragment.rb +15 -0
  125. data/lib/nokogiri/html/element_description.rb +23 -0
  126. data/lib/nokogiri/html/entity_lookup.rb +2 -0
  127. data/lib/nokogiri/html/sax/parser.rb +27 -1
  128. data/lib/nokogiri/version.rb +26 -1
  129. data/lib/nokogiri/version_warning.rb +11 -0
  130. data/lib/nokogiri/xml.rb +25 -51
  131. data/lib/nokogiri/xml/builder.rb +166 -10
  132. data/lib/nokogiri/xml/cdata.rb +3 -1
  133. data/lib/nokogiri/xml/document.rb +39 -6
  134. data/lib/nokogiri/xml/document_fragment.rb +41 -1
  135. data/lib/nokogiri/xml/dtd.rb +3 -1
  136. data/lib/nokogiri/xml/entity_declaration.rb +3 -1
  137. data/lib/nokogiri/xml/fragment_handler.rb +24 -3
  138. data/lib/nokogiri/xml/namespace.rb +7 -0
  139. data/lib/nokogiri/xml/node.rb +314 -65
  140. data/lib/nokogiri/xml/node/save_options.rb +12 -2
  141. data/lib/nokogiri/xml/node_set.rb +58 -8
  142. data/lib/nokogiri/xml/parse_options.rb +80 -0
  143. data/lib/nokogiri/xml/processing_instruction.rb +2 -0
  144. data/lib/nokogiri/xml/reader.rb +42 -3
  145. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  146. data/lib/nokogiri/xml/sax.rb +0 -7
  147. data/lib/nokogiri/xml/sax/document.rb +84 -0
  148. data/lib/nokogiri/xml/sax/parser.rb +38 -2
  149. data/lib/nokogiri/xml/sax/push_parser.rb +12 -0
  150. data/lib/nokogiri/xml/schema.rb +65 -0
  151. data/lib/nokogiri/xml/syntax_error.rb +11 -0
  152. data/lib/nokogiri/xml/xpath.rb +1 -1
  153. data/lib/nokogiri/xml/xpath_context.rb +2 -0
  154. data/lib/nokogiri/xslt.rb +21 -1
  155. data/lib/nokogiri/xslt/stylesheet.rb +19 -0
  156. data/lib/xsd/xmlparser/nokogiri.rb +12 -2
  157. data/tasks/test.rb +42 -19
  158. data/test/css/test_parser.rb +29 -0
  159. data/test/ffi/test_document.rb +35 -0
  160. data/test/files/address_book.rlx +12 -0
  161. data/test/files/address_book.xml +10 -0
  162. data/test/files/po.xml +32 -0
  163. data/test/files/po.xsd +66 -0
  164. data/test/helper.rb +38 -8
  165. data/test/html/sax/test_parser.rb +12 -0
  166. data/test/html/test_builder.rb +25 -2
  167. data/test/html/test_document.rb +91 -20
  168. data/test/html/test_document_fragment.rb +97 -0
  169. data/test/html/test_element_description.rb +95 -0
  170. data/test/html/test_node.rb +66 -3
  171. data/test/test_convert_xpath.rb +1 -1
  172. data/test/test_memory_leak.rb +57 -18
  173. data/test/test_nokogiri.rb +24 -2
  174. data/test/test_reader.rb +77 -0
  175. data/test/test_xslt_transforms.rb +120 -82
  176. data/test/xml/node/test_subclass.rb +44 -0
  177. data/test/xml/sax/test_parser.rb +9 -0
  178. data/test/xml/sax/test_push_parser.rb +24 -0
  179. data/test/xml/test_attr.rb +7 -0
  180. data/test/xml/test_builder.rb +48 -0
  181. data/test/xml/test_cdata.rb +19 -0
  182. data/test/xml/test_comment.rb +6 -0
  183. data/test/xml/test_document.rb +101 -2
  184. data/test/xml/test_document_fragment.rb +55 -3
  185. data/test/xml/test_entity_reference.rb +4 -0
  186. data/test/xml/test_namespace.rb +43 -0
  187. data/test/xml/test_node.rb +255 -8
  188. data/test/xml/test_node_attributes.rb +34 -0
  189. data/test/xml/test_node_encoding.rb +9 -2
  190. data/test/xml/test_node_set.rb +197 -1
  191. data/test/xml/test_parse_options.rb +52 -0
  192. data/test/xml/test_processing_instruction.rb +5 -0
  193. data/test/xml/test_relax_ng.rb +60 -0
  194. data/test/xml/test_schema.rb +65 -0
  195. data/test/xml/test_text.rb +5 -0
  196. data/test/xml/test_unparented_node.rb +3 -3
  197. metadata +128 -12
  198. data/lib/nokogiri/xml/comment.rb +0 -6
  199. data/lib/nokogiri/xml/element.rb +0 -6
  200. data/lib/nokogiri/xml/text.rb +0 -6
@@ -1,7 +1,7 @@
1
1
  #ifndef NOKOGIRI_XML_DOCUMENT_FRAGMENT
2
2
  #define NOKOGIRI_XML_DOCUMENT_FRAGMENT
3
3
 
4
- #include <native.h>
4
+ #include <nokogiri.h>
5
5
 
6
6
  void init_xml_document_fragment();
7
7
 
@@ -20,7 +20,7 @@ static void element_copier(void *_payload, void *data, xmlChar *name)
20
20
  VALUE hash = (VALUE)data;
21
21
  xmlNodePtr payload = (xmlNodePtr)_payload;
22
22
 
23
- VALUE element = Nokogiri_wrap_xml_node(payload);
23
+ VALUE element = Nokogiri_wrap_xml_node(Qnil, payload);
24
24
 
25
25
  rb_hash_aset(hash, NOKOGIRI_STR_NEW2(name, payload->doc->encoding), element);
26
26
  }
@@ -1,7 +1,7 @@
1
1
  #ifndef NOKOGIRI_XML_DTD
2
2
  #define NOKOGIRI_XML_DTD
3
3
 
4
- #include <native.h>
4
+ #include <nokogiri.h>
5
5
 
6
6
  void init_xml_dtd();
7
7
 
@@ -6,17 +6,26 @@
6
6
  *
7
7
  * Create a new EntityReference element on the +document+ with +name+
8
8
  */
9
- static VALUE new(VALUE klass, VALUE doc, VALUE name)
9
+ static VALUE new(int argc, VALUE *argv, VALUE klass)
10
10
  {
11
11
  xmlDocPtr xml_doc;
12
- Data_Get_Struct(doc, xmlDoc, xml_doc);
12
+ VALUE document;
13
+ VALUE name;
14
+ VALUE rest;
15
+
16
+ rb_scan_args(argc, argv, "2*", &document, &name, &rest);
17
+
18
+ Data_Get_Struct(document, xmlDoc, xml_doc);
13
19
 
14
20
  xmlNodePtr node = xmlNewReference(
15
21
  xml_doc,
16
22
  (const xmlChar *)StringValuePtr(name)
17
23
  );
18
24
 
19
- VALUE rb_node = Nokogiri_wrap_xml_node(node);
25
+ NOKOGIRI_ROOT_NODE(node);
26
+
27
+ VALUE rb_node = Nokogiri_wrap_xml_node(klass, node);
28
+ rb_funcall2(rb_node, rb_intern("initialize"), argc, argv);
20
29
 
21
30
  if(rb_block_given_p()) rb_yield(rb_node);
22
31
 
@@ -37,5 +46,5 @@ void init_xml_entity_reference()
37
46
 
38
47
  cNokogiriXmlEntityReference = klass;
39
48
 
40
- rb_define_singleton_method(klass, "new", new, 2);
49
+ rb_define_singleton_method(klass, "new", new, -1);
41
50
  }
@@ -1,7 +1,7 @@
1
1
  #ifndef NOKOGIRI_XML_ENTITY_REFERENCE
2
2
  #define NOKOGIRI_XML_ENTITY_REFERENCE
3
3
 
4
- #include <native.h>
4
+ #include <nokogiri.h>
5
5
 
6
6
  void init_xml_entity_reference();
7
7
 
@@ -1,7 +1,7 @@
1
1
  #ifndef NOKOGIRI_XML_IO
2
2
  #define NOKOGIRI_XML_IO
3
3
 
4
- #include <native.h>
4
+ #include <nokogiri.h>
5
5
 
6
6
  int io_read_callback(void * ctx, char * buffer, int len);
7
7
  int io_write_callback(void * ctx, char * buffer, int len);
@@ -0,0 +1,69 @@
1
+ #include <xml_namespace.h>
2
+
3
+ VALUE cNokogiriXmlNamespace ;
4
+
5
+ /*
6
+ * call-seq:
7
+ * prefix
8
+ *
9
+ * Get the prefix for this namespace. Returns +nil+ if there is no prefix.
10
+ */
11
+ static VALUE prefix(VALUE self)
12
+ {
13
+ xmlNsPtr ns;
14
+ xmlDocPtr doc;
15
+
16
+ Data_Get_Struct(self, xmlNs, ns);
17
+ if(!ns->prefix) return Qnil;
18
+
19
+ Data_Get_Struct(rb_iv_get(self, "@document"), xmlDoc, doc);
20
+
21
+ return NOKOGIRI_STR_NEW2(ns->prefix, doc->encoding);
22
+ }
23
+
24
+ /*
25
+ * call-seq:
26
+ * href
27
+ *
28
+ * Get the href for this namespace
29
+ */
30
+ static VALUE href(VALUE self)
31
+ {
32
+ xmlNsPtr ns;
33
+ xmlDocPtr doc;
34
+
35
+ Data_Get_Struct(self, xmlNs, ns);
36
+ if(!ns->href) return Qnil;
37
+
38
+ Data_Get_Struct(rb_iv_get(self, "@document"), xmlDoc, doc);
39
+
40
+ return NOKOGIRI_STR_NEW2(ns->href, doc->encoding);
41
+ }
42
+
43
+ VALUE Nokogiri_wrap_xml_namespace(xmlDocPtr doc, xmlNsPtr node)
44
+ {
45
+ assert(doc->_private);
46
+
47
+ if(node->_private)
48
+ return (VALUE)node->_private;
49
+
50
+ VALUE ns = Data_Wrap_Struct(cNokogiriXmlNamespace, 0, 0, node);
51
+
52
+ rb_iv_set(ns, "@document", DOC_RUBY_OBJECT(doc));
53
+
54
+ node->_private = (void *)ns;
55
+
56
+ return ns;
57
+ }
58
+
59
+ void init_xml_namespace()
60
+ {
61
+ VALUE nokogiri = rb_define_module("Nokogiri");
62
+ VALUE xml = rb_define_module_under(nokogiri, "XML");
63
+ VALUE klass = rb_define_class_under(xml, "Namespace", rb_cObject);
64
+
65
+ cNokogiriXmlNamespace = klass;
66
+
67
+ rb_define_method(klass, "prefix", prefix, 0);
68
+ rb_define_method(klass, "href", href, 0);
69
+ }
@@ -0,0 +1,12 @@
1
+ #ifndef NOKOGIRI_XML_NAMESPACE
2
+ #define NOKOGIRI_XML_NAMESPACE
3
+
4
+ #include <nokogiri.h>
5
+
6
+ void init_xml_namespace();
7
+
8
+ extern VALUE cNokogiriXmlNamespace ;
9
+
10
+ VALUE Nokogiri_wrap_xml_namespace(xmlDocPtr doc, xmlNsPtr node) ;
11
+
12
+ #endif
@@ -10,20 +10,64 @@ static void debug_node_dealloc(xmlNodePtr x)
10
10
  # define debug_node_dealloc 0
11
11
  #endif
12
12
 
13
+ static void mark(xmlNodePtr node)
14
+ {
15
+ rb_gc_mark(DOC_RUBY_OBJECT(node->doc));
16
+ }
17
+
13
18
  /* :nodoc: */
14
19
  typedef xmlNodePtr (*node_other_func)(xmlNodePtr, xmlNodePtr);
15
20
 
21
+ /* :nodoc: */
22
+ static void relink_namespace(xmlNodePtr reparented)
23
+ {
24
+ // Make sure that our reparented node has the correct namespaces
25
+ if(reparented->doc != (xmlDocPtr)reparented->parent)
26
+ xmlSetNs(reparented, reparented->parent->ns);
27
+
28
+ // Search our parents for an existing definition
29
+ if(reparented->nsDef) {
30
+ xmlNsPtr ns = xmlSearchNsByHref(
31
+ reparented->doc,
32
+ reparented->parent,
33
+ reparented->nsDef->href
34
+ );
35
+ if(ns && ns != reparented->nsDef) reparented->nsDef = NULL;
36
+ }
37
+
38
+ // Only walk all children if there actually is a namespace we need to
39
+ // reparent.
40
+ if(NULL == reparented->ns) return;
41
+
42
+ // When a node gets reparented, walk it's children to make sure that
43
+ // their namespaces are reparented as well.
44
+ xmlNodePtr child = reparented->children;
45
+ while(NULL != child) {
46
+ relink_namespace(child);
47
+ child = child->next;
48
+ }
49
+ }
50
+
16
51
  /* :nodoc: */
17
52
  static VALUE reparent_node_with(VALUE node_obj, VALUE other_obj, node_other_func func)
18
53
  {
19
54
  VALUE reparented_obj ;
20
55
  xmlNodePtr node, other, reparented ;
21
56
 
57
+ if(! rb_funcall(node_obj, rb_intern("is_a?"), 1, cNokogiriXmlNode))
58
+ rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
59
+
22
60
  Data_Get_Struct(node_obj, xmlNode, node);
23
61
  Data_Get_Struct(other_obj, xmlNode, other);
24
62
 
25
63
  if (node->doc == other->doc) {
26
64
  xmlUnlinkNode(node) ;
65
+ if ( node->type == XML_TEXT_NODE
66
+ && other->type == XML_TEXT_NODE
67
+ && is_2_6_16() ) {
68
+ other->content = xmlStrdup(other->content); // we'd rather leak than segfault.
69
+ }
70
+
27
71
  if(!(reparented = (*func)(other, node))) {
28
72
  rb_raise(rb_eRuntimeError, "Could not reparent node (1)");
29
73
  }
@@ -47,21 +91,10 @@ static VALUE reparent_node_with(VALUE node_obj, VALUE other_obj, node_other_func
47
91
  DATA_PTR(node_obj) = reparented ;
48
92
  }
49
93
 
50
- // Make sure that our reparented node has the correct namespaces
51
- if(reparented->doc != (xmlDocPtr)reparented->parent)
52
- reparented->ns = reparented->parent->ns;
53
-
54
- // Search our parents for an existing definition
55
- if(reparented->nsDef) {
56
- xmlNsPtr ns = xmlSearchNsByHref(
57
- reparented->doc,
58
- reparented,
59
- reparented->nsDef->href
60
- );
61
- if(ns) reparented->nsDef = NULL;
62
- }
94
+ // Appropriately link in namespaces
95
+ relink_namespace(reparented);
63
96
 
64
- reparented_obj = Nokogiri_wrap_xml_node(reparented);
97
+ reparented_obj = Nokogiri_wrap_xml_node(Qnil, reparented);
65
98
 
66
99
  rb_funcall(reparented_obj, rb_intern("decorate!"), 0);
67
100
 
@@ -69,6 +102,19 @@ static VALUE reparent_node_with(VALUE node_obj, VALUE other_obj, node_other_func
69
102
  }
70
103
 
71
104
 
105
+ /*
106
+ * call-seq:
107
+ * document
108
+ *
109
+ * Get the document for this Node
110
+ */
111
+ static VALUE document(VALUE self)
112
+ {
113
+ xmlNodePtr node;
114
+ Data_Get_Struct(self, xmlNode, node);
115
+ return DOC_RUBY_OBJECT(node->doc);
116
+ }
117
+
72
118
  /*
73
119
  * call-seq:
74
120
  * pointer_id
@@ -123,7 +169,7 @@ static VALUE internal_subset(VALUE self)
123
169
 
124
170
  if(!dtd) return Qnil;
125
171
 
126
- return Nokogiri_wrap_xml_node((xmlNodePtr)dtd);
172
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
127
173
  }
128
174
 
129
175
  /*
@@ -146,7 +192,7 @@ static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
146
192
  dup = xmlDocCopyNode(node, node->doc, NUM2INT(level));
147
193
  if(dup == NULL) return Qnil;
148
194
 
149
- return Nokogiri_wrap_xml_node(dup);
195
+ return Nokogiri_wrap_xml_node(rb_obj_class(self), dup);
150
196
  }
151
197
 
152
198
  /*
@@ -193,7 +239,7 @@ static VALUE next_sibling(VALUE self)
193
239
  sibling = node->next;
194
240
  if(!sibling) return Qnil;
195
241
 
196
- return Nokogiri_wrap_xml_node(sibling) ;
242
+ return Nokogiri_wrap_xml_node(Qnil, sibling) ;
197
243
  }
198
244
 
199
245
  /*
@@ -210,7 +256,7 @@ static VALUE previous_sibling(VALUE self)
210
256
  sibling = node->prev;
211
257
  if(!sibling) return Qnil;
212
258
 
213
- return Nokogiri_wrap_xml_node(sibling);
259
+ return Nokogiri_wrap_xml_node(Qnil, sibling);
214
260
  }
215
261
 
216
262
  /* :nodoc: */
@@ -221,6 +267,9 @@ static VALUE replace(VALUE self, VALUE _new_node)
221
267
  Data_Get_Struct(_new_node, xmlNode, new_node);
222
268
 
223
269
  xmlReplaceNode(node, new_node);
270
+
271
+ // Appropriately link in namespaces
272
+ relink_namespace(new_node);
224
273
  return self ;
225
274
  }
226
275
 
@@ -246,7 +295,10 @@ static VALUE children(VALUE self)
246
295
  child = child->next;
247
296
  }
248
297
 
249
- return Nokogiri_wrap_xml_node_set(set);
298
+ VALUE node_set = Nokogiri_wrap_xml_node_set(set);
299
+ rb_iv_set(node_set, "@document", DOC_RUBY_OBJECT(node->doc));
300
+
301
+ return node_set;
250
302
  }
251
303
 
252
304
  /*
@@ -263,7 +315,7 @@ static VALUE child(VALUE self)
263
315
  child = node->children;
264
316
  if(!child) return Qnil;
265
317
 
266
- return Nokogiri_wrap_xml_node(child);
318
+ return Nokogiri_wrap_xml_node(Qnil, child);
267
319
  }
268
320
 
269
321
  /*
@@ -281,6 +333,22 @@ static VALUE key_eh(VALUE self, VALUE attribute)
281
333
  return Qfalse;
282
334
  }
283
335
 
336
+ /*
337
+ * call-seq:
338
+ * namespaced_key?(attribute, namespace)
339
+ *
340
+ * Returns true if +attribute+ is set with +namespace+
341
+ */
342
+ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
343
+ {
344
+ xmlNodePtr node;
345
+ Data_Get_Struct(self, xmlNode, node);
346
+ if(xmlHasNsProp(node, (xmlChar *)StringValuePtr(attribute),
347
+ Qnil == namespace ? NULL : (xmlChar *)StringValuePtr(namespace)))
348
+ return Qtrue;
349
+ return Qfalse;
350
+ }
351
+
284
352
  /*
285
353
  * call-seq:
286
354
  * []=(property, value)
@@ -323,6 +391,25 @@ static VALUE get(VALUE self, VALUE attribute)
323
391
  return rval ;
324
392
  }
325
393
 
394
+ /*
395
+ * call-seq:
396
+ * set_namespace(namespace)
397
+ *
398
+ * Set the namespace to +namespace+
399
+ */
400
+ static VALUE set_namespace(VALUE self, VALUE namespace)
401
+ {
402
+ xmlNodePtr node;
403
+ xmlNsPtr ns;
404
+
405
+ Data_Get_Struct(self, xmlNode, node);
406
+ Data_Get_Struct(namespace, xmlNs, ns);
407
+
408
+ xmlSetNs(node, ns);
409
+
410
+ return self;
411
+ }
412
+
326
413
  /*
327
414
  * call-seq:
328
415
  * attribute(name)
@@ -337,7 +424,25 @@ static VALUE attr(VALUE self, VALUE name)
337
424
  prop = xmlHasProp(node, (xmlChar *)StringValuePtr(name));
338
425
 
339
426
  if(! prop) return Qnil;
340
- return Nokogiri_wrap_xml_node((xmlNodePtr)prop);
427
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
428
+ }
429
+
430
+ /*
431
+ * call-seq:
432
+ * attribute_with_ns(name, namespace)
433
+ *
434
+ * Get the attribute node with +name+ and +namespace+
435
+ */
436
+ static VALUE attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
437
+ {
438
+ xmlNodePtr node;
439
+ xmlAttrPtr prop;
440
+ Data_Get_Struct(self, xmlNode, node);
441
+ prop = xmlHasNsProp(node, (xmlChar *)StringValuePtr(name),
442
+ Qnil == namespace ? NULL : (xmlChar *)StringValuePtr(namespace));
443
+
444
+ if(! prop) return Qnil;
445
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
341
446
  }
342
447
 
343
448
  /*
@@ -365,36 +470,44 @@ static VALUE attribute_nodes(VALUE self)
365
470
  * call-seq:
366
471
  * namespace()
367
472
  *
368
- * returns the namespace prefix for the node, if one exists.
473
+ * returns the Nokogiri::XML::Namespace for the node, if one exists.
369
474
  */
370
475
  static VALUE namespace(VALUE self)
371
476
  {
372
477
  xmlNodePtr node ;
373
478
  Data_Get_Struct(self, xmlNode, node);
374
- if (node->ns && node->ns->prefix) {
375
- return NOKOGIRI_STR_NEW2(node->ns->prefix, node->doc->encoding);
376
- }
479
+
480
+ if (node->ns)
481
+ return Nokogiri_wrap_xml_namespace(node->doc, node->ns);
482
+
377
483
  return Qnil ;
378
484
  }
379
485
 
380
486
  /*
381
487
  * call-seq:
382
- * namespaces()
488
+ * namespace_definitions()
383
489
  *
384
- * returns a hash containing the node's namespaces.
490
+ * returns a list of Namespace nodes defined on _self_
385
491
  */
386
- static VALUE namespaces(VALUE self)
492
+ static VALUE namespace_definitions(VALUE self)
387
493
  {
388
- /* this code in the mode of xmlHasProp() */
389
- xmlNodePtr node ;
390
- VALUE attr ;
494
+ /* this code in the mode of xmlHasProp() */
495
+ xmlNodePtr node ;
391
496
 
392
- attr = rb_hash_new() ;
393
- Data_Get_Struct(self, xmlNode, node);
497
+ Data_Get_Struct(self, xmlNode, node);
394
498
 
395
- Nokogiri_xml_node_namespaces(node, attr);
499
+ VALUE list = rb_ary_new();
396
500
 
397
- return attr ;
501
+ xmlNsPtr ns = node->nsDef;
502
+
503
+ if(!ns) return list;
504
+
505
+ while(NULL != ns) {
506
+ rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns));
507
+ ns = ns->next;
508
+ }
509
+
510
+ return list;
398
511
  }
399
512
 
400
513
  /*
@@ -469,7 +582,7 @@ static VALUE get_parent(VALUE self)
469
582
  parent = node->parent;
470
583
  if(!parent) return Qnil;
471
584
 
472
- return Nokogiri_wrap_xml_node(parent) ;
585
+ return Nokogiri_wrap_xml_node(Qnil, parent) ;
473
586
  }
474
587
 
475
588
  /*
@@ -547,12 +660,21 @@ static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
547
660
  *
548
661
  * Write this Node to +io+ with +encoding+ and +options+
549
662
  */
550
- static VALUE native_write_to(VALUE self, VALUE io, VALUE encoding, VALUE options)
551
- {
663
+ static VALUE native_write_to(
664
+ VALUE self,
665
+ VALUE io,
666
+ VALUE encoding,
667
+ VALUE indent_string,
668
+ VALUE options
669
+ ) {
552
670
  xmlNodePtr node;
553
671
 
554
672
  Data_Get_Struct(self, xmlNode, node);
555
673
 
674
+ xmlIndentTreeOutput = 1;
675
+
676
+ xmlTreeIndentString = StringValuePtr(indent_string);
677
+
556
678
  xmlSaveCtxtPtr savectx = xmlSaveToIO(
557
679
  (xmlOutputWriteCallback)io_write_callback,
558
680
  (xmlOutputCloseCallback)io_close_callback,
@@ -582,51 +704,50 @@ static VALUE line(VALUE self)
582
704
 
583
705
  /*
584
706
  * call-seq:
585
- * add_namespace(prefix, href)
707
+ * add_namespace_definition(prefix, href)
586
708
  *
587
- * Add a namespace with +prefix+ using +href+
709
+ * Adds a namespace definition with +prefix+ using +href+
588
710
  */
589
- static VALUE add_namespace(VALUE self, VALUE prefix, VALUE href)
711
+ static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
590
712
  {
591
713
  xmlNodePtr node;
592
714
  Data_Get_Struct(self, xmlNode, node);
593
715
 
716
+
594
717
  xmlNsPtr ns = xmlNewNs(
595
718
  node,
596
719
  (const xmlChar *)StringValuePtr(href),
597
- (const xmlChar *)StringValuePtr(prefix)
720
+ (const xmlChar *)(prefix == Qnil ? NULL : StringValuePtr(prefix))
598
721
  );
599
722
 
600
- if(NULL == ns) return self;
723
+ if(Qnil == prefix) xmlSetNs(node, ns);
601
724
 
602
- /*
603
- xmlNewNsProp(
604
- node,
605
- ns,
606
- (const xmlChar *)StringValuePtr(href),
607
- (const xmlChar *)StringValuePtr(prefix)
608
- );
609
- */
610
-
611
- return self;
725
+ return Nokogiri_wrap_xml_namespace(node->doc, ns);
612
726
  }
613
727
 
614
728
  /*
615
729
  * call-seq:
616
- * new(name)
730
+ * new(name, document)
617
731
  *
618
- * Create a new node with +name+
732
+ * Create a new node with +name+ sharing GC lifecycle with +document+
619
733
  */
620
- static VALUE new(VALUE klass, VALUE name, VALUE document)
734
+ static VALUE new(int argc, VALUE *argv, VALUE klass)
621
735
  {
622
736
  xmlDocPtr doc;
737
+ VALUE name;
738
+ VALUE document;
739
+ VALUE rest;
740
+
741
+ rb_scan_args(argc, argv, "2*", &name, &document, &rest);
623
742
 
624
743
  Data_Get_Struct(document, xmlDoc, doc);
625
744
 
626
745
  xmlNodePtr node = xmlNewNode(NULL, (xmlChar *)StringValuePtr(name));
627
746
  node->doc = doc->doc;
747
+ NOKOGIRI_ROOT_NODE(node);
628
748
 
629
- VALUE rb_node = Nokogiri_wrap_xml_node(node);
749
+ VALUE rb_node = Nokogiri_wrap_xml_node(klass, node);
750
+ rb_funcall2(rb_node, rb_intern("initialize"), argc, argv);
630
751
 
631
752
  if(rb_block_given_p()) rb_yield(rb_node);
632
753
 
@@ -655,11 +776,25 @@ static VALUE dump_html(VALUE self)
655
776
  return html ;
656
777
  }
657
778
 
658
- VALUE Nokogiri_wrap_xml_node(xmlNodePtr node)
779
+ /*
780
+ * call-seq:
781
+ * compare(other)
782
+ *
783
+ * Compare this Node to +other+ with respect to their Document
784
+ */
785
+ static VALUE compare(VALUE self, VALUE _other)
786
+ {
787
+ xmlNodePtr node, other;
788
+ Data_Get_Struct(self, xmlNode, node);
789
+ Data_Get_Struct(_other, xmlNode, other);
790
+
791
+ return INT2NUM(xmlXPathCmpNodes(other, node));
792
+ }
793
+
794
+ VALUE Nokogiri_wrap_xml_node(VALUE klass, xmlNodePtr node)
659
795
  {
660
796
  assert(node);
661
797
 
662
- VALUE index = INT2NUM((int)node);
663
798
  VALUE document = Qnil ;
664
799
  VALUE node_cache = Qnil ;
665
800
  VALUE rb_node = Qnil ;
@@ -669,64 +804,70 @@ VALUE Nokogiri_wrap_xml_node(xmlNodePtr node)
669
804
 
670
805
  if(NULL != node->_private) return (VALUE)node->_private;
671
806
 
672
- switch(node->type)
673
- {
674
- VALUE klass;
807
+ if(RTEST(klass))
808
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
675
809
 
810
+ if(!RTEST(klass)) switch(node->type)
811
+ {
676
812
  case XML_ELEMENT_NODE:
677
813
  klass = cNokogiriXmlElement;
678
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
814
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
679
815
  break;
680
816
  case XML_TEXT_NODE:
681
817
  klass = cNokogiriXmlText;
682
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
818
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
683
819
  break;
684
820
  case XML_ENTITY_REF_NODE:
685
821
  klass = cNokogiriXmlEntityReference;
686
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
822
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
687
823
  break;
688
824
  case XML_COMMENT_NODE:
689
825
  klass = cNokogiriXmlComment;
690
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
826
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
691
827
  break;
692
828
  case XML_DOCUMENT_FRAG_NODE:
693
829
  klass = cNokogiriXmlDocumentFragment;
694
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
830
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
695
831
  break;
696
832
  case XML_PI_NODE:
697
833
  klass = cNokogiriXmlProcessingInstruction;
698
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
834
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
699
835
  break;
700
836
  case XML_ATTRIBUTE_NODE:
701
837
  klass = cNokogiriXmlAttr;
702
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
838
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
703
839
  break;
704
840
  case XML_ENTITY_DECL:
705
- klass = rb_const_get(mNokogiriXml, rb_intern("EntityDeclaration"));
706
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
841
+ klass = cNokogiriXmlEntityDeclaration;
842
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
707
843
  break;
708
844
  case XML_CDATA_SECTION_NODE:
709
845
  klass = cNokogiriXmlCData;
710
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
846
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
711
847
  break;
712
848
  case XML_DTD_NODE:
713
849
  klass = rb_const_get(mNokogiriXml, rb_intern("DTD"));
714
- rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
850
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
715
851
  break;
716
852
  default:
717
- rb_node = Data_Wrap_Struct(cNokogiriXmlNode, 0, debug_node_dealloc, node) ;
853
+ rb_node = Data_Wrap_Struct(
854
+ cNokogiriXmlNode,
855
+ mark,
856
+ debug_node_dealloc,
857
+ node
858
+ );
718
859
  }
719
860
 
720
861
  node->_private = (void *)rb_node;
721
862
 
722
863
  if (DOC_RUBY_OBJECT_TEST(node->doc) && DOC_RUBY_OBJECT(node->doc)) {
723
864
  document = DOC_RUBY_OBJECT(node->doc);
724
- node_cache = rb_funcall(document, rb_intern("node_cache"), 0);
865
+ node_cache = rb_iv_get(document, "@node_cache");
725
866
  }
726
867
 
727
- if (node_cache != Qnil) rb_hash_aset(node_cache, index, rb_node);
728
- rb_iv_set(rb_node, "@document", document);
729
- rb_funcall(rb_node, rb_intern("decorate!"), 0);
868
+ rb_ary_push(node_cache, rb_node);
869
+ //rb_iv_set(rb_node, "@document", document);
870
+ rb_funcall(document, rb_intern("decorate"), 1, rb_node);
730
871
 
731
872
  return rb_node ;
732
873
  }
@@ -737,54 +878,14 @@ void Nokogiri_xml_node_properties(xmlNodePtr node, VALUE attr_list)
737
878
  xmlAttrPtr prop;
738
879
  prop = node->properties ;
739
880
  while (prop != NULL) {
740
- rb_ary_push(attr_list, Nokogiri_wrap_xml_node((xmlNodePtr)prop));
881
+ rb_ary_push(attr_list, Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop));
741
882
  prop = prop->next ;
742
883
  }
743
884
  }
744
885
 
745
-
746
- #define XMLNS_PREFIX "xmlns"
747
- #define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */
748
- #define XMLNS_BUFFER_LEN 128
749
- void Nokogiri_xml_node_namespaces(xmlNodePtr node, VALUE attr_hash)
750
- {
751
- xmlNsPtr ns;
752
- static char buffer[XMLNS_BUFFER_LEN] ;
753
- char *key ;
754
- size_t keylen ;
755
-
756
- if (node->type != XML_ELEMENT_NODE) return ;
757
-
758
- ns = node->nsDef;
759
- while (ns != NULL) {
760
-
761
- keylen = XMLNS_PREFIX_LEN + (ns->prefix ? (strlen((const char*)ns->prefix) + 1) : 0) ;
762
- if (keylen > XMLNS_BUFFER_LEN) {
763
- key = (char*)malloc(keylen) ;
764
- } else {
765
- key = buffer ;
766
- }
767
-
768
- if (ns->prefix) {
769
- sprintf(key, "%s:%s", XMLNS_PREFIX, ns->prefix);
770
- } else {
771
- sprintf(key, "%s", XMLNS_PREFIX);
772
- }
773
-
774
- rb_hash_aset(attr_hash,
775
- NOKOGIRI_STR_NEW2(key, node->doc->encoding),
776
- NOKOGIRI_STR_NEW2(ns->href, node->doc->encoding)
777
- );
778
- if (key != buffer) {
779
- free(key);
780
- }
781
- ns = ns->next ;
782
- }
783
- }
784
-
785
-
786
886
  VALUE cNokogiriXmlNode ;
787
887
  VALUE cNokogiriXmlElement ;
888
+ VALUE cNokogiriXmlEntityDeclaration ;
788
889
 
789
890
  void init_xml_node()
790
891
  {
@@ -795,11 +896,14 @@ void init_xml_node()
795
896
  cNokogiriXmlNode = klass;
796
897
 
797
898
  cNokogiriXmlElement = rb_define_class_under(xml, "Element", klass);
899
+ cNokogiriXmlEntityDeclaration =
900
+ rb_define_class_under(xml, "EntityDeclaration", klass);
798
901
 
799
- rb_define_singleton_method(klass, "new", new, 2);
902
+ rb_define_singleton_method(klass, "new", new, -1);
800
903
 
801
- rb_define_method(klass, "add_namespace", add_namespace, 2);
904
+ rb_define_method(klass, "add_namespace_definition", add_namespace_definition, 2);
802
905
  rb_define_method(klass, "node_name", get_name, 0);
906
+ rb_define_method(klass, "document", document, 0);
803
907
  rb_define_method(klass, "node_name=", set_name, 1);
804
908
  rb_define_method(klass, "add_child", add_child, 1);
805
909
  rb_define_method(klass, "parent", get_parent, 0);
@@ -811,12 +915,14 @@ void init_xml_node()
811
915
  rb_define_method(klass, "content", get_content, 0);
812
916
  rb_define_method(klass, "path", path, 0);
813
917
  rb_define_method(klass, "key?", key_eh, 1);
918
+ rb_define_method(klass, "namespaced_key?", namespaced_key_eh, 2);
814
919
  rb_define_method(klass, "blank?", blank_eh, 0);
815
920
  rb_define_method(klass, "[]=", set, 2);
816
921
  rb_define_method(klass, "attribute_nodes", attribute_nodes, 0);
817
922
  rb_define_method(klass, "attribute", attr, 1);
923
+ rb_define_method(klass, "attribute_with_ns", attribute_with_ns, 2);
818
924
  rb_define_method(klass, "namespace", namespace, 0);
819
- rb_define_method(klass, "namespaces", namespaces, 0);
925
+ rb_define_method(klass, "namespace_definitions", namespace_definitions, 0);
820
926
  rb_define_method(klass, "add_previous_sibling", add_previous_sibling, 1);
821
927
  rb_define_method(klass, "add_next_sibling", add_next_sibling, 1);
822
928
  rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
@@ -827,8 +933,10 @@ void init_xml_node()
827
933
  rb_define_method(klass, "line", line, 0);
828
934
 
829
935
  rb_define_private_method(klass, "dump_html", dump_html, 0);
830
- rb_define_private_method(klass, "native_write_to", native_write_to, 3);
936
+ rb_define_private_method(klass, "native_write_to", native_write_to, 4);
831
937
  rb_define_private_method(klass, "replace_with_node", replace, 1);
832
938
  rb_define_private_method(klass, "native_content=", set_content, 1);
833
939
  rb_define_private_method(klass, "get", get, 1);
940
+ rb_define_private_method(klass, "set_namespace", set_namespace, 1);
941
+ rb_define_private_method(klass, "compare", compare, 1);
834
942
  }