tenderlove-nokogiri 0.0.0.20081001111445

Sign up to get free protection for your applications and to get access to all the features.
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
+ }