libxml-ruby 1.1.2-x86-mswin32-60 → 1.1.3-x86-mswin32-60
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +20 -0
- data/ext/libxml/build.log +4 -4
- data/ext/libxml/extconf.rb +278 -278
- data/ext/libxml/libxml.c +77 -77
- data/ext/libxml/ruby_xml.c +80 -42
- data/ext/libxml/ruby_xml.h +1 -0
- data/ext/libxml/ruby_xml_attr.c +352 -352
- data/ext/libxml/ruby_xml_attr_decl.c +1 -1
- data/ext/libxml/ruby_xml_attributes.c +3 -3
- data/ext/libxml/ruby_xml_cbg.c +86 -86
- data/ext/libxml/ruby_xml_document.c +936 -915
- data/ext/libxml/ruby_xml_dtd.c +1 -1
- data/ext/libxml/ruby_xml_error.c +5 -4
- data/ext/libxml/ruby_xml_html_parser_context.c +18 -0
- data/ext/libxml/ruby_xml_node.c +131 -177
- data/ext/libxml/ruby_xml_node.h +2 -3
- data/ext/libxml/ruby_xml_parser_context.c +32 -2
- data/ext/libxml/ruby_xml_version.h +3 -3
- data/ext/mingw/libxml_ruby.dll.a +0 -0
- data/ext/mingw/libxml_ruby.so +0 -0
- data/lib/libxml/node.rb +11 -0
- data/test/tc_document.rb +13 -2
- data/test/tc_dtd.rb +5 -4
- data/test/tc_node.rb +1 -1
- data/test/tc_node_edit.rb +28 -4
- data/test/tc_xml.rb +12 -0
- data/test/tc_xpath.rb +0 -10
- metadata +2 -3
- data/test/cro_events.html +0 -740
data/ext/libxml/ruby_xml_dtd.c
CHANGED
data/ext/libxml/ruby_xml_error.c
CHANGED
@@ -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));
|
data/ext/libxml/ruby_xml_node.c
CHANGED
@@ -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
|
-
*
|
44
|
-
*
|
45
|
-
*
|
46
|
-
*
|
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)->
|
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
|
-
/*
|
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
|
-
/*
|
70
|
-
|
71
|
-
|
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
|
73
|
+
void rxml_node_mark(xmlNodePtr xnode)
|
77
74
|
{
|
78
|
-
|
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
|
-
|
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 =
|
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(
|
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
|
-
*
|
420
|
+
* curr_node << "<p>A paragraph</p>"
|
421
|
+
* curr_node << node
|
436
422
|
*
|
437
|
-
*
|
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
|
-
*
|
449
|
-
*
|
450
|
-
*
|
451
|
-
*
|
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
|
-
|
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
|
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
|
-
*
|
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
|
-
*
|
913
|
+
* curr_node.next = node
|
943
914
|
*
|
944
|
-
*
|
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
|
-
|
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
|
-
*
|
1016
|
+
* curr_node.prev = node
|
1054
1017
|
*
|
1055
|
-
*
|
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
|
-
|
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
|
-
*
|
1119
|
-
*
|
1120
|
-
|
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
|
-
/*
|
1082
|
+
/* First unlink the node from its parent. */
|
1130
1083
|
xmlUnlinkNode(xnode);
|
1131
1084
|
|
1132
|
-
/* Now
|
1133
|
-
|
1134
|
-
|
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
|
-
|
1101
|
+
do something with it.*/
|
1138
1102
|
return self;
|
1139
1103
|
}
|
1140
1104
|
|
1141
1105
|
/*
|
1142
1106
|
* call-seq:
|
1143
|
-
*
|
1107
|
+
* curr_node.sibling = node
|
1144
1108
|
*
|
1145
|
-
*
|
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
|
-
|
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, "
|
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);
|