tenderlove-nokogiri 0.0.0.20081001111445

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. data/History.txt +6 -0
  2. data/Manifest.txt +105 -0
  3. data/README.txt +51 -0
  4. data/Rakefile +70 -0
  5. data/ext/nokogiri/extconf.rb +24 -0
  6. data/ext/nokogiri/html_document.c +85 -0
  7. data/ext/nokogiri/html_document.h +10 -0
  8. data/ext/nokogiri/html_sax_parser.c +32 -0
  9. data/ext/nokogiri/html_sax_parser.h +11 -0
  10. data/ext/nokogiri/native.c +35 -0
  11. data/ext/nokogiri/native.h +32 -0
  12. data/ext/nokogiri/xml_cdata.c +36 -0
  13. data/ext/nokogiri/xml_cdata.h +9 -0
  14. data/ext/nokogiri/xml_document.c +159 -0
  15. data/ext/nokogiri/xml_document.h +10 -0
  16. data/ext/nokogiri/xml_node.c +573 -0
  17. data/ext/nokogiri/xml_node.h +13 -0
  18. data/ext/nokogiri/xml_node_set.c +90 -0
  19. data/ext/nokogiri/xml_node_set.h +9 -0
  20. data/ext/nokogiri/xml_reader.c +420 -0
  21. data/ext/nokogiri/xml_reader.h +10 -0
  22. data/ext/nokogiri/xml_sax_parser.c +161 -0
  23. data/ext/nokogiri/xml_sax_parser.h +10 -0
  24. data/ext/nokogiri/xml_text.c +25 -0
  25. data/ext/nokogiri/xml_text.h +9 -0
  26. data/ext/nokogiri/xml_xpath.c +39 -0
  27. data/ext/nokogiri/xml_xpath.h +11 -0
  28. data/ext/nokogiri/xml_xpath_context.c +69 -0
  29. data/ext/nokogiri/xml_xpath_context.h +9 -0
  30. data/ext/nokogiri/xslt_stylesheet.c +83 -0
  31. data/ext/nokogiri/xslt_stylesheet.h +9 -0
  32. data/lib/nokogiri.rb +45 -0
  33. data/lib/nokogiri/css.rb +6 -0
  34. data/lib/nokogiri/css/node.rb +95 -0
  35. data/lib/nokogiri/css/parser.rb +24 -0
  36. data/lib/nokogiri/css/parser.y +198 -0
  37. data/lib/nokogiri/css/tokenizer.rb +9 -0
  38. data/lib/nokogiri/css/tokenizer.rex +63 -0
  39. data/lib/nokogiri/css/xpath_visitor.rb +153 -0
  40. data/lib/nokogiri/decorators.rb +1 -0
  41. data/lib/nokogiri/decorators/hpricot.rb +3 -0
  42. data/lib/nokogiri/decorators/hpricot/node.rb +47 -0
  43. data/lib/nokogiri/decorators/hpricot/node_set.rb +14 -0
  44. data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +13 -0
  45. data/lib/nokogiri/hpricot.rb +46 -0
  46. data/lib/nokogiri/html.rb +64 -0
  47. data/lib/nokogiri/html/builder.rb +9 -0
  48. data/lib/nokogiri/html/document.rb +9 -0
  49. data/lib/nokogiri/html/sax/parser.rb +21 -0
  50. data/lib/nokogiri/version.rb +3 -0
  51. data/lib/nokogiri/xml.rb +29 -0
  52. data/lib/nokogiri/xml/after_handler.rb +18 -0
  53. data/lib/nokogiri/xml/before_handler.rb +32 -0
  54. data/lib/nokogiri/xml/builder.rb +79 -0
  55. data/lib/nokogiri/xml/document.rb +22 -0
  56. data/lib/nokogiri/xml/node.rb +162 -0
  57. data/lib/nokogiri/xml/node_set.rb +136 -0
  58. data/lib/nokogiri/xml/reader.rb +14 -0
  59. data/lib/nokogiri/xml/sax.rb +9 -0
  60. data/lib/nokogiri/xml/sax/document.rb +59 -0
  61. data/lib/nokogiri/xml/sax/parser.rb +33 -0
  62. data/lib/nokogiri/xml/text.rb +6 -0
  63. data/lib/nokogiri/xml/xpath.rb +6 -0
  64. data/lib/nokogiri/xslt.rb +11 -0
  65. data/lib/nokogiri/xslt/stylesheet.rb +6 -0
  66. data/nokogiri.gemspec +33 -0
  67. data/test/css/test_nthiness.rb +141 -0
  68. data/test/css/test_parser.rb +214 -0
  69. data/test/css/test_tokenizer.rb +162 -0
  70. data/test/files/staff.xml +57 -0
  71. data/test/files/staff.xslt +32 -0
  72. data/test/files/tlm.html +850 -0
  73. data/test/helper.rb +70 -0
  74. data/test/hpricot/files/basic.xhtml +17 -0
  75. data/test/hpricot/files/boingboing.html +2266 -0
  76. data/test/hpricot/files/cy0.html +3653 -0
  77. data/test/hpricot/files/immob.html +400 -0
  78. data/test/hpricot/files/pace_application.html +1320 -0
  79. data/test/hpricot/files/tenderlove.html +16 -0
  80. data/test/hpricot/files/uswebgen.html +220 -0
  81. data/test/hpricot/files/utf8.html +1054 -0
  82. data/test/hpricot/files/week9.html +1723 -0
  83. data/test/hpricot/files/why.xml +19 -0
  84. data/test/hpricot/load_files.rb +7 -0
  85. data/test/hpricot/test_alter.rb +67 -0
  86. data/test/hpricot/test_builder.rb +27 -0
  87. data/test/hpricot/test_parser.rb +412 -0
  88. data/test/hpricot/test_paths.rb +15 -0
  89. data/test/hpricot/test_preserved.rb +72 -0
  90. data/test/hpricot/test_xml.rb +26 -0
  91. data/test/html/sax/test_parser.rb +27 -0
  92. data/test/html/test_builder.rb +78 -0
  93. data/test/html/test_document.rb +22 -0
  94. data/test/test_convert_xpath.rb +173 -0
  95. data/test/test_nokogiri.rb +36 -0
  96. data/test/test_reader.rb +222 -0
  97. data/test/test_xslt_transforms.rb +29 -0
  98. data/test/xml/sax/test_parser.rb +93 -0
  99. data/test/xml/test_builder.rb +16 -0
  100. data/test/xml/test_document.rb +141 -0
  101. data/test/xml/test_node.rb +148 -0
  102. data/test/xml/test_node_set.rb +54 -0
  103. data/test/xml/test_text.rb +13 -0
  104. metadata +191 -0
@@ -0,0 +1,36 @@
1
+ #include <xml_cdata.h>
2
+
3
+ static void dealloc(xmlNodePtr node)
4
+ {
5
+ if(node->doc == NULL) xmlFreeNode(node);
6
+ }
7
+
8
+ static VALUE new(VALUE klass, VALUE doc, VALUE content)
9
+ {
10
+ xmlDocPtr xml_doc;
11
+ Data_Get_Struct(doc, xmlDoc, xml_doc);
12
+
13
+ xmlNodePtr node = xmlNewCDataBlock(
14
+ xml_doc,
15
+ (const xmlChar *)StringValuePtr(content),
16
+ NUM2INT(rb_funcall(content, rb_intern("length"), 0))
17
+ );
18
+
19
+ VALUE rb_node = Data_Wrap_Struct(klass, NULL, dealloc, node);
20
+ node->_private = (void *)rb_node;
21
+
22
+ if(rb_block_given_p()) rb_yield(rb_node);
23
+
24
+ return rb_node;
25
+ }
26
+
27
+ VALUE cNokogiriXmlCData;
28
+ void init_xml_cdata()
29
+ {
30
+ VALUE nokogiri = rb_define_module("Nokogiri");
31
+ VALUE xml = rb_define_module_under(nokogiri, "XML");
32
+ VALUE klass = rb_define_class_under(xml, "CData", cNokogiriXmlNode);
33
+ cNokogiriXmlCData = klass;
34
+
35
+ rb_define_singleton_method(klass, "new", new, 2);
36
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef NOKOGIRI_XML_CDATA
2
+ #define NOKOGIRI_XML_CDATA
3
+
4
+ #include <native.h>
5
+
6
+ void init_xml_cdata();
7
+
8
+ extern VALUE cNokogiriXmlCData;
9
+ #endif
@@ -0,0 +1,159 @@
1
+ #include <xml_document.h>
2
+
3
+ /*
4
+ * note that xmlDocPtr is being cast as an xmlNodePtr, which is legal for the
5
+ * "common part" struct header which contains only node pointers. casting like
6
+ * this allows us to recurse through the tree with a single function.
7
+ */
8
+ static void gc_mark(xmlNodePtr doc)
9
+ {
10
+ xmlNodePtr j ;
11
+ j = doc->children ;
12
+ while (j != NULL) {
13
+ if (j->_private)
14
+ rb_gc_mark((VALUE)j->_private);
15
+ gc_mark(j); /* recurse */
16
+ j = j->next ;
17
+ }
18
+ }
19
+
20
+ static void dealloc(xmlDocPtr doc)
21
+ {
22
+ xmlFreeDoc(doc);
23
+ }
24
+
25
+ /*
26
+ * call-seq:
27
+ * serialize
28
+ *
29
+ * Serialize this document
30
+ */
31
+ static VALUE serialize(VALUE self)
32
+ {
33
+ xmlDocPtr doc;
34
+ xmlChar *buf;
35
+ int size;
36
+ Data_Get_Struct(self, xmlDoc, doc);
37
+
38
+ xmlDocDumpMemory(doc, &buf, &size);
39
+ VALUE rb_str = rb_str_new((char *)buf, (long)size);
40
+ free(buf);
41
+ return rb_str;
42
+ }
43
+
44
+ /*
45
+ * call-seq:
46
+ * root=
47
+ *
48
+ * Set the root element on this document
49
+ */
50
+ static VALUE set_root(VALUE self, VALUE root)
51
+ {
52
+ xmlDocPtr doc;
53
+ xmlNodePtr new_root;
54
+
55
+ Data_Get_Struct(self, xmlDoc, doc);
56
+ Data_Get_Struct(root, xmlNode, new_root);
57
+
58
+ xmlDocSetRootElement(doc, new_root);
59
+ return root;
60
+ }
61
+
62
+ /*
63
+ * call-seq:
64
+ * root
65
+ *
66
+ * Get the root node for this document.
67
+ */
68
+ static VALUE root(VALUE self)
69
+ {
70
+ xmlDocPtr doc;
71
+ Data_Get_Struct(self, xmlDoc, doc);
72
+
73
+ xmlNodePtr root = xmlDocGetRootElement(doc);
74
+
75
+ if(!root) return Qnil;
76
+ return Nokogiri_wrap_xml_node(root) ;
77
+ }
78
+
79
+ static VALUE read_memory( VALUE klass,
80
+ VALUE string,
81
+ VALUE url,
82
+ VALUE encoding,
83
+ VALUE options )
84
+ {
85
+ const char * c_buffer = StringValuePtr(string);
86
+ const char * c_url = (url == Qnil) ? NULL : StringValuePtr(url);
87
+ const char * c_enc = (encoding == Qnil) ? NULL : StringValuePtr(encoding);
88
+ int len = RSTRING(string)->len ;
89
+
90
+ xmlInitParser();
91
+ xmlDocPtr doc = xmlReadMemory(c_buffer, len, c_url, c_enc, NUM2INT(options));
92
+
93
+ if(doc == NULL) {
94
+ xmlFreeDoc(doc);
95
+ rb_raise(rb_eRuntimeError, "Couldn't create a document");
96
+ }
97
+
98
+ return Nokogiri_wrap_xml_document(klass, doc);
99
+ }
100
+
101
+ static VALUE new(int argc, VALUE *argv, VALUE klass)
102
+ {
103
+ VALUE version;
104
+ if(rb_scan_args(argc, argv, "01", &version) == 0)
105
+ version = rb_str_new2("1.0");
106
+
107
+ xmlDocPtr doc = xmlNewDoc((xmlChar *)StringValuePtr(version));
108
+ return Nokogiri_wrap_xml_document(klass, doc);
109
+ }
110
+
111
+ /*
112
+ * call-seq:
113
+ * substitute_entities_set bool)
114
+ *
115
+ * Set the global XML default for substitute entities.
116
+ */
117
+ static VALUE substitute_entities_set(VALUE klass, VALUE value)
118
+ {
119
+ xmlSubstituteEntitiesDefault(NUM2INT(value));
120
+ return Qnil ;
121
+ }
122
+
123
+ /*
124
+ * call-seq:
125
+ * substitute_entities_set bool)
126
+ *
127
+ * Set the global XML default for load external subsets.
128
+ */
129
+ static VALUE load_external_subsets_set(VALUE klass, VALUE value)
130
+ {
131
+ xmlLoadExtDtdDefaultValue = NUM2INT(value);
132
+ return Qnil ;
133
+ }
134
+
135
+ VALUE cNokogiriXmlDocument ;
136
+ void init_xml_document()
137
+ {
138
+ VALUE klass = cNokogiriXmlDocument = rb_const_get(mNokogiriXml, rb_intern("Document"));
139
+
140
+ rb_define_singleton_method(klass, "read_memory", read_memory, 4);
141
+ rb_define_singleton_method(klass, "new", new, -1);
142
+ rb_define_singleton_method(klass, "substitute_entities=", substitute_entities_set, 1);
143
+ rb_define_singleton_method(klass, "load_external_subsets=", load_external_subsets_set, 1);
144
+
145
+ rb_define_method(klass, "root", root, 0);
146
+ rb_define_method(klass, "root=", set_root, 1);
147
+ rb_define_method(klass, "serialize", serialize, 0);
148
+ }
149
+
150
+
151
+ /* this takes klass as a param because it's used for HtmlDocument, too. */
152
+ VALUE Nokogiri_wrap_xml_document(VALUE klass, xmlDocPtr doc)
153
+ {
154
+ if (doc->_private)
155
+ return (VALUE)doc->_private ;
156
+ VALUE rb_doc = Data_Wrap_Struct(klass ? klass : cNokogiriXmlDocument, gc_mark, dealloc, doc) ;
157
+ doc->_private = (void*)rb_doc ;
158
+ return rb_doc ;
159
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef NOKOGIRI_XML_DOCUMENT
2
+ #define NOKOGIRI_XML_DOCUMENT
3
+
4
+ #include <native.h>
5
+
6
+ void init_xml_document();
7
+ VALUE Nokogiri_wrap_xml_document(VALUE klass, xmlDocPtr doc);
8
+
9
+ extern VALUE cNokogiriXmlDocument ;
10
+ #endif
@@ -0,0 +1,573 @@
1
+ #include <xml_node.h>
2
+
3
+ /*
4
+ * call-seq:
5
+ * encode_special_chars(string)
6
+ *
7
+ * Encode any special characters in +string+
8
+ */
9
+ static VALUE encode_special_chars(VALUE self, VALUE string)
10
+ {
11
+ xmlNodePtr node;
12
+ Data_Get_Struct(self, xmlNode, node);
13
+ xmlChar * encoded = xmlEncodeSpecialChars(
14
+ node->doc,
15
+ (const xmlChar *)StringValuePtr(string)
16
+ );
17
+
18
+ VALUE encoded_str = rb_str_new2((const char *)encoded);
19
+ free(encoded);
20
+
21
+ return encoded_str;
22
+ }
23
+
24
+ /*
25
+ * call-seq:
26
+ * dup
27
+ *
28
+ * Copy this node
29
+ */
30
+ static VALUE dup(VALUE self)
31
+ {
32
+ xmlNodePtr node, dup;
33
+ Data_Get_Struct(self, xmlNode, node);
34
+
35
+ dup = xmlCopyNode(node, 1);
36
+ if(dup == NULL) return Qnil;
37
+
38
+ return Nokogiri_wrap_xml_node(dup);
39
+ }
40
+
41
+ /*
42
+ * call-seq:
43
+ * blank?
44
+ *
45
+ * Is this node blank?
46
+ */
47
+ static VALUE blank_eh(VALUE self)
48
+ {
49
+ xmlNodePtr node;
50
+ Data_Get_Struct(self, xmlNode, node);
51
+ if(1 == xmlIsBlankNode(node))
52
+ return Qtrue;
53
+ return Qfalse;
54
+ }
55
+
56
+ /*
57
+ * call-seq:
58
+ * next_sibling
59
+ *
60
+ * Returns the next sibling node
61
+ */
62
+ static VALUE next_sibling(VALUE self)
63
+ {
64
+ xmlNodePtr node, sibling;
65
+ Data_Get_Struct(self, xmlNode, node);
66
+
67
+ sibling = node->next;
68
+ if(!sibling) return Qnil;
69
+
70
+ return Nokogiri_wrap_xml_node(sibling) ;
71
+ }
72
+
73
+ /*
74
+ * call-seq:
75
+ * previous_sibling
76
+ *
77
+ * Returns the previous sibling node
78
+ */
79
+ static VALUE previous_sibling(VALUE self)
80
+ {
81
+ xmlNodePtr node, sibling;
82
+ Data_Get_Struct(self, xmlNode, node);
83
+
84
+ sibling = node->prev;
85
+ if(!sibling) return Qnil;
86
+
87
+ return Nokogiri_wrap_xml_node(sibling);
88
+ }
89
+
90
+ /*
91
+ * call-seq:
92
+ * replace(new_node)
93
+ *
94
+ * replace node with the new node in the document.
95
+ */
96
+ static VALUE replace(VALUE self, VALUE _new_node)
97
+ {
98
+ xmlNodePtr node, new_node;
99
+ Data_Get_Struct(self, xmlNode, node);
100
+ Data_Get_Struct(_new_node, xmlNode, new_node);
101
+
102
+ xmlReplaceNode(node, new_node);
103
+ return self ;
104
+ }
105
+
106
+
107
+ /*
108
+ * call-seq:
109
+ * child
110
+ *
111
+ * Returns the child node
112
+ */
113
+ static VALUE child(VALUE self)
114
+ {
115
+ xmlNodePtr node, child;
116
+ Data_Get_Struct(self, xmlNode, node);
117
+
118
+ child = node->children;
119
+ if(!child) return Qnil;
120
+
121
+ return Nokogiri_wrap_xml_node(child);
122
+ }
123
+
124
+ /*
125
+ * call-seq:
126
+ * key?(attribute)
127
+ *
128
+ * Returns true if +attribute+ is set
129
+ */
130
+ static VALUE key_eh(VALUE self, VALUE attribute)
131
+ {
132
+ xmlNodePtr node;
133
+ Data_Get_Struct(self, xmlNode, node);
134
+ if(xmlHasProp(node, (xmlChar *)StringValuePtr(attribute)))
135
+ return Qtrue;
136
+ return Qfalse;
137
+ }
138
+
139
+ /*
140
+ * call-seq:
141
+ * []=(property, value)
142
+ *
143
+ * Set the +property+ to +value+
144
+ */
145
+ static VALUE set(VALUE self, VALUE property, VALUE value)
146
+ {
147
+ xmlNodePtr node;
148
+ Data_Get_Struct(self, xmlNode, node);
149
+ xmlSetProp(node, (xmlChar *)StringValuePtr(property),
150
+ (xmlChar *)StringValuePtr(value));
151
+
152
+ return value;
153
+ }
154
+
155
+ /*
156
+ * call-seq:
157
+ * remove(property)
158
+ *
159
+ * remove the property +property+
160
+ */
161
+ static VALUE remove_prop(VALUE self, VALUE property)
162
+ {
163
+ xmlNodePtr node;
164
+ xmlAttrPtr attr ;
165
+ Data_Get_Struct(self, xmlNode, node);
166
+ attr = xmlHasProp(node, (xmlChar *)StringValuePtr(property));
167
+ if (attr) { xmlRemoveProp(attr); }
168
+ return Qnil;
169
+ }
170
+
171
+ /*
172
+ * call-seq
173
+ * get(attribute)
174
+ *
175
+ * Get the value for +attribute+
176
+ */
177
+ static VALUE get(VALUE self, VALUE attribute)
178
+ {
179
+ xmlNodePtr node;
180
+ xmlChar* propstr ;
181
+ VALUE rval ;
182
+ Data_Get_Struct(self, xmlNode, node);
183
+ propstr = xmlGetProp(node, (xmlChar *)StringValuePtr(attribute));
184
+ rval = rb_str_new2((char *)propstr) ;
185
+ xmlFree(propstr);
186
+ return rval ;
187
+ }
188
+
189
+ /*
190
+ * call-seq
191
+ * attributes()
192
+ *
193
+ * returns a hash containing the node's attributes.
194
+ */
195
+ static VALUE attributes(VALUE self)
196
+ {
197
+ /* this code in the mode of xmlHasProp() */
198
+ xmlNodePtr node ;
199
+ VALUE attr ;
200
+
201
+ attr = rb_hash_new() ;
202
+ Data_Get_Struct(self, xmlNode, node);
203
+
204
+ Nokogiri_xml_node_properties(node, attr);
205
+
206
+ return attr ;
207
+ }
208
+
209
+ /*
210
+ * call-seq:
211
+ * type
212
+ *
213
+ * Get the type for this node
214
+ */
215
+ static VALUE type(VALUE self)
216
+ {
217
+ xmlNodePtr node;
218
+ Data_Get_Struct(self, xmlNode, node);
219
+ return INT2NUM((int)node->type);
220
+ }
221
+
222
+ /*
223
+ * call-seq:
224
+ * content=
225
+ *
226
+ * Set the content for this Node
227
+ */
228
+ static VALUE set_content(VALUE self, VALUE content)
229
+ {
230
+ xmlNodePtr node;
231
+ Data_Get_Struct(self, xmlNode, node);
232
+ xmlNodeSetContent(node, (xmlChar *)StringValuePtr(content));
233
+ return content;
234
+ }
235
+
236
+ /*
237
+ * call-seq:
238
+ * content
239
+ *
240
+ * Returns the content for this Node
241
+ */
242
+ static VALUE get_content(VALUE self)
243
+ {
244
+ xmlNodePtr node;
245
+ Data_Get_Struct(self, xmlNode, node);
246
+
247
+ xmlChar * content = xmlNodeGetContent(node);
248
+ if(content) {
249
+ VALUE rval = rb_str_new2((char *)content);
250
+ xmlFree(content);
251
+ return rval;
252
+ }
253
+ return Qnil;
254
+ }
255
+
256
+ /*
257
+ * call-seq:
258
+ * parent=(parent_node)
259
+ *
260
+ * Set the parent Node for this Node
261
+ */
262
+ static VALUE set_parent(VALUE self, VALUE parent_node)
263
+ {
264
+ xmlNodePtr node, parent;
265
+ Data_Get_Struct(self, xmlNode, node);
266
+ Data_Get_Struct(parent_node, xmlNode, parent);
267
+
268
+ xmlAddChild(parent, node);
269
+ return parent_node;
270
+ }
271
+
272
+ /*
273
+ * call-seq:
274
+ * parent
275
+ *
276
+ * Get the parent Node for this Node
277
+ */
278
+ static VALUE get_parent(VALUE self)
279
+ {
280
+ xmlNodePtr node, parent;
281
+ Data_Get_Struct(self, xmlNode, node);
282
+
283
+ parent = node->parent;
284
+ if(!parent) return Qnil;
285
+
286
+ return Nokogiri_wrap_xml_node(parent) ;
287
+ }
288
+
289
+ /*
290
+ * call-seq:
291
+ * name=(new_name)
292
+ *
293
+ * Set the name for this Node
294
+ */
295
+ static VALUE set_name(VALUE self, VALUE new_name)
296
+ {
297
+ xmlNodePtr node;
298
+ Data_Get_Struct(self, xmlNode, node);
299
+ xmlNodeSetName(node, (xmlChar*)StringValuePtr(new_name));
300
+ return new_name;
301
+ }
302
+
303
+ /*
304
+ * call-seq:
305
+ * name
306
+ *
307
+ * Returns the name for this Node
308
+ */
309
+ static VALUE get_name(VALUE self)
310
+ {
311
+ xmlNodePtr node;
312
+ Data_Get_Struct(self, xmlNode, node);
313
+ return rb_str_new2((const char *)node->name);
314
+ }
315
+
316
+ /*
317
+ * call-seq:
318
+ * path
319
+ *
320
+ * Returns the path associated with this Node
321
+ */
322
+ static VALUE path(VALUE self)
323
+ {
324
+ xmlNodePtr node;
325
+ xmlChar *path ;
326
+ VALUE rval ;
327
+ Data_Get_Struct(self, xmlNode, node);
328
+
329
+ path = xmlGetNodePath(node);
330
+ rval = rb_str_new2((char *)path);
331
+ xmlFree(path);
332
+ return rval ;
333
+ }
334
+
335
+ /*
336
+ * call-seq:
337
+ * document
338
+ *
339
+ * Returns the Nokogiri::XML::Document associated with this Node
340
+ */
341
+ static VALUE document(VALUE self)
342
+ {
343
+ xmlNodePtr node;
344
+ Data_Get_Struct(self, xmlNode, node);
345
+
346
+ if(!node->doc) return Qnil;
347
+ return (VALUE)node->doc->_private;
348
+ }
349
+
350
+ /*
351
+ * call-seq:
352
+ * add_next_sibling(node)
353
+ *
354
+ * Insert +node+ after this node (as a sibling).
355
+ */
356
+ static VALUE add_next_sibling(VALUE self, VALUE rb_node)
357
+ {
358
+ xmlNodePtr node, new_sibling;
359
+ Data_Get_Struct(self, xmlNode, node);
360
+ Data_Get_Struct(rb_node, xmlNode, new_sibling);
361
+ xmlAddNextSibling(node, new_sibling);
362
+
363
+ rb_funcall(rb_node, rb_intern("decorate!"), 0);
364
+
365
+ return rb_node;
366
+ }
367
+
368
+ /*
369
+ * call-seq:
370
+ * add_previous_sibling(node)
371
+ *
372
+ * Insert +node+ before this node (as a sibling).
373
+ */
374
+ static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
375
+ {
376
+ xmlNodePtr node, new_sibling;
377
+ Data_Get_Struct(self, xmlNode, node);
378
+ Data_Get_Struct(rb_node, xmlNode, new_sibling);
379
+ xmlAddPrevSibling(node, new_sibling);
380
+
381
+ rb_funcall(rb_node, rb_intern("decorate!"), 0);
382
+
383
+ return rb_node;
384
+ }
385
+
386
+ /*
387
+ * call-seq:
388
+ * to_xml
389
+ *
390
+ * Returns this node as XML
391
+ */
392
+ static VALUE to_xml(VALUE self)
393
+ {
394
+ xmlBufferPtr buf ;
395
+ xmlNodePtr node ;
396
+ VALUE xml ;
397
+
398
+ Data_Get_Struct(self, xmlNode, node);
399
+
400
+ buf = xmlBufferCreate() ;
401
+ xmlNodeDump(buf, node->doc, node, 2, 1);
402
+ xml = rb_str_new2((char*)buf->content);
403
+ xmlBufferFree(buf);
404
+ return xml ;
405
+ }
406
+
407
+
408
+ /*
409
+ * call-seq
410
+ * new(name, namespace=nil)
411
+ *
412
+ * Create a new node with +name+ and options +namespace+
413
+ */
414
+ static VALUE new(int argc, VALUE *argv, VALUE klass)
415
+ {
416
+ VALUE name, ns;
417
+ xmlNsPtr xml_ns = NULL;
418
+
419
+ rb_scan_args(argc, argv, "11", &name, &ns);
420
+
421
+ if (RTEST(ns))
422
+ Data_Get_Struct(ns, xmlNs, xml_ns);
423
+
424
+ xmlNodePtr node = xmlNewNode(xml_ns, (xmlChar *)StringValuePtr(name));
425
+ VALUE rb_node = Nokogiri_wrap_xml_node(node) ;
426
+
427
+ if(rb_block_given_p()) rb_yield(rb_node);
428
+
429
+ return rb_node;
430
+ }
431
+
432
+
433
+ /*
434
+ * call-seq
435
+ * new_from_str(string)
436
+ *
437
+ * Create a new node by parsing +string+
438
+ */
439
+ static VALUE new_from_str(VALUE klass, VALUE xml)
440
+ {
441
+ /*
442
+ * I couldn't find a more efficient way to do this. So we create a new
443
+ * document and copy (recursively) the root node.
444
+ */
445
+ VALUE rb_doc ;
446
+ xmlDocPtr doc ;
447
+ xmlNodePtr node ;
448
+
449
+ rb_doc = rb_funcall(cNokogiriXmlDocument, rb_intern("read_memory"), 4,
450
+ xml, Qnil, Qnil, INT2NUM(0));
451
+ Data_Get_Struct(rb_doc, xmlDoc, doc);
452
+ node = xmlCopyNode(xmlDocGetRootElement(doc), 1); /* 1 => recursive */
453
+ return Nokogiri_wrap_xml_node(node);
454
+ }
455
+
456
+ static void deallocate(xmlNodePtr node)
457
+ {
458
+ if (node && !node->doc) {
459
+ node->_private = NULL;
460
+ xmlFreeNode(node);
461
+ }
462
+ }
463
+
464
+ static void gc_mark_node(xmlNodePtr node)
465
+ {
466
+ if (node && node->doc && node->doc->_private)
467
+ rb_gc_mark((VALUE)node->doc->_private);
468
+ }
469
+
470
+ VALUE Nokogiri_wrap_xml_node(xmlNodePtr node)
471
+ {
472
+ if (node->_private)
473
+ return (VALUE)node->_private ;
474
+ VALUE rb_node = Data_Wrap_Struct(cNokogiriXmlNode, gc_mark_node, deallocate, node) ;
475
+ node->_private = (void*)rb_node ;
476
+ rb_funcall(rb_node, rb_intern("decorate!"), 0);
477
+ return rb_node ;
478
+ }
479
+
480
+
481
+ void Nokogiri_xml_node_properties(xmlNodePtr node, VALUE attr_hash)
482
+ {
483
+ xmlAttrPtr prop;
484
+ xmlChar* propstr ;
485
+ prop = node->properties ;
486
+ while (prop != NULL) {
487
+ propstr = xmlGetProp(node, prop->name) ;
488
+ rb_hash_aset(attr_hash, rb_str_new2((const char*)prop->name),
489
+ rb_str_new2((char*)propstr));
490
+ xmlFree(propstr);
491
+ prop = prop->next ;
492
+ }
493
+ }
494
+
495
+
496
+ #define XMLNS_PREFIX "xmlns"
497
+ #define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */
498
+ #define XMLNS_BUFFER_LEN 128
499
+ void Nokogiri_xml_node_namespaces(xmlNodePtr node, VALUE attr_hash)
500
+ {
501
+ xmlNsPtr ns;
502
+ static char buffer[XMLNS_BUFFER_LEN] ;
503
+ char *key ;
504
+ size_t keylen ;
505
+
506
+ ns = node->nsDef;
507
+ while (ns != NULL) {
508
+
509
+ keylen = XMLNS_PREFIX_LEN + (ns->prefix ? (strlen((const char*)ns->prefix) + 1) : 0) ;
510
+ if (keylen > XMLNS_BUFFER_LEN) {
511
+ key = (char*)malloc(keylen) ;
512
+ } else {
513
+ key = buffer ;
514
+ }
515
+
516
+ if (ns->prefix) {
517
+ sprintf(key, "%s:%s", XMLNS_PREFIX, ns->prefix);
518
+ } else {
519
+ sprintf(key, "%s", XMLNS_PREFIX);
520
+ }
521
+
522
+ rb_hash_aset(attr_hash, rb_str_new2(key), rb_str_new2((const char*)ns->href)) ;
523
+ if (key != buffer) {
524
+ free(key);
525
+ }
526
+ ns = ns->next ;
527
+ }
528
+ }
529
+
530
+
531
+ VALUE cNokogiriXmlNode ;
532
+ void init_xml_node()
533
+ {
534
+ /*
535
+ * HACK. This is so that rdoc will work with this C file.
536
+ */
537
+ /*
538
+ VALUE nokogiri = rb_define_module("Nokogiri");
539
+ VALUE xml = rb_define_module_under(nokogiri, "XML");
540
+ VALUE klass = rb_define_class_under(xml, "Node", rb_cObject);
541
+ */
542
+
543
+ VALUE klass = cNokogiriXmlNode = rb_const_get(mNokogiriXml, rb_intern("Node"));
544
+
545
+ rb_define_singleton_method(klass, "new", new, -1);
546
+ rb_define_singleton_method(klass, "new_from_str", new_from_str, 1);
547
+
548
+ rb_define_method(klass, "document", document, 0);
549
+ rb_define_method(klass, "name", get_name, 0);
550
+ rb_define_method(klass, "name=", set_name, 1);
551
+ rb_define_method(klass, "parent=", set_parent, 1);
552
+ rb_define_method(klass, "parent", get_parent, 0);
553
+ rb_define_method(klass, "child", child, 0);
554
+ rb_define_method(klass, "next_sibling", next_sibling, 0);
555
+ rb_define_method(klass, "previous_sibling", previous_sibling, 0);
556
+ rb_define_method(klass, "replace", replace, 1);
557
+ rb_define_method(klass, "type", type, 0);
558
+ rb_define_method(klass, "content", get_content, 0);
559
+ rb_define_method(klass, "path", path, 0);
560
+ rb_define_method(klass, "key?", key_eh, 1);
561
+ rb_define_method(klass, "blank?", blank_eh, 0);
562
+ rb_define_method(klass, "[]=", set, 2);
563
+ rb_define_method(klass, "remove", remove_prop, 1);
564
+ rb_define_method(klass, "attributes", attributes, 0);
565
+ rb_define_method(klass, "add_previous_sibling", add_previous_sibling, 1);
566
+ rb_define_method(klass, "add_next_sibling", add_next_sibling, 1);
567
+ rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
568
+ rb_define_method(klass, "to_xml", to_xml, 0);
569
+ rb_define_method(klass, "dup", dup, 0);
570
+
571
+ rb_define_private_method(klass, "native_content=", set_content, 1);
572
+ rb_define_private_method(klass, "get", get, 1);
573
+ }