libxml-ruby 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/CHANGES +1 -1
  2. data/LICENSE +22 -22
  3. data/README +160 -160
  4. data/Rakefile +0 -9
  5. data/ext/libxml/Makefile +156 -0
  6. data/ext/libxml/extconf.h +5 -0
  7. data/ext/libxml/extconf.rb +4 -160
  8. data/ext/libxml/libxml-ruby.so.a +0 -0
  9. data/ext/libxml/libxml.o +0 -0
  10. data/ext/libxml/libxml_ruby.so +0 -0
  11. data/ext/libxml/mkmf.log +129 -0
  12. data/ext/libxml/ruby_xml.o +0 -0
  13. data/ext/libxml/ruby_xml_attr.c +1 -1
  14. data/ext/libxml/ruby_xml_attr.h +1 -1
  15. data/ext/libxml/ruby_xml_attr.o +0 -0
  16. data/ext/libxml/ruby_xml_attr_decl.o +0 -0
  17. data/ext/libxml/ruby_xml_attributes.o +0 -0
  18. data/ext/libxml/ruby_xml_cbg.o +0 -0
  19. data/ext/libxml/ruby_xml_document.c +936 -936
  20. data/ext/libxml/ruby_xml_document.h +1 -1
  21. data/ext/libxml/ruby_xml_document.o +0 -0
  22. data/ext/libxml/ruby_xml_dtd.o +0 -0
  23. data/ext/libxml/ruby_xml_encoding.o +0 -0
  24. data/ext/libxml/ruby_xml_error.o +0 -0
  25. data/ext/libxml/ruby_xml_html_parser.c +1 -1
  26. data/ext/libxml/ruby_xml_html_parser.h +1 -1
  27. data/ext/libxml/ruby_xml_html_parser.o +0 -0
  28. data/ext/libxml/ruby_xml_html_parser_context.o +0 -0
  29. data/ext/libxml/ruby_xml_html_parser_options.o +0 -0
  30. data/ext/libxml/ruby_xml_input_cbg.o +0 -0
  31. data/ext/libxml/ruby_xml_io.o +0 -0
  32. data/ext/libxml/ruby_xml_namespace.c +1 -1
  33. data/ext/libxml/ruby_xml_namespace.h +1 -1
  34. data/ext/libxml/ruby_xml_namespace.o +0 -0
  35. data/ext/libxml/ruby_xml_namespaces.o +0 -0
  36. data/ext/libxml/ruby_xml_node.c +1386 -1386
  37. data/ext/libxml/ruby_xml_node.h +1 -1
  38. data/ext/libxml/ruby_xml_node.o +0 -0
  39. data/ext/libxml/ruby_xml_parser.c +1 -1
  40. data/ext/libxml/ruby_xml_parser.h +1 -1
  41. data/ext/libxml/ruby_xml_parser.o +0 -0
  42. data/ext/libxml/ruby_xml_parser_context.c +1 -1
  43. data/ext/libxml/ruby_xml_parser_context.h +1 -1
  44. data/ext/libxml/ruby_xml_parser_context.o +0 -0
  45. data/ext/libxml/ruby_xml_parser_options.o +0 -0
  46. data/ext/libxml/ruby_xml_reader.o +0 -0
  47. data/ext/libxml/ruby_xml_relaxng.o +0 -0
  48. data/ext/libxml/ruby_xml_sax2_handler.o +0 -0
  49. data/ext/libxml/ruby_xml_sax_parser.c +1 -1
  50. data/ext/libxml/ruby_xml_sax_parser.h +1 -1
  51. data/ext/libxml/ruby_xml_sax_parser.o +0 -0
  52. data/ext/libxml/ruby_xml_schema.o +0 -0
  53. data/ext/libxml/ruby_xml_version.h +3 -3
  54. data/ext/libxml/ruby_xml_xinclude.c +1 -1
  55. data/ext/libxml/ruby_xml_xinclude.h +1 -1
  56. data/ext/libxml/ruby_xml_xinclude.o +0 -0
  57. data/ext/libxml/ruby_xml_xpath.c +1 -1
  58. data/ext/libxml/ruby_xml_xpath.h +1 -1
  59. data/ext/libxml/ruby_xml_xpath.o +0 -0
  60. data/ext/libxml/ruby_xml_xpath_context.c +1 -1
  61. data/ext/libxml/ruby_xml_xpath_context.h +1 -1
  62. data/ext/libxml/ruby_xml_xpath_context.o +0 -0
  63. data/ext/libxml/ruby_xml_xpath_expression.o +0 -0
  64. data/ext/libxml/ruby_xml_xpath_object.o +0 -0
  65. data/ext/libxml/ruby_xml_xpointer.c +1 -1
  66. data/ext/libxml/ruby_xml_xpointer.h +1 -1
  67. data/ext/libxml/ruby_xml_xpointer.o +0 -0
  68. data/ext/mingw/build.rake +3 -3
  69. data/lib/libxml.rb +29 -29
  70. data/test/model/merge_bug_data.xml +58 -58
  71. data/test/model/rubynet.xml +79 -79
  72. data/test/model/xinclude.xml +4 -4
  73. data/test/tc_attr.rb +170 -170
  74. data/test/tc_document.rb +113 -113
  75. data/test/tc_document_write.rb +117 -117
  76. data/test/tc_dtd.rb +123 -123
  77. data/test/tc_html_parser.rb +137 -137
  78. data/test/tc_node.rb +180 -180
  79. data/test/tc_node_cdata.rb +49 -49
  80. data/test/tc_node_comment.rb +30 -30
  81. data/test/tc_node_edit.rb +157 -157
  82. data/test/tc_node_xlink.rb +26 -26
  83. data/test/tc_parser.rb +329 -329
  84. data/test/tc_parser_context.rb +185 -185
  85. data/test/tc_reader.rb +283 -283
  86. data/test/tc_sax_parser.rb +273 -273
  87. data/test/tc_schema.rb +51 -51
  88. data/test/tc_xinclude.rb +19 -19
  89. data/test/tc_xpath.rb +193 -193
  90. data/test/tc_xpointer.rb +72 -72
  91. metadata +55 -14
  92. data/ext/libxml/build.log +0 -4
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_document.h 758 2009-01-25 20:36:03Z cfis $ */
1
+ /* $Id$ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
Binary file
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_html_parser.c 758 2009-01-25 20:36:03Z cfis $ */
1
+ /* $Id$ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_html_parser.h 758 2009-01-25 20:36:03Z cfis $ */
1
+ /* $Id$ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
Binary file
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_namespace.c 758 2009-01-25 20:36:03Z cfis $ */
1
+ /* $Id$ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_namespace.h 758 2009-01-25 20:36:03Z cfis $ */
1
+ /* $Id$ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -1,1386 +1,1386 @@
1
- #include "ruby_libxml.h"
2
- #include "ruby_xml_node.h"
3
- #include <assert.h>
4
-
5
- VALUE cXMLNode;
6
-
7
- /* Document-class: LibXML::XML::Node
8
- *
9
- * Nodes are the primary objects that make up an XML document.
10
- * The node class represents most node types that are found in
11
- * an XML document (but not LibXML::XML::Attributes, see LibXML::XML::Attr).
12
- * It exposes libxml's full API for creating, querying
13
- * moving and deleting node objects. Many of these methods are
14
- * documented in the DOM Level 3 specification found at:
15
- * http://www.w3.org/TR/DOM-Level-3-Core/. */
16
-
17
-
18
- /* Memory management:
19
- *
20
- * The bindings create a one-to-one mapping between libxml nodes
21
- * and Ruby nodes. If a libxml node is wraped, its _private member
22
- * is set with a reference to the Ruby object.
23
- *
24
- * When a libxml document or top level node is freed, it will free
25
- * all its children. Thus Ruby is responsible for:
26
- *
27
- * * Using the mark function to keep alive any documents Ruby is
28
- * referencing via the document or child nodes.
29
- * * Using the mark function to keep alive any top level, free
30
- * standing nodes Ruby is referencing via the node or its children.
31
- *
32
- * In general use, this will cause Ruby nodes to be freed before
33
- * a libxml document. When a Ruby node is freed, the _private
34
- * field is set back to null.
35
- *
36
- * In the sweep phase in Ruby 1.9.1, the document is freed before
37
- * the nodes. To support that, the bindingds register a callback
38
- * function with libxml that is called each time a node is freed.
39
- * In that case, the data_ptr is set to null, so the bindings
40
- * can recognize the situtation.
41
- */
42
-
43
- static void rxml_node_deregisterNode(xmlNodePtr xnode)
44
- {
45
- /* Has the node been wrapped and exposed to Ruby? */
46
- if (xnode->_private)
47
- {
48
- /* Node was wrapped. Set the _private member to free and
49
- then dislabe the dfree function so that Ruby will not
50
- try to free the node a second time. */
51
- VALUE node = (VALUE) xnode->_private;
52
- RDATA(node)->data = NULL;
53
- }
54
- }
55
-
56
- static void rxml_node_free(xmlNodePtr xnode)
57
- {
58
- /* Either the node has been created yet in initialize
59
- or it has been freed by libxml already in Ruby's
60
- mark phase. */
61
- if (xnode == NULL)
62
- return;
63
-
64
- /* The ruby object wrapping the xml object no longer exists. */
65
- xnode->_private = NULL;
66
-
67
- /* Ruby is responsible for freeing this node since it
68
- has no parent. */
69
- if (xnode->parent == NULL)
70
- xmlFreeNode(xnode);
71
- }
72
-
73
- void rxml_node_mark(xmlNodePtr xnode)
74
- {
75
- /* Either the node has been created yet in initialize
76
- or it has been freed by libxml already in Ruby's
77
- mark phase. */
78
- if (xnode == NULL)
79
- return;
80
-
81
- if (xnode->doc != NULL)
82
- rb_gc_mark((VALUE) xnode->doc->_private);
83
-
84
- if (xnode->parent != NULL)
85
- rb_gc_mark((VALUE) xnode->_private);
86
- }
87
-
88
- VALUE rxml_node_wrap(xmlNodePtr xnode)
89
- {
90
- /* Is the node already wrapped? */
91
- if (xnode->_private != NULL)
92
- {
93
- return (VALUE) xnode->_private;
94
- }
95
- else
96
- {
97
- VALUE node = Data_Wrap_Struct(cXMLNode, rxml_node_mark, rxml_node_free, xnode);
98
- xnode->_private = (void*) node;
99
- return node;
100
- }
101
- }
102
-
103
- static VALUE rxml_node_alloc(VALUE klass)
104
- {
105
- /* Ruby is responsible for freeing this node not libxml but don't set
106
- up mark and free yet until we assign the node. */
107
- return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node_free, NULL);
108
- }
109
-
110
- /*
111
- * call-seq:
112
- * XML::Node.new_cdata(content = nil) -> XML::Node
113
- *
114
- * Create a new #CDATA node, optionally setting
115
- * the node's content.
116
- */
117
- static VALUE rxml_node_new_cdata(int argc, VALUE *argv, VALUE klass)
118
- {
119
- VALUE content = Qnil;
120
- xmlNodePtr xnode;
121
-
122
- rb_scan_args(argc, argv, "01", &content);
123
-
124
- if (NIL_P(content))
125
- {
126
- xnode = xmlNewCDataBlock(NULL, NULL, 0);
127
- }
128
- else
129
- {
130
- content = rb_obj_as_string(content);
131
- xnode = xmlNewCDataBlock(NULL, (xmlChar*) StringValuePtr(content),
132
- RSTRING_LEN(content));
133
- }
134
-
135
- if (xnode == NULL)
136
- rxml_raise(&xmlLastError);
137
-
138
- return rxml_node_wrap(xnode);
139
- }
140
-
141
- /*
142
- * call-seq:
143
- * XML::Node.new_comment(content = nil) -> XML::Node
144
- *
145
- * Create a new comment node, optionally setting
146
- * the node's content.
147
- *
148
- */
149
- static VALUE rxml_node_new_comment(int argc, VALUE *argv, VALUE klass)
150
- {
151
- VALUE content = Qnil;
152
- xmlNodePtr xnode;
153
-
154
- rb_scan_args(argc, argv, "01", &content);
155
-
156
- if (NIL_P(content))
157
- {
158
- xnode = xmlNewComment(NULL);
159
- }
160
- else
161
- {
162
- content = rb_obj_as_string(content);
163
- xnode = xmlNewComment((xmlChar*) StringValueCStr(content));
164
- }
165
-
166
- if (xnode == NULL)
167
- rxml_raise(&xmlLastError);
168
-
169
- return rxml_node_wrap(xnode);
170
- }
171
-
172
- /*
173
- * call-seq:
174
- * XML::Node.new_text(content) -> XML::Node
175
- *
176
- * Create a new text node.
177
- *
178
- */
179
- static VALUE rxml_node_new_text(VALUE klass, VALUE content)
180
- {
181
- xmlNodePtr xnode;
182
- Check_Type(content, T_STRING);
183
- content = rb_obj_as_string(content);
184
-
185
- xnode = xmlNewText((xmlChar*) StringValueCStr(content));
186
-
187
- if (xnode == NULL)
188
- rxml_raise(&xmlLastError);
189
-
190
- return rxml_node_wrap(xnode);
191
- }
192
-
193
- static VALUE rxml_node_content_set(VALUE self, VALUE content);
194
-
195
- /*
196
- * call-seq:
197
- * XML::Node.initialize(name, content = nil, namespace = nil) -> XML::Node
198
- *
199
- * Creates a new element with the specified name, content and
200
- * namespace. The content and namespace may be nil.
201
- */
202
- static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self)
203
- {
204
- VALUE name;
205
- VALUE content;
206
- VALUE ns;
207
- xmlNodePtr xnode = NULL;
208
- xmlNsPtr xns = NULL;
209
-
210
- rb_scan_args(argc, argv, "12", &name, &content, &ns);
211
-
212
- name = rb_obj_as_string(name);
213
-
214
- if (!NIL_P(ns))
215
- Data_Get_Struct(ns, xmlNs, xns);
216
-
217
- xnode = xmlNewNode(xns, (xmlChar*) StringValuePtr(name));
218
-
219
- if (xnode == NULL)
220
- rxml_raise(&xmlLastError);
221
-
222
- /* Link the Ruby object to the libxml object and vice-versa. */
223
- xnode->_private = (void*) self;
224
- DATA_PTR(self) = xnode;
225
-
226
- if (!NIL_P(content))
227
- rxml_node_content_set(self, content);
228
-
229
- return self;
230
- }
231
-
232
- static VALUE rxml_node_modify_dom(VALUE self, VALUE target,
233
- xmlNodePtr (*xmlFunc)(xmlNodePtr, xmlNodePtr))
234
- {
235
- xmlNodePtr xnode, xtarget, xresult;
236
-
237
- if (rb_obj_is_kind_of(target, cXMLNode) == Qfalse)
238
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
239
-
240
- Data_Get_Struct(self, xmlNode, xnode);
241
- Data_Get_Struct(target, xmlNode, xtarget);
242
-
243
- if (xtarget->doc != NULL && xtarget->doc != xnode->doc)
244
- rb_raise(eXMLError, "Nodes belong to different documents. You must first import the by calling XML::Document.import");
245
-
246
- /* This target node could be freed here. */
247
- xresult = xmlFunc(xnode, xtarget);
248
-
249
- if (!xresult)
250
- rxml_raise(&xmlLastError);
251
-
252
- /* Was the target freed? If yes, then wrap the new node */
253
- if (xresult != xtarget)
254
- {
255
- RDATA(target)->data = xresult;
256
- xresult->_private = (void*) target;
257
- }
258
-
259
- return target;
260
- }
261
-
262
- /*
263
- * call-seq:
264
- * node.base_uri -> "uri"
265
- *
266
- * Obtain this node's base URI.
267
- */
268
- static VALUE rxml_node_base_uri_get(VALUE self)
269
- {
270
- xmlNodePtr xnode;
271
- xmlChar* base_uri;
272
- VALUE result = Qnil;
273
-
274
- Data_Get_Struct(self, xmlNode, xnode);
275
-
276
- if (xnode->doc == NULL)
277
- return (result);
278
-
279
- base_uri = xmlNodeGetBase(xnode->doc, xnode);
280
- if (base_uri)
281
- {
282
- result = rb_str_new2((const char*) base_uri);
283
- xmlFree(base_uri);
284
- }
285
-
286
- return (result);
287
- }
288
-
289
- // TODO node_base_set should support setting back to nil
290
-
291
- /*
292
- * call-seq:
293
- * node.base_uri = "uri"
294
- *
295
- * Set this node's base URI.
296
- */
297
- static VALUE rxml_node_base_uri_set(VALUE self, VALUE uri)
298
- {
299
- xmlNodePtr xnode;
300
-
301
- Check_Type(uri, T_STRING);
302
- Data_Get_Struct(self, xmlNode, xnode);
303
- if (xnode->doc == NULL)
304
- return (Qnil);
305
-
306
- xmlNodeSetBase(xnode, (xmlChar*) StringValuePtr(uri));
307
- return (Qtrue);
308
- }
309
-
310
- /*
311
- * call-seq:
312
- * node.content -> "string"
313
- *
314
- * Obtain this node's content as a string.
315
- */
316
- static VALUE rxml_node_content_get(VALUE self)
317
- {
318
- xmlNodePtr xnode;
319
- xmlChar *content;
320
- VALUE result = Qnil;
321
-
322
- Data_Get_Struct(self, xmlNode, xnode);
323
- content = xmlNodeGetContent(xnode);
324
- if (content)
325
- {
326
- result = rb_str_new2((const char *) content);
327
- xmlFree(content);
328
- }
329
-
330
- return result;
331
- }
332
-
333
- /*
334
- * call-seq:
335
- * node.content = "string"
336
- *
337
- * Set this node's content to the specified string.
338
- */
339
- static VALUE rxml_node_content_set(VALUE self, VALUE content)
340
- {
341
- xmlNodePtr xnode;
342
-
343
- Check_Type(content, T_STRING);
344
- Data_Get_Struct(self, xmlNode, xnode);
345
- // XXX docs indicate need for escaping entites, need to be done? danj
346
- xmlNodeSetContent(xnode, (xmlChar*) StringValuePtr(content));
347
- return (Qtrue);
348
- }
349
-
350
- /*
351
- * call-seq:
352
- * node.content_stripped -> "string"
353
- *
354
- * Obtain this node's stripped content.
355
- *
356
- * *Deprecated*: Stripped content can be obtained via the
357
- * +content+ method.
358
- */
359
- static VALUE rxml_node_content_stripped_get(VALUE self)
360
- {
361
- xmlNodePtr xnode;
362
- xmlChar* content;
363
- VALUE result = Qnil;
364
-
365
- Data_Get_Struct(self, xmlNode, xnode);
366
-
367
- if (!xnode->content)
368
- return result;
369
-
370
- content = xmlNodeGetContent(xnode);
371
- if (content)
372
- {
373
- result = rb_str_new2((const char*) content);
374
- xmlFree(content);
375
- }
376
- return (result);
377
- }
378
-
379
- /*
380
- * call-seq:
381
- * node.debug -> true|false
382
- *
383
- * Print libxml debugging information to stdout.
384
- * Requires that libxml was compiled with debugging enabled.
385
- */
386
- static VALUE rxml_node_debug(VALUE self)
387
- {
388
- #ifdef LIBXML_DEBUG_ENABLED
389
- xmlNodePtr xnode;
390
- Data_Get_Struct(self, xmlNode, xnode);
391
- xmlDebugDumpNode(NULL, xnode, 2);
392
- return Qtrue;
393
- #else
394
- rb_warn("libxml was compiled without debugging support.")
395
- return Qfalse;
396
- #endif
397
- }
398
-
399
- /*
400
- * call-seq:
401
- * node.first -> XML::Node
402
- *
403
- * Returns this node's first child node if any.
404
- */
405
- static VALUE rxml_node_first_get(VALUE self)
406
- {
407
- xmlNodePtr xnode;
408
-
409
- Data_Get_Struct(self, xmlNode, xnode);
410
-
411
- if (xnode->children)
412
- return (rxml_node_wrap(xnode->children));
413
- else
414
- return (Qnil);
415
- }
416
-
417
-
418
- /*
419
- * call-seq:
420
- * curr_node << "<p>A paragraph</p>"
421
- * curr_node << node
422
- *
423
- * Add the specified text or XML::Node as a new child node to the
424
- * current node.
425
- *
426
- * If the specified argument is a string, it should be a raw string
427
- * that contains unescaped XML special characters. Entity references
428
- * are not supported.
429
- *
430
- * The method will return the current node.
431
- */
432
- static VALUE rxml_node_content_add(VALUE self, VALUE obj)
433
- {
434
- xmlNodePtr xnode;
435
- VALUE str;
436
-
437
- Data_Get_Struct(self, xmlNode, xnode);
438
- /* XXX This should only be legal for a CDATA type node, I think,
439
- * resulting in a merge of content, as if a string were passed
440
- * danj 070827
441
- */
442
- if (rb_obj_is_kind_of(obj, cXMLNode))
443
- {
444
- xmlNodePtr xtarget;
445
- Data_Get_Struct(obj, xmlNode, xtarget);
446
- xmlUnlinkNode(xtarget);
447
- rxml_node_modify_dom(self, obj, xmlAddChild);
448
- }
449
- else
450
- {
451
- str = rb_obj_as_string(obj);
452
- if (NIL_P(str) || TYPE(str) != T_STRING)
453
- rb_raise(rb_eTypeError, "invalid argument: must be string or XML::Node");
454
-
455
- xmlNodeAddContent(xnode, (xmlChar*) StringValuePtr(str));
456
- }
457
- return self;
458
- }
459
-
460
- /*
461
- * call-seq:
462
- * node.doc -> document
463
- *
464
- * Obtain the XML::Document this node belongs to.
465
- */
466
- static VALUE rxml_node_doc(VALUE self)
467
- {
468
- xmlNodePtr xnode;
469
- xmlDocPtr doc = NULL;
470
-
471
- Data_Get_Struct(self, xmlNode, xnode);
472
-
473
- switch (xnode->type)
474
- {
475
- case XML_DOCUMENT_NODE:
476
- #ifdef LIBXML_DOCB_ENABLED
477
- case XML_DOCB_DOCUMENT_NODE:
478
- #endif
479
- case XML_HTML_DOCUMENT_NODE:
480
- doc = NULL;
481
- break;
482
- case XML_ATTRIBUTE_NODE:
483
- {
484
- xmlAttrPtr attr = (xmlAttrPtr) xnode;
485
- doc = attr->doc;
486
- break;
487
- }
488
- case XML_NAMESPACE_DECL:
489
- doc = NULL;
490
- break;
491
- default:
492
- doc = xnode->doc;
493
- break;
494
- }
495
-
496
- if (doc == NULL)
497
- return (Qnil);
498
-
499
- if (doc->_private == NULL)
500
- rb_raise(rb_eRuntimeError, "existing document object has no ruby-instance");
501
-
502
- return (VALUE) doc->_private;
503
- }
504
-
505
- /*
506
- * call-seq:
507
- * node.to_s -> "string"
508
- * node.to_s(:indent => true, :encoding => 'UTF-8', :level => 0) -> "string"
509
- *
510
- * Converts a node, and all of its children, to a string representation.
511
- * To include only the node's children, use the the XML::Node#inner_xml
512
- * method.
513
- *
514
- * You may provide an optional hash table to control how the string is
515
- * generated. Valid options are:
516
- *
517
- * :indent - Specifies if the string should be indented. The default value
518
- * is true. Note that indentation is only added if both :indent is
519
- * true and XML.indent_tree_output is true. If :indent is set to false,
520
- * then both indentation and line feeds are removed from the result.
521
- *
522
- * :level - Specifies the indentation level. The amount of indentation
523
- * is equal to the (level * number_spaces) + number_spaces, where libxml
524
- * defaults the number of spaces to 2. Thus a level of 0 results in
525
- * 2 spaces, level 1 results in 4 spaces, level 2 results in 6 spaces, etc.
526
- *
527
- * :encoding - Specifies the output encoding of the string. It
528
- * defaults to XML::Encoding::UTF8. To change it, use one of the
529
- * XML::Encoding encoding constants. */
530
-
531
- static VALUE rxml_node_to_s(int argc, VALUE *argv, VALUE self)
532
- {
533
- VALUE result = Qnil;
534
- VALUE options = Qnil;
535
- xmlNodePtr xnode;
536
- xmlCharEncodingHandlerPtr encodingHandler;
537
- xmlOutputBufferPtr output;
538
-
539
- int level = 0;
540
- int indent = 1;
541
- const char *xencoding = NULL;
542
-
543
- rb_scan_args(argc, argv, "01", &options);
544
-
545
- if (!NIL_P(options))
546
- {
547
- VALUE rencoding, rindent, rlevel;
548
- Check_Type(options, T_HASH);
549
- rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
550
- rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
551
- rlevel = rb_hash_aref(options, ID2SYM(rb_intern("level")));
552
-
553
- if (rindent == Qfalse)
554
- indent = 0;
555
-
556
- if (rlevel != Qnil)
557
- level = NUM2INT(rlevel);
558
-
559
- if (rencoding != Qnil)
560
- {
561
- xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
562
- if (!xencoding)
563
- rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
564
- }
565
- }
566
-
567
- encodingHandler = xmlFindCharEncodingHandler(xencoding);
568
- output = xmlAllocOutputBuffer(encodingHandler);
569
-
570
- Data_Get_Struct(self, xmlNode, xnode);
571
- xmlNodeDumpOutput(output, xnode->doc, xnode, level, indent, xencoding);
572
- xmlOutputBufferFlush(output);
573
-
574
- if (output->conv)
575
- result = rb_str_new2((const char*) output->conv->content);
576
- else
577
- result = rb_str_new2((const char*) output->buffer->content);
578
-
579
- xmlOutputBufferClose(output);
580
-
581
- return result;
582
- }
583
-
584
-
585
- /*
586
- * call-seq:
587
- * node.each -> XML::Node
588
- *
589
- * Iterates over this node's children, including text
590
- * nodes, element nodes, etc. If you wish to iterate
591
- * only over child elements, use XML::Node#each_element.
592
- *
593
- * doc = XML::Document.new('model/books.xml')
594
- * doc.root.each {|node| puts node}
595
- */
596
- static VALUE rxml_node_each(VALUE self)
597
- {
598
- xmlNodePtr xnode;
599
- xmlNodePtr xcurrent;
600
- Data_Get_Struct(self, xmlNode, xnode);
601
-
602
- xcurrent = xnode->children;
603
-
604
- while (xcurrent)
605
- {
606
- /* The user could remove this node, so first stache
607
- away the next node. */
608
- xmlNodePtr xnext = xcurrent->next;
609
-
610
- rb_yield(rxml_node_wrap(xcurrent));
611
- xcurrent = xnext;
612
- }
613
- return Qnil;
614
- }
615
-
616
- /*
617
- * call-seq:
618
- * node.empty? -> (true|false)
619
- *
620
- * Determine whether this node is empty.
621
- */
622
- static VALUE rxml_node_empty_q(VALUE self)
623
- {
624
- xmlNodePtr xnode;
625
- Data_Get_Struct(self, xmlNode, xnode);
626
- if (xnode == NULL)
627
- return (Qnil);
628
-
629
- return ((xmlIsBlankNode(xnode) == 1) ? Qtrue : Qfalse);
630
- }
631
-
632
-
633
- /*
634
- * call-seq:
635
- * node.eql?(other_node) => (true|false)
636
- *
637
- * Test equality between the two nodes. Two nodes are equal
638
- * if they are the same node or have the same XML representation.*/
639
- static VALUE rxml_node_eql_q(VALUE self, VALUE other)
640
- {
641
- if(self == other)
642
- {
643
- return Qtrue;
644
- }
645
- else if (NIL_P(other))
646
- {
647
- return Qfalse;
648
- }
649
- else
650
- {
651
- VALUE self_xml;
652
- VALUE other_xml;
653
-
654
- if (rb_obj_is_kind_of(other, cXMLNode) == Qfalse)
655
- rb_raise(rb_eTypeError, "Nodes can only be compared against other nodes");
656
-
657
- self_xml = rxml_node_to_s(0, NULL, self);
658
- other_xml = rxml_node_to_s(0, NULL, other);
659
- return(rb_funcall(self_xml, rb_intern("=="), 1, other_xml));
660
- }
661
- }
662
-
663
- /*
664
- * call-seq:
665
- * node.lang -> "string"
666
- *
667
- * Obtain the language set for this node, if any.
668
- * This is set in XML via the xml:lang attribute.
669
- */
670
- static VALUE rxml_node_lang_get(VALUE self)
671
- {
672
- xmlNodePtr xnode;
673
- xmlChar *lang;
674
- VALUE result = Qnil;
675
-
676
- Data_Get_Struct(self, xmlNode, xnode);
677
- lang = xmlNodeGetLang(xnode);
678
-
679
- if (lang)
680
- {
681
- result = rb_str_new2((const char*) lang);
682
- xmlFree(lang);
683
- }
684
-
685
- return (result);
686
- }
687
-
688
- // TODO node_lang_set should support setting back to nil
689
-
690
- /*
691
- * call-seq:
692
- * node.lang = "string"
693
- *
694
- * Set the language for this node. This affects the value
695
- * of the xml:lang attribute.
696
- */
697
- static VALUE rxml_node_lang_set(VALUE self, VALUE lang)
698
- {
699
- xmlNodePtr xnode;
700
-
701
- Check_Type(lang, T_STRING);
702
- Data_Get_Struct(self, xmlNode, xnode);
703
- xmlNodeSetLang(xnode, (xmlChar*) StringValuePtr(lang));
704
-
705
- return (Qtrue);
706
- }
707
-
708
- /*
709
- * call-seq:
710
- * node.last -> XML::Node
711
- *
712
- * Obtain the last child node of this node, if any.
713
- */
714
- static VALUE rxml_node_last_get(VALUE self)
715
- {
716
- xmlNodePtr xnode;
717
-
718
- Data_Get_Struct(self, xmlNode, xnode);
719
-
720
- if (xnode->last)
721
- return (rxml_node_wrap(xnode->last));
722
- else
723
- return (Qnil);
724
- }
725
-
726
- /*
727
- * call-seq:
728
- * node.line_num -> num
729
- *
730
- * Obtain the line number (in the XML document) that this
731
- * node was read from. If +default_line_numbers+ is set
732
- * false (the default), this method returns zero.
733
- */
734
- static VALUE rxml_node_line_num(VALUE self)
735
- {
736
- xmlNodePtr xnode;
737
- long line_num;
738
- Data_Get_Struct(self, xmlNode, xnode);
739
-
740
- if (!xmlLineNumbersDefaultValue)
741
- rb_warn(
742
- "Line numbers were not retained: use XML::Parser::default_line_numbers=true");
743
-
744
- line_num = xmlGetLineNo(xnode);
745
- if (line_num == -1)
746
- return (Qnil);
747
- else
748
- return (INT2NUM((long) line_num));
749
- }
750
-
751
- /*
752
- * call-seq:
753
- * node.xlink? -> (true|false)
754
- *
755
- * Determine whether this node is an xlink node.
756
- */
757
- static VALUE rxml_node_xlink_q(VALUE self)
758
- {
759
- xmlNodePtr xnode;
760
- xlinkType xlt;
761
-
762
- Data_Get_Struct(self, xmlNode, xnode);
763
- xlt = xlinkIsLink(xnode->doc, xnode);
764
-
765
- if (xlt == XLINK_TYPE_NONE)
766
- return (Qfalse);
767
- else
768
- return (Qtrue);
769
- }
770
-
771
- /*
772
- * call-seq:
773
- * node.xlink_type -> num
774
- *
775
- * Obtain the type identifier for this xlink, if applicable.
776
- * If this is not an xlink node (see +xlink?+), will return
777
- * nil.
778
- */
779
- static VALUE rxml_node_xlink_type(VALUE self)
780
- {
781
- xmlNodePtr xnode;
782
- xlinkType xlt;
783
-
784
- Data_Get_Struct(self, xmlNode, xnode);
785
- xlt = xlinkIsLink(xnode->doc, xnode);
786
-
787
- if (xlt == XLINK_TYPE_NONE)
788
- return (Qnil);
789
- else
790
- return (INT2NUM(xlt));
791
- }
792
-
793
- /*
794
- * call-seq:
795
- * node.xlink_type_name -> "string"
796
- *
797
- * Obtain the type name for this xlink, if applicable.
798
- * If this is not an xlink node (see +xlink?+), will return
799
- * nil.
800
- */
801
- static VALUE rxml_node_xlink_type_name(VALUE self)
802
- {
803
- xmlNodePtr xnode;
804
- xlinkType xlt;
805
-
806
- Data_Get_Struct(self, xmlNode, xnode);
807
- xlt = xlinkIsLink(xnode->doc, xnode);
808
-
809
- switch (xlt)
810
- {
811
- case XLINK_TYPE_NONE:
812
- return (Qnil);
813
- case XLINK_TYPE_SIMPLE:
814
- return (rb_str_new2("simple"));
815
- case XLINK_TYPE_EXTENDED:
816
- return (rb_str_new2("extended"));
817
- case XLINK_TYPE_EXTENDED_SET:
818
- return (rb_str_new2("extended_set"));
819
- default:
820
- rb_fatal("Unknowng xlink type, %d", xlt);
821
- }
822
- }
823
-
824
- /*
825
- * call-seq:
826
- * node.name -> "string"
827
- *
828
- * Obtain this node's name.
829
- */
830
- static VALUE rxml_node_name_get(VALUE self)
831
- {
832
- xmlNodePtr xnode;
833
- const xmlChar *name;
834
-
835
- Data_Get_Struct(self, xmlNode, xnode);
836
-
837
- switch (xnode->type)
838
- {
839
- case XML_DOCUMENT_NODE:
840
- #ifdef LIBXML_DOCB_ENABLED
841
- case XML_DOCB_DOCUMENT_NODE:
842
- #endif
843
- case XML_HTML_DOCUMENT_NODE:
844
- {
845
- xmlDocPtr doc = (xmlDocPtr) xnode;
846
- name = doc->URL;
847
- break;
848
- }
849
- case XML_ATTRIBUTE_NODE:
850
- {
851
- xmlAttrPtr attr = (xmlAttrPtr) xnode;
852
- name = attr->name;
853
- break;
854
- }
855
- case XML_NAMESPACE_DECL:
856
- {
857
- xmlNsPtr ns = (xmlNsPtr) xnode;
858
- name = ns->prefix;
859
- break;
860
- }
861
- default:
862
- name = xnode->name;
863
- break;
864
- }
865
-
866
- if (xnode->name == NULL)
867
- return (Qnil);
868
- else
869
- return (rb_str_new2((const char*) name));
870
- }
871
-
872
- /*
873
- * call-seq:
874
- * node.name = "string"
875
- *
876
- * Set this node's name.
877
- */
878
- static VALUE rxml_node_name_set(VALUE self, VALUE name)
879
- {
880
- xmlNodePtr xnode;
881
- const xmlChar *xname;
882
-
883
- Check_Type(name, T_STRING);
884
- Data_Get_Struct(self, xmlNode, xnode);
885
- xname = (const xmlChar*)StringValuePtr(name);
886
-
887
- /* Note: calling xmlNodeSetName() for a text node is ignored by libXML. */
888
- xmlNodeSetName(xnode, xname);
889
-
890
- return (Qtrue);
891
- }
892
-
893
- /*
894
- * call-seq:
895
- * node.next -> XML::Node
896
- *
897
- * Returns the next sibling node if one exists.
898
- */
899
- static VALUE rxml_node_next_get(VALUE self)
900
- {
901
- xmlNodePtr xnode;
902
-
903
- Data_Get_Struct(self, xmlNode, xnode);
904
-
905
- if (xnode->next)
906
- return (rxml_node_wrap(xnode->next));
907
- else
908
- return (Qnil);
909
- }
910
-
911
- /*
912
- * call-seq:
913
- * curr_node.next = node
914
- *
915
- * Adds the specified node as the next sibling of the current node.
916
- * If the node already exists in the document, it is first removed
917
- * from its existing context. Any adjacent text nodes will be
918
- * merged together, meaning the returned node may be different
919
- * than the original node.
920
- */
921
- static VALUE rxml_node_next_set(VALUE self, VALUE next)
922
- {
923
- return rxml_node_modify_dom(self, next, xmlAddNextSibling);
924
- }
925
-
926
- /*
927
- * call-seq:
928
- * node.parent -> XML::Node
929
- *
930
- * Obtain this node's parent node, if any.
931
- */
932
- static VALUE rxml_node_parent_get(VALUE self)
933
- {
934
- xmlNodePtr xnode;
935
-
936
- Data_Get_Struct(self, xmlNode, xnode);
937
-
938
- if (xnode->parent)
939
- return (rxml_node_wrap(xnode->parent));
940
- else
941
- return (Qnil);
942
- }
943
-
944
- /*
945
- * call-seq:
946
- * node.path -> path
947
- *
948
- * Obtain this node's path.
949
- */
950
- static VALUE rxml_node_path(VALUE self)
951
- {
952
- xmlNodePtr xnode;
953
- xmlChar *path;
954
-
955
- Data_Get_Struct(self, xmlNode, xnode);
956
- path = xmlGetNodePath(xnode);
957
-
958
- if (path == NULL)
959
- return (Qnil);
960
- else
961
- return (rb_str_new2((const char*) path));
962
- }
963
-
964
- /*
965
- * call-seq:
966
- * node.pointer -> XML::NodeSet
967
- *
968
- * Evaluates an XPointer expression relative to this node.
969
- */
970
- static VALUE rxml_node_pointer(VALUE self, VALUE xptr_str)
971
- {
972
- return (rxml_xpointer_point2(self, xptr_str));
973
- }
974
-
975
- /*
976
- * call-seq:
977
- * node.prev -> XML::Node
978
- *
979
- * Obtain the previous sibling, if any.
980
- */
981
- static VALUE rxml_node_prev_get(VALUE self)
982
- {
983
- xmlNodePtr xnode;
984
- xmlNodePtr node;
985
- Data_Get_Struct(self, xmlNode, xnode);
986
-
987
- switch (xnode->type)
988
- {
989
- case XML_DOCUMENT_NODE:
990
- #ifdef LIBXML_DOCB_ENABLED
991
- case XML_DOCB_DOCUMENT_NODE:
992
- #endif
993
- case XML_HTML_DOCUMENT_NODE:
994
- case XML_NAMESPACE_DECL:
995
- node = NULL;
996
- break;
997
- case XML_ATTRIBUTE_NODE:
998
- {
999
- xmlAttrPtr attr = (xmlAttrPtr) xnode;
1000
- node = (xmlNodePtr) attr->prev;
1001
- }
1002
- break;
1003
- default:
1004
- node = xnode->prev;
1005
- break;
1006
- }
1007
-
1008
- if (node == NULL)
1009
- return (Qnil);
1010
- else
1011
- return (rxml_node_wrap(node));
1012
- }
1013
-
1014
- /*
1015
- * call-seq:
1016
- * curr_node.prev = node
1017
- *
1018
- * Adds the specified node as the previous sibling of the current node.
1019
- * If the node already exists in the document, it is first removed
1020
- * from its existing context. Any adjacent text nodes will be
1021
- * merged together, meaning the returned node may be different
1022
- * than the original node.
1023
- */
1024
- static VALUE rxml_node_prev_set(VALUE self, VALUE prev)
1025
- {
1026
- return rxml_node_modify_dom(self, prev, xmlAddPrevSibling);
1027
- }
1028
-
1029
- /*
1030
- * call-seq:
1031
- * node.attributes -> attributes
1032
- *
1033
- * Returns the XML::Attributes for this node.
1034
- */
1035
- static VALUE rxml_node_attributes_get(VALUE self)
1036
- {
1037
- xmlNodePtr xnode;
1038
-
1039
- Data_Get_Struct(self, xmlNode, xnode);
1040
- return rxml_attributes_new(xnode);
1041
- }
1042
-
1043
- /*
1044
- * call-seq:
1045
- * node.property("name") -> "string"
1046
- * node["name"] -> "string"
1047
- *
1048
- * Obtain the named pyroperty.
1049
- */
1050
- static VALUE rxml_node_attribute_get(VALUE self, VALUE name)
1051
- {
1052
- VALUE attributes = rxml_node_attributes_get(self);
1053
- return rxml_attributes_attribute_get(attributes, name);
1054
- }
1055
-
1056
- /*
1057
- * call-seq:
1058
- * node["name"] = "string"
1059
- *
1060
- * Set the named property.
1061
- */
1062
- static VALUE rxml_node_property_set(VALUE self, VALUE name, VALUE value)
1063
- {
1064
- VALUE attributes = rxml_node_attributes_get(self);
1065
- return rxml_attributes_attribute_set(attributes, name, value);
1066
- }
1067
-
1068
- /*
1069
- * call-seq:
1070
- * node.remove! -> node
1071
- *
1072
- * Removes this node and its children from the document tree by setting its document,
1073
- * parent and siblings to nil. You can add the returned node back into a document.
1074
- * Otherwise, the node will be freed once any references to it go out of scope.
1075
- */
1076
-
1077
- static VALUE rxml_node_remove_ex(VALUE self)
1078
- {
1079
- xmlNodePtr xnode, xresult;
1080
- Data_Get_Struct(self, xmlNode, xnode);
1081
-
1082
- /* First unlink the node from its parent. */
1083
- xmlUnlinkNode(xnode);
1084
-
1085
- /* Now copy the node we want to remove and make the
1086
- current Ruby object point to it. We do this because
1087
- a node has a number of dependencies on its parent
1088
- document - its name (if using a dictionary), entities,
1089
- namespaces, etc. For a node to live on its own, it
1090
- needs to get its own copies of this information.*/
1091
- xresult = xmlDocCopyNode(xnode, NULL, 1);
1092
-
1093
- /* Now free the original node. */
1094
- xmlFreeNode(xnode);
1095
-
1096
- /* Now wrap the new node */
1097
- RDATA(self)->data = xresult;
1098
- xresult->_private = (void*) self;
1099
-
1100
- /* Now return the removed node so the user can
1101
- do something with it.*/
1102
- return self;
1103
- }
1104
-
1105
- /*
1106
- * call-seq:
1107
- * curr_node.sibling = node
1108
- *
1109
- * Adds the specified node as the end of the current node's list
1110
- * of siblings. If the node already exists in the document, it
1111
- * is first removed from its existing context. Any adjacent text
1112
- * nodes will be merged together, meaning the returned node may
1113
- * be different than the original node.
1114
- */
1115
- static VALUE rxml_node_sibling_set(VALUE self, VALUE sibling)
1116
- {
1117
- return rxml_node_modify_dom(self, sibling, xmlAddSibling);
1118
- }
1119
-
1120
- /*
1121
- * call-seq:
1122
- * text_node.output_escaping? -> (true|false)
1123
- * element_node.output_escaping? -> (true|false|nil)
1124
- * attribute_node.output_escaping? -> (true|false|nil)
1125
- * other_node.output_escaping? -> (nil)
1126
- *
1127
- * Determine whether this node escapes it's output or not.
1128
- *
1129
- * Text nodes return only +true+ or +false+. Element and attribute nodes
1130
- * examine their immediate text node children to determine the value.
1131
- * Any other type of node always returns +nil+.
1132
- *
1133
- * If an element or attribute node has at least one immediate child text node
1134
- * and all the immediate text node children have the same +output_escaping?+
1135
- * value, that value is returned. Otherwise, +nil+ is returned.
1136
- */
1137
- static VALUE rxml_node_output_escaping_q(VALUE self)
1138
- {
1139
- xmlNodePtr xnode;
1140
- Data_Get_Struct(self, xmlNode, xnode);
1141
-
1142
- switch (xnode->type) {
1143
- case XML_TEXT_NODE:
1144
- return xnode->name==xmlStringTextNoenc ? Qfalse : Qtrue;
1145
- case XML_ELEMENT_NODE:
1146
- case XML_ATTRIBUTE_NODE:
1147
- {
1148
- xmlNodePtr tmp = xnode->children;
1149
- const xmlChar *match = NULL;
1150
-
1151
- /* Find the first text node and use it as the reference. */
1152
- while (tmp && tmp->type != XML_TEXT_NODE)
1153
- tmp = tmp->next;
1154
- if (! tmp)
1155
- return Qnil;
1156
- match = tmp->name;
1157
-
1158
- /* Walk the remaining text nodes until we run out or one doesn't match. */
1159
- while (tmp && (tmp->type != XML_TEXT_NODE || match == tmp->name))
1160
- tmp = tmp->next;
1161
-
1162
- /* We're left with either the mismatched node or the aggregate result. */
1163
- return tmp ? Qnil : (match==xmlStringTextNoenc ? Qfalse : Qtrue);
1164
- }
1165
- break;
1166
- default:
1167
- return Qnil;
1168
- }
1169
- }
1170
-
1171
- /*
1172
- * call-seq:
1173
- * text_node.output_escaping = true|false
1174
- * element_node.output_escaping = true|false
1175
- * attribute_node.output_escaping = true|false
1176
- *
1177
- * Controls whether this text node or the immediate text node children of an
1178
- * element or attribute node escapes their output. Any other type of node
1179
- * will simply ignore this operation.
1180
- *
1181
- * Text nodes which are added to an element or attribute node will be affected
1182
- * by any previous setting of this property.
1183
- */
1184
- static VALUE rxml_node_output_escaping_set(VALUE self, VALUE bool)
1185
- {
1186
- xmlNodePtr xnode;
1187
- Data_Get_Struct(self, xmlNode, xnode);
1188
-
1189
- switch (xnode->type) {
1190
- case XML_TEXT_NODE:
1191
- xnode->name = (bool!=Qfalse && bool!=Qnil) ? xmlStringText : xmlStringTextNoenc;
1192
- break;
1193
- case XML_ELEMENT_NODE:
1194
- case XML_ATTRIBUTE_NODE:
1195
- {
1196
- const xmlChar *name = (bool!=Qfalse && bool!=Qnil) ? xmlStringText : xmlStringTextNoenc;
1197
- xmlNodePtr tmp;
1198
- for (tmp = xnode->children; tmp; tmp = tmp->next)
1199
- if (tmp->type == XML_TEXT_NODE)
1200
- tmp->name = name;
1201
- }
1202
- break;
1203
- default:
1204
- return Qnil;
1205
- }
1206
-
1207
- return (bool!=Qfalse && bool!=Qnil) ? Qtrue : Qfalse;
1208
- }
1209
-
1210
- /*
1211
- * call-seq:
1212
- * node.space_preserve -> (true|false)
1213
- *
1214
- * Determine whether this node preserves whitespace.
1215
- */
1216
- static VALUE rxml_node_space_preserve_get(VALUE self)
1217
- {
1218
- xmlNodePtr xnode;
1219
-
1220
- Data_Get_Struct(self, xmlNode, xnode);
1221
- return (INT2NUM(xmlNodeGetSpacePreserve(xnode)));
1222
- }
1223
-
1224
- /*
1225
- * call-seq:
1226
- * node.space_preserve = true|false
1227
- *
1228
- * Control whether this node preserves whitespace.
1229
- */
1230
- static VALUE rxml_node_space_preserve_set(VALUE self, VALUE bool)
1231
- {
1232
- xmlNodePtr xnode;
1233
- Data_Get_Struct(self, xmlNode, xnode);
1234
-
1235
- if (TYPE(bool) == T_FALSE)
1236
- xmlNodeSetSpacePreserve(xnode, 1);
1237
- else
1238
- xmlNodeSetSpacePreserve(xnode, 0);
1239
-
1240
- return (Qnil);
1241
- }
1242
-
1243
- /*
1244
- * call-seq:
1245
- * node.type -> num
1246
- *
1247
- * Obtain this node's type identifier.
1248
- */
1249
- static VALUE rxml_node_type(VALUE self)
1250
- {
1251
- xmlNodePtr xnode;
1252
- Data_Get_Struct(self, xmlNode, xnode);
1253
- return (INT2NUM(xnode->type));
1254
- }
1255
-
1256
- /*
1257
- * call-seq:
1258
- * node.copy -> XML::Node
1259
- *
1260
- * Creates a copy of this node. To create a
1261
- * shallow copy set the deep parameter to false.
1262
- * To create a deep copy set the deep parameter
1263
- * to true.
1264
- *
1265
- */
1266
- static VALUE rxml_node_copy(VALUE self, VALUE deep)
1267
- {
1268
- xmlNodePtr xnode;
1269
- xmlNodePtr xcopy;
1270
- int recursive = (deep == Qnil || deep == Qfalse) ? 0 : 1;
1271
- Data_Get_Struct(self, xmlNode, xnode);
1272
-
1273
- xcopy = xmlCopyNode(xnode, recursive);
1274
-
1275
- if (xcopy)
1276
- return rxml_node_wrap(xcopy);
1277
- else
1278
- return Qnil;
1279
- }
1280
-
1281
- void rxml_init_node(void)
1282
- {
1283
- xmlDeregisterNodeDefault(rxml_node_deregisterNode);
1284
-
1285
- cXMLNode = rb_define_class_under(mXML, "Node", rb_cObject);
1286
-
1287
- rb_define_const(cXMLNode, "SPACE_DEFAULT", INT2NUM(0));
1288
- rb_define_const(cXMLNode, "SPACE_PRESERVE", INT2NUM(1));
1289
- rb_define_const(cXMLNode, "SPACE_NOT_INHERIT", INT2NUM(-1));
1290
- rb_define_const(cXMLNode, "XLINK_ACTUATE_AUTO", INT2NUM(1));
1291
- rb_define_const(cXMLNode, "XLINK_ACTUATE_NONE", INT2NUM(0));
1292
- rb_define_const(cXMLNode, "XLINK_ACTUATE_ONREQUEST", INT2NUM(2));
1293
- rb_define_const(cXMLNode, "XLINK_SHOW_EMBED", INT2NUM(2));
1294
- rb_define_const(cXMLNode, "XLINK_SHOW_NEW", INT2NUM(1));
1295
- rb_define_const(cXMLNode, "XLINK_SHOW_NONE", INT2NUM(0));
1296
- rb_define_const(cXMLNode, "XLINK_SHOW_REPLACE", INT2NUM(3));
1297
- rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED", INT2NUM(2));
1298
- rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED_SET", INT2NUM(3));
1299
- rb_define_const(cXMLNode, "XLINK_TYPE_NONE", INT2NUM(0));
1300
- rb_define_const(cXMLNode, "XLINK_TYPE_SIMPLE", INT2NUM(1));
1301
-
1302
- rb_define_const(cXMLNode, "ELEMENT_NODE", INT2FIX(XML_ELEMENT_NODE));
1303
- rb_define_const(cXMLNode, "ATTRIBUTE_NODE", INT2FIX(XML_ATTRIBUTE_NODE));
1304
- rb_define_const(cXMLNode, "TEXT_NODE", INT2FIX(XML_TEXT_NODE));
1305
- rb_define_const(cXMLNode, "CDATA_SECTION_NODE", INT2FIX(XML_CDATA_SECTION_NODE));
1306
- rb_define_const(cXMLNode, "ENTITY_REF_NODE", INT2FIX(XML_ENTITY_REF_NODE));
1307
- rb_define_const(cXMLNode, "ENTITY_NODE", INT2FIX(XML_ENTITY_NODE));
1308
- rb_define_const(cXMLNode, "PI_NODE", INT2FIX(XML_PI_NODE));
1309
- rb_define_const(cXMLNode, "COMMENT_NODE", INT2FIX(XML_COMMENT_NODE));
1310
- rb_define_const(cXMLNode, "DOCUMENT_NODE", INT2FIX(XML_DOCUMENT_NODE));
1311
- rb_define_const(cXMLNode, "DOCUMENT_TYPE_NODE", INT2FIX(XML_DOCUMENT_TYPE_NODE));
1312
- rb_define_const(cXMLNode, "DOCUMENT_FRAG_NODE", INT2FIX(XML_DOCUMENT_FRAG_NODE));
1313
- rb_define_const(cXMLNode, "NOTATION_NODE", INT2FIX(XML_NOTATION_NODE));
1314
- rb_define_const(cXMLNode, "HTML_DOCUMENT_NODE", INT2FIX(XML_HTML_DOCUMENT_NODE));
1315
- rb_define_const(cXMLNode, "DTD_NODE", INT2FIX(XML_DTD_NODE));
1316
- rb_define_const(cXMLNode, "ELEMENT_DECL", INT2FIX(XML_ELEMENT_DECL));
1317
- rb_define_const(cXMLNode, "ATTRIBUTE_DECL", INT2FIX(XML_ATTRIBUTE_DECL));
1318
- rb_define_const(cXMLNode, "ENTITY_DECL", INT2FIX(XML_ENTITY_DECL));
1319
- rb_define_const(cXMLNode, "NAMESPACE_DECL", INT2FIX(XML_NAMESPACE_DECL));
1320
- rb_define_const(cXMLNode, "XINCLUDE_START", INT2FIX(XML_XINCLUDE_START));
1321
- rb_define_const(cXMLNode, "XINCLUDE_END", INT2FIX(XML_XINCLUDE_END));
1322
-
1323
- #ifdef LIBXML_DOCB_ENABLED
1324
- rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", INT2FIX(XML_DOCB_DOCUMENT_NODE));
1325
- #else
1326
- rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", Qnil);
1327
- #endif
1328
-
1329
- rb_define_singleton_method(cXMLNode, "new_cdata", rxml_node_new_cdata, -1);
1330
- rb_define_singleton_method(cXMLNode, "new_comment", rxml_node_new_comment, -1);
1331
- rb_define_singleton_method(cXMLNode, "new_text", rxml_node_new_text, 1);
1332
-
1333
- /* Initialization */
1334
- rb_define_alloc_func(cXMLNode, rxml_node_alloc);
1335
- rb_define_method(cXMLNode, "initialize", rxml_node_initialize, -1);
1336
-
1337
- /* Traversal */
1338
- rb_include_module(cXMLNode, rb_mEnumerable);
1339
- rb_define_method(cXMLNode, "[]", rxml_node_attribute_get, 1);
1340
- rb_define_method(cXMLNode, "each", rxml_node_each, 0);
1341
- rb_define_method(cXMLNode, "first", rxml_node_first_get, 0);
1342
- rb_define_method(cXMLNode, "last", rxml_node_last_get, 0);
1343
- rb_define_method(cXMLNode, "next", rxml_node_next_get, 0);
1344
- rb_define_method(cXMLNode, "parent", rxml_node_parent_get, 0);
1345
- rb_define_method(cXMLNode, "prev", rxml_node_prev_get, 0);
1346
-
1347
- /* Modification */
1348
- rb_define_method(cXMLNode, "[]=", rxml_node_property_set, 2);
1349
- rb_define_method(cXMLNode, "<<", rxml_node_content_add, 1);
1350
- rb_define_method(cXMLNode, "sibling=", rxml_node_sibling_set, 1);
1351
- rb_define_method(cXMLNode, "next=", rxml_node_next_set, 1);
1352
- rb_define_method(cXMLNode, "prev=", rxml_node_prev_set, 1);
1353
-
1354
- /* Rest of the node api */
1355
- rb_define_method(cXMLNode, "attributes", rxml_node_attributes_get, 0);
1356
- rb_define_method(cXMLNode, "base_uri", rxml_node_base_uri_get, 0);
1357
- rb_define_method(cXMLNode, "base_uri=", rxml_node_base_uri_set, 1);
1358
- rb_define_method(cXMLNode, "blank?", rxml_node_empty_q, 0);
1359
- rb_define_method(cXMLNode, "copy", rxml_node_copy, 1);
1360
- rb_define_method(cXMLNode, "content", rxml_node_content_get, 0);
1361
- rb_define_method(cXMLNode, "content=", rxml_node_content_set, 1);
1362
- rb_define_method(cXMLNode, "content_stripped", rxml_node_content_stripped_get, 0);
1363
- rb_define_method(cXMLNode, "debug", rxml_node_debug, 0);
1364
- rb_define_method(cXMLNode, "doc", rxml_node_doc, 0);
1365
- rb_define_method(cXMLNode, "empty?", rxml_node_empty_q, 0);
1366
- rb_define_method(cXMLNode, "eql?", rxml_node_eql_q, 1);
1367
- rb_define_method(cXMLNode, "lang", rxml_node_lang_get, 0);
1368
- rb_define_method(cXMLNode, "lang=", rxml_node_lang_set, 1);
1369
- rb_define_method(cXMLNode, "line_num", rxml_node_line_num, 0);
1370
- rb_define_method(cXMLNode, "name", rxml_node_name_get, 0);
1371
- rb_define_method(cXMLNode, "name=", rxml_node_name_set, 1);
1372
- rb_define_method(cXMLNode, "node_type", rxml_node_type, 0);
1373
- rb_define_method(cXMLNode, "output_escaping?", rxml_node_output_escaping_q, 0);
1374
- rb_define_method(cXMLNode, "output_escaping=", rxml_node_output_escaping_set, 1);
1375
- rb_define_method(cXMLNode, "path", rxml_node_path, 0);
1376
- rb_define_method(cXMLNode, "pointer", rxml_node_pointer, 1);
1377
- rb_define_method(cXMLNode, "remove!", rxml_node_remove_ex, 0);
1378
- rb_define_method(cXMLNode, "space_preserve", rxml_node_space_preserve_get, 0);
1379
- rb_define_method(cXMLNode, "space_preserve=", rxml_node_space_preserve_set, 1);
1380
- rb_define_method(cXMLNode, "to_s", rxml_node_to_s, -1);
1381
- rb_define_method(cXMLNode, "xlink?", rxml_node_xlink_q, 0);
1382
- rb_define_method(cXMLNode, "xlink_type", rxml_node_xlink_type, 0);
1383
- rb_define_method(cXMLNode, "xlink_type_name", rxml_node_xlink_type_name, 0);
1384
-
1385
- rb_define_alias(cXMLNode, "==", "eql?");
1386
- }
1
+ #include "ruby_libxml.h"
2
+ #include "ruby_xml_node.h"
3
+ #include <assert.h>
4
+
5
+ VALUE cXMLNode;
6
+
7
+ /* Document-class: LibXML::XML::Node
8
+ *
9
+ * Nodes are the primary objects that make up an XML document.
10
+ * The node class represents most node types that are found in
11
+ * an XML document (but not LibXML::XML::Attributes, see LibXML::XML::Attr).
12
+ * It exposes libxml's full API for creating, querying
13
+ * moving and deleting node objects. Many of these methods are
14
+ * documented in the DOM Level 3 specification found at:
15
+ * http://www.w3.org/TR/DOM-Level-3-Core/. */
16
+
17
+
18
+ /* Memory management:
19
+ *
20
+ * The bindings create a one-to-one mapping between libxml nodes
21
+ * and Ruby nodes. If a libxml node is wraped, its _private member
22
+ * is set with a reference to the Ruby object.
23
+ *
24
+ * When a libxml document or top level node is freed, it will free
25
+ * all its children. Thus Ruby is responsible for:
26
+ *
27
+ * * Using the mark function to keep alive any documents Ruby is
28
+ * referencing via the document or child nodes.
29
+ * * Using the mark function to keep alive any top level, free
30
+ * standing nodes Ruby is referencing via the node or its children.
31
+ *
32
+ * In general use, this will cause Ruby nodes to be freed before
33
+ * a libxml document. When a Ruby node is freed, the _private
34
+ * field is set back to null.
35
+ *
36
+ * In the sweep phase in Ruby 1.9.1, the document is freed before
37
+ * the nodes. To support that, the bindingds register a callback
38
+ * function with libxml that is called each time a node is freed.
39
+ * In that case, the data_ptr is set to null, so the bindings
40
+ * can recognize the situtation.
41
+ */
42
+
43
+ static void rxml_node_deregisterNode(xmlNodePtr xnode)
44
+ {
45
+ /* Has the node been wrapped and exposed to Ruby? */
46
+ if (xnode->_private)
47
+ {
48
+ /* Node was wrapped. Set the _private member to free and
49
+ then dislabe the dfree function so that Ruby will not
50
+ try to free the node a second time. */
51
+ VALUE node = (VALUE) xnode->_private;
52
+ RDATA(node)->data = NULL;
53
+ }
54
+ }
55
+
56
+ static void rxml_node_free(xmlNodePtr xnode)
57
+ {
58
+ /* Either the node has been created yet in initialize
59
+ or it has been freed by libxml already in Ruby's
60
+ mark phase. */
61
+ if (xnode == NULL)
62
+ return;
63
+
64
+ /* The ruby object wrapping the xml object no longer exists. */
65
+ xnode->_private = NULL;
66
+
67
+ /* Ruby is responsible for freeing this node since it
68
+ has no parent. */
69
+ if (xnode->parent == NULL)
70
+ xmlFreeNode(xnode);
71
+ }
72
+
73
+ void rxml_node_mark(xmlNodePtr xnode)
74
+ {
75
+ /* Either the node has been created yet in initialize
76
+ or it has been freed by libxml already in Ruby's
77
+ mark phase. */
78
+ if (xnode == NULL)
79
+ return;
80
+
81
+ if (xnode->doc != NULL)
82
+ rb_gc_mark((VALUE) xnode->doc->_private);
83
+
84
+ if (xnode->parent != NULL)
85
+ rb_gc_mark((VALUE) xnode->_private);
86
+ }
87
+
88
+ VALUE rxml_node_wrap(xmlNodePtr xnode)
89
+ {
90
+ /* Is the node already wrapped? */
91
+ if (xnode->_private != NULL)
92
+ {
93
+ return (VALUE) xnode->_private;
94
+ }
95
+ else
96
+ {
97
+ VALUE node = Data_Wrap_Struct(cXMLNode, rxml_node_mark, rxml_node_free, xnode);
98
+ xnode->_private = (void*) node;
99
+ return node;
100
+ }
101
+ }
102
+
103
+ static VALUE rxml_node_alloc(VALUE klass)
104
+ {
105
+ /* Ruby is responsible for freeing this node not libxml but don't set
106
+ up mark and free yet until we assign the node. */
107
+ return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node_free, NULL);
108
+ }
109
+
110
+ /*
111
+ * call-seq:
112
+ * XML::Node.new_cdata(content = nil) -> XML::Node
113
+ *
114
+ * Create a new #CDATA node, optionally setting
115
+ * the node's content.
116
+ */
117
+ static VALUE rxml_node_new_cdata(int argc, VALUE *argv, VALUE klass)
118
+ {
119
+ VALUE content = Qnil;
120
+ xmlNodePtr xnode;
121
+
122
+ rb_scan_args(argc, argv, "01", &content);
123
+
124
+ if (NIL_P(content))
125
+ {
126
+ xnode = xmlNewCDataBlock(NULL, NULL, 0);
127
+ }
128
+ else
129
+ {
130
+ content = rb_obj_as_string(content);
131
+ xnode = xmlNewCDataBlock(NULL, (xmlChar*) StringValuePtr(content),
132
+ RSTRING_LEN(content));
133
+ }
134
+
135
+ if (xnode == NULL)
136
+ rxml_raise(&xmlLastError);
137
+
138
+ return rxml_node_wrap(xnode);
139
+ }
140
+
141
+ /*
142
+ * call-seq:
143
+ * XML::Node.new_comment(content = nil) -> XML::Node
144
+ *
145
+ * Create a new comment node, optionally setting
146
+ * the node's content.
147
+ *
148
+ */
149
+ static VALUE rxml_node_new_comment(int argc, VALUE *argv, VALUE klass)
150
+ {
151
+ VALUE content = Qnil;
152
+ xmlNodePtr xnode;
153
+
154
+ rb_scan_args(argc, argv, "01", &content);
155
+
156
+ if (NIL_P(content))
157
+ {
158
+ xnode = xmlNewComment(NULL);
159
+ }
160
+ else
161
+ {
162
+ content = rb_obj_as_string(content);
163
+ xnode = xmlNewComment((xmlChar*) StringValueCStr(content));
164
+ }
165
+
166
+ if (xnode == NULL)
167
+ rxml_raise(&xmlLastError);
168
+
169
+ return rxml_node_wrap(xnode);
170
+ }
171
+
172
+ /*
173
+ * call-seq:
174
+ * XML::Node.new_text(content) -> XML::Node
175
+ *
176
+ * Create a new text node.
177
+ *
178
+ */
179
+ static VALUE rxml_node_new_text(VALUE klass, VALUE content)
180
+ {
181
+ xmlNodePtr xnode;
182
+ Check_Type(content, T_STRING);
183
+ content = rb_obj_as_string(content);
184
+
185
+ xnode = xmlNewText((xmlChar*) StringValueCStr(content));
186
+
187
+ if (xnode == NULL)
188
+ rxml_raise(&xmlLastError);
189
+
190
+ return rxml_node_wrap(xnode);
191
+ }
192
+
193
+ static VALUE rxml_node_content_set(VALUE self, VALUE content);
194
+
195
+ /*
196
+ * call-seq:
197
+ * XML::Node.initialize(name, content = nil, namespace = nil) -> XML::Node
198
+ *
199
+ * Creates a new element with the specified name, content and
200
+ * namespace. The content and namespace may be nil.
201
+ */
202
+ static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self)
203
+ {
204
+ VALUE name;
205
+ VALUE content;
206
+ VALUE ns;
207
+ xmlNodePtr xnode = NULL;
208
+ xmlNsPtr xns = NULL;
209
+
210
+ rb_scan_args(argc, argv, "12", &name, &content, &ns);
211
+
212
+ name = rb_obj_as_string(name);
213
+
214
+ if (!NIL_P(ns))
215
+ Data_Get_Struct(ns, xmlNs, xns);
216
+
217
+ xnode = xmlNewNode(xns, (xmlChar*) StringValuePtr(name));
218
+
219
+ if (xnode == NULL)
220
+ rxml_raise(&xmlLastError);
221
+
222
+ /* Link the Ruby object to the libxml object and vice-versa. */
223
+ xnode->_private = (void*) self;
224
+ DATA_PTR(self) = xnode;
225
+
226
+ if (!NIL_P(content))
227
+ rxml_node_content_set(self, content);
228
+
229
+ return self;
230
+ }
231
+
232
+ static VALUE rxml_node_modify_dom(VALUE self, VALUE target,
233
+ xmlNodePtr (*xmlFunc)(xmlNodePtr, xmlNodePtr))
234
+ {
235
+ xmlNodePtr xnode, xtarget, xresult;
236
+
237
+ if (rb_obj_is_kind_of(target, cXMLNode) == Qfalse)
238
+ rb_raise(rb_eTypeError, "Must pass an XML::Node object");
239
+
240
+ Data_Get_Struct(self, xmlNode, xnode);
241
+ Data_Get_Struct(target, xmlNode, xtarget);
242
+
243
+ if (xtarget->doc != NULL && xtarget->doc != xnode->doc)
244
+ rb_raise(eXMLError, "Nodes belong to different documents. You must first import the by calling XML::Document.import");
245
+
246
+ /* This target node could be freed here. */
247
+ xresult = xmlFunc(xnode, xtarget);
248
+
249
+ if (!xresult)
250
+ rxml_raise(&xmlLastError);
251
+
252
+ /* Was the target freed? If yes, then wrap the new node */
253
+ if (xresult != xtarget)
254
+ {
255
+ RDATA(target)->data = xresult;
256
+ xresult->_private = (void*) target;
257
+ }
258
+
259
+ return target;
260
+ }
261
+
262
+ /*
263
+ * call-seq:
264
+ * node.base_uri -> "uri"
265
+ *
266
+ * Obtain this node's base URI.
267
+ */
268
+ static VALUE rxml_node_base_uri_get(VALUE self)
269
+ {
270
+ xmlNodePtr xnode;
271
+ xmlChar* base_uri;
272
+ VALUE result = Qnil;
273
+
274
+ Data_Get_Struct(self, xmlNode, xnode);
275
+
276
+ if (xnode->doc == NULL)
277
+ return (result);
278
+
279
+ base_uri = xmlNodeGetBase(xnode->doc, xnode);
280
+ if (base_uri)
281
+ {
282
+ result = rb_str_new2((const char*) base_uri);
283
+ xmlFree(base_uri);
284
+ }
285
+
286
+ return (result);
287
+ }
288
+
289
+ // TODO node_base_set should support setting back to nil
290
+
291
+ /*
292
+ * call-seq:
293
+ * node.base_uri = "uri"
294
+ *
295
+ * Set this node's base URI.
296
+ */
297
+ static VALUE rxml_node_base_uri_set(VALUE self, VALUE uri)
298
+ {
299
+ xmlNodePtr xnode;
300
+
301
+ Check_Type(uri, T_STRING);
302
+ Data_Get_Struct(self, xmlNode, xnode);
303
+ if (xnode->doc == NULL)
304
+ return (Qnil);
305
+
306
+ xmlNodeSetBase(xnode, (xmlChar*) StringValuePtr(uri));
307
+ return (Qtrue);
308
+ }
309
+
310
+ /*
311
+ * call-seq:
312
+ * node.content -> "string"
313
+ *
314
+ * Obtain this node's content as a string.
315
+ */
316
+ static VALUE rxml_node_content_get(VALUE self)
317
+ {
318
+ xmlNodePtr xnode;
319
+ xmlChar *content;
320
+ VALUE result = Qnil;
321
+
322
+ Data_Get_Struct(self, xmlNode, xnode);
323
+ content = xmlNodeGetContent(xnode);
324
+ if (content)
325
+ {
326
+ result = rb_str_new2((const char *) content);
327
+ xmlFree(content);
328
+ }
329
+
330
+ return result;
331
+ }
332
+
333
+ /*
334
+ * call-seq:
335
+ * node.content = "string"
336
+ *
337
+ * Set this node's content to the specified string.
338
+ */
339
+ static VALUE rxml_node_content_set(VALUE self, VALUE content)
340
+ {
341
+ xmlNodePtr xnode;
342
+
343
+ Check_Type(content, T_STRING);
344
+ Data_Get_Struct(self, xmlNode, xnode);
345
+ // XXX docs indicate need for escaping entites, need to be done? danj
346
+ xmlNodeSetContent(xnode, (xmlChar*) StringValuePtr(content));
347
+ return (Qtrue);
348
+ }
349
+
350
+ /*
351
+ * call-seq:
352
+ * node.content_stripped -> "string"
353
+ *
354
+ * Obtain this node's stripped content.
355
+ *
356
+ * *Deprecated*: Stripped content can be obtained via the
357
+ * +content+ method.
358
+ */
359
+ static VALUE rxml_node_content_stripped_get(VALUE self)
360
+ {
361
+ xmlNodePtr xnode;
362
+ xmlChar* content;
363
+ VALUE result = Qnil;
364
+
365
+ Data_Get_Struct(self, xmlNode, xnode);
366
+
367
+ if (!xnode->content)
368
+ return result;
369
+
370
+ content = xmlNodeGetContent(xnode);
371
+ if (content)
372
+ {
373
+ result = rb_str_new2((const char*) content);
374
+ xmlFree(content);
375
+ }
376
+ return (result);
377
+ }
378
+
379
+ /*
380
+ * call-seq:
381
+ * node.debug -> true|false
382
+ *
383
+ * Print libxml debugging information to stdout.
384
+ * Requires that libxml was compiled with debugging enabled.
385
+ */
386
+ static VALUE rxml_node_debug(VALUE self)
387
+ {
388
+ #ifdef LIBXML_DEBUG_ENABLED
389
+ xmlNodePtr xnode;
390
+ Data_Get_Struct(self, xmlNode, xnode);
391
+ xmlDebugDumpNode(NULL, xnode, 2);
392
+ return Qtrue;
393
+ #else
394
+ rb_warn("libxml was compiled without debugging support.")
395
+ return Qfalse;
396
+ #endif
397
+ }
398
+
399
+ /*
400
+ * call-seq:
401
+ * node.first -> XML::Node
402
+ *
403
+ * Returns this node's first child node if any.
404
+ */
405
+ static VALUE rxml_node_first_get(VALUE self)
406
+ {
407
+ xmlNodePtr xnode;
408
+
409
+ Data_Get_Struct(self, xmlNode, xnode);
410
+
411
+ if (xnode->children)
412
+ return (rxml_node_wrap(xnode->children));
413
+ else
414
+ return (Qnil);
415
+ }
416
+
417
+
418
+ /*
419
+ * call-seq:
420
+ * curr_node << "Some text"
421
+ * curr_node << node
422
+ *
423
+ * Add the specified text or XML::Node as a new child node to the
424
+ * current node.
425
+ *
426
+ * If the specified argument is a string, it should be a raw string
427
+ * that contains unescaped XML special characters. Entity references
428
+ * are not supported.
429
+ *
430
+ * The method will return the current node.
431
+ */
432
+ static VALUE rxml_node_content_add(VALUE self, VALUE obj)
433
+ {
434
+ xmlNodePtr xnode;
435
+ VALUE str;
436
+
437
+ Data_Get_Struct(self, xmlNode, xnode);
438
+ /* XXX This should only be legal for a CDATA type node, I think,
439
+ * resulting in a merge of content, as if a string were passed
440
+ * danj 070827
441
+ */
442
+ if (rb_obj_is_kind_of(obj, cXMLNode))
443
+ {
444
+ xmlNodePtr xtarget;
445
+ Data_Get_Struct(obj, xmlNode, xtarget);
446
+ xmlUnlinkNode(xtarget);
447
+ rxml_node_modify_dom(self, obj, xmlAddChild);
448
+ }
449
+ else
450
+ {
451
+ str = rb_obj_as_string(obj);
452
+ if (NIL_P(str) || TYPE(str) != T_STRING)
453
+ rb_raise(rb_eTypeError, "invalid argument: must be string or XML::Node");
454
+
455
+ xmlNodeAddContent(xnode, (xmlChar*) StringValuePtr(str));
456
+ }
457
+ return self;
458
+ }
459
+
460
+ /*
461
+ * call-seq:
462
+ * node.doc -> document
463
+ *
464
+ * Obtain the XML::Document this node belongs to.
465
+ */
466
+ static VALUE rxml_node_doc(VALUE self)
467
+ {
468
+ xmlNodePtr xnode;
469
+ xmlDocPtr doc = NULL;
470
+
471
+ Data_Get_Struct(self, xmlNode, xnode);
472
+
473
+ switch (xnode->type)
474
+ {
475
+ case XML_DOCUMENT_NODE:
476
+ #ifdef LIBXML_DOCB_ENABLED
477
+ case XML_DOCB_DOCUMENT_NODE:
478
+ #endif
479
+ case XML_HTML_DOCUMENT_NODE:
480
+ doc = NULL;
481
+ break;
482
+ case XML_ATTRIBUTE_NODE:
483
+ {
484
+ xmlAttrPtr attr = (xmlAttrPtr) xnode;
485
+ doc = attr->doc;
486
+ break;
487
+ }
488
+ case XML_NAMESPACE_DECL:
489
+ doc = NULL;
490
+ break;
491
+ default:
492
+ doc = xnode->doc;
493
+ break;
494
+ }
495
+
496
+ if (doc == NULL)
497
+ return (Qnil);
498
+
499
+ if (doc->_private == NULL)
500
+ rb_raise(rb_eRuntimeError, "existing document object has no ruby-instance");
501
+
502
+ return (VALUE) doc->_private;
503
+ }
504
+
505
+ /*
506
+ * call-seq:
507
+ * node.to_s -> "string"
508
+ * node.to_s(:indent => true, :encoding => 'UTF-8', :level => 0) -> "string"
509
+ *
510
+ * Converts a node, and all of its children, to a string representation.
511
+ * To include only the node's children, use the the XML::Node#inner_xml
512
+ * method.
513
+ *
514
+ * You may provide an optional hash table to control how the string is
515
+ * generated. Valid options are:
516
+ *
517
+ * :indent - Specifies if the string should be indented. The default value
518
+ * is true. Note that indentation is only added if both :indent is
519
+ * true and XML.indent_tree_output is true. If :indent is set to false,
520
+ * then both indentation and line feeds are removed from the result.
521
+ *
522
+ * :level - Specifies the indentation level. The amount of indentation
523
+ * is equal to the (level * number_spaces) + number_spaces, where libxml
524
+ * defaults the number of spaces to 2. Thus a level of 0 results in
525
+ * 2 spaces, level 1 results in 4 spaces, level 2 results in 6 spaces, etc.
526
+ *
527
+ * :encoding - Specifies the output encoding of the string. It
528
+ * defaults to XML::Encoding::UTF8. To change it, use one of the
529
+ * XML::Encoding encoding constants. */
530
+
531
+ static VALUE rxml_node_to_s(int argc, VALUE *argv, VALUE self)
532
+ {
533
+ VALUE result = Qnil;
534
+ VALUE options = Qnil;
535
+ xmlNodePtr xnode;
536
+ xmlCharEncodingHandlerPtr encodingHandler;
537
+ xmlOutputBufferPtr output;
538
+
539
+ int level = 0;
540
+ int indent = 1;
541
+ const char *xencoding = NULL;
542
+
543
+ rb_scan_args(argc, argv, "01", &options);
544
+
545
+ if (!NIL_P(options))
546
+ {
547
+ VALUE rencoding, rindent, rlevel;
548
+ Check_Type(options, T_HASH);
549
+ rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
550
+ rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
551
+ rlevel = rb_hash_aref(options, ID2SYM(rb_intern("level")));
552
+
553
+ if (rindent == Qfalse)
554
+ indent = 0;
555
+
556
+ if (rlevel != Qnil)
557
+ level = NUM2INT(rlevel);
558
+
559
+ if (rencoding != Qnil)
560
+ {
561
+ xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
562
+ if (!xencoding)
563
+ rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
564
+ }
565
+ }
566
+
567
+ encodingHandler = xmlFindCharEncodingHandler(xencoding);
568
+ output = xmlAllocOutputBuffer(encodingHandler);
569
+
570
+ Data_Get_Struct(self, xmlNode, xnode);
571
+ xmlNodeDumpOutput(output, xnode->doc, xnode, level, indent, xencoding);
572
+ xmlOutputBufferFlush(output);
573
+
574
+ if (output->conv)
575
+ result = rb_str_new2((const char*) output->conv->content);
576
+ else
577
+ result = rb_str_new2((const char*) output->buffer->content);
578
+
579
+ xmlOutputBufferClose(output);
580
+
581
+ return result;
582
+ }
583
+
584
+
585
+ /*
586
+ * call-seq:
587
+ * node.each -> XML::Node
588
+ *
589
+ * Iterates over this node's children, including text
590
+ * nodes, element nodes, etc. If you wish to iterate
591
+ * only over child elements, use XML::Node#each_element.
592
+ *
593
+ * doc = XML::Document.new('model/books.xml')
594
+ * doc.root.each {|node| puts node}
595
+ */
596
+ static VALUE rxml_node_each(VALUE self)
597
+ {
598
+ xmlNodePtr xnode;
599
+ xmlNodePtr xcurrent;
600
+ Data_Get_Struct(self, xmlNode, xnode);
601
+
602
+ xcurrent = xnode->children;
603
+
604
+ while (xcurrent)
605
+ {
606
+ /* The user could remove this node, so first stache
607
+ away the next node. */
608
+ xmlNodePtr xnext = xcurrent->next;
609
+
610
+ rb_yield(rxml_node_wrap(xcurrent));
611
+ xcurrent = xnext;
612
+ }
613
+ return Qnil;
614
+ }
615
+
616
+ /*
617
+ * call-seq:
618
+ * node.empty? -> (true|false)
619
+ *
620
+ * Determine whether this node is empty.
621
+ */
622
+ static VALUE rxml_node_empty_q(VALUE self)
623
+ {
624
+ xmlNodePtr xnode;
625
+ Data_Get_Struct(self, xmlNode, xnode);
626
+ if (xnode == NULL)
627
+ return (Qnil);
628
+
629
+ return ((xmlIsBlankNode(xnode) == 1) ? Qtrue : Qfalse);
630
+ }
631
+
632
+
633
+ /*
634
+ * call-seq:
635
+ * node.eql?(other_node) => (true|false)
636
+ *
637
+ * Test equality between the two nodes. Two nodes are equal
638
+ * if they are the same node or have the same XML representation.*/
639
+ static VALUE rxml_node_eql_q(VALUE self, VALUE other)
640
+ {
641
+ if(self == other)
642
+ {
643
+ return Qtrue;
644
+ }
645
+ else if (NIL_P(other))
646
+ {
647
+ return Qfalse;
648
+ }
649
+ else
650
+ {
651
+ VALUE self_xml;
652
+ VALUE other_xml;
653
+
654
+ if (rb_obj_is_kind_of(other, cXMLNode) == Qfalse)
655
+ rb_raise(rb_eTypeError, "Nodes can only be compared against other nodes");
656
+
657
+ self_xml = rxml_node_to_s(0, NULL, self);
658
+ other_xml = rxml_node_to_s(0, NULL, other);
659
+ return(rb_funcall(self_xml, rb_intern("=="), 1, other_xml));
660
+ }
661
+ }
662
+
663
+ /*
664
+ * call-seq:
665
+ * node.lang -> "string"
666
+ *
667
+ * Obtain the language set for this node, if any.
668
+ * This is set in XML via the xml:lang attribute.
669
+ */
670
+ static VALUE rxml_node_lang_get(VALUE self)
671
+ {
672
+ xmlNodePtr xnode;
673
+ xmlChar *lang;
674
+ VALUE result = Qnil;
675
+
676
+ Data_Get_Struct(self, xmlNode, xnode);
677
+ lang = xmlNodeGetLang(xnode);
678
+
679
+ if (lang)
680
+ {
681
+ result = rb_str_new2((const char*) lang);
682
+ xmlFree(lang);
683
+ }
684
+
685
+ return (result);
686
+ }
687
+
688
+ // TODO node_lang_set should support setting back to nil
689
+
690
+ /*
691
+ * call-seq:
692
+ * node.lang = "string"
693
+ *
694
+ * Set the language for this node. This affects the value
695
+ * of the xml:lang attribute.
696
+ */
697
+ static VALUE rxml_node_lang_set(VALUE self, VALUE lang)
698
+ {
699
+ xmlNodePtr xnode;
700
+
701
+ Check_Type(lang, T_STRING);
702
+ Data_Get_Struct(self, xmlNode, xnode);
703
+ xmlNodeSetLang(xnode, (xmlChar*) StringValuePtr(lang));
704
+
705
+ return (Qtrue);
706
+ }
707
+
708
+ /*
709
+ * call-seq:
710
+ * node.last -> XML::Node
711
+ *
712
+ * Obtain the last child node of this node, if any.
713
+ */
714
+ static VALUE rxml_node_last_get(VALUE self)
715
+ {
716
+ xmlNodePtr xnode;
717
+
718
+ Data_Get_Struct(self, xmlNode, xnode);
719
+
720
+ if (xnode->last)
721
+ return (rxml_node_wrap(xnode->last));
722
+ else
723
+ return (Qnil);
724
+ }
725
+
726
+ /*
727
+ * call-seq:
728
+ * node.line_num -> num
729
+ *
730
+ * Obtain the line number (in the XML document) that this
731
+ * node was read from. If +default_line_numbers+ is set
732
+ * false (the default), this method returns zero.
733
+ */
734
+ static VALUE rxml_node_line_num(VALUE self)
735
+ {
736
+ xmlNodePtr xnode;
737
+ long line_num;
738
+ Data_Get_Struct(self, xmlNode, xnode);
739
+
740
+ if (!xmlLineNumbersDefaultValue)
741
+ rb_warn(
742
+ "Line numbers were not retained: use XML::Parser::default_line_numbers=true");
743
+
744
+ line_num = xmlGetLineNo(xnode);
745
+ if (line_num == -1)
746
+ return (Qnil);
747
+ else
748
+ return (INT2NUM((long) line_num));
749
+ }
750
+
751
+ /*
752
+ * call-seq:
753
+ * node.xlink? -> (true|false)
754
+ *
755
+ * Determine whether this node is an xlink node.
756
+ */
757
+ static VALUE rxml_node_xlink_q(VALUE self)
758
+ {
759
+ xmlNodePtr xnode;
760
+ xlinkType xlt;
761
+
762
+ Data_Get_Struct(self, xmlNode, xnode);
763
+ xlt = xlinkIsLink(xnode->doc, xnode);
764
+
765
+ if (xlt == XLINK_TYPE_NONE)
766
+ return (Qfalse);
767
+ else
768
+ return (Qtrue);
769
+ }
770
+
771
+ /*
772
+ * call-seq:
773
+ * node.xlink_type -> num
774
+ *
775
+ * Obtain the type identifier for this xlink, if applicable.
776
+ * If this is not an xlink node (see +xlink?+), will return
777
+ * nil.
778
+ */
779
+ static VALUE rxml_node_xlink_type(VALUE self)
780
+ {
781
+ xmlNodePtr xnode;
782
+ xlinkType xlt;
783
+
784
+ Data_Get_Struct(self, xmlNode, xnode);
785
+ xlt = xlinkIsLink(xnode->doc, xnode);
786
+
787
+ if (xlt == XLINK_TYPE_NONE)
788
+ return (Qnil);
789
+ else
790
+ return (INT2NUM(xlt));
791
+ }
792
+
793
+ /*
794
+ * call-seq:
795
+ * node.xlink_type_name -> "string"
796
+ *
797
+ * Obtain the type name for this xlink, if applicable.
798
+ * If this is not an xlink node (see +xlink?+), will return
799
+ * nil.
800
+ */
801
+ static VALUE rxml_node_xlink_type_name(VALUE self)
802
+ {
803
+ xmlNodePtr xnode;
804
+ xlinkType xlt;
805
+
806
+ Data_Get_Struct(self, xmlNode, xnode);
807
+ xlt = xlinkIsLink(xnode->doc, xnode);
808
+
809
+ switch (xlt)
810
+ {
811
+ case XLINK_TYPE_NONE:
812
+ return (Qnil);
813
+ case XLINK_TYPE_SIMPLE:
814
+ return (rb_str_new2("simple"));
815
+ case XLINK_TYPE_EXTENDED:
816
+ return (rb_str_new2("extended"));
817
+ case XLINK_TYPE_EXTENDED_SET:
818
+ return (rb_str_new2("extended_set"));
819
+ default:
820
+ rb_fatal("Unknowng xlink type, %d", xlt);
821
+ }
822
+ }
823
+
824
+ /*
825
+ * call-seq:
826
+ * node.name -> "string"
827
+ *
828
+ * Obtain this node's name.
829
+ */
830
+ static VALUE rxml_node_name_get(VALUE self)
831
+ {
832
+ xmlNodePtr xnode;
833
+ const xmlChar *name;
834
+
835
+ Data_Get_Struct(self, xmlNode, xnode);
836
+
837
+ switch (xnode->type)
838
+ {
839
+ case XML_DOCUMENT_NODE:
840
+ #ifdef LIBXML_DOCB_ENABLED
841
+ case XML_DOCB_DOCUMENT_NODE:
842
+ #endif
843
+ case XML_HTML_DOCUMENT_NODE:
844
+ {
845
+ xmlDocPtr doc = (xmlDocPtr) xnode;
846
+ name = doc->URL;
847
+ break;
848
+ }
849
+ case XML_ATTRIBUTE_NODE:
850
+ {
851
+ xmlAttrPtr attr = (xmlAttrPtr) xnode;
852
+ name = attr->name;
853
+ break;
854
+ }
855
+ case XML_NAMESPACE_DECL:
856
+ {
857
+ xmlNsPtr ns = (xmlNsPtr) xnode;
858
+ name = ns->prefix;
859
+ break;
860
+ }
861
+ default:
862
+ name = xnode->name;
863
+ break;
864
+ }
865
+
866
+ if (xnode->name == NULL)
867
+ return (Qnil);
868
+ else
869
+ return (rb_str_new2((const char*) name));
870
+ }
871
+
872
+ /*
873
+ * call-seq:
874
+ * node.name = "string"
875
+ *
876
+ * Set this node's name.
877
+ */
878
+ static VALUE rxml_node_name_set(VALUE self, VALUE name)
879
+ {
880
+ xmlNodePtr xnode;
881
+ const xmlChar *xname;
882
+
883
+ Check_Type(name, T_STRING);
884
+ Data_Get_Struct(self, xmlNode, xnode);
885
+ xname = (const xmlChar*)StringValuePtr(name);
886
+
887
+ /* Note: calling xmlNodeSetName() for a text node is ignored by libXML. */
888
+ xmlNodeSetName(xnode, xname);
889
+
890
+ return (Qtrue);
891
+ }
892
+
893
+ /*
894
+ * call-seq:
895
+ * node.next -> XML::Node
896
+ *
897
+ * Returns the next sibling node if one exists.
898
+ */
899
+ static VALUE rxml_node_next_get(VALUE self)
900
+ {
901
+ xmlNodePtr xnode;
902
+
903
+ Data_Get_Struct(self, xmlNode, xnode);
904
+
905
+ if (xnode->next)
906
+ return (rxml_node_wrap(xnode->next));
907
+ else
908
+ return (Qnil);
909
+ }
910
+
911
+ /*
912
+ * call-seq:
913
+ * curr_node.next = node
914
+ *
915
+ * Adds the specified node as the next sibling of the current node.
916
+ * If the node already exists in the document, it is first removed
917
+ * from its existing context. Any adjacent text nodes will be
918
+ * merged together, meaning the returned node may be different
919
+ * than the original node.
920
+ */
921
+ static VALUE rxml_node_next_set(VALUE self, VALUE next)
922
+ {
923
+ return rxml_node_modify_dom(self, next, xmlAddNextSibling);
924
+ }
925
+
926
+ /*
927
+ * call-seq:
928
+ * node.parent -> XML::Node
929
+ *
930
+ * Obtain this node's parent node, if any.
931
+ */
932
+ static VALUE rxml_node_parent_get(VALUE self)
933
+ {
934
+ xmlNodePtr xnode;
935
+
936
+ Data_Get_Struct(self, xmlNode, xnode);
937
+
938
+ if (xnode->parent)
939
+ return (rxml_node_wrap(xnode->parent));
940
+ else
941
+ return (Qnil);
942
+ }
943
+
944
+ /*
945
+ * call-seq:
946
+ * node.path -> path
947
+ *
948
+ * Obtain this node's path.
949
+ */
950
+ static VALUE rxml_node_path(VALUE self)
951
+ {
952
+ xmlNodePtr xnode;
953
+ xmlChar *path;
954
+
955
+ Data_Get_Struct(self, xmlNode, xnode);
956
+ path = xmlGetNodePath(xnode);
957
+
958
+ if (path == NULL)
959
+ return (Qnil);
960
+ else
961
+ return (rb_str_new2((const char*) path));
962
+ }
963
+
964
+ /*
965
+ * call-seq:
966
+ * node.pointer -> XML::NodeSet
967
+ *
968
+ * Evaluates an XPointer expression relative to this node.
969
+ */
970
+ static VALUE rxml_node_pointer(VALUE self, VALUE xptr_str)
971
+ {
972
+ return (rxml_xpointer_point2(self, xptr_str));
973
+ }
974
+
975
+ /*
976
+ * call-seq:
977
+ * node.prev -> XML::Node
978
+ *
979
+ * Obtain the previous sibling, if any.
980
+ */
981
+ static VALUE rxml_node_prev_get(VALUE self)
982
+ {
983
+ xmlNodePtr xnode;
984
+ xmlNodePtr node;
985
+ Data_Get_Struct(self, xmlNode, xnode);
986
+
987
+ switch (xnode->type)
988
+ {
989
+ case XML_DOCUMENT_NODE:
990
+ #ifdef LIBXML_DOCB_ENABLED
991
+ case XML_DOCB_DOCUMENT_NODE:
992
+ #endif
993
+ case XML_HTML_DOCUMENT_NODE:
994
+ case XML_NAMESPACE_DECL:
995
+ node = NULL;
996
+ break;
997
+ case XML_ATTRIBUTE_NODE:
998
+ {
999
+ xmlAttrPtr attr = (xmlAttrPtr) xnode;
1000
+ node = (xmlNodePtr) attr->prev;
1001
+ }
1002
+ break;
1003
+ default:
1004
+ node = xnode->prev;
1005
+ break;
1006
+ }
1007
+
1008
+ if (node == NULL)
1009
+ return (Qnil);
1010
+ else
1011
+ return (rxml_node_wrap(node));
1012
+ }
1013
+
1014
+ /*
1015
+ * call-seq:
1016
+ * curr_node.prev = node
1017
+ *
1018
+ * Adds the specified node as the previous sibling of the current node.
1019
+ * If the node already exists in the document, it is first removed
1020
+ * from its existing context. Any adjacent text nodes will be
1021
+ * merged together, meaning the returned node may be different
1022
+ * than the original node.
1023
+ */
1024
+ static VALUE rxml_node_prev_set(VALUE self, VALUE prev)
1025
+ {
1026
+ return rxml_node_modify_dom(self, prev, xmlAddPrevSibling);
1027
+ }
1028
+
1029
+ /*
1030
+ * call-seq:
1031
+ * node.attributes -> attributes
1032
+ *
1033
+ * Returns the XML::Attributes for this node.
1034
+ */
1035
+ static VALUE rxml_node_attributes_get(VALUE self)
1036
+ {
1037
+ xmlNodePtr xnode;
1038
+
1039
+ Data_Get_Struct(self, xmlNode, xnode);
1040
+ return rxml_attributes_new(xnode);
1041
+ }
1042
+
1043
+ /*
1044
+ * call-seq:
1045
+ * node.property("name") -> "string"
1046
+ * node["name"] -> "string"
1047
+ *
1048
+ * Obtain the named pyroperty.
1049
+ */
1050
+ static VALUE rxml_node_attribute_get(VALUE self, VALUE name)
1051
+ {
1052
+ VALUE attributes = rxml_node_attributes_get(self);
1053
+ return rxml_attributes_attribute_get(attributes, name);
1054
+ }
1055
+
1056
+ /*
1057
+ * call-seq:
1058
+ * node["name"] = "string"
1059
+ *
1060
+ * Set the named property.
1061
+ */
1062
+ static VALUE rxml_node_property_set(VALUE self, VALUE name, VALUE value)
1063
+ {
1064
+ VALUE attributes = rxml_node_attributes_get(self);
1065
+ return rxml_attributes_attribute_set(attributes, name, value);
1066
+ }
1067
+
1068
+ /*
1069
+ * call-seq:
1070
+ * node.remove! -> node
1071
+ *
1072
+ * Removes this node and its children from the document tree by setting its document,
1073
+ * parent and siblings to nil. You can add the returned node back into a document.
1074
+ * Otherwise, the node will be freed once any references to it go out of scope.
1075
+ */
1076
+
1077
+ static VALUE rxml_node_remove_ex(VALUE self)
1078
+ {
1079
+ xmlNodePtr xnode, xresult;
1080
+ Data_Get_Struct(self, xmlNode, xnode);
1081
+
1082
+ /* First unlink the node from its parent. */
1083
+ xmlUnlinkNode(xnode);
1084
+
1085
+ /* Now copy the node we want to remove and make the
1086
+ current Ruby object point to it. We do this because
1087
+ a node has a number of dependencies on its parent
1088
+ document - its name (if using a dictionary), entities,
1089
+ namespaces, etc. For a node to live on its own, it
1090
+ needs to get its own copies of this information.*/
1091
+ xresult = xmlDocCopyNode(xnode, NULL, 1);
1092
+
1093
+ /* Now free the original node. */
1094
+ xmlFreeNode(xnode);
1095
+
1096
+ /* Now wrap the new node */
1097
+ RDATA(self)->data = xresult;
1098
+ xresult->_private = (void*) self;
1099
+
1100
+ /* Now return the removed node so the user can
1101
+ do something with it.*/
1102
+ return self;
1103
+ }
1104
+
1105
+ /*
1106
+ * call-seq:
1107
+ * curr_node.sibling = node
1108
+ *
1109
+ * Adds the specified node as the end of the current node's list
1110
+ * of siblings. If the node already exists in the document, it
1111
+ * is first removed from its existing context. Any adjacent text
1112
+ * nodes will be merged together, meaning the returned node may
1113
+ * be different than the original node.
1114
+ */
1115
+ static VALUE rxml_node_sibling_set(VALUE self, VALUE sibling)
1116
+ {
1117
+ return rxml_node_modify_dom(self, sibling, xmlAddSibling);
1118
+ }
1119
+
1120
+ /*
1121
+ * call-seq:
1122
+ * text_node.output_escaping? -> (true|false)
1123
+ * element_node.output_escaping? -> (true|false|nil)
1124
+ * attribute_node.output_escaping? -> (true|false|nil)
1125
+ * other_node.output_escaping? -> (nil)
1126
+ *
1127
+ * Determine whether this node escapes it's output or not.
1128
+ *
1129
+ * Text nodes return only +true+ or +false+. Element and attribute nodes
1130
+ * examine their immediate text node children to determine the value.
1131
+ * Any other type of node always returns +nil+.
1132
+ *
1133
+ * If an element or attribute node has at least one immediate child text node
1134
+ * and all the immediate text node children have the same +output_escaping?+
1135
+ * value, that value is returned. Otherwise, +nil+ is returned.
1136
+ */
1137
+ static VALUE rxml_node_output_escaping_q(VALUE self)
1138
+ {
1139
+ xmlNodePtr xnode;
1140
+ Data_Get_Struct(self, xmlNode, xnode);
1141
+
1142
+ switch (xnode->type) {
1143
+ case XML_TEXT_NODE:
1144
+ return xnode->name==xmlStringTextNoenc ? Qfalse : Qtrue;
1145
+ case XML_ELEMENT_NODE:
1146
+ case XML_ATTRIBUTE_NODE:
1147
+ {
1148
+ xmlNodePtr tmp = xnode->children;
1149
+ const xmlChar *match = NULL;
1150
+
1151
+ /* Find the first text node and use it as the reference. */
1152
+ while (tmp && tmp->type != XML_TEXT_NODE)
1153
+ tmp = tmp->next;
1154
+ if (! tmp)
1155
+ return Qnil;
1156
+ match = tmp->name;
1157
+
1158
+ /* Walk the remaining text nodes until we run out or one doesn't match. */
1159
+ while (tmp && (tmp->type != XML_TEXT_NODE || match == tmp->name))
1160
+ tmp = tmp->next;
1161
+
1162
+ /* We're left with either the mismatched node or the aggregate result. */
1163
+ return tmp ? Qnil : (match==xmlStringTextNoenc ? Qfalse : Qtrue);
1164
+ }
1165
+ break;
1166
+ default:
1167
+ return Qnil;
1168
+ }
1169
+ }
1170
+
1171
+ /*
1172
+ * call-seq:
1173
+ * text_node.output_escaping = true|false
1174
+ * element_node.output_escaping = true|false
1175
+ * attribute_node.output_escaping = true|false
1176
+ *
1177
+ * Controls whether this text node or the immediate text node children of an
1178
+ * element or attribute node escapes their output. Any other type of node
1179
+ * will simply ignore this operation.
1180
+ *
1181
+ * Text nodes which are added to an element or attribute node will be affected
1182
+ * by any previous setting of this property.
1183
+ */
1184
+ static VALUE rxml_node_output_escaping_set(VALUE self, VALUE bool)
1185
+ {
1186
+ xmlNodePtr xnode;
1187
+ Data_Get_Struct(self, xmlNode, xnode);
1188
+
1189
+ switch (xnode->type) {
1190
+ case XML_TEXT_NODE:
1191
+ xnode->name = (bool!=Qfalse && bool!=Qnil) ? xmlStringText : xmlStringTextNoenc;
1192
+ break;
1193
+ case XML_ELEMENT_NODE:
1194
+ case XML_ATTRIBUTE_NODE:
1195
+ {
1196
+ const xmlChar *name = (bool!=Qfalse && bool!=Qnil) ? xmlStringText : xmlStringTextNoenc;
1197
+ xmlNodePtr tmp;
1198
+ for (tmp = xnode->children; tmp; tmp = tmp->next)
1199
+ if (tmp->type == XML_TEXT_NODE)
1200
+ tmp->name = name;
1201
+ }
1202
+ break;
1203
+ default:
1204
+ return Qnil;
1205
+ }
1206
+
1207
+ return (bool!=Qfalse && bool!=Qnil) ? Qtrue : Qfalse;
1208
+ }
1209
+
1210
+ /*
1211
+ * call-seq:
1212
+ * node.space_preserve -> (true|false)
1213
+ *
1214
+ * Determine whether this node preserves whitespace.
1215
+ */
1216
+ static VALUE rxml_node_space_preserve_get(VALUE self)
1217
+ {
1218
+ xmlNodePtr xnode;
1219
+
1220
+ Data_Get_Struct(self, xmlNode, xnode);
1221
+ return (INT2NUM(xmlNodeGetSpacePreserve(xnode)));
1222
+ }
1223
+
1224
+ /*
1225
+ * call-seq:
1226
+ * node.space_preserve = true|false
1227
+ *
1228
+ * Control whether this node preserves whitespace.
1229
+ */
1230
+ static VALUE rxml_node_space_preserve_set(VALUE self, VALUE bool)
1231
+ {
1232
+ xmlNodePtr xnode;
1233
+ Data_Get_Struct(self, xmlNode, xnode);
1234
+
1235
+ if (TYPE(bool) == T_FALSE)
1236
+ xmlNodeSetSpacePreserve(xnode, 1);
1237
+ else
1238
+ xmlNodeSetSpacePreserve(xnode, 0);
1239
+
1240
+ return (Qnil);
1241
+ }
1242
+
1243
+ /*
1244
+ * call-seq:
1245
+ * node.type -> num
1246
+ *
1247
+ * Obtain this node's type identifier.
1248
+ */
1249
+ static VALUE rxml_node_type(VALUE self)
1250
+ {
1251
+ xmlNodePtr xnode;
1252
+ Data_Get_Struct(self, xmlNode, xnode);
1253
+ return (INT2NUM(xnode->type));
1254
+ }
1255
+
1256
+ /*
1257
+ * call-seq:
1258
+ * node.copy -> XML::Node
1259
+ *
1260
+ * Creates a copy of this node. To create a
1261
+ * shallow copy set the deep parameter to false.
1262
+ * To create a deep copy set the deep parameter
1263
+ * to true.
1264
+ *
1265
+ */
1266
+ static VALUE rxml_node_copy(VALUE self, VALUE deep)
1267
+ {
1268
+ xmlNodePtr xnode;
1269
+ xmlNodePtr xcopy;
1270
+ int recursive = (deep == Qnil || deep == Qfalse) ? 0 : 1;
1271
+ Data_Get_Struct(self, xmlNode, xnode);
1272
+
1273
+ xcopy = xmlCopyNode(xnode, recursive);
1274
+
1275
+ if (xcopy)
1276
+ return rxml_node_wrap(xcopy);
1277
+ else
1278
+ return Qnil;
1279
+ }
1280
+
1281
+ void rxml_init_node(void)
1282
+ {
1283
+ xmlDeregisterNodeDefault(rxml_node_deregisterNode);
1284
+
1285
+ cXMLNode = rb_define_class_under(mXML, "Node", rb_cObject);
1286
+
1287
+ rb_define_const(cXMLNode, "SPACE_DEFAULT", INT2NUM(0));
1288
+ rb_define_const(cXMLNode, "SPACE_PRESERVE", INT2NUM(1));
1289
+ rb_define_const(cXMLNode, "SPACE_NOT_INHERIT", INT2NUM(-1));
1290
+ rb_define_const(cXMLNode, "XLINK_ACTUATE_AUTO", INT2NUM(1));
1291
+ rb_define_const(cXMLNode, "XLINK_ACTUATE_NONE", INT2NUM(0));
1292
+ rb_define_const(cXMLNode, "XLINK_ACTUATE_ONREQUEST", INT2NUM(2));
1293
+ rb_define_const(cXMLNode, "XLINK_SHOW_EMBED", INT2NUM(2));
1294
+ rb_define_const(cXMLNode, "XLINK_SHOW_NEW", INT2NUM(1));
1295
+ rb_define_const(cXMLNode, "XLINK_SHOW_NONE", INT2NUM(0));
1296
+ rb_define_const(cXMLNode, "XLINK_SHOW_REPLACE", INT2NUM(3));
1297
+ rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED", INT2NUM(2));
1298
+ rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED_SET", INT2NUM(3));
1299
+ rb_define_const(cXMLNode, "XLINK_TYPE_NONE", INT2NUM(0));
1300
+ rb_define_const(cXMLNode, "XLINK_TYPE_SIMPLE", INT2NUM(1));
1301
+
1302
+ rb_define_const(cXMLNode, "ELEMENT_NODE", INT2FIX(XML_ELEMENT_NODE));
1303
+ rb_define_const(cXMLNode, "ATTRIBUTE_NODE", INT2FIX(XML_ATTRIBUTE_NODE));
1304
+ rb_define_const(cXMLNode, "TEXT_NODE", INT2FIX(XML_TEXT_NODE));
1305
+ rb_define_const(cXMLNode, "CDATA_SECTION_NODE", INT2FIX(XML_CDATA_SECTION_NODE));
1306
+ rb_define_const(cXMLNode, "ENTITY_REF_NODE", INT2FIX(XML_ENTITY_REF_NODE));
1307
+ rb_define_const(cXMLNode, "ENTITY_NODE", INT2FIX(XML_ENTITY_NODE));
1308
+ rb_define_const(cXMLNode, "PI_NODE", INT2FIX(XML_PI_NODE));
1309
+ rb_define_const(cXMLNode, "COMMENT_NODE", INT2FIX(XML_COMMENT_NODE));
1310
+ rb_define_const(cXMLNode, "DOCUMENT_NODE", INT2FIX(XML_DOCUMENT_NODE));
1311
+ rb_define_const(cXMLNode, "DOCUMENT_TYPE_NODE", INT2FIX(XML_DOCUMENT_TYPE_NODE));
1312
+ rb_define_const(cXMLNode, "DOCUMENT_FRAG_NODE", INT2FIX(XML_DOCUMENT_FRAG_NODE));
1313
+ rb_define_const(cXMLNode, "NOTATION_NODE", INT2FIX(XML_NOTATION_NODE));
1314
+ rb_define_const(cXMLNode, "HTML_DOCUMENT_NODE", INT2FIX(XML_HTML_DOCUMENT_NODE));
1315
+ rb_define_const(cXMLNode, "DTD_NODE", INT2FIX(XML_DTD_NODE));
1316
+ rb_define_const(cXMLNode, "ELEMENT_DECL", INT2FIX(XML_ELEMENT_DECL));
1317
+ rb_define_const(cXMLNode, "ATTRIBUTE_DECL", INT2FIX(XML_ATTRIBUTE_DECL));
1318
+ rb_define_const(cXMLNode, "ENTITY_DECL", INT2FIX(XML_ENTITY_DECL));
1319
+ rb_define_const(cXMLNode, "NAMESPACE_DECL", INT2FIX(XML_NAMESPACE_DECL));
1320
+ rb_define_const(cXMLNode, "XINCLUDE_START", INT2FIX(XML_XINCLUDE_START));
1321
+ rb_define_const(cXMLNode, "XINCLUDE_END", INT2FIX(XML_XINCLUDE_END));
1322
+
1323
+ #ifdef LIBXML_DOCB_ENABLED
1324
+ rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", INT2FIX(XML_DOCB_DOCUMENT_NODE));
1325
+ #else
1326
+ rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", Qnil);
1327
+ #endif
1328
+
1329
+ rb_define_singleton_method(cXMLNode, "new_cdata", rxml_node_new_cdata, -1);
1330
+ rb_define_singleton_method(cXMLNode, "new_comment", rxml_node_new_comment, -1);
1331
+ rb_define_singleton_method(cXMLNode, "new_text", rxml_node_new_text, 1);
1332
+
1333
+ /* Initialization */
1334
+ rb_define_alloc_func(cXMLNode, rxml_node_alloc);
1335
+ rb_define_method(cXMLNode, "initialize", rxml_node_initialize, -1);
1336
+
1337
+ /* Traversal */
1338
+ rb_include_module(cXMLNode, rb_mEnumerable);
1339
+ rb_define_method(cXMLNode, "[]", rxml_node_attribute_get, 1);
1340
+ rb_define_method(cXMLNode, "each", rxml_node_each, 0);
1341
+ rb_define_method(cXMLNode, "first", rxml_node_first_get, 0);
1342
+ rb_define_method(cXMLNode, "last", rxml_node_last_get, 0);
1343
+ rb_define_method(cXMLNode, "next", rxml_node_next_get, 0);
1344
+ rb_define_method(cXMLNode, "parent", rxml_node_parent_get, 0);
1345
+ rb_define_method(cXMLNode, "prev", rxml_node_prev_get, 0);
1346
+
1347
+ /* Modification */
1348
+ rb_define_method(cXMLNode, "[]=", rxml_node_property_set, 2);
1349
+ rb_define_method(cXMLNode, "<<", rxml_node_content_add, 1);
1350
+ rb_define_method(cXMLNode, "sibling=", rxml_node_sibling_set, 1);
1351
+ rb_define_method(cXMLNode, "next=", rxml_node_next_set, 1);
1352
+ rb_define_method(cXMLNode, "prev=", rxml_node_prev_set, 1);
1353
+
1354
+ /* Rest of the node api */
1355
+ rb_define_method(cXMLNode, "attributes", rxml_node_attributes_get, 0);
1356
+ rb_define_method(cXMLNode, "base_uri", rxml_node_base_uri_get, 0);
1357
+ rb_define_method(cXMLNode, "base_uri=", rxml_node_base_uri_set, 1);
1358
+ rb_define_method(cXMLNode, "blank?", rxml_node_empty_q, 0);
1359
+ rb_define_method(cXMLNode, "copy", rxml_node_copy, 1);
1360
+ rb_define_method(cXMLNode, "content", rxml_node_content_get, 0);
1361
+ rb_define_method(cXMLNode, "content=", rxml_node_content_set, 1);
1362
+ rb_define_method(cXMLNode, "content_stripped", rxml_node_content_stripped_get, 0);
1363
+ rb_define_method(cXMLNode, "debug", rxml_node_debug, 0);
1364
+ rb_define_method(cXMLNode, "doc", rxml_node_doc, 0);
1365
+ rb_define_method(cXMLNode, "empty?", rxml_node_empty_q, 0);
1366
+ rb_define_method(cXMLNode, "eql?", rxml_node_eql_q, 1);
1367
+ rb_define_method(cXMLNode, "lang", rxml_node_lang_get, 0);
1368
+ rb_define_method(cXMLNode, "lang=", rxml_node_lang_set, 1);
1369
+ rb_define_method(cXMLNode, "line_num", rxml_node_line_num, 0);
1370
+ rb_define_method(cXMLNode, "name", rxml_node_name_get, 0);
1371
+ rb_define_method(cXMLNode, "name=", rxml_node_name_set, 1);
1372
+ rb_define_method(cXMLNode, "node_type", rxml_node_type, 0);
1373
+ rb_define_method(cXMLNode, "output_escaping?", rxml_node_output_escaping_q, 0);
1374
+ rb_define_method(cXMLNode, "output_escaping=", rxml_node_output_escaping_set, 1);
1375
+ rb_define_method(cXMLNode, "path", rxml_node_path, 0);
1376
+ rb_define_method(cXMLNode, "pointer", rxml_node_pointer, 1);
1377
+ rb_define_method(cXMLNode, "remove!", rxml_node_remove_ex, 0);
1378
+ rb_define_method(cXMLNode, "space_preserve", rxml_node_space_preserve_get, 0);
1379
+ rb_define_method(cXMLNode, "space_preserve=", rxml_node_space_preserve_set, 1);
1380
+ rb_define_method(cXMLNode, "to_s", rxml_node_to_s, -1);
1381
+ rb_define_method(cXMLNode, "xlink?", rxml_node_xlink_q, 0);
1382
+ rb_define_method(cXMLNode, "xlink_type", rxml_node_xlink_type, 0);
1383
+ rb_define_method(cXMLNode, "xlink_type_name", rxml_node_xlink_type_name, 0);
1384
+
1385
+ rb_define_alias(cXMLNode, "==", "eql?");
1386
+ }