libxml-ruby 1.1.2-x86-mswin32-60 → 1.1.3-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,7 +51,7 @@ void rxml_dtd_mark(xmlDtdPtr xdtd)
51
51
  return;
52
52
  }
53
53
 
54
- rxml_node_mark_common((xmlNodePtr) xdtd);
54
+ rxml_node_mark((xmlNodePtr) xdtd);
55
55
  }
56
56
 
57
57
 
@@ -81,6 +81,7 @@ static VALUE rxml_error_reset_handler(VALUE self)
81
81
  VALUE rxml_error_wrap(xmlErrorPtr xerror)
82
82
  {
83
83
  VALUE result = Qnil;
84
+
84
85
  if (xerror->message)
85
86
  result = rb_exc_new2(eXMLError, xerror->message);
86
87
  else
@@ -171,6 +172,10 @@ void rxml_raise(xmlErrorPtr xerror)
171
172
 
172
173
  void rxml_init_error()
173
174
  {
175
+ ON_ERROR_METHOD = rb_intern("on_error");
176
+ CALL_METHOD = rb_intern("call");
177
+ ERROR_HANDLER_ID = rb_intern("@@__error_handler_callback__");
178
+
174
179
  /* Intercept libxml error handlers */
175
180
  xmlSetStructuredErrorFunc(NULL, structuredErrorFunc);
176
181
 
@@ -179,11 +184,7 @@ void rxml_init_error()
179
184
  rb_define_singleton_method(eXMLError, "set_handler", rxml_error_set_handler, 0);
180
185
  rb_define_singleton_method(eXMLError, "reset_handler", rxml_error_reset_handler, 0);
181
186
 
182
- ON_ERROR_METHOD = rb_intern("on_error");
183
- CALL_METHOD = rb_intern("call");
184
-
185
187
  /* Ruby callback to receive errors - set it to nil by default. */
186
- ERROR_HANDLER_ID = rb_intern("@@__error_handler_callback__");
187
188
  rxml_set_handler(eXMLError, Qnil);
188
189
 
189
190
  /* Error attributes */
@@ -155,6 +155,12 @@ static VALUE rxml_html_parser_context_file(VALUE klass, VALUE file)
155
155
  if (!ctxt)
156
156
  rxml_raise(&xmlLastError);
157
157
 
158
+ /* This is annoying, but xmlInitParserCtxt (called indirectly above) and
159
+ xmlCtxtUseOptionsInternal (called below) initialize slightly different
160
+ context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt
161
+ sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */
162
+ htmlCtxtUseOptions(ctxt, rxml_libxml_default_options());
163
+
158
164
  return rxml_html_parser_context_wrap(ctxt);
159
165
  }
160
166
 
@@ -187,6 +193,12 @@ static VALUE rxml_html_parser_context_io(VALUE klass, VALUE io)
187
193
  rxml_raise(&xmlLastError);
188
194
  }
189
195
 
196
+ /* This is annoying, but xmlInitParserCtxt (called indirectly above) and
197
+ xmlCtxtUseOptionsInternal (called below) initialize slightly different
198
+ context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt
199
+ sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */
200
+ htmlCtxtUseOptions(ctxt, rxml_libxml_default_options());
201
+
190
202
  stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
191
203
 
192
204
  if (!stream)
@@ -226,6 +238,12 @@ static VALUE rxml_html_parser_context_string(VALUE klass, VALUE string)
226
238
  if (!ctxt)
227
239
  rxml_raise(&xmlLastError);
228
240
 
241
+ /* This is annoying, but xmlInitParserCtxt (called indirectly above) and
242
+ xmlCtxtUseOptionsInternal (called below) initialize slightly different
243
+ context options, in particular XML_PARSE_NODICT which xmlInitParserCtxt
244
+ sets to 0 and xmlCtxtUseOptionsInternal sets to 1. So we have to call both. */
245
+ htmlCtxtUseOptions(ctxt, rxml_libxml_default_options());
246
+
229
247
  htmlDefaultSAXHandlerInit();
230
248
  if (ctxt->sax != NULL)
231
249
  memcpy(ctxt->sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1));
@@ -1,5 +1,6 @@
1
1
  #include "ruby_libxml.h"
2
2
  #include "ruby_xml_node.h"
3
+ #include <assert.h>
3
4
 
4
5
  VALUE cXMLNode;
5
6
 
@@ -13,18 +14,6 @@ VALUE cXMLNode;
13
14
  * documented in the DOM Level 3 specification found at:
14
15
  * http://www.w3.org/TR/DOM-Level-3-Core/. */
15
16
 
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
17
 
29
18
  /* Memory management:
30
19
  *
@@ -40,13 +29,18 @@ VALUE check_string_or_symbol(VALUE val)
40
29
  * * Using the mark function to keep alive any top level, free
41
30
  * standing nodes Ruby is referencing via the node or its children.
42
31
  *
43
- * Ruby will always set a free function when wrapping a node. However,
44
- * the bindings also register a callback that is invoked by libxml
45
- * each time a node is freed. When the callback is called, the node's
46
- * dfree member is set to NULL since Ruby no longer should free the node.
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.
47
41
  */
48
42
 
49
- void rxml_node_deregisterNode(xmlNodePtr xnode)
43
+ static void rxml_node_deregisterNode(xmlNodePtr xnode)
50
44
  {
51
45
  /* Has the node been wrapped and exposed to Ruby? */
52
46
  if (xnode->_private)
@@ -55,59 +49,40 @@ void rxml_node_deregisterNode(xmlNodePtr xnode)
55
49
  then dislabe the dfree function so that Ruby will not
56
50
  try to free the node a second time. */
57
51
  VALUE node = (VALUE) xnode->_private;
58
- RDATA(node)->dmark = NULL;
59
- RDATA(node)->dfree = NULL;
60
- xnode->_private = NULL;
52
+ RDATA(node)->data = NULL;
61
53
  }
62
54
  }
63
55
 
64
- void rxml_node_free(xmlNodePtr xnode)
56
+ static void rxml_node_free(xmlNodePtr xnode)
65
57
  {
66
- /* The Ruby object that wraps the node no longer exists. */
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. */
67
65
  xnode->_private = NULL;
68
66
 
69
- /* Only free nodes that are stand-alone, top level nodes.
70
- If a node belongs to a document, or a parent node, then
71
- the document or parent node will free thsi node. */
72
- if (xnode->doc == NULL && xnode->parent == NULL)
67
+ /* Ruby is responsible for freeing this node since it
68
+ has no parent. */
69
+ if (xnode->parent == NULL)
73
70
  xmlFreeNode(xnode);
74
71
  }
75
72
 
76
- void rxml_node_mark_common(xmlNodePtr xnode)
73
+ void rxml_node_mark(xmlNodePtr xnode)
77
74
  {
78
- if (xnode->parent == NULL)
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
79
  return;
80
80
 
81
81
  if (xnode->doc != NULL)
82
- {
83
- if (xnode->doc->_private == NULL)
84
- rb_bug("XmlNode Doc is not bound! (%s:%d)", __FILE__,__LINE__);
85
82
  rb_gc_mark((VALUE) xnode->doc->_private);
86
- }
87
- else
88
- {
89
- while (xnode->parent != NULL)
90
- xnode = xnode->parent;
91
-
92
- if (xnode->_private == NULL)
93
- rb_warning("XmlNode Root Parent is not bound! (%s:%d)", __FILE__,__LINE__);
94
- else
95
- rb_gc_mark((VALUE) xnode->_private);
96
- }
97
- }
98
-
99
- void rxml_node_mark(xmlNodePtr xnode)
100
- {
101
- if (xnode == NULL)
102
- return;
103
-
104
- if (xnode->_private == NULL)
105
- {
106
- rb_warning("XmlNode is not bound! (%s:%d)", __FILE__, __LINE__);
107
- return;
108
- }
109
-
110
- rxml_node_mark_common(xnode);
83
+
84
+ if (xnode->parent != NULL)
85
+ rb_gc_mark((VALUE) xnode->_private);
111
86
  }
112
87
 
113
88
  VALUE rxml_node_wrap(xmlNodePtr xnode)
@@ -119,9 +94,6 @@ VALUE rxml_node_wrap(xmlNodePtr xnode)
119
94
  }
120
95
  else
121
96
  {
122
- /* Assume Ruby is responsible for freeing this node. If libxml frees it
123
- instead, the rxml_node_deregisterNode callback is executed, and
124
- we set the free function to NULL. */
125
97
  VALUE node = Data_Wrap_Struct(cXMLNode, rxml_node_mark, rxml_node_free, xnode);
126
98
  xnode->_private = (void*) node;
127
99
  return node;
@@ -130,7 +102,8 @@ VALUE rxml_node_wrap(xmlNodePtr xnode)
130
102
 
131
103
  static VALUE rxml_node_alloc(VALUE klass)
132
104
  {
133
- /* Ruby is responsible for freeing this node not libxml. */
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. */
134
107
  return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node_free, NULL);
135
108
  }
136
109
 
@@ -217,6 +190,8 @@ static VALUE rxml_node_new_text(VALUE klass, VALUE content)
217
190
  return rxml_node_wrap(xnode);
218
191
  }
219
192
 
193
+ static VALUE rxml_node_content_set(VALUE self, VALUE content);
194
+
220
195
  /*
221
196
  * call-seq:
222
197
  * XML::Node.initialize(name, content = nil, namespace = nil) -> XML::Node
@@ -234,14 +209,19 @@ static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self)
234
209
 
235
210
  rb_scan_args(argc, argv, "12", &name, &content, &ns);
236
211
 
237
- name = check_string_or_symbol(name);
212
+ name = rb_obj_as_string(name);
238
213
 
239
214
  if (!NIL_P(ns))
240
215
  Data_Get_Struct(ns, xmlNs, xns);
241
216
 
242
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. */
243
223
  xnode->_private = (void*) self;
244
- DATA_PTR( self) = xnode;
224
+ DATA_PTR(self) = xnode;
245
225
 
246
226
  if (!NIL_P(content))
247
227
  rxml_node_content_set(self, content);
@@ -249,6 +229,36 @@ static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self)
249
229
  return self;
250
230
  }
251
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
+
252
262
  /*
253
263
  * call-seq:
254
264
  * node.base_uri -> "uri"
@@ -404,51 +414,20 @@ static VALUE rxml_node_first_get(VALUE self)
404
414
  return (Qnil);
405
415
  }
406
416
 
407
- /*
408
- * underlying for child_set and child_add, difference being
409
- * former raises on implicit copy, latter does not.
410
- */
411
- static VALUE rxml_node_child_set_aux(VALUE self, VALUE child)
412
- {
413
- xmlNodePtr xnode, xchild, xresult;
414
-
415
- if (rb_obj_is_kind_of(child, cXMLNode) == Qfalse)
416
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
417
-
418
- Data_Get_Struct(self, xmlNode, xnode);
419
- Data_Get_Struct(child, xmlNode, xchild);
420
-
421
- if (xchild->parent != NULL || xchild->doc != NULL)
422
- rb_raise(rb_eRuntimeError,
423
- "Cannot move a node from one document to another with child= or <<. First copy the node before moving it.");
424
-
425
- xresult = xmlAddChild(xnode, xchild);
426
-
427
- if (!xresult)
428
- rxml_raise(&xmlLastError);
429
-
430
- return rxml_node_wrap(xresult);
431
- }
432
417
 
433
418
  /*
434
419
  * call-seq:
435
- * node.child = node
420
+ * curr_node << "<p>A paragraph</p>"
421
+ * curr_node << node
436
422
  *
437
- * Set a child node for this node. Also called for <<
438
- */
439
- static VALUE rxml_node_child_set(VALUE self, VALUE rnode)
440
- {
441
- return rxml_node_child_set_aux(self, rnode);
442
- }
443
-
444
- /*
445
- * call-seq:
446
- * node << ("string" | node) -> XML::Node
423
+ * Add the specified text or XML::Node as a new child node to the
424
+ * current node.
447
425
  *
448
- * Add the specified string or XML::Node to this node's
449
- * content. The returned node is the node that was
450
- * added and not self, thereby allowing << calls to
451
- * be chained.
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.
452
431
  */
453
432
  static VALUE rxml_node_content_add(VALUE self, VALUE obj)
454
433
  {
@@ -461,8 +440,11 @@ static VALUE rxml_node_content_add(VALUE self, VALUE obj)
461
440
  * danj 070827
462
441
  */
463
442
  if (rb_obj_is_kind_of(obj, cXMLNode))
464
- {
465
- rxml_node_child_set(self, obj);
443
+ {
444
+ xmlNodePtr xtarget;
445
+ Data_Get_Struct(obj, xmlNode, xtarget);
446
+ xmlUnlinkNode(xtarget);
447
+ rxml_node_modify_dom(self, obj, xmlAddChild);
466
448
  }
467
449
  else
468
450
  {
@@ -472,18 +454,7 @@ static VALUE rxml_node_content_add(VALUE self, VALUE obj)
472
454
 
473
455
  xmlNodeAddContent(xnode, (xmlChar*) StringValuePtr(str));
474
456
  }
475
- return (self);
476
- }
477
-
478
- /*
479
- * call-seq:
480
- * node.child_add(node)
481
- *
482
- * Set a child node for this node.
483
- */
484
- static VALUE rxml_node_child_add(VALUE self, VALUE rnode)
485
- {
486
- return rxml_node_child_set_aux(self, rnode);
457
+ return self;
487
458
  }
488
459
 
489
460
  /*
@@ -923,7 +894,7 @@ static VALUE rxml_node_name_set(VALUE self, VALUE name)
923
894
  * call-seq:
924
895
  * node.next -> XML::Node
925
896
  *
926
- * Obtain the next sibling node, if any.
897
+ * Returns the next sibling node if one exists.
927
898
  */
928
899
  static VALUE rxml_node_next_get(VALUE self)
929
900
  {
@@ -939,25 +910,17 @@ static VALUE rxml_node_next_get(VALUE self)
939
910
 
940
911
  /*
941
912
  * call-seq:
942
- * node.next = node
913
+ * curr_node.next = node
943
914
  *
944
- * Insert the specified node as this node's next sibling.
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.
945
920
  */
946
921
  static VALUE rxml_node_next_set(VALUE self, VALUE next)
947
922
  {
948
- xmlNodePtr xnode, xnext, xresult;
949
-
950
- if (rb_obj_is_kind_of(next, cXMLNode) == Qfalse)
951
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
952
-
953
- Data_Get_Struct(self, xmlNode, xnode);
954
- Data_Get_Struct(next, xmlNode, xnext);
955
-
956
- xresult = xmlAddNextSibling(xnode, xnext);
957
- if (xresult == NULL)
958
- rxml_raise(&xmlLastError);
959
-
960
- return rxml_node_wrap(xresult);
923
+ return rxml_node_modify_dom(self, next, xmlAddNextSibling);
961
924
  }
962
925
 
963
926
  /*
@@ -1050,25 +1013,17 @@ static VALUE rxml_node_prev_get(VALUE self)
1050
1013
 
1051
1014
  /*
1052
1015
  * call-seq:
1053
- * node.prev = node
1016
+ * curr_node.prev = node
1054
1017
  *
1055
- * Insert the specified node as this node's previous sibling.
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.
1056
1023
  */
1057
1024
  static VALUE rxml_node_prev_set(VALUE self, VALUE prev)
1058
1025
  {
1059
- xmlNodePtr xnode, xprev, xresult;
1060
-
1061
- if (rb_obj_is_kind_of(prev, cXMLNode) == Qfalse)
1062
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1063
-
1064
- Data_Get_Struct(self, xmlNode, xnode);
1065
- Data_Get_Struct(prev, xmlNode, xprev);
1066
-
1067
- xresult = xmlAddPrevSibling(xnode, xprev);
1068
- if (xresult == NULL)
1069
- rxml_raise(&xmlLastError);
1070
-
1071
- return rxml_node_wrap(xresult);
1026
+ return rxml_node_modify_dom(self, prev, xmlAddPrevSibling);
1072
1027
  }
1073
1028
 
1074
1029
  /*
@@ -1114,51 +1069,52 @@ static VALUE rxml_node_property_set(VALUE self, VALUE name, VALUE value)
1114
1069
  * call-seq:
1115
1070
  * node.remove! -> node
1116
1071
  *
1117
- * Removes this node and its children from its
1118
- * document tree by setting its document,
1119
- * parent and siblings to nil. You can add
1120
- * the returned node back into a document.
1121
- * Otherwise, the node will be freed once
1122
- * any references to it go out of scope. */
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
+ */
1123
1076
 
1124
1077
  static VALUE rxml_node_remove_ex(VALUE self)
1125
1078
  {
1126
- xmlNodePtr xnode;
1079
+ xmlNodePtr xnode, xresult;
1127
1080
  Data_Get_Struct(self, xmlNode, xnode);
1128
1081
 
1129
- /* Unlink the node from its parent. */
1082
+ /* First unlink the node from its parent. */
1130
1083
  xmlUnlinkNode(xnode);
1131
1084
 
1132
- /* Now set the nodes parent to nil so it can
1133
- be freed if the reference to it goes out of scope*/
1134
- xmlSetTreeDoc(xnode, NULL);
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;
1135
1099
 
1136
1100
  /* Now return the removed node so the user can
1137
- do something wiht it.*/
1101
+ do something with it.*/
1138
1102
  return self;
1139
1103
  }
1140
1104
 
1141
1105
  /*
1142
1106
  * call-seq:
1143
- * node.sibling(node) -> XML::Node
1107
+ * curr_node.sibling = node
1144
1108
  *
1145
- * Add the specified node as a sibling of this node.
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.
1146
1114
  */
1147
1115
  static VALUE rxml_node_sibling_set(VALUE self, VALUE sibling)
1148
1116
  {
1149
- xmlNodePtr xnode, xsibling, xresult;
1150
-
1151
- if (rb_obj_is_kind_of(sibling, cXMLNode) == Qfalse)
1152
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1153
-
1154
- Data_Get_Struct(self, xmlNode, xnode);
1155
- Data_Get_Struct(sibling, xmlNode, xsibling);
1156
-
1157
- xresult = xmlAddSibling(xnode, xsibling);
1158
- if (xresult == NULL)
1159
- rxml_raise(&xmlLastError);
1160
-
1161
- return rxml_node_wrap(xresult);
1117
+ return rxml_node_modify_dom(self, sibling, xmlAddSibling);
1162
1118
  }
1163
1119
 
1164
1120
  /*
@@ -1389,10 +1345,8 @@ void rxml_init_node(void)
1389
1345
  rb_define_method(cXMLNode, "prev", rxml_node_prev_get, 0);
1390
1346
 
1391
1347
  /* Modification */
1392
- rb_define_method(cXMLNode, "<<", rxml_node_content_add, 1);
1393
1348
  rb_define_method(cXMLNode, "[]=", rxml_node_property_set, 2);
1394
- rb_define_method(cXMLNode, "child_add", rxml_node_child_add, 1);
1395
- rb_define_method(cXMLNode, "child=", rxml_node_child_set, 1);
1349
+ rb_define_method(cXMLNode, "<<", rxml_node_content_add, 1);
1396
1350
  rb_define_method(cXMLNode, "sibling=", rxml_node_sibling_set, 1);
1397
1351
  rb_define_method(cXMLNode, "next=", rxml_node_next_set, 1);
1398
1352
  rb_define_method(cXMLNode, "prev=", rxml_node_prev_set, 1);