libxml-ruby 0.9.6 → 0.9.7

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