libxml-ruby 2.0.2-x86-mingw32 → 2.0.3-x86-mingw32

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.
data/HISTORY CHANGED
@@ -1,6 +1,57 @@
1
1
  = Release History
2
2
 
3
- == 2.0.1 / 2011-04-17 Charlie Savage
3
+ == 2.0.3 / 2011-05-01 Charlie Savage
4
+
5
+ * The biggest change in this release is supporting the use of libxml-ruby in
6
+ native background Ruby threads. Previously, the use of libxml-ruby in
7
+ background threads in Ruby 1.9.x and higher would often cause
8
+ segmentation faults. This has now been fixed (Charlie Savage).
9
+
10
+ * Update Reader#expand so that returned node correctly remembers its
11
+ encoding in Ruby 1.9.x (zerebubuth).
12
+
13
+ * Add check to verify a node has not been deleted. This can happen when
14
+ a ruby variable holds a reference to a child node that gets freed
15
+ when its parent gets freed. Previously when this happened a
16
+ segmentation fault would occur, now an exception is raised (Charlie Savage, fixes
17
+ RubyForge #26839.
18
+
19
+ * Do not unlink nodes before internal validations have run - avoids
20
+ segmentation faults caused by freeing a node twice (Charlie Savage).
21
+
22
+ * Add support for Document#canonicalization (Victor Lin).
23
+
24
+ * Fix memory leak in Reader#lookup_namespace (Charlie Savage).
25
+
26
+ * Fix memory leak in Reader#[] (Nathan Kriege).
27
+
28
+ * Fix usage of @io instance variable (Jeffrey Taylor)
29
+
30
+ * Removed old sax error handling code that has been fixed in newer
31
+ versions of libxml (Charlie Savage).
32
+
33
+ * Code cleanup - remove unused variables and commented out code (Charlie Savage)
34
+
35
+ * Minor text changes and documentation fixes (Charlie Savage).
36
+
37
+ * Fix documentation error (fixes RubyForge #26888).
38
+
39
+ * Update documentation for Document#validation* methods (fixes RubyForge #24833).
40
+
41
+ * Update documentation and test (fixes Ruby Forge Issue #28770).
42
+
43
+ * Updated documentation in README (Anurag Priyam):
44
+ 1. rake doc does not work; use rake rdoc.
45
+ 2. gem mislav-hanna does not exist; use hanna.
46
+ 3. rake rdoc 'depends' on hanna; no need of RDOCOPTS
47
+ 4. Point to the github issue tracker instead of Ruby Forge
48
+ 5. Point to the github (gh-pages) site for docs
49
+
50
+ * Add tc_error to test suite (Charlie Savage).
51
+
52
+ * Add sax test (Stanislav O.Pogrebnyak).
53
+
54
+ == 2.0.2 / 2011-04-17 Charlie Savage
4
55
 
5
56
  * Added binaries for windows (Charlie Savage).
6
57
 
data/README.rdoc CHANGED
@@ -75,9 +75,9 @@ then install the libxslt gem which is available at
75
75
  http://rubyforge.org/projects/libxsl/.
76
76
 
77
77
  == Usage
78
- For information about using libxml-ruby please refer
79
- to its documentation at http://libxml.rubyforge.org/rdoc/index.html.
80
- Some tutorials are also available at https://github.com/xml4r/libxml-ruby/wiki.
78
+ For information about using libxml-ruby please refer to its documentation at
79
+ http://xml4r.github.com/libxml-ruby/rdoc/index.html Some tutorials are also
80
+ available at https://github.com/xml4r/libxml-ruby/wiki.
81
81
 
82
82
  All libxml classes are in the LibXML::XML module. The easiest
83
83
  way to use libxml is to require 'xml'. This will mixin
@@ -111,6 +111,34 @@ For example:
111
111
 
112
112
  For simplicity's sake, the documentation uses the xml module in its examples.
113
113
 
114
+ == Memory Management
115
+ libxml-ruby automatically manages memory associated with the
116
+ underlying libxml2 library. There is however one corner case that
117
+ your code must handle. If a node is imported into a document, but not
118
+ added to the document, a segmentation fault may occur on program termination.
119
+
120
+ # Do NOT do this
121
+ require 'xml'
122
+ doc1 = XML::Document.string("test1")
123
+ doc2 = XML::Document.string("test2")
124
+ node = doc2.import(doc1.root)
125
+
126
+ If doc2 is freed before node2 a segmentatin fault will occur since
127
+ node2 references the document. To avoid this, simply make sure to add the
128
+ node to the document:
129
+
130
+ # DO this instead
131
+ doc1 = XML::Document.string("test1")
132
+ doc2 = XML::Document.string("test2")
133
+ doc2.root << doc2.import(doc1.root)
134
+
135
+ Alternatively, you can call node2.remove! to disassociate node2 from doc2.
136
+
137
+ == Threading
138
+ libxml-ruby fully supports native, background Ruby threads. This of course
139
+ only applies to Ruby 1.9.x and higher since earlier versions of Ruby do not
140
+ support native threads.
141
+
114
142
  == Performance
115
143
  In addition to being feature rich and conformation, the main reason
116
144
  people use libxml-ruby is for performance. Here are the results
@@ -134,12 +162,14 @@ From https://svn.concord.org/svn/projects/trunk/common/ruby/xml_benchmarks/
134
162
 
135
163
 
136
164
  == Documentation
137
- Documentation is available via rdoc. To generate the documentation,
138
- run the the command 'rake doc'. libxml-ruby's online documentation
139
- is generated using Hanna. To use hanna:
165
+ Documentation is available via rdoc, and is installed automatically with the
166
+ gem.
167
+
168
+ libxml-ruby's online documentation is generated using Hanna. To generate
169
+ documentation from source:
140
170
 
141
- gem install mislav-hanna
142
- rake rdoc RDOCOPT="-S -T hanna"
171
+ gem install hanna
172
+ rake rdoc
143
173
 
144
174
  Note that older versions of Rdoc, which ship with Ruby 1.8.x, will report
145
175
  a number of errors. To avoid them, install Rdoc 2.1 or higher from
@@ -152,8 +182,8 @@ ruby/lib/ruby/1.8/rdoc_old.
152
182
 
153
183
  If you have any questions about using libxml-ruby, please send them to
154
184
  libxml-devel@rubyforge.org. If you have found any bugs in libxml-devel,
155
- or have developed new patches, please submit them to Ruby Forge at
156
- http://rubyforge.org/tracker/?group_id=494.
185
+ or have developed new patches, please submit them to Git Hub at
186
+ https://github.com/xml4r/libxml-ruby/issues.
157
187
 
158
188
  == License
159
189
  See LICENSE for license information.
@@ -14,6 +14,7 @@
14
14
  #include <libxml/catalog.h>
15
15
  #include <libxml/HTMLparser.h>
16
16
  #include <libxml/xmlreader.h>
17
+ #include <libxml/c14n.h>
17
18
 
18
19
  /* Needed for Ruby 1.8.5 */
19
20
  #ifndef RARRAY_LEN
@@ -186,7 +186,7 @@ static VALUE rxml_attr_name_get(VALUE self)
186
186
  if (xattr->name == NULL)
187
187
  return Qnil;
188
188
  else
189
- return rxml_str_new2((const char*) xattr->name, xattr->doc->encoding);
189
+ return rxml_str_new2((const char*) xattr->name, (xattr->doc ? xattr->doc->encoding : NULL));
190
190
  }
191
191
 
192
192
  /*
@@ -302,7 +302,7 @@ VALUE rxml_attr_value_get(VALUE self)
302
302
 
303
303
  if (value != NULL)
304
304
  {
305
- result = rxml_str_new2((const char*) value, xattr->doc->encoding);
305
+ result = rxml_str_new2((const char*) value, (xattr->doc ? xattr->doc->encoding : NULL));
306
306
  xmlFree(value);
307
307
  }
308
308
  return result;
@@ -20,7 +20,7 @@
20
20
  * doc = XML::Document.new()
21
21
  * doc.root = XML::Node.new('root_node')
22
22
  * doc.root << XML::Node.new('elem1')
23
- * doc.save(filename, :indent => true, :encoding => 'UTF-8')
23
+ * doc.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8)
24
24
  *
25
25
  * To write a document to a file:
26
26
  *
@@ -45,7 +45,7 @@
45
45
  *
46
46
  * elem3['attr'] = 'baz'
47
47
  *
48
- * doc.save(filename, :indent => true, :encoding => 'UTF-8')
48
+ * doc.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8)
49
49
  */
50
50
 
51
51
  #include <stdarg.h>
@@ -123,6 +123,40 @@ static VALUE rxml_document_initialize(int argc, VALUE *argv, VALUE self)
123
123
  return self;
124
124
  }
125
125
 
126
+ /*
127
+ * call-seq:
128
+ * document.canonicalize(comments) -> String
129
+ *
130
+ * Returns a string containing the canonicalized form of the document.
131
+ *
132
+ * :comments - Specifies if comments should be output. This is an optional
133
+ * parameter whose default value is false.
134
+ */
135
+ static VALUE rxml_document_canonicalize(int argc, VALUE *argv, VALUE self)
136
+ {
137
+ VALUE result = Qnil;
138
+ VALUE comments = Qnil ;
139
+ xmlDocPtr xdoc;
140
+ xmlChar *buffer = NULL;
141
+ int length;
142
+
143
+ rb_scan_args(argc, argv, "01", &comments);
144
+
145
+ Data_Get_Struct(self, xmlDoc, xdoc);
146
+ length = xmlC14NDocDumpMemory(xdoc, NULL, XML_C14N_1_1, NULL,
147
+ (comments == Qtrue ? 1 : 0),
148
+ &buffer);
149
+
150
+ if (buffer)
151
+ {
152
+ result = rxml_str_new2((const char*) buffer, (const char*)xdoc->encoding);
153
+ xmlFree(buffer);
154
+ }
155
+
156
+ return result;
157
+ }
158
+
159
+
126
160
  /*
127
161
  * call-seq:
128
162
  * document.compression -> num
@@ -285,16 +319,17 @@ static VALUE rxml_document_encoding_get(VALUE self)
285
319
  * Returns the Ruby encoding specified by this document
286
320
  * (available on Ruby 1.9.x and higher).
287
321
  */
322
+ #ifdef HAVE_RUBY_ENCODING_H
288
323
  static VALUE rxml_document_rb_encoding_get(VALUE self)
289
324
  {
290
325
  xmlDocPtr xdoc;
291
326
  const char *xencoding;
292
- VALUE encoding;
293
327
  Data_Get_Struct(self, xmlDoc, xdoc);
294
328
 
295
329
  xencoding = (const char*)xdoc->encoding;
296
330
  return rxml_xml_encoding_to_rb_encoding(mXMLEncoding, xmlParseCharEncoding(xencoding));
297
331
  }
332
+ #endif
298
333
 
299
334
  /*
300
335
  * call-seq:
@@ -322,6 +357,11 @@ static VALUE rxml_document_encoding_set(VALUE self, VALUE encoding)
322
357
  *
323
358
  * Creates a copy of the node that can be inserted into the
324
359
  * current document.
360
+ *
361
+ * IMPORTANT - The returned node MUST be inserted into the document.
362
+ * This is because the returned node refereces internal LibXML data
363
+ * structures owned by the document. Therefore, if the document is
364
+ * is freed before the the node is freed a segmentation fault will occur.
325
365
  */
326
366
  static VALUE rxml_document_import(VALUE self, VALUE node)
327
367
  {
@@ -534,6 +574,9 @@ static VALUE rxml_document_root_set(VALUE self, VALUE node)
534
574
  Data_Get_Struct(self, xmlDoc, xdoc);
535
575
  Data_Get_Struct(node, xmlNode, xnode);
536
576
 
577
+ if (xnode->doc != NULL && xnode->doc != xdoc)
578
+ rb_raise(eXMLError, "Nodes belong to different documents. You must first import the node by calling XML::Document.import");
579
+
537
580
  xroot = xmlDocSetRootElement(xdoc, xnode);
538
581
  return node;
539
582
  }
@@ -541,7 +584,7 @@ static VALUE rxml_document_root_set(VALUE self, VALUE node)
541
584
  /*
542
585
  * call-seq:
543
586
  * document.save(filename) -> int
544
- * document.save(filename, :indent => true, :encoding => 'UTF-8') -> int
587
+ * document.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8) -> int
545
588
  *
546
589
  * Saves a document to a file. You may provide an optional hash table
547
590
  * to control how the string is generated. Valid options are:
@@ -619,7 +662,7 @@ static VALUE rxml_document_standalone_q(VALUE self)
619
662
  /*
620
663
  * call-seq:
621
664
  * document.to_s -> "string"
622
- * document.to_s(:indent => true, :encoding => 'UTF-8') -> "string"
665
+ * document.to_s(:indent => true, :encoding => XML::Encoding::UTF_8) -> "string"
623
666
  *
624
667
  * Converts a document, and all of its children, to a string representation.
625
668
  * You may provide an optional hash table to control how the string is
@@ -771,9 +814,11 @@ static VALUE rxml_document_order_elements(VALUE self)
771
814
 
772
815
  /*
773
816
  * call-seq:
774
- * document.validate_schema(schema) -> (true|false)
817
+ * document.validate_schema(schema)
775
818
  *
776
819
  * Validate this document against the specified XML::Schema.
820
+ * If the document is valid the method returns true. Otherwise an
821
+ * exception is raised with validation information.
777
822
  */
778
823
  static VALUE rxml_document_validate_schema(VALUE self, VALUE schema)
779
824
  {
@@ -802,9 +847,11 @@ static VALUE rxml_document_validate_schema(VALUE self, VALUE schema)
802
847
 
803
848
  /*
804
849
  * call-seq:
805
- * document.validate_schema(relaxng) -> (true|false)
850
+ * document.validate_relaxng(relaxng)
806
851
  *
807
852
  * Validate this document against the specified XML::RelaxNG.
853
+ * If the document is valid the method returns true. Otherwise an
854
+ * exception is raised with validation information.
808
855
  */
809
856
  static VALUE rxml_document_validate_relaxng(VALUE self, VALUE relaxng)
810
857
  {
@@ -836,6 +883,8 @@ static VALUE rxml_document_validate_relaxng(VALUE self, VALUE relaxng)
836
883
  * document.validate(dtd) -> (true|false)
837
884
  *
838
885
  * Validate this document against the specified XML::DTD.
886
+ * If the document is valid the method returns true. Otherwise an
887
+ * exception is raised with validation information.
839
888
  */
840
889
  static VALUE rxml_document_validate_dtd(VALUE self, VALUE dtd)
841
890
  {
@@ -871,6 +920,7 @@ void rxml_init_document(void)
871
920
  rb_define_alloc_func(cXMLDocument, rxml_document_alloc);
872
921
 
873
922
  rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1);
923
+ rb_define_method(cXMLDocument, "canonicalize", rxml_document_canonicalize, -1);
874
924
  rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0);
875
925
  rb_define_method(cXMLDocument, "child?", rxml_document_child_q, 0);
876
926
  rb_define_method(cXMLDocument, "compression", rxml_document_compression_get, 0);
@@ -131,18 +131,6 @@ static void structuredErrorFunc(void *userData, xmlErrorPtr xerror)
131
131
  /* Wrap error up as Ruby object and send it off to ruby */
132
132
  VALUE block = rb_cvar_get(eXMLError, ERROR_HANDLER_ID);
133
133
 
134
- /* This next bit of code is a total hack to get around a bug
135
- in libxml which causes error handlers on sax handlers to
136
- be ignored in favor of the global handler. In addition,
137
- the correct context is also not passed in. So try to
138
- dig it out. */
139
- if (!userData && xerror->ctxt)
140
- {
141
- xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) xerror->ctxt;
142
- if (ctxt != ctxt->userData)
143
- userData = ctxt->userData;
144
- }
145
-
146
134
  /* Now call global handler */
147
135
  if (block != Qnil)
148
136
  {
@@ -33,11 +33,11 @@ VALUE cXMLNode;
33
33
  * a libxml document. When a Ruby node is freed, the _private
34
34
  * field is set back to null.
35
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.
36
+ * In the sweep phase in Ruby 1.9.*, the document tends to be
37
+ * freed before the nodes. To support this, the bindings register
38
+ * a callback function with libxml that is called each time a node
39
+ * is freed. In that case, the data_ptr is set to null, so the bindings
40
+ * can recognize the situation.
41
41
  */
42
42
 
43
43
  static void rxml_node_deregisterNode(xmlNodePtr xnode)
@@ -50,6 +50,8 @@ static void rxml_node_deregisterNode(xmlNodePtr xnode)
50
50
  try to free the node a second time. */
51
51
  VALUE node = (VALUE) xnode->_private;
52
52
  RDATA(node)->data = NULL;
53
+ RDATA(node)->dfree = NULL;
54
+ RDATA(node)->dmark = NULL;
53
55
  }
54
56
  }
55
57
 
@@ -64,40 +66,46 @@ static void rxml_node_free(xmlNodePtr xnode)
64
66
  /* The ruby object wrapping the xml object no longer exists. */
65
67
  xnode->_private = NULL;
66
68
 
67
- /* Ruby is responsible for freeing this node since it
68
- has no parent. */
69
+ /* Ruby is responsible for freeing this node if it does not
70
+ have a parent and is not owned by a document. Note a corner
71
+ case here - calling node2 = doc.import(node1) will cause node2
72
+ to not have a parent but to have a document. */
69
73
  if (xnode->parent == NULL)
74
+ {
70
75
  xmlFreeNode(xnode);
76
+ }
71
77
  }
72
78
 
73
79
  void rxml_node_mark(xmlNodePtr xnode)
74
80
  {
75
- /* Either the node has been created yet in initialize
81
+ /* Either the node has not been created yet in initialize
76
82
  or it has been freed by libxml already in Ruby's
77
83
  mark phase. */
78
84
  if (xnode == NULL)
79
85
  return;
80
86
 
81
- if (xnode->doc != NULL)
87
+ if (xnode->doc && xnode->doc->_private)
82
88
  rb_gc_mark((VALUE) xnode->doc->_private);
83
89
 
84
- if (xnode->parent != NULL)
90
+ if (xnode->parent && xnode->parent->_private)
85
91
  rb_gc_mark((VALUE) xnode->_private);
86
92
  }
87
93
 
88
94
  VALUE rxml_node_wrap(xmlNodePtr xnode)
89
95
  {
96
+ VALUE result;
97
+
90
98
  /* Is the node already wrapped? */
91
99
  if (xnode->_private != NULL)
92
100
  {
93
- return (VALUE) xnode->_private;
101
+ result = (VALUE) xnode->_private;
94
102
  }
95
103
  else
96
104
  {
97
- VALUE node = Data_Wrap_Struct(cXMLNode, rxml_node_mark, rxml_node_free, xnode);
98
- xnode->_private = (void*) node;
99
- return node;
105
+ result = Data_Wrap_Struct(cXMLNode, rxml_node_mark, rxml_node_free, xnode);
106
+ xnode->_private = (void*) result;
100
107
  }
108
+ return result;
101
109
  }
102
110
 
103
111
  static VALUE rxml_node_alloc(VALUE klass)
@@ -107,6 +115,17 @@ static VALUE rxml_node_alloc(VALUE klass)
107
115
  return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node_free, NULL);
108
116
  }
109
117
 
118
+ static xmlNodePtr rxml_get_xnode(VALUE node)
119
+ {
120
+ xmlNodePtr result;
121
+ Data_Get_Struct(node, xmlNode, result);
122
+
123
+ if (!result)
124
+ rb_raise(rb_eRuntimeError, "This node has already been freed.");
125
+
126
+ return result;
127
+ }
128
+
110
129
  /*
111
130
  * call-seq:
112
131
  * XML::Node.new_cdata(content = nil) -> XML::Node
@@ -237,11 +256,13 @@ static VALUE rxml_node_modify_dom(VALUE self, VALUE target,
237
256
  if (rb_obj_is_kind_of(target, cXMLNode) == Qfalse)
238
257
  rb_raise(rb_eTypeError, "Must pass an XML::Node object");
239
258
 
240
- Data_Get_Struct(self, xmlNode, xnode);
241
- Data_Get_Struct(target, xmlNode, xtarget);
259
+ xnode = rxml_get_xnode(self);
260
+ xtarget = rxml_get_xnode(target);
242
261
 
243
262
  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");
263
+ rb_raise(eXMLError, "Nodes belong to different documents. You must first import the node by calling XML::Document.import");
264
+
265
+ xmlUnlinkNode(xtarget);
245
266
 
246
267
  /* This target node could be freed here. */
247
268
  xresult = xmlFunc(xnode, xtarget);
@@ -271,7 +292,7 @@ static VALUE rxml_node_base_uri_get(VALUE self)
271
292
  xmlChar* base_uri;
272
293
  VALUE result = Qnil;
273
294
 
274
- Data_Get_Struct(self, xmlNode, xnode);
295
+ xnode = rxml_get_xnode(self);
275
296
 
276
297
  if (xnode->doc == NULL)
277
298
  return (result);
@@ -299,7 +320,7 @@ static VALUE rxml_node_base_uri_set(VALUE self, VALUE uri)
299
320
  xmlNodePtr xnode;
300
321
 
301
322
  Check_Type(uri, T_STRING);
302
- Data_Get_Struct(self, xmlNode, xnode);
323
+ xnode = rxml_get_xnode(self);
303
324
  if (xnode->doc == NULL)
304
325
  return (Qnil);
305
326
 
@@ -319,7 +340,7 @@ static VALUE rxml_node_content_get(VALUE self)
319
340
  xmlChar *content;
320
341
  VALUE result = Qnil;
321
342
 
322
- Data_Get_Struct(self, xmlNode, xnode);
343
+ xnode = rxml_get_xnode(self);
323
344
  content = xmlNodeGetContent(xnode);
324
345
  if (content)
325
346
  {
@@ -341,7 +362,7 @@ static VALUE rxml_node_content_set(VALUE self, VALUE content)
341
362
  xmlNodePtr xnode;
342
363
 
343
364
  Check_Type(content, T_STRING);
344
- Data_Get_Struct(self, xmlNode, xnode);
365
+ xnode = rxml_get_xnode(self);
345
366
  // XXX docs indicate need for escaping entites, need to be done? danj
346
367
  xmlNodeSetContent(xnode, (xmlChar*) StringValuePtr(content));
347
368
  return (Qtrue);
@@ -362,7 +383,7 @@ static VALUE rxml_node_content_stripped_get(VALUE self)
362
383
  xmlChar* content;
363
384
  VALUE result = Qnil;
364
385
 
365
- Data_Get_Struct(self, xmlNode, xnode);
386
+ xnode = rxml_get_xnode(self);
366
387
 
367
388
  if (!xnode->content)
368
389
  return result;
@@ -387,7 +408,7 @@ static VALUE rxml_node_debug(VALUE self)
387
408
  {
388
409
  #ifdef LIBXML_DEBUG_ENABLED
389
410
  xmlNodePtr xnode;
390
- Data_Get_Struct(self, xmlNode, xnode);
411
+ xnode = rxml_get_xnode(self);
391
412
  xmlDebugDumpNode(NULL, xnode, 2);
392
413
  return Qtrue;
393
414
  #else
@@ -406,7 +427,7 @@ static VALUE rxml_node_first_get(VALUE self)
406
427
  {
407
428
  xmlNodePtr xnode;
408
429
 
409
- Data_Get_Struct(self, xmlNode, xnode);
430
+ xnode = rxml_get_xnode(self);
410
431
 
411
432
  if (xnode->children)
412
433
  return (rxml_node_wrap(xnode->children));
@@ -434,16 +455,14 @@ static VALUE rxml_node_content_add(VALUE self, VALUE obj)
434
455
  xmlNodePtr xnode;
435
456
  VALUE str;
436
457
 
437
- Data_Get_Struct(self, xmlNode, xnode);
458
+ xnode = rxml_get_xnode(self);
459
+
438
460
  /* XXX This should only be legal for a CDATA type node, I think,
439
461
  * resulting in a merge of content, as if a string were passed
440
462
  * danj 070827
441
463
  */
442
464
  if (rb_obj_is_kind_of(obj, cXMLNode))
443
465
  {
444
- xmlNodePtr xtarget;
445
- Data_Get_Struct(obj, xmlNode, xtarget);
446
- xmlUnlinkNode(xtarget);
447
466
  rxml_node_modify_dom(self, obj, xmlAddChild);
448
467
  }
449
468
  else
@@ -465,41 +484,32 @@ static VALUE rxml_node_content_add(VALUE self, VALUE obj)
465
484
  */
466
485
  static VALUE rxml_node_doc(VALUE self)
467
486
  {
468
- xmlNodePtr xnode;
469
- xmlDocPtr doc = NULL;
470
-
471
- Data_Get_Struct(self, xmlNode, xnode);
487
+ xmlDocPtr xdoc = NULL;
488
+ xmlNodePtr xnode = rxml_get_xnode(self);
472
489
 
473
490
  switch (xnode->type)
474
491
  {
475
492
  case XML_DOCUMENT_NODE:
476
493
  #ifdef LIBXML_DOCB_ENABLED
477
- case XML_DOCB_DOCUMENT_NODE:
494
+ case XML_DOCB_DOCUMENT_NODE:
478
495
  #endif
479
496
  case XML_HTML_DOCUMENT_NODE:
480
- doc = NULL;
497
+ case XML_NAMESPACE_DECL:
481
498
  break;
482
499
  case XML_ATTRIBUTE_NODE:
483
- {
484
- xmlAttrPtr attr = (xmlAttrPtr) xnode;
485
- doc = attr->doc;
486
- break;
487
- }
488
- case XML_NAMESPACE_DECL:
489
- doc = NULL;
500
+ xdoc = (xmlDocPtr)((xmlAttrPtr) xnode->doc);
490
501
  break;
491
502
  default:
492
- doc = xnode->doc;
493
- break;
503
+ xdoc = xnode->doc;
494
504
  }
495
505
 
496
- if (doc == NULL)
506
+ if (xdoc == NULL)
497
507
  return (Qnil);
498
-
499
- if (doc->_private == NULL)
500
- rb_raise(rb_eRuntimeError, "existing document object has no ruby-instance");
501
-
502
- return (VALUE) doc->_private;
508
+ else if (xdoc->_private)
509
+ return (VALUE) xdoc->_private;
510
+ else
511
+ /* This can happen by calling Reader#expand.doc */
512
+ rb_raise(eXMLError, "Document is not accessible to Ruby (hint - did you call Reader#expand?)");
503
513
  }
504
514
 
505
515
  /*
@@ -567,7 +577,8 @@ static VALUE rxml_node_to_s(int argc, VALUE *argv, VALUE self)
567
577
  encodingHandler = xmlFindCharEncodingHandler(xencoding);
568
578
  output = xmlAllocOutputBuffer(encodingHandler);
569
579
 
570
- Data_Get_Struct(self, xmlNode, xnode);
580
+ xnode = rxml_get_xnode(self);
581
+
571
582
  xmlNodeDumpOutput(output, xnode->doc, xnode, level, indent, xencoding);
572
583
  xmlOutputBufferFlush(output);
573
584
 
@@ -597,7 +608,7 @@ static VALUE rxml_node_each(VALUE self)
597
608
  {
598
609
  xmlNodePtr xnode;
599
610
  xmlNodePtr xcurrent;
600
- Data_Get_Struct(self, xmlNode, xnode);
611
+ xnode = rxml_get_xnode(self);
601
612
 
602
613
  xcurrent = xnode->children;
603
614
 
@@ -617,12 +628,12 @@ static VALUE rxml_node_each(VALUE self)
617
628
  * call-seq:
618
629
  * node.empty? -> (true|false)
619
630
  *
620
- * Determine whether this node is empty.
631
+ * Determine whether this node is an empty or whitespace only text-node.
621
632
  */
622
633
  static VALUE rxml_node_empty_q(VALUE self)
623
634
  {
624
635
  xmlNodePtr xnode;
625
- Data_Get_Struct(self, xmlNode, xnode);
636
+ xnode = rxml_get_xnode(self);
626
637
  if (xnode == NULL)
627
638
  return (Qnil);
628
639
 
@@ -638,26 +649,26 @@ static VALUE rxml_node_empty_q(VALUE self)
638
649
  * if they are the same node or have the same XML representation.*/
639
650
  static VALUE rxml_node_eql_q(VALUE self, VALUE other)
640
651
  {
641
- if(self == other)
642
- {
643
- return Qtrue;
644
- }
645
- else if (NIL_P(other))
646
- {
647
- return Qfalse;
648
- }
649
- else
650
- {
651
- VALUE self_xml;
652
- VALUE other_xml;
652
+ if(self == other)
653
+ {
654
+ return Qtrue;
655
+ }
656
+ else if (NIL_P(other))
657
+ {
658
+ return Qfalse;
659
+ }
660
+ else
661
+ {
662
+ VALUE self_xml;
663
+ VALUE other_xml;
653
664
 
654
- if (rb_obj_is_kind_of(other, cXMLNode) == Qfalse)
655
- rb_raise(rb_eTypeError, "Nodes can only be compared against other nodes");
665
+ if (rb_obj_is_kind_of(other, cXMLNode) == Qfalse)
666
+ rb_raise(rb_eTypeError, "Nodes can only be compared against other nodes");
656
667
 
657
- self_xml = rxml_node_to_s(0, NULL, self);
658
- other_xml = rxml_node_to_s(0, NULL, other);
659
- return(rb_funcall(self_xml, rb_intern("=="), 1, other_xml));
660
- }
668
+ self_xml = rxml_node_to_s(0, NULL, self);
669
+ other_xml = rxml_node_to_s(0, NULL, other);
670
+ return(rb_funcall(self_xml, rb_intern("=="), 1, other_xml));
671
+ }
661
672
  }
662
673
 
663
674
  /*
@@ -673,7 +684,7 @@ static VALUE rxml_node_lang_get(VALUE self)
673
684
  xmlChar *lang;
674
685
  VALUE result = Qnil;
675
686
 
676
- Data_Get_Struct(self, xmlNode, xnode);
687
+ xnode = rxml_get_xnode(self);
677
688
  lang = xmlNodeGetLang(xnode);
678
689
 
679
690
  if (lang)
@@ -699,7 +710,7 @@ static VALUE rxml_node_lang_set(VALUE self, VALUE lang)
699
710
  xmlNodePtr xnode;
700
711
 
701
712
  Check_Type(lang, T_STRING);
702
- Data_Get_Struct(self, xmlNode, xnode);
713
+ xnode = rxml_get_xnode(self);
703
714
  xmlNodeSetLang(xnode, (xmlChar*) StringValuePtr(lang));
704
715
 
705
716
  return (Qtrue);
@@ -715,7 +726,7 @@ static VALUE rxml_node_last_get(VALUE self)
715
726
  {
716
727
  xmlNodePtr xnode;
717
728
 
718
- Data_Get_Struct(self, xmlNode, xnode);
729
+ xnode = rxml_get_xnode(self);
719
730
 
720
731
  if (xnode->last)
721
732
  return (rxml_node_wrap(xnode->last));
@@ -735,7 +746,7 @@ static VALUE rxml_node_line_num(VALUE self)
735
746
  {
736
747
  xmlNodePtr xnode;
737
748
  long line_num;
738
- Data_Get_Struct(self, xmlNode, xnode);
749
+ xnode = rxml_get_xnode(self);
739
750
 
740
751
  if (!xmlLineNumbersDefaultValue)
741
752
  rb_warn(
@@ -759,7 +770,7 @@ static VALUE rxml_node_xlink_q(VALUE self)
759
770
  xmlNodePtr xnode;
760
771
  xlinkType xlt;
761
772
 
762
- Data_Get_Struct(self, xmlNode, xnode);
773
+ xnode = rxml_get_xnode(self);
763
774
  xlt = xlinkIsLink(xnode->doc, xnode);
764
775
 
765
776
  if (xlt == XLINK_TYPE_NONE)
@@ -781,7 +792,7 @@ static VALUE rxml_node_xlink_type(VALUE self)
781
792
  xmlNodePtr xnode;
782
793
  xlinkType xlt;
783
794
 
784
- Data_Get_Struct(self, xmlNode, xnode);
795
+ xnode = rxml_get_xnode(self);
785
796
  xlt = xlinkIsLink(xnode->doc, xnode);
786
797
 
787
798
  if (xlt == XLINK_TYPE_NONE)
@@ -803,7 +814,7 @@ static VALUE rxml_node_xlink_type_name(VALUE self)
803
814
  xmlNodePtr xnode;
804
815
  xlinkType xlt;
805
816
 
806
- Data_Get_Struct(self, xmlNode, xnode);
817
+ xnode = rxml_get_xnode(self);
807
818
  xlt = xlinkIsLink(xnode->doc, xnode);
808
819
 
809
820
  switch (xlt)
@@ -832,7 +843,7 @@ static VALUE rxml_node_name_get(VALUE self)
832
843
  xmlNodePtr xnode;
833
844
  const xmlChar *name;
834
845
 
835
- Data_Get_Struct(self, xmlNode, xnode);
846
+ xnode = rxml_get_xnode(self);
836
847
 
837
848
  switch (xnode->type)
838
849
  {
@@ -881,7 +892,7 @@ static VALUE rxml_node_name_set(VALUE self, VALUE name)
881
892
  const xmlChar *xname;
882
893
 
883
894
  Check_Type(name, T_STRING);
884
- Data_Get_Struct(self, xmlNode, xnode);
895
+ xnode = rxml_get_xnode(self);
885
896
  xname = (const xmlChar*)StringValuePtr(name);
886
897
 
887
898
  /* Note: calling xmlNodeSetName() for a text node is ignored by libXML. */
@@ -900,7 +911,7 @@ static VALUE rxml_node_next_get(VALUE self)
900
911
  {
901
912
  xmlNodePtr xnode;
902
913
 
903
- Data_Get_Struct(self, xmlNode, xnode);
914
+ xnode = rxml_get_xnode(self);
904
915
 
905
916
  if (xnode->next)
906
917
  return (rxml_node_wrap(xnode->next));
@@ -933,7 +944,7 @@ static VALUE rxml_node_parent_get(VALUE self)
933
944
  {
934
945
  xmlNodePtr xnode;
935
946
 
936
- Data_Get_Struct(self, xmlNode, xnode);
947
+ xnode = rxml_get_xnode(self);
937
948
 
938
949
  if (xnode->parent)
939
950
  return (rxml_node_wrap(xnode->parent));
@@ -952,7 +963,7 @@ static VALUE rxml_node_path(VALUE self)
952
963
  xmlNodePtr xnode;
953
964
  xmlChar *path;
954
965
 
955
- Data_Get_Struct(self, xmlNode, xnode);
966
+ xnode = rxml_get_xnode(self);
956
967
  path = xmlGetNodePath(xnode);
957
968
 
958
969
  if (path == NULL)
@@ -982,7 +993,7 @@ static VALUE rxml_node_prev_get(VALUE self)
982
993
  {
983
994
  xmlNodePtr xnode;
984
995
  xmlNodePtr node;
985
- Data_Get_Struct(self, xmlNode, xnode);
996
+ xnode = rxml_get_xnode(self);
986
997
 
987
998
  switch (xnode->type)
988
999
  {
@@ -1036,7 +1047,7 @@ static VALUE rxml_node_attributes_get(VALUE self)
1036
1047
  {
1037
1048
  xmlNodePtr xnode;
1038
1049
 
1039
- Data_Get_Struct(self, xmlNode, xnode);
1050
+ xnode = rxml_get_xnode(self);
1040
1051
  return rxml_attributes_new(xnode);
1041
1052
  }
1042
1053
 
@@ -1077,7 +1088,7 @@ static VALUE rxml_node_property_set(VALUE self, VALUE name, VALUE value)
1077
1088
  static VALUE rxml_node_remove_ex(VALUE self)
1078
1089
  {
1079
1090
  xmlNodePtr xnode, xresult;
1080
- Data_Get_Struct(self, xmlNode, xnode);
1091
+ xnode = rxml_get_xnode(self);
1081
1092
 
1082
1093
  /* First unlink the node from its parent. */
1083
1094
  xmlUnlinkNode(xnode);
@@ -1137,7 +1148,7 @@ static VALUE rxml_node_sibling_set(VALUE self, VALUE sibling)
1137
1148
  static VALUE rxml_node_output_escaping_q(VALUE self)
1138
1149
  {
1139
1150
  xmlNodePtr xnode;
1140
- Data_Get_Struct(self, xmlNode, xnode);
1151
+ xnode = rxml_get_xnode(self);
1141
1152
 
1142
1153
  switch (xnode->type) {
1143
1154
  case XML_TEXT_NODE:
@@ -1184,7 +1195,7 @@ static VALUE rxml_node_output_escaping_q(VALUE self)
1184
1195
  static VALUE rxml_node_output_escaping_set(VALUE self, VALUE bool)
1185
1196
  {
1186
1197
  xmlNodePtr xnode;
1187
- Data_Get_Struct(self, xmlNode, xnode);
1198
+ xnode = rxml_get_xnode(self);
1188
1199
 
1189
1200
  switch (xnode->type) {
1190
1201
  case XML_TEXT_NODE:
@@ -1217,7 +1228,7 @@ static VALUE rxml_node_space_preserve_get(VALUE self)
1217
1228
  {
1218
1229
  xmlNodePtr xnode;
1219
1230
 
1220
- Data_Get_Struct(self, xmlNode, xnode);
1231
+ xnode = rxml_get_xnode(self);
1221
1232
  return (INT2NUM(xmlNodeGetSpacePreserve(xnode)));
1222
1233
  }
1223
1234
 
@@ -1230,7 +1241,7 @@ static VALUE rxml_node_space_preserve_get(VALUE self)
1230
1241
  static VALUE rxml_node_space_preserve_set(VALUE self, VALUE bool)
1231
1242
  {
1232
1243
  xmlNodePtr xnode;
1233
- Data_Get_Struct(self, xmlNode, xnode);
1244
+ xnode = rxml_get_xnode(self);
1234
1245
 
1235
1246
  if (TYPE(bool) == T_FALSE)
1236
1247
  xmlNodeSetSpacePreserve(xnode, 0);
@@ -1249,7 +1260,7 @@ static VALUE rxml_node_space_preserve_set(VALUE self, VALUE bool)
1249
1260
  static VALUE rxml_node_type(VALUE self)
1250
1261
  {
1251
1262
  xmlNodePtr xnode;
1252
- Data_Get_Struct(self, xmlNode, xnode);
1263
+ xnode = rxml_get_xnode(self);
1253
1264
  return (INT2NUM(xnode->type));
1254
1265
  }
1255
1266
 
@@ -1268,7 +1279,7 @@ static VALUE rxml_node_copy(VALUE self, VALUE deep)
1268
1279
  xmlNodePtr xnode;
1269
1280
  xmlNodePtr xcopy;
1270
1281
  int recursive = (deep == Qnil || deep == Qfalse) ? 0 : 1;
1271
- Data_Get_Struct(self, xmlNode, xnode);
1282
+ xnode = rxml_get_xnode(self);
1272
1283
 
1273
1284
  xcopy = xmlCopyNode(xnode, recursive);
1274
1285
 
@@ -1280,8 +1291,12 @@ static VALUE rxml_node_copy(VALUE self, VALUE deep)
1280
1291
 
1281
1292
  void rxml_init_node(void)
1282
1293
  {
1294
+ /* Register callback for main thread */
1283
1295
  xmlDeregisterNodeDefault(rxml_node_deregisterNode);
1284
1296
 
1297
+ /* Register callback for all other threads */
1298
+ xmlThrDefDeregisterNodeDefault(rxml_node_deregisterNode);
1299
+
1285
1300
  cXMLNode = rb_define_class_under(mXML, "Node", rb_cObject);
1286
1301
 
1287
1302
  rb_define_const(cXMLNode, "SPACE_DEFAULT", INT2NUM(0));