superfeedr-nokogiri 1.4.0.20091116183308

Sign up to get free protection for your applications and to get access to all the features.
Files changed (270) hide show
  1. data/.autotest +27 -0
  2. data/CHANGELOG.ja.rdoc +330 -0
  3. data/CHANGELOG.rdoc +314 -0
  4. data/Manifest.txt +269 -0
  5. data/README.ja.rdoc +105 -0
  6. data/README.rdoc +118 -0
  7. data/Rakefile +244 -0
  8. data/bin/nokogiri +49 -0
  9. data/ext/nokogiri/extconf.rb +145 -0
  10. data/ext/nokogiri/html_document.c +145 -0
  11. data/ext/nokogiri/html_document.h +10 -0
  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.c +32 -0
  15. data/ext/nokogiri/html_entity_lookup.h +8 -0
  16. data/ext/nokogiri/html_sax_parser_context.c +92 -0
  17. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  18. data/ext/nokogiri/nokogiri.c +89 -0
  19. data/ext/nokogiri/nokogiri.h +145 -0
  20. data/ext/nokogiri/xml_attr.c +92 -0
  21. data/ext/nokogiri/xml_attr.h +9 -0
  22. data/ext/nokogiri/xml_attribute_decl.c +67 -0
  23. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  24. data/ext/nokogiri/xml_cdata.c +54 -0
  25. data/ext/nokogiri/xml_cdata.h +9 -0
  26. data/ext/nokogiri/xml_comment.c +52 -0
  27. data/ext/nokogiri/xml_comment.h +9 -0
  28. data/ext/nokogiri/xml_document.c +388 -0
  29. data/ext/nokogiri/xml_document.h +24 -0
  30. data/ext/nokogiri/xml_document_fragment.c +46 -0
  31. data/ext/nokogiri/xml_document_fragment.h +10 -0
  32. data/ext/nokogiri/xml_dtd.c +192 -0
  33. data/ext/nokogiri/xml_dtd.h +10 -0
  34. data/ext/nokogiri/xml_element_content.c +123 -0
  35. data/ext/nokogiri/xml_element_content.h +10 -0
  36. data/ext/nokogiri/xml_element_decl.c +69 -0
  37. data/ext/nokogiri/xml_element_decl.h +9 -0
  38. data/ext/nokogiri/xml_entity_decl.c +97 -0
  39. data/ext/nokogiri/xml_entity_decl.h +10 -0
  40. data/ext/nokogiri/xml_entity_reference.c +50 -0
  41. data/ext/nokogiri/xml_entity_reference.h +9 -0
  42. data/ext/nokogiri/xml_io.c +31 -0
  43. data/ext/nokogiri/xml_io.h +11 -0
  44. data/ext/nokogiri/xml_namespace.c +74 -0
  45. data/ext/nokogiri/xml_namespace.h +12 -0
  46. data/ext/nokogiri/xml_node.c +1060 -0
  47. data/ext/nokogiri/xml_node.h +13 -0
  48. data/ext/nokogiri/xml_node_set.c +397 -0
  49. data/ext/nokogiri/xml_node_set.h +9 -0
  50. data/ext/nokogiri/xml_processing_instruction.c +54 -0
  51. data/ext/nokogiri/xml_processing_instruction.h +9 -0
  52. data/ext/nokogiri/xml_reader.c +593 -0
  53. data/ext/nokogiri/xml_reader.h +10 -0
  54. data/ext/nokogiri/xml_relax_ng.c +159 -0
  55. data/ext/nokogiri/xml_relax_ng.h +9 -0
  56. data/ext/nokogiri/xml_sax_parser.c +286 -0
  57. data/ext/nokogiri/xml_sax_parser.h +43 -0
  58. data/ext/nokogiri/xml_sax_parser_context.c +155 -0
  59. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  60. data/ext/nokogiri/xml_sax_push_parser.c +114 -0
  61. data/ext/nokogiri/xml_sax_push_parser.h +9 -0
  62. data/ext/nokogiri/xml_schema.c +156 -0
  63. data/ext/nokogiri/xml_schema.h +9 -0
  64. data/ext/nokogiri/xml_syntax_error.c +261 -0
  65. data/ext/nokogiri/xml_syntax_error.h +13 -0
  66. data/ext/nokogiri/xml_text.c +48 -0
  67. data/ext/nokogiri/xml_text.h +9 -0
  68. data/ext/nokogiri/xml_xpath.c +53 -0
  69. data/ext/nokogiri/xml_xpath.h +11 -0
  70. data/ext/nokogiri/xml_xpath_context.c +239 -0
  71. data/ext/nokogiri/xml_xpath_context.h +9 -0
  72. data/ext/nokogiri/xslt_stylesheet.c +131 -0
  73. data/ext/nokogiri/xslt_stylesheet.h +9 -0
  74. data/lib/nokogiri.rb +116 -0
  75. data/lib/nokogiri/css.rb +25 -0
  76. data/lib/nokogiri/css/generated_parser.rb +646 -0
  77. data/lib/nokogiri/css/generated_tokenizer.rb +142 -0
  78. data/lib/nokogiri/css/node.rb +99 -0
  79. data/lib/nokogiri/css/parser.rb +82 -0
  80. data/lib/nokogiri/css/parser.y +227 -0
  81. data/lib/nokogiri/css/syntax_error.rb +7 -0
  82. data/lib/nokogiri/css/tokenizer.rb +7 -0
  83. data/lib/nokogiri/css/tokenizer.rex +54 -0
  84. data/lib/nokogiri/css/xpath_visitor.rb +162 -0
  85. data/lib/nokogiri/decorators/slop.rb +33 -0
  86. data/lib/nokogiri/ffi/html/document.rb +28 -0
  87. data/lib/nokogiri/ffi/html/element_description.rb +85 -0
  88. data/lib/nokogiri/ffi/html/entity_lookup.rb +16 -0
  89. data/lib/nokogiri/ffi/html/sax/parser_context.rb +38 -0
  90. data/lib/nokogiri/ffi/io_callbacks.rb +42 -0
  91. data/lib/nokogiri/ffi/libxml.rb +356 -0
  92. data/lib/nokogiri/ffi/structs/common_node.rb +26 -0
  93. data/lib/nokogiri/ffi/structs/html_elem_desc.rb +24 -0
  94. data/lib/nokogiri/ffi/structs/html_entity_desc.rb +13 -0
  95. data/lib/nokogiri/ffi/structs/xml_alloc.rb +16 -0
  96. data/lib/nokogiri/ffi/structs/xml_attr.rb +19 -0
  97. data/lib/nokogiri/ffi/structs/xml_attribute.rb +27 -0
  98. data/lib/nokogiri/ffi/structs/xml_buffer.rb +16 -0
  99. data/lib/nokogiri/ffi/structs/xml_document.rb +108 -0
  100. data/lib/nokogiri/ffi/structs/xml_dtd.rb +28 -0
  101. data/lib/nokogiri/ffi/structs/xml_element.rb +26 -0
  102. data/lib/nokogiri/ffi/structs/xml_element_content.rb +17 -0
  103. data/lib/nokogiri/ffi/structs/xml_entity.rb +32 -0
  104. data/lib/nokogiri/ffi/structs/xml_enumeration.rb +12 -0
  105. data/lib/nokogiri/ffi/structs/xml_node.rb +28 -0
  106. data/lib/nokogiri/ffi/structs/xml_node_set.rb +53 -0
  107. data/lib/nokogiri/ffi/structs/xml_notation.rb +11 -0
  108. data/lib/nokogiri/ffi/structs/xml_ns.rb +15 -0
  109. data/lib/nokogiri/ffi/structs/xml_parser_context.rb +19 -0
  110. data/lib/nokogiri/ffi/structs/xml_relax_ng.rb +14 -0
  111. data/lib/nokogiri/ffi/structs/xml_sax_handler.rb +51 -0
  112. data/lib/nokogiri/ffi/structs/xml_sax_push_parser_context.rb +15 -0
  113. data/lib/nokogiri/ffi/structs/xml_schema.rb +13 -0
  114. data/lib/nokogiri/ffi/structs/xml_syntax_error.rb +31 -0
  115. data/lib/nokogiri/ffi/structs/xml_text_reader.rb +12 -0
  116. data/lib/nokogiri/ffi/structs/xml_xpath_context.rb +37 -0
  117. data/lib/nokogiri/ffi/structs/xml_xpath_object.rb +35 -0
  118. data/lib/nokogiri/ffi/structs/xml_xpath_parser_context.rb +20 -0
  119. data/lib/nokogiri/ffi/structs/xslt_stylesheet.rb +13 -0
  120. data/lib/nokogiri/ffi/xml/attr.rb +41 -0
  121. data/lib/nokogiri/ffi/xml/attribute_decl.rb +27 -0
  122. data/lib/nokogiri/ffi/xml/cdata.rb +19 -0
  123. data/lib/nokogiri/ffi/xml/comment.rb +18 -0
  124. data/lib/nokogiri/ffi/xml/document.rb +135 -0
  125. data/lib/nokogiri/ffi/xml/document_fragment.rb +21 -0
  126. data/lib/nokogiri/ffi/xml/dtd.rb +69 -0
  127. data/lib/nokogiri/ffi/xml/element_content.rb +43 -0
  128. data/lib/nokogiri/ffi/xml/element_decl.rb +19 -0
  129. data/lib/nokogiri/ffi/xml/entity_decl.rb +27 -0
  130. data/lib/nokogiri/ffi/xml/entity_reference.rb +19 -0
  131. data/lib/nokogiri/ffi/xml/namespace.rb +44 -0
  132. data/lib/nokogiri/ffi/xml/node.rb +444 -0
  133. data/lib/nokogiri/ffi/xml/node_set.rb +133 -0
  134. data/lib/nokogiri/ffi/xml/processing_instruction.rb +20 -0
  135. data/lib/nokogiri/ffi/xml/reader.rb +227 -0
  136. data/lib/nokogiri/ffi/xml/relax_ng.rb +85 -0
  137. data/lib/nokogiri/ffi/xml/sax/parser.rb +142 -0
  138. data/lib/nokogiri/ffi/xml/sax/parser_context.rb +67 -0
  139. data/lib/nokogiri/ffi/xml/sax/push_parser.rb +39 -0
  140. data/lib/nokogiri/ffi/xml/schema.rb +92 -0
  141. data/lib/nokogiri/ffi/xml/syntax_error.rb +91 -0
  142. data/lib/nokogiri/ffi/xml/text.rb +18 -0
  143. data/lib/nokogiri/ffi/xml/xpath.rb +19 -0
  144. data/lib/nokogiri/ffi/xml/xpath_context.rb +135 -0
  145. data/lib/nokogiri/ffi/xslt/stylesheet.rb +47 -0
  146. data/lib/nokogiri/html.rb +35 -0
  147. data/lib/nokogiri/html/builder.rb +35 -0
  148. data/lib/nokogiri/html/document.rb +88 -0
  149. data/lib/nokogiri/html/document_fragment.rb +15 -0
  150. data/lib/nokogiri/html/element_description.rb +23 -0
  151. data/lib/nokogiri/html/entity_lookup.rb +13 -0
  152. data/lib/nokogiri/html/sax/parser.rb +48 -0
  153. data/lib/nokogiri/html/sax/parser_context.rb +16 -0
  154. data/lib/nokogiri/syntax_error.rb +4 -0
  155. data/lib/nokogiri/version.rb +33 -0
  156. data/lib/nokogiri/version_warning.rb +11 -0
  157. data/lib/nokogiri/xml.rb +67 -0
  158. data/lib/nokogiri/xml/attr.rb +14 -0
  159. data/lib/nokogiri/xml/attribute_decl.rb +18 -0
  160. data/lib/nokogiri/xml/builder.rb +405 -0
  161. data/lib/nokogiri/xml/cdata.rb +11 -0
  162. data/lib/nokogiri/xml/character_data.rb +7 -0
  163. data/lib/nokogiri/xml/document.rb +131 -0
  164. data/lib/nokogiri/xml/document_fragment.rb +69 -0
  165. data/lib/nokogiri/xml/dtd.rb +11 -0
  166. data/lib/nokogiri/xml/element_content.rb +36 -0
  167. data/lib/nokogiri/xml/element_decl.rb +13 -0
  168. data/lib/nokogiri/xml/entity_decl.rb +15 -0
  169. data/lib/nokogiri/xml/fragment_handler.rb +71 -0
  170. data/lib/nokogiri/xml/namespace.rb +13 -0
  171. data/lib/nokogiri/xml/node.rb +665 -0
  172. data/lib/nokogiri/xml/node/save_options.rb +42 -0
  173. data/lib/nokogiri/xml/node_set.rb +307 -0
  174. data/lib/nokogiri/xml/notation.rb +6 -0
  175. data/lib/nokogiri/xml/parse_options.rb +85 -0
  176. data/lib/nokogiri/xml/pp.rb +2 -0
  177. data/lib/nokogiri/xml/pp/character_data.rb +18 -0
  178. data/lib/nokogiri/xml/pp/node.rb +56 -0
  179. data/lib/nokogiri/xml/processing_instruction.rb +8 -0
  180. data/lib/nokogiri/xml/reader.rb +74 -0
  181. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  182. data/lib/nokogiri/xml/sax.rb +4 -0
  183. data/lib/nokogiri/xml/sax/document.rb +160 -0
  184. data/lib/nokogiri/xml/sax/parser.rb +115 -0
  185. data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
  186. data/lib/nokogiri/xml/sax/push_parser.rb +60 -0
  187. data/lib/nokogiri/xml/schema.rb +61 -0
  188. data/lib/nokogiri/xml/syntax_error.rb +38 -0
  189. data/lib/nokogiri/xml/xpath.rb +10 -0
  190. data/lib/nokogiri/xml/xpath/syntax_error.rb +8 -0
  191. data/lib/nokogiri/xml/xpath_context.rb +16 -0
  192. data/lib/nokogiri/xslt.rb +48 -0
  193. data/lib/nokogiri/xslt/stylesheet.rb +25 -0
  194. data/lib/xsd/xmlparser/nokogiri.rb +71 -0
  195. data/tasks/test.rb +100 -0
  196. data/test/css/test_nthiness.rb +159 -0
  197. data/test/css/test_parser.rb +277 -0
  198. data/test/css/test_tokenizer.rb +183 -0
  199. data/test/css/test_xpath_visitor.rb +76 -0
  200. data/test/ffi/test_document.rb +35 -0
  201. data/test/files/2ch.html +108 -0
  202. data/test/files/address_book.rlx +12 -0
  203. data/test/files/address_book.xml +10 -0
  204. data/test/files/bar/bar.xsd +4 -0
  205. data/test/files/dont_hurt_em_why.xml +422 -0
  206. data/test/files/exslt.xml +8 -0
  207. data/test/files/exslt.xslt +35 -0
  208. data/test/files/foo/foo.xsd +4 -0
  209. data/test/files/po.xml +32 -0
  210. data/test/files/po.xsd +66 -0
  211. data/test/files/shift_jis.html +10 -0
  212. data/test/files/shift_jis.xml +5 -0
  213. data/test/files/snuggles.xml +3 -0
  214. data/test/files/staff.dtd +10 -0
  215. data/test/files/staff.xml +59 -0
  216. data/test/files/staff.xslt +32 -0
  217. data/test/files/tlm.html +850 -0
  218. data/test/files/valid_bar.xml +2 -0
  219. data/test/helper.rb +136 -0
  220. data/test/html/sax/test_parser.rb +64 -0
  221. data/test/html/sax/test_parser_context.rb +48 -0
  222. data/test/html/test_builder.rb +164 -0
  223. data/test/html/test_document.rb +390 -0
  224. data/test/html/test_document_encoding.rb +77 -0
  225. data/test/html/test_document_fragment.rb +132 -0
  226. data/test/html/test_element_description.rb +94 -0
  227. data/test/html/test_named_characters.rb +14 -0
  228. data/test/html/test_node.rb +228 -0
  229. data/test/html/test_node_encoding.rb +27 -0
  230. data/test/test_convert_xpath.rb +135 -0
  231. data/test/test_css_cache.rb +45 -0
  232. data/test/test_gc.rb +15 -0
  233. data/test/test_memory_leak.rb +77 -0
  234. data/test/test_nokogiri.rb +134 -0
  235. data/test/test_reader.rb +358 -0
  236. data/test/test_xslt_transforms.rb +131 -0
  237. data/test/xml/node/test_save_options.rb +20 -0
  238. data/test/xml/node/test_subclass.rb +44 -0
  239. data/test/xml/sax/test_parser.rb +307 -0
  240. data/test/xml/sax/test_parser_context.rb +56 -0
  241. data/test/xml/sax/test_push_parser.rb +131 -0
  242. data/test/xml/test_attr.rb +38 -0
  243. data/test/xml/test_attribute_decl.rb +82 -0
  244. data/test/xml/test_builder.rb +167 -0
  245. data/test/xml/test_cdata.rb +38 -0
  246. data/test/xml/test_comment.rb +29 -0
  247. data/test/xml/test_document.rb +607 -0
  248. data/test/xml/test_document_encoding.rb +26 -0
  249. data/test/xml/test_document_fragment.rb +138 -0
  250. data/test/xml/test_dtd.rb +82 -0
  251. data/test/xml/test_dtd_encoding.rb +33 -0
  252. data/test/xml/test_element_content.rb +56 -0
  253. data/test/xml/test_element_decl.rb +73 -0
  254. data/test/xml/test_entity_decl.rb +83 -0
  255. data/test/xml/test_entity_reference.rb +21 -0
  256. data/test/xml/test_namespace.rb +68 -0
  257. data/test/xml/test_node.rb +889 -0
  258. data/test/xml/test_node_attributes.rb +34 -0
  259. data/test/xml/test_node_encoding.rb +107 -0
  260. data/test/xml/test_node_set.rb +531 -0
  261. data/test/xml/test_parse_options.rb +52 -0
  262. data/test/xml/test_processing_instruction.rb +30 -0
  263. data/test/xml/test_reader_encoding.rb +126 -0
  264. data/test/xml/test_relax_ng.rb +60 -0
  265. data/test/xml/test_schema.rb +89 -0
  266. data/test/xml/test_syntax_error.rb +27 -0
  267. data/test/xml/test_text.rb +30 -0
  268. data/test/xml/test_unparented_node.rb +381 -0
  269. data/test/xml/test_xpath.rb +106 -0
  270. metadata +430 -0
@@ -0,0 +1,10 @@
1
+ #ifndef NOKOGIRI_XML_ENTITY_DECL
2
+ #define NOKOGIRI_XML_ENTITY_DECL
3
+
4
+ #include <nokogiri.h>
5
+
6
+ void init_xml_entity_decl();
7
+
8
+ extern VALUE cNokogiriXmlEntityDecl;
9
+ #endif
10
+
@@ -0,0 +1,50 @@
1
+ #include <xml_entity_reference.h>
2
+
3
+ /*
4
+ * call-seq:
5
+ * new(document, content)
6
+ *
7
+ * Create a new EntityReference element on the +document+ with +name+
8
+ */
9
+ static VALUE new(int argc, VALUE *argv, VALUE klass)
10
+ {
11
+ xmlDocPtr 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);
19
+
20
+ xmlNodePtr node = xmlNewReference(
21
+ xml_doc,
22
+ (const xmlChar *)StringValuePtr(name)
23
+ );
24
+
25
+ NOKOGIRI_ROOT_NODE(node);
26
+
27
+ VALUE rb_node = Nokogiri_wrap_xml_node(klass, node);
28
+ rb_obj_call_init(rb_node, argc, argv);
29
+
30
+ if(rb_block_given_p()) rb_yield(rb_node);
31
+
32
+ return rb_node;
33
+ }
34
+
35
+ VALUE cNokogiriXmlEntityReference;
36
+ void init_xml_entity_reference()
37
+ {
38
+ VALUE nokogiri = rb_define_module("Nokogiri");
39
+ VALUE xml = rb_define_module_under(nokogiri, "XML");
40
+ VALUE node = rb_define_class_under(xml, "Node", rb_cObject);
41
+
42
+ /*
43
+ * EntityReference represents an EntityReference node in an xml document.
44
+ */
45
+ VALUE klass = rb_define_class_under(xml, "EntityReference", node);
46
+
47
+ cNokogiriXmlEntityReference = klass;
48
+
49
+ rb_define_singleton_method(klass, "new", new, -1);
50
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef NOKOGIRI_XML_ENTITY_REFERENCE
2
+ #define NOKOGIRI_XML_ENTITY_REFERENCE
3
+
4
+ #include <nokogiri.h>
5
+
6
+ void init_xml_entity_reference();
7
+
8
+ extern VALUE cNokogiriXmlEntityReference;
9
+ #endif
@@ -0,0 +1,31 @@
1
+ #include <xml_io.h>
2
+
3
+ static ID id_read, id_write;
4
+
5
+ int io_read_callback(void * ctx, char * buffer, int len) {
6
+ VALUE io = (VALUE)ctx;
7
+ VALUE string = rb_funcall(io, id_read, 1, INT2NUM(len));
8
+
9
+ if(NIL_P(string)) return 0;
10
+
11
+ memcpy(buffer, StringValuePtr(string), (unsigned int)RSTRING_LEN(string));
12
+
13
+ return RSTRING_LEN(string);
14
+ }
15
+
16
+ int io_write_callback(void * ctx, char * buffer, int len) {
17
+ VALUE io = (VALUE)ctx;
18
+ VALUE string = rb_str_new(buffer, len);
19
+
20
+ rb_funcall(io, id_write, 1, string);
21
+ return len;
22
+ }
23
+
24
+ int io_close_callback(void * ctx) {
25
+ return 0;
26
+ }
27
+
28
+ void init_nokogiri_io() {
29
+ id_read = rb_intern("read");
30
+ id_write = rb_intern("write");
31
+ }
@@ -0,0 +1,11 @@
1
+ #ifndef NOKOGIRI_XML_IO
2
+ #define NOKOGIRI_XML_IO
3
+
4
+ #include <nokogiri.h>
5
+
6
+ int io_read_callback(void * ctx, char * buffer, int len);
7
+ int io_write_callback(void * ctx, char * buffer, int len);
8
+ int io_close_callback(void * ctx);
9
+ void init_nokogiri_io();
10
+
11
+ #endif
@@ -0,0 +1,74 @@
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);
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);
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
+ VALUE document = DOC_RUBY_OBJECT(doc);
53
+
54
+ VALUE node_cache = rb_iv_get(document, "@node_cache");
55
+ rb_ary_push(node_cache, ns);
56
+
57
+ rb_iv_set(ns, "@document", DOC_RUBY_OBJECT(doc));
58
+
59
+ node->_private = (void *)ns;
60
+
61
+ return ns;
62
+ }
63
+
64
+ void init_xml_namespace()
65
+ {
66
+ VALUE nokogiri = rb_define_module("Nokogiri");
67
+ VALUE xml = rb_define_module_under(nokogiri, "XML");
68
+ VALUE klass = rb_define_class_under(xml, "Namespace", rb_cObject);
69
+
70
+ cNokogiriXmlNamespace = klass;
71
+
72
+ rb_define_method(klass, "prefix", prefix, 0);
73
+ rb_define_method(klass, "href", href, 0);
74
+ }
@@ -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
@@ -0,0 +1,1060 @@
1
+ #include <xml_node.h>
2
+
3
+ static ID decorate, decorate_bang;
4
+
5
+ #ifdef DEBUG
6
+ static void debug_node_dealloc(xmlNodePtr x)
7
+ {
8
+ NOKOGIRI_DEBUG_START(x)
9
+ NOKOGIRI_DEBUG_END(x)
10
+ }
11
+ #else
12
+ # define debug_node_dealloc 0
13
+ #endif
14
+
15
+ static void mark(xmlNodePtr node)
16
+ {
17
+ // it's OK if the document isn't fully realized (as in XML::Reader).
18
+ // see http://github.com/tenderlove/nokogiri/issues/closed/#issue/95
19
+ if (DOC_RUBY_OBJECT_TEST(node->doc) && DOC_RUBY_OBJECT(node->doc))
20
+ rb_gc_mark(DOC_RUBY_OBJECT(node->doc));
21
+ }
22
+
23
+ /* :nodoc: */
24
+ typedef xmlNodePtr (*node_other_func)(xmlNodePtr, xmlNodePtr);
25
+
26
+ /* :nodoc: */
27
+ static void relink_namespace(xmlNodePtr reparented)
28
+ {
29
+ // Avoid segv when relinking against unlinked nodes.
30
+ if(!reparented->parent) return;
31
+
32
+ // Make sure that our reparented node has the correct namespaces
33
+ if(!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent)
34
+ xmlSetNs(reparented, reparented->parent->ns);
35
+
36
+ // Search our parents for an existing definition
37
+ if(reparented->nsDef) {
38
+ xmlNsPtr ns = xmlSearchNsByHref(
39
+ reparented->doc,
40
+ reparented->parent,
41
+ reparented->nsDef->href
42
+ );
43
+ if(ns && ns != reparented->nsDef) reparented->nsDef = NULL;
44
+ }
45
+
46
+ // Only walk all children if there actually is a namespace we need to
47
+ // reparent.
48
+ if(NULL == reparented->ns) return;
49
+
50
+ // When a node gets reparented, walk it's children to make sure that
51
+ // their namespaces are reparented as well.
52
+ xmlNodePtr child = reparented->children;
53
+ while(NULL != child) {
54
+ relink_namespace(child);
55
+ child = child->next;
56
+ }
57
+ }
58
+
59
+ /* :nodoc: */
60
+ static VALUE reparent_node_with(VALUE node_obj, VALUE other_obj, node_other_func func)
61
+ {
62
+ VALUE reparented_obj ;
63
+ xmlNodePtr node, other, reparented ;
64
+
65
+ if(!rb_obj_is_kind_of(node_obj, cNokogiriXmlNode))
66
+ rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
67
+
68
+ Data_Get_Struct(node_obj, xmlNode, node);
69
+ Data_Get_Struct(other_obj, xmlNode, other);
70
+
71
+ if(XML_DOCUMENT_NODE == node->type || XML_HTML_DOCUMENT_NODE == node->type)
72
+ rb_raise(rb_eArgError, "cannot reparent a document node");
73
+
74
+ // If a document fragment is added, we need to reparent all of it's children
75
+ if(node->type == XML_DOCUMENT_FRAG_NODE)
76
+ {
77
+ xmlNodePtr child = node->children;
78
+ while(NULL != child) {
79
+ reparent_node_with(Nokogiri_wrap_xml_node((VALUE)NULL, child), other_obj, func);
80
+ child = child->next;
81
+ }
82
+ return node_obj;
83
+ }
84
+
85
+ if(node->type == XML_TEXT_NODE) {
86
+ NOKOGIRI_ROOT_NODE(node);
87
+ node = xmlDocCopyNode(node, other->doc, 1);
88
+ }
89
+
90
+ if (node->doc == other->doc) {
91
+ xmlUnlinkNode(node) ;
92
+
93
+ // TODO: I really want to remove this. We shouldn't support 2.6.16 anymore
94
+ if ( node->type == XML_TEXT_NODE
95
+ && other->type == XML_TEXT_NODE
96
+ && is_2_6_16() ) {
97
+
98
+ // we'd rather leak than segfault.
99
+ other->content = xmlStrdup(other->content);
100
+
101
+ }
102
+
103
+ if(!(reparented = (*func)(other, node))) {
104
+ rb_raise(rb_eRuntimeError, "Could not reparent node (1)");
105
+ }
106
+ } else {
107
+ xmlNodePtr duped_node ;
108
+ // recursively copy to the new document
109
+ if (!(duped_node = xmlDocCopyNode(node, other->doc, 1))) {
110
+ rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
111
+ }
112
+ if(!(reparented = (*func)(other, duped_node))) {
113
+ rb_raise(rb_eRuntimeError, "Could not reparent node (2)");
114
+ }
115
+ xmlUnlinkNode(node);
116
+ NOKOGIRI_ROOT_NODE(node);
117
+ }
118
+
119
+ // the child was a text node that was coalesced. we need to have the object
120
+ // point at SOMETHING, or we'll totally bomb out.
121
+ if (reparented != node) {
122
+ DATA_PTR(node_obj) = reparented ;
123
+ }
124
+
125
+ // Appropriately link in namespaces
126
+ relink_namespace(reparented);
127
+
128
+ reparented_obj = Nokogiri_wrap_xml_node(Qnil, reparented);
129
+
130
+ rb_funcall(reparented_obj, decorate_bang, 0);
131
+
132
+ return reparented_obj ;
133
+ }
134
+
135
+
136
+ /*
137
+ * call-seq:
138
+ * document
139
+ *
140
+ * Get the document for this Node
141
+ */
142
+ static VALUE document(VALUE self)
143
+ {
144
+ xmlNodePtr node;
145
+ Data_Get_Struct(self, xmlNode, node);
146
+ return DOC_RUBY_OBJECT(node->doc);
147
+ }
148
+
149
+ /*
150
+ * call-seq:
151
+ * pointer_id
152
+ *
153
+ * Get the internal pointer number
154
+ */
155
+ static VALUE pointer_id(VALUE self)
156
+ {
157
+ xmlNodePtr node;
158
+ Data_Get_Struct(self, xmlNode, node);
159
+
160
+ return INT2NUM((long)(node));
161
+ }
162
+
163
+ /*
164
+ * call-seq:
165
+ * encode_special_chars(string)
166
+ *
167
+ * Encode any special characters in +string+
168
+ */
169
+ static VALUE encode_special_chars(VALUE self, VALUE string)
170
+ {
171
+ xmlNodePtr node;
172
+ Data_Get_Struct(self, xmlNode, node);
173
+ xmlChar * encoded = xmlEncodeSpecialChars(
174
+ node->doc,
175
+ (const xmlChar *)StringValuePtr(string)
176
+ );
177
+
178
+ VALUE encoded_str = NOKOGIRI_STR_NEW2(encoded);
179
+ xmlFree(encoded);
180
+
181
+ return encoded_str;
182
+ }
183
+
184
+ /*
185
+ * call-seq:
186
+ * create_internal_subset(name, external_id, system_id)
187
+ *
188
+ * Create an internal subset
189
+ */
190
+ static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
191
+ {
192
+ xmlNodePtr node;
193
+ xmlDocPtr doc;
194
+ Data_Get_Struct(self, xmlNode, node);
195
+
196
+ doc = node->doc;
197
+
198
+ if(xmlGetIntSubset(doc))
199
+ rb_raise(rb_eRuntimeError, "Document already has an internal subset");
200
+
201
+ xmlDtdPtr dtd = xmlCreateIntSubset(
202
+ doc,
203
+ NIL_P(name) ? NULL : (const xmlChar *)StringValuePtr(name),
204
+ NIL_P(external_id) ? NULL : (const xmlChar *)StringValuePtr(external_id),
205
+ NIL_P(system_id) ? NULL : (const xmlChar *)StringValuePtr(system_id)
206
+ );
207
+
208
+ if(!dtd) return Qnil;
209
+
210
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
211
+ }
212
+
213
+ /*
214
+ * call-seq:
215
+ * create_external_subset(name, external_id, system_id)
216
+ *
217
+ * Create an external subset
218
+ */
219
+ static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
220
+ {
221
+ xmlNodePtr node;
222
+ xmlDocPtr doc;
223
+ Data_Get_Struct(self, xmlNode, node);
224
+
225
+ doc = node->doc;
226
+
227
+ if(doc->extSubset)
228
+ rb_raise(rb_eRuntimeError, "Document already has an external subset");
229
+
230
+ xmlDtdPtr dtd = xmlNewDtd(
231
+ doc,
232
+ NIL_P(name) ? NULL : (const xmlChar *)StringValuePtr(name),
233
+ NIL_P(external_id) ? NULL : (const xmlChar *)StringValuePtr(external_id),
234
+ NIL_P(system_id) ? NULL : (const xmlChar *)StringValuePtr(system_id)
235
+ );
236
+
237
+ if(!dtd) return Qnil;
238
+
239
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
240
+ }
241
+
242
+ /*
243
+ * call-seq:
244
+ * external_subset
245
+ *
246
+ * Get the external subset
247
+ */
248
+ static VALUE external_subset(VALUE self)
249
+ {
250
+ xmlNodePtr node;
251
+ xmlDocPtr doc;
252
+ Data_Get_Struct(self, xmlNode, node);
253
+
254
+ if(!node->doc) return Qnil;
255
+
256
+ doc = node->doc;
257
+ xmlDtdPtr dtd = doc->extSubset;
258
+
259
+ if(!dtd) return Qnil;
260
+
261
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
262
+ }
263
+
264
+ /*
265
+ * call-seq:
266
+ * internal_subset
267
+ *
268
+ * Get the internal subset
269
+ */
270
+ static VALUE internal_subset(VALUE self)
271
+ {
272
+ xmlNodePtr node;
273
+ xmlDocPtr doc;
274
+ Data_Get_Struct(self, xmlNode, node);
275
+
276
+ if(!node->doc) return Qnil;
277
+
278
+ doc = node->doc;
279
+ xmlDtdPtr dtd = xmlGetIntSubset(doc);
280
+
281
+ if(!dtd) return Qnil;
282
+
283
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
284
+ }
285
+
286
+ /*
287
+ * call-seq:
288
+ * dup
289
+ *
290
+ * Copy this node. An optional depth may be passed in, but it defaults
291
+ * to a deep copy. 0 is a shallow copy, 1 is a deep copy.
292
+ */
293
+ static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
294
+ {
295
+ VALUE level;
296
+
297
+ if(rb_scan_args(argc, argv, "01", &level) == 0)
298
+ level = INT2NUM((long)1);
299
+
300
+ xmlNodePtr node, dup;
301
+ Data_Get_Struct(self, xmlNode, node);
302
+
303
+ dup = xmlDocCopyNode(node, node->doc, (int)NUM2INT(level));
304
+ if(dup == NULL) return Qnil;
305
+
306
+ return Nokogiri_wrap_xml_node(rb_obj_class(self), dup);
307
+ }
308
+
309
+ /*
310
+ * call-seq:
311
+ * unlink
312
+ *
313
+ * Unlink this node from its current context.
314
+ */
315
+ static VALUE unlink_node(VALUE self)
316
+ {
317
+ xmlNodePtr node;
318
+ Data_Get_Struct(self, xmlNode, node);
319
+ xmlUnlinkNode(node);
320
+ NOKOGIRI_ROOT_NODE(node);
321
+ return self;
322
+ }
323
+
324
+ /*
325
+ * call-seq:
326
+ * blank?
327
+ *
328
+ * Is this node blank?
329
+ */
330
+ static VALUE blank_eh(VALUE self)
331
+ {
332
+ xmlNodePtr node;
333
+ Data_Get_Struct(self, xmlNode, node);
334
+ if(1 == xmlIsBlankNode(node))
335
+ return Qtrue;
336
+ return Qfalse;
337
+ }
338
+
339
+ /*
340
+ * call-seq:
341
+ * next_sibling
342
+ *
343
+ * Returns the next sibling node
344
+ */
345
+ static VALUE next_sibling(VALUE self)
346
+ {
347
+ xmlNodePtr node, sibling;
348
+ Data_Get_Struct(self, xmlNode, node);
349
+
350
+ sibling = node->next;
351
+ if(!sibling) return Qnil;
352
+
353
+ return Nokogiri_wrap_xml_node(Qnil, sibling) ;
354
+ }
355
+
356
+ /*
357
+ * call-seq:
358
+ * previous_sibling
359
+ *
360
+ * Returns the previous sibling node
361
+ */
362
+ static VALUE previous_sibling(VALUE self)
363
+ {
364
+ xmlNodePtr node, sibling;
365
+ Data_Get_Struct(self, xmlNode, node);
366
+
367
+ sibling = node->prev;
368
+ if(!sibling) return Qnil;
369
+
370
+ return Nokogiri_wrap_xml_node(Qnil, sibling);
371
+ }
372
+
373
+ /* :nodoc: */
374
+ static VALUE replace(VALUE self, VALUE _new_node)
375
+ {
376
+ xmlNodePtr node, new_node;
377
+ Data_Get_Struct(self, xmlNode, node);
378
+ Data_Get_Struct(_new_node, xmlNode, new_node);
379
+
380
+ xmlReplaceNode(node, new_node);
381
+
382
+ // Appropriately link in namespaces
383
+ relink_namespace(new_node);
384
+ return self ;
385
+ }
386
+
387
+ /*
388
+ * call-seq:
389
+ * children
390
+ *
391
+ * Get the list of children for this node as a NodeSet
392
+ */
393
+ static VALUE children(VALUE self)
394
+ {
395
+ xmlNodePtr node;
396
+ Data_Get_Struct(self, xmlNode, node);
397
+
398
+ xmlNodePtr child = node->children;
399
+ xmlNodeSetPtr set = xmlXPathNodeSetCreate(child);
400
+
401
+ if(!child) return Nokogiri_wrap_xml_node_set(set);
402
+
403
+ child = child->next;
404
+ while(NULL != child) {
405
+ xmlXPathNodeSetAdd(set, child);
406
+ child = child->next;
407
+ }
408
+
409
+ VALUE node_set = Nokogiri_wrap_xml_node_set(set);
410
+ rb_iv_set(node_set, "@document", DOC_RUBY_OBJECT(node->doc));
411
+
412
+ return node_set;
413
+ }
414
+
415
+ /*
416
+ * call-seq:
417
+ * child
418
+ *
419
+ * Returns the child node
420
+ */
421
+ static VALUE child(VALUE self)
422
+ {
423
+ xmlNodePtr node, child;
424
+ Data_Get_Struct(self, xmlNode, node);
425
+
426
+ child = node->children;
427
+ if(!child) return Qnil;
428
+
429
+ return Nokogiri_wrap_xml_node(Qnil, child);
430
+ }
431
+
432
+ /*
433
+ * call-seq:
434
+ * key?(attribute)
435
+ *
436
+ * Returns true if +attribute+ is set
437
+ */
438
+ static VALUE key_eh(VALUE self, VALUE attribute)
439
+ {
440
+ xmlNodePtr node;
441
+ Data_Get_Struct(self, xmlNode, node);
442
+ if(xmlHasProp(node, (xmlChar *)StringValuePtr(attribute)))
443
+ return Qtrue;
444
+ return Qfalse;
445
+ }
446
+
447
+ /*
448
+ * call-seq:
449
+ * namespaced_key?(attribute, namespace)
450
+ *
451
+ * Returns true if +attribute+ is set with +namespace+
452
+ */
453
+ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
454
+ {
455
+ xmlNodePtr node;
456
+ Data_Get_Struct(self, xmlNode, node);
457
+ if(xmlHasNsProp(node, (xmlChar *)StringValuePtr(attribute),
458
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValuePtr(namespace)))
459
+ return Qtrue;
460
+ return Qfalse;
461
+ }
462
+
463
+ /*
464
+ * call-seq:
465
+ * []=(property, value)
466
+ *
467
+ * Set the +property+ to +value+
468
+ */
469
+ static VALUE set(VALUE self, VALUE property, VALUE value)
470
+ {
471
+ xmlNodePtr node;
472
+ Data_Get_Struct(self, xmlNode, node);
473
+
474
+ xmlSetProp(node, (xmlChar *)StringValuePtr(property),
475
+ (xmlChar *)StringValuePtr(value));
476
+
477
+ return value;
478
+ }
479
+
480
+ /*
481
+ * call-seq:
482
+ * get(attribute)
483
+ *
484
+ * Get the value for +attribute+
485
+ */
486
+ static VALUE get(VALUE self, VALUE attribute)
487
+ {
488
+ xmlNodePtr node;
489
+ xmlChar* propstr ;
490
+ VALUE rval ;
491
+ Data_Get_Struct(self, xmlNode, node);
492
+
493
+ if(NIL_P(attribute)) return Qnil;
494
+
495
+ propstr = xmlGetProp(node, (xmlChar *)StringValuePtr(attribute));
496
+
497
+ if(!propstr) return Qnil;
498
+
499
+ rval = NOKOGIRI_STR_NEW2(propstr);
500
+
501
+ xmlFree(propstr);
502
+ return rval ;
503
+ }
504
+
505
+ /*
506
+ * call-seq:
507
+ * set_namespace(namespace)
508
+ *
509
+ * Set the namespace to +namespace+
510
+ */
511
+ static VALUE set_namespace(VALUE self, VALUE namespace)
512
+ {
513
+ xmlNodePtr node;
514
+ xmlNsPtr ns;
515
+
516
+ Data_Get_Struct(self, xmlNode, node);
517
+ Data_Get_Struct(namespace, xmlNs, ns);
518
+
519
+ xmlSetNs(node, ns);
520
+
521
+ return self;
522
+ }
523
+
524
+ /*
525
+ * call-seq:
526
+ * attribute(name)
527
+ *
528
+ * Get the attribute node with +name+
529
+ */
530
+ static VALUE attr(VALUE self, VALUE name)
531
+ {
532
+ xmlNodePtr node;
533
+ xmlAttrPtr prop;
534
+ Data_Get_Struct(self, xmlNode, node);
535
+ prop = xmlHasProp(node, (xmlChar *)StringValuePtr(name));
536
+
537
+ if(! prop) return Qnil;
538
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
539
+ }
540
+
541
+ /*
542
+ * call-seq:
543
+ * attribute_with_ns(name, namespace)
544
+ *
545
+ * Get the attribute node with +name+ and +namespace+
546
+ */
547
+ static VALUE attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
548
+ {
549
+ xmlNodePtr node;
550
+ xmlAttrPtr prop;
551
+ Data_Get_Struct(self, xmlNode, node);
552
+ prop = xmlHasNsProp(node, (xmlChar *)StringValuePtr(name),
553
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValuePtr(namespace));
554
+
555
+ if(! prop) return Qnil;
556
+ return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
557
+ }
558
+
559
+ /*
560
+ * call-seq:
561
+ * attribute_nodes()
562
+ *
563
+ * returns a list containing the Node attributes.
564
+ */
565
+ static VALUE attribute_nodes(VALUE self)
566
+ {
567
+ /* this code in the mode of xmlHasProp() */
568
+ xmlNodePtr node;
569
+
570
+ Data_Get_Struct(self, xmlNode, node);
571
+
572
+ VALUE attr = rb_ary_new();
573
+ Nokogiri_xml_node_properties(node, attr);
574
+
575
+ return attr ;
576
+ }
577
+
578
+
579
+ /*
580
+ * call-seq:
581
+ * namespace()
582
+ *
583
+ * returns the Nokogiri::XML::Namespace for the node, if one exists.
584
+ */
585
+ static VALUE namespace(VALUE self)
586
+ {
587
+ xmlNodePtr node ;
588
+ Data_Get_Struct(self, xmlNode, node);
589
+
590
+ if (node->ns)
591
+ return Nokogiri_wrap_xml_namespace(node->doc, node->ns);
592
+
593
+ return Qnil ;
594
+ }
595
+
596
+ /*
597
+ * call-seq:
598
+ * namespace_definitions()
599
+ *
600
+ * returns a list of Namespace nodes defined on _self_
601
+ */
602
+ static VALUE namespace_definitions(VALUE self)
603
+ {
604
+ /* this code in the mode of xmlHasProp() */
605
+ xmlNodePtr node ;
606
+
607
+ Data_Get_Struct(self, xmlNode, node);
608
+
609
+ VALUE list = rb_ary_new();
610
+
611
+ xmlNsPtr ns = node->nsDef;
612
+
613
+ if(!ns) return list;
614
+
615
+ while(NULL != ns) {
616
+ rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns));
617
+ ns = ns->next;
618
+ }
619
+
620
+ return list;
621
+ }
622
+
623
+ /*
624
+ * call-seq:
625
+ * node_type
626
+ *
627
+ * Get the type for this Node
628
+ */
629
+ static VALUE node_type(VALUE self)
630
+ {
631
+ xmlNodePtr node;
632
+ Data_Get_Struct(self, xmlNode, node);
633
+ return INT2NUM((long)node->type);
634
+ }
635
+
636
+ /*
637
+ * call-seq:
638
+ * content=
639
+ *
640
+ * Set the content for this Node
641
+ */
642
+ static VALUE set_content(VALUE self, VALUE content)
643
+ {
644
+ xmlNodePtr node;
645
+ Data_Get_Struct(self, xmlNode, node);
646
+ xmlNodeSetContent(node, (xmlChar *)StringValuePtr(content));
647
+ return content;
648
+ }
649
+
650
+ /*
651
+ * call-seq:
652
+ * content
653
+ *
654
+ * Returns the content for this Node
655
+ */
656
+ static VALUE get_content(VALUE self)
657
+ {
658
+ xmlNodePtr node;
659
+ Data_Get_Struct(self, xmlNode, node);
660
+
661
+ xmlChar * content = xmlNodeGetContent(node);
662
+ if(content) {
663
+ VALUE rval = NOKOGIRI_STR_NEW2(content);
664
+ xmlFree(content);
665
+ return rval;
666
+ }
667
+ return Qnil;
668
+ }
669
+
670
+ /*
671
+ * call-seq:
672
+ * add_child(node)
673
+ *
674
+ * Add +node+ as a child of this node. Returns the new child node.
675
+ */
676
+ static VALUE add_child(VALUE self, VALUE child)
677
+ {
678
+ return reparent_node_with(child, self, xmlAddChild);
679
+ }
680
+
681
+ /*
682
+ * call-seq:
683
+ * parent
684
+ *
685
+ * Get the parent Node for this Node
686
+ */
687
+ static VALUE get_parent(VALUE self)
688
+ {
689
+ xmlNodePtr node, parent;
690
+ Data_Get_Struct(self, xmlNode, node);
691
+
692
+ parent = node->parent;
693
+ if(!parent) return Qnil;
694
+
695
+ return Nokogiri_wrap_xml_node(Qnil, parent) ;
696
+ }
697
+
698
+ /*
699
+ * call-seq:
700
+ * name=(new_name)
701
+ *
702
+ * Set the name for this Node
703
+ */
704
+ static VALUE set_name(VALUE self, VALUE new_name)
705
+ {
706
+ xmlNodePtr node;
707
+ Data_Get_Struct(self, xmlNode, node);
708
+ xmlNodeSetName(node, (xmlChar*)StringValuePtr(new_name));
709
+ return new_name;
710
+ }
711
+
712
+ /*
713
+ * call-seq:
714
+ * name
715
+ *
716
+ * Returns the name for this Node
717
+ */
718
+ static VALUE get_name(VALUE self)
719
+ {
720
+ xmlNodePtr node;
721
+ Data_Get_Struct(self, xmlNode, node);
722
+ if(node->name)
723
+ return NOKOGIRI_STR_NEW2(node->name);
724
+ return Qnil;
725
+ }
726
+
727
+ /*
728
+ * call-seq:
729
+ * path
730
+ *
731
+ * Returns the path associated with this Node
732
+ */
733
+ static VALUE path(VALUE self)
734
+ {
735
+ xmlNodePtr node;
736
+ xmlChar *path ;
737
+ Data_Get_Struct(self, xmlNode, node);
738
+
739
+ path = xmlGetNodePath(node);
740
+ VALUE rval = NOKOGIRI_STR_NEW2(path);
741
+ xmlFree(path);
742
+ return rval ;
743
+ }
744
+
745
+ /*
746
+ * call-seq:
747
+ * add_next_sibling(node)
748
+ *
749
+ * Insert +node+ after this node (as a sibling).
750
+ */
751
+ static VALUE add_next_sibling(VALUE self, VALUE rb_node)
752
+ {
753
+ return reparent_node_with(rb_node, self, xmlAddNextSibling) ;
754
+ }
755
+
756
+ /*
757
+ * call-seq:
758
+ * add_previous_sibling(node)
759
+ *
760
+ * Insert +node+ before this node (as a sibling).
761
+ */
762
+ static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
763
+ {
764
+ return reparent_node_with(rb_node, self, xmlAddPrevSibling) ;
765
+ }
766
+
767
+ /*
768
+ * call-seq:
769
+ * native_write_to(io, encoding, options)
770
+ *
771
+ * Write this Node to +io+ with +encoding+ and +options+
772
+ */
773
+ static VALUE native_write_to(
774
+ VALUE self,
775
+ VALUE io,
776
+ VALUE encoding,
777
+ VALUE indent_string,
778
+ VALUE options
779
+ ) {
780
+ xmlNodePtr node;
781
+
782
+ Data_Get_Struct(self, xmlNode, node);
783
+
784
+ xmlIndentTreeOutput = 1;
785
+
786
+ const char * before_indent = xmlTreeIndentString;
787
+
788
+ xmlTreeIndentString = StringValuePtr(indent_string);
789
+
790
+ xmlSaveCtxtPtr savectx = xmlSaveToIO(
791
+ (xmlOutputWriteCallback)io_write_callback,
792
+ (xmlOutputCloseCallback)io_close_callback,
793
+ (void *)io,
794
+ RTEST(encoding) ? StringValuePtr(encoding) : NULL,
795
+ (int)NUM2INT(options)
796
+ );
797
+
798
+ xmlSaveTree(savectx, node);
799
+ xmlSaveClose(savectx);
800
+
801
+ xmlTreeIndentString = before_indent;
802
+ return io;
803
+ }
804
+
805
+ /*
806
+ * call-seq:
807
+ * line
808
+ *
809
+ * Returns the line for this Node
810
+ */
811
+ static VALUE line(VALUE self)
812
+ {
813
+ xmlNodePtr node;
814
+ Data_Get_Struct(self, xmlNode, node);
815
+
816
+ return INT2NUM(xmlGetLineNo(node));
817
+ }
818
+
819
+ /*
820
+ * call-seq:
821
+ * add_namespace_definition(prefix, href)
822
+ *
823
+ * Adds a namespace definition with +prefix+ using +href+
824
+ */
825
+ static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
826
+ {
827
+ xmlNodePtr node;
828
+ Data_Get_Struct(self, xmlNode, node);
829
+
830
+
831
+ xmlNsPtr ns = xmlNewNs(
832
+ node,
833
+ (const xmlChar *)StringValuePtr(href),
834
+ (const xmlChar *)(NIL_P(prefix) ? NULL : StringValuePtr(prefix))
835
+ );
836
+
837
+ if(!ns) {
838
+ ns = xmlSearchNs(
839
+ node->doc,
840
+ node,
841
+ (const xmlChar *)(NIL_P(prefix) ? NULL : StringValuePtr(prefix))
842
+ );
843
+ }
844
+
845
+ if(NIL_P(prefix)) xmlSetNs(node, ns);
846
+
847
+ return Nokogiri_wrap_xml_namespace(node->doc, ns);
848
+ }
849
+
850
+ /*
851
+ * call-seq:
852
+ * new(name, document)
853
+ *
854
+ * Create a new node with +name+ sharing GC lifecycle with +document+
855
+ */
856
+ static VALUE new(int argc, VALUE *argv, VALUE klass)
857
+ {
858
+ xmlDocPtr doc;
859
+ VALUE name;
860
+ VALUE document;
861
+ VALUE rest;
862
+
863
+ rb_scan_args(argc, argv, "2*", &name, &document, &rest);
864
+
865
+ Data_Get_Struct(document, xmlDoc, doc);
866
+
867
+ xmlNodePtr node = xmlNewNode(NULL, (xmlChar *)StringValuePtr(name));
868
+ node->doc = doc->doc;
869
+ NOKOGIRI_ROOT_NODE(node);
870
+
871
+ VALUE rb_node = Nokogiri_wrap_xml_node(
872
+ klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
873
+ node
874
+ );
875
+ rb_obj_call_init(rb_node, argc, argv);
876
+
877
+ if(rb_block_given_p()) rb_yield(rb_node);
878
+
879
+ return rb_node;
880
+ }
881
+
882
+ /*
883
+ * call-seq:
884
+ * dump_html
885
+ *
886
+ * Returns the Node as html.
887
+ */
888
+ static VALUE dump_html(VALUE self)
889
+ {
890
+ xmlBufferPtr buf ;
891
+ xmlNodePtr node ;
892
+ Data_Get_Struct(self, xmlNode, node);
893
+
894
+ buf = xmlBufferCreate() ;
895
+ htmlNodeDump(buf, node->doc, node);
896
+ VALUE html = NOKOGIRI_STR_NEW2(buf->content);
897
+ xmlBufferFree(buf);
898
+ return html ;
899
+ }
900
+
901
+ /*
902
+ * call-seq:
903
+ * compare(other)
904
+ *
905
+ * Compare this Node to +other+ with respect to their Document
906
+ */
907
+ static VALUE compare(VALUE self, VALUE _other)
908
+ {
909
+ xmlNodePtr node, other;
910
+ Data_Get_Struct(self, xmlNode, node);
911
+ Data_Get_Struct(_other, xmlNode, other);
912
+
913
+ return INT2NUM((long)xmlXPathCmpNodes(other, node));
914
+ }
915
+
916
+ VALUE Nokogiri_wrap_xml_node(VALUE klass, xmlNodePtr node)
917
+ {
918
+ assert(node);
919
+
920
+ VALUE document = Qnil ;
921
+ VALUE node_cache = Qnil ;
922
+ VALUE rb_node = Qnil ;
923
+
924
+ if(node->type == XML_DOCUMENT_NODE || node->type == XML_HTML_DOCUMENT_NODE)
925
+ return DOC_RUBY_OBJECT(node->doc);
926
+
927
+ if(NULL != node->_private) return (VALUE)node->_private;
928
+
929
+ if(RTEST(klass))
930
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
931
+
932
+ else switch(node->type)
933
+ {
934
+ case XML_ELEMENT_NODE:
935
+ klass = cNokogiriXmlElement;
936
+ break;
937
+ case XML_TEXT_NODE:
938
+ klass = cNokogiriXmlText;
939
+ break;
940
+ case XML_ATTRIBUTE_NODE:
941
+ klass = cNokogiriXmlAttr;
942
+ break;
943
+ case XML_ENTITY_REF_NODE:
944
+ klass = cNokogiriXmlEntityReference;
945
+ break;
946
+ case XML_COMMENT_NODE:
947
+ klass = cNokogiriXmlComment;
948
+ break;
949
+ case XML_DOCUMENT_FRAG_NODE:
950
+ klass = cNokogiriXmlDocumentFragment;
951
+ break;
952
+ case XML_PI_NODE:
953
+ klass = cNokogiriXmlProcessingInstruction;
954
+ break;
955
+ case XML_ENTITY_DECL:
956
+ klass = cNokogiriXmlEntityDecl;
957
+ break;
958
+ case XML_CDATA_SECTION_NODE:
959
+ klass = cNokogiriXmlCData;
960
+ break;
961
+ case XML_DTD_NODE:
962
+ klass = cNokogiriXmlDtd;
963
+ break;
964
+ case XML_ATTRIBUTE_DECL:
965
+ klass = cNokogiriXmlAttributeDecl;
966
+ break;
967
+ case XML_ELEMENT_DECL:
968
+ klass = cNokogiriXmlElementDecl;
969
+ break;
970
+ default:
971
+ klass = cNokogiriXmlNode;
972
+ }
973
+
974
+ rb_node = Data_Wrap_Struct(klass, mark, debug_node_dealloc, node) ;
975
+
976
+ node->_private = (void *)rb_node;
977
+
978
+ if (DOC_RUBY_OBJECT_TEST(node->doc) && DOC_RUBY_OBJECT(node->doc)) {
979
+ // it's OK if the document isn't fully realized (as in XML::Reader).
980
+ // see http://github.com/tenderlove/nokogiri/issues/closed/#issue/95
981
+ document = DOC_RUBY_OBJECT(node->doc);
982
+ node_cache = DOC_NODE_CACHE(node->doc);
983
+ rb_ary_push(node_cache, rb_node);
984
+ rb_funcall(document, decorate, 1, rb_node);
985
+ }
986
+
987
+ return rb_node ;
988
+ }
989
+
990
+
991
+ void Nokogiri_xml_node_properties(xmlNodePtr node, VALUE attr_list)
992
+ {
993
+ xmlAttrPtr prop;
994
+ prop = node->properties ;
995
+ while (prop != NULL) {
996
+ rb_ary_push(attr_list, Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop));
997
+ prop = prop->next ;
998
+ }
999
+ }
1000
+
1001
+ VALUE cNokogiriXmlNode ;
1002
+ VALUE cNokogiriXmlElement ;
1003
+
1004
+ void init_xml_node()
1005
+ {
1006
+ VALUE nokogiri = rb_define_module("Nokogiri");
1007
+ VALUE xml = rb_define_module_under(nokogiri, "XML");
1008
+ VALUE klass = rb_define_class_under(xml, "Node", rb_cObject);
1009
+
1010
+ cNokogiriXmlNode = klass;
1011
+
1012
+ cNokogiriXmlElement = rb_define_class_under(xml, "Element", klass);
1013
+
1014
+ rb_define_singleton_method(klass, "new", new, -1);
1015
+
1016
+ rb_define_method(klass, "add_namespace_definition", add_namespace_definition, 2);
1017
+ rb_define_method(klass, "node_name", get_name, 0);
1018
+ rb_define_method(klass, "document", document, 0);
1019
+ rb_define_method(klass, "node_name=", set_name, 1);
1020
+ rb_define_method(klass, "add_child", add_child, 1);
1021
+ rb_define_method(klass, "parent", get_parent, 0);
1022
+ rb_define_method(klass, "child", child, 0);
1023
+ rb_define_method(klass, "children", children, 0);
1024
+ rb_define_method(klass, "next_sibling", next_sibling, 0);
1025
+ rb_define_method(klass, "previous_sibling", previous_sibling, 0);
1026
+ rb_define_method(klass, "node_type", node_type, 0);
1027
+ rb_define_method(klass, "content", get_content, 0);
1028
+ rb_define_method(klass, "path", path, 0);
1029
+ rb_define_method(klass, "key?", key_eh, 1);
1030
+ rb_define_method(klass, "namespaced_key?", namespaced_key_eh, 2);
1031
+ rb_define_method(klass, "blank?", blank_eh, 0);
1032
+ rb_define_method(klass, "[]=", set, 2);
1033
+ rb_define_method(klass, "attribute_nodes", attribute_nodes, 0);
1034
+ rb_define_method(klass, "attribute", attr, 1);
1035
+ rb_define_method(klass, "attribute_with_ns", attribute_with_ns, 2);
1036
+ rb_define_method(klass, "namespace", namespace, 0);
1037
+ rb_define_method(klass, "namespace_definitions", namespace_definitions, 0);
1038
+ rb_define_method(klass, "add_previous_sibling", add_previous_sibling, 1);
1039
+ rb_define_method(klass, "add_next_sibling", add_next_sibling, 1);
1040
+ rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
1041
+ rb_define_method(klass, "dup", duplicate_node, -1);
1042
+ rb_define_method(klass, "unlink", unlink_node, 0);
1043
+ rb_define_method(klass, "internal_subset", internal_subset, 0);
1044
+ rb_define_method(klass, "external_subset", external_subset, 0);
1045
+ rb_define_method(klass, "create_internal_subset", create_internal_subset, 3);
1046
+ rb_define_method(klass, "create_external_subset", create_external_subset, 3);
1047
+ rb_define_method(klass, "pointer_id", pointer_id, 0);
1048
+ rb_define_method(klass, "line", line, 0);
1049
+
1050
+ rb_define_private_method(klass, "dump_html", dump_html, 0);
1051
+ rb_define_private_method(klass, "native_write_to", native_write_to, 4);
1052
+ rb_define_private_method(klass, "replace_with_node", replace, 1);
1053
+ rb_define_private_method(klass, "native_content=", set_content, 1);
1054
+ rb_define_private_method(klass, "get", get, 1);
1055
+ rb_define_private_method(klass, "set_namespace", set_namespace, 1);
1056
+ rb_define_private_method(klass, "compare", compare, 1);
1057
+
1058
+ decorate = rb_intern("decorate");
1059
+ decorate_bang = rb_intern("decorate!");
1060
+ }