libxml-ruby 2.2.2 → 2.3.0

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.
Files changed (55) hide show
  1. data/HISTORY +14 -2
  2. data/MANIFEST +1 -0
  3. data/README.rdoc +2 -2
  4. data/ext/libxml/ruby_xml_document.c +191 -29
  5. data/ext/libxml/ruby_xml_document.h +1 -0
  6. data/ext/libxml/ruby_xml_encoding.c +21 -7
  7. data/ext/libxml/ruby_xml_encoding.h +1 -0
  8. data/ext/libxml/ruby_xml_node.c +38 -0
  9. data/ext/libxml/ruby_xml_sax2_handler.c +30 -34
  10. data/ext/libxml/ruby_xml_sax_parser.c +0 -14
  11. data/ext/libxml/ruby_xml_version.h +4 -4
  12. data/lib/libxml/document.rb +18 -16
  13. data/libxml-ruby.gemspec +3 -2
  14. data/test/c14n/given/doc.dtd +1 -0
  15. data/test/c14n/given/example-1.xml +14 -0
  16. data/test/c14n/given/example-2.xml +11 -0
  17. data/test/c14n/given/example-3.xml +18 -0
  18. data/test/c14n/given/example-4.xml +9 -0
  19. data/test/c14n/given/example-5.xml +12 -0
  20. data/test/c14n/given/example-6.xml +2 -0
  21. data/test/c14n/given/example-7.xml +11 -0
  22. data/test/c14n/given/example-8.xml +11 -0
  23. data/test/c14n/given/example-8.xpath +10 -0
  24. data/test/c14n/given/world.txt +1 -0
  25. data/test/c14n/result/1-1-without-comments/example-1 +4 -0
  26. data/test/c14n/result/1-1-without-comments/example-2 +11 -0
  27. data/test/c14n/result/1-1-without-comments/example-3 +14 -0
  28. data/test/c14n/result/1-1-without-comments/example-4 +9 -0
  29. data/test/c14n/result/1-1-without-comments/example-5 +3 -0
  30. data/test/c14n/result/1-1-without-comments/example-6 +1 -0
  31. data/test/c14n/result/1-1-without-comments/example-7 +1 -0
  32. data/test/c14n/result/1-1-without-comments/example-8 +1 -0
  33. data/test/c14n/result/with-comments/example-1 +6 -0
  34. data/test/c14n/result/with-comments/example-2 +11 -0
  35. data/test/c14n/result/with-comments/example-3 +14 -0
  36. data/test/c14n/result/with-comments/example-4 +9 -0
  37. data/test/c14n/result/with-comments/example-5 +4 -0
  38. data/test/c14n/result/with-comments/example-6 +1 -0
  39. data/test/c14n/result/with-comments/example-7 +1 -0
  40. data/test/c14n/result/without-comments/example-1 +4 -0
  41. data/test/c14n/result/without-comments/example-2 +11 -0
  42. data/test/c14n/result/without-comments/example-3 +14 -0
  43. data/test/c14n/result/without-comments/example-4 +9 -0
  44. data/test/c14n/result/without-comments/example-5 +3 -0
  45. data/test/c14n/result/without-comments/example-6 +1 -0
  46. data/test/c14n/result/without-comments/example-7 +1 -0
  47. data/test/tc_canonicalize.rb +125 -0
  48. data/test/tc_document.rb +2 -18
  49. data/test/tc_encoding.rb +7 -5
  50. data/test/tc_encoding_sax.rb +115 -0
  51. data/test/tc_node_pi.rb +40 -0
  52. data/test/tc_xpath.rb +23 -0
  53. data/test/test_suite.rb +7 -1
  54. metadata +45 -6
  55. data/test/new_main.rb +0 -29
data/HISTORY CHANGED
@@ -1,6 +1,18 @@
1
1
  = Release History
2
2
 
3
- == 2.2.2 / 2011-08-13 Charlie Savage
3
+ == 2.3.0 / 2012-02-22 Ryan Johnson
4
+
5
+ * Add ability to insert new PI-nodes into the xmltree (Axel Struebing).
6
+
7
+ * Added full pass-through access to libxml2 xmlC14NDocDumpMemory method via
8
+ LibXML::XML::Document#canonicalize method with optional arguments.
9
+
10
+ * Added full test data for C14N based off of W3C spec.
11
+ (http://www.w3.org/TR/xml-c14n#Examples)
12
+
13
+ * Update sax handler to support encodings on Ruby 1.9 and higher.
14
+
15
+ == 2.2.2 / 2011-08-29 Charlie Savage
4
16
 
5
17
  * ++API CHANGE+++
6
18
 
@@ -24,7 +36,7 @@ Fixes GitHub issue #30.
24
36
  * Fixed bug where Node#inner_xml caused an error when it had no child nodes.
25
37
  Fixes GitHub issues #31
26
38
 
27
- * Don't require 'rake' in the gemspec to avoid annoying Bunlder bugs
39
+ * Don't require 'rake' in the gemspec to avoid annoying Bundler bugs
28
40
 
29
41
  == 2.2.1 / 2011-08-13 Charlie Savage
30
42
 
data/MANIFEST CHANGED
@@ -138,6 +138,7 @@ test/tc_node_cdata.rb
138
138
  test/tc_node_comment.rb
139
139
  test/tc_node_copy.rb
140
140
  test/tc_node_edit.rb
141
+ test/tc_node_pi.rb
141
142
  test/tc_node_text.rb
142
143
  test/tc_node_write.rb
143
144
  test/tc_node_xlink.rb
@@ -94,12 +94,12 @@ namespace, in which case you can either write your code like this:
94
94
  require 'libxml'
95
95
  document = LibXML::XML::Document.new
96
96
 
97
- Or you can utilize a namespace for you own work and include LibXML into it.
97
+ Or you can utilize a namespace for your own work and include LibXML into it.
98
98
  For example:
99
99
 
100
100
  require 'libxml'
101
101
 
102
- mdoule MyApplication
102
+ module MyApplication
103
103
  include LibXML
104
104
 
105
105
  class MyClass
@@ -58,7 +58,7 @@ VALUE cXMLDocument;
58
58
  void rxml_document_mark_node_list(xmlNodePtr xnode)
59
59
  {
60
60
  if (xnode == NULL) return;
61
-
61
+
62
62
  while (xnode != NULL)
63
63
  {
64
64
  rxml_document_mark_node_list(xnode->children);
@@ -149,28 +149,183 @@ static VALUE rxml_document_initialize(int argc, VALUE *argv, VALUE self)
149
149
  #endif
150
150
 
151
151
  /*
152
- * call-seq:
153
- * document.canonicalize(comments) -> String
152
+ * :call-seq:
153
+ * document.canonicalize -> String
154
+ * document.canonicalize(options) -> String
154
155
  *
155
- * Returns a string containing the canonicalized form of the document.
156
+ * Returns a string containing the canonicalized form of the document.
157
+ * Implemented to include all of the functionality of the libxml2
158
+ * {xmlC14NDocDumpMemory}[http://xmlsoft.org/html/libxml-c14n.html#xmlC14NDocDumpMemory]
159
+ * method.
156
160
  *
157
- * :comments - Specifies if comments should be output. This is an optional
158
- * parameter whose default value is false.
161
+ * === Options
162
+ * [comments]
163
+ * * *Type:* Boolean
164
+ * * *Default:* false
165
+ * Specifies if comments should be output.
166
+ * * Must be boolean, otherwise defaults to false.
167
+ * [inclusive_ns_prefixes]
168
+ * * *Type:* Array of strings
169
+ * * *Default:* empty array
170
+ * Array of namespace prefixes to include in exclusive canonicalization only.
171
+ * * The last item in the list is reserved for a NULL value because the C method demands it, therefore
172
+ * up to the first 255 valid entries will be used.
173
+ * * <em>Only used for *XML_C14N_EXCLUSIVE_1_0* mode. Ignored otherwise.</em>
174
+ * [mode]
175
+ * * *Type:* XML::Document Constant
176
+ * * *Default:* XML_C14N_1_0
177
+ * Specifies the mode of canonicalization.
178
+ * * *NOTE:* XML_C14N_1_1 may not be fully implemented upon compilation due to C library compatibility.
179
+ * Please check if XML_C14N_1_0 and XML_C14N_1_1 are the same value prior to using XML_C14N_1_1.
180
+ * [nodes]
181
+ * * *Type:* Array of XML::Node objects
182
+ * * *Default:* empty array
183
+ * XML::Nodes to include in the canonicalization process
184
+ * * For large lists of more than 256 valid namespaces, up to the first 256 valid entries will be used.
159
185
  */
160
- static VALUE rxml_document_canonicalize(int argc, VALUE *argv, VALUE self)
186
+ #define C14N_NS_LIMIT 256
187
+ #define C14N_NODESET_LIMIT 256
188
+
189
+ static VALUE
190
+ rxml_document_canonicalize(int argc, VALUE *argv, VALUE self)
161
191
  {
162
192
  VALUE result = Qnil;
163
- VALUE comments = Qnil ;
193
+ int length;
164
194
  xmlDocPtr xdoc;
165
195
  xmlChar *buffer = NULL;
166
- int length;
196
+ VALUE option_hash = Qnil;
197
+ VALUE o_nodes = Qnil;
198
+
199
+ // :comments option
200
+ VALUE comments = Qfalse;
201
+ // :mode option
202
+ int c14n_mode = XML_C14N_1_0;
203
+ // :inclusive_ns_prefixes option (ARRAY)
204
+
205
+ xmlChar * inc_ns_prefixes_ptr[C14N_NS_LIMIT];
206
+
207
+ // :nodes option (ARRAY)
208
+ xmlNodePtr node_ptr_array[C14N_NODESET_LIMIT];
209
+ xmlNodeSet nodeset = {
210
+ 0, C14N_NODESET_LIMIT, NULL
211
+ };
212
+
213
+ /* At least one NULL value must be defined in the array or the extension will
214
+ * segfault when using XML_C14N_EXCLUSIVE_1_0 mode.
215
+ * API docs: "list of inclusive namespace prefixes ended with a NULL"
216
+ */
217
+ inc_ns_prefixes_ptr[0] = NULL;
218
+
219
+ rb_scan_args(argc, argv, "01", &option_hash);
220
+ // Do stuff if ruby hash passed as argument
221
+ if (!NIL_P(option_hash))
222
+ {
223
+ VALUE o_comments = Qnil;
224
+ VALUE o_mode = Qnil;
225
+ VALUE o_i_ns_prefixes = Qnil;
226
+ VALUE * list_in = NULL;
227
+
228
+ Check_Type(option_hash, T_HASH);
229
+
230
+ o_comments = rb_hash_aref(option_hash, ID2SYM(rb_intern("comments")));
231
+ comments = (RTEST(o_comments) ? 1 : 0);
232
+
233
+ o_mode = rb_hash_aref(option_hash, ID2SYM(rb_intern("mode")));
234
+ if (!NIL_P(o_mode))
235
+ {
236
+ Check_Type(o_mode, T_FIXNUM);
237
+ c14n_mode = NUM2INT(o_mode);
238
+ //TODO: clean this up
239
+ //if (c14n_mode > 2) { c14n_mode = 0; }
240
+ //mode_int = (NUM2INT(o_mode) > 2 ? 0 : NUM2INT(o_mode));
241
+ }
242
+
243
+ o_i_ns_prefixes = rb_hash_aref(option_hash, ID2SYM(rb_intern("inclusive_ns_prefixes")));
244
+ if (!NIL_P(o_i_ns_prefixes))
245
+ {
246
+ int i;
247
+ int p = 0; //pointer array index
248
+ VALUE *list_in = NULL;
249
+ int list_size = 0;
250
+
251
+ Check_Type(o_i_ns_prefixes, T_ARRAY);
252
+ list_in = RARRAY_PTR(o_i_ns_prefixes);
253
+ list_size = RARRAY_LEN(o_i_ns_prefixes);
254
+
255
+ if (list_size > 0)
256
+ {
257
+ for(i=0; i < list_size; ++i) {
258
+ if (p >= C14N_NS_LIMIT) { break; }
259
+
260
+ if (RTEST(list_in[i]))
261
+ {
262
+ if (TYPE(list_in[i]) == T_STRING)
263
+ {
264
+ inc_ns_prefixes_ptr[p] = (xmlChar *)StringValueCStr(list_in[i]);
265
+ p++;
266
+ }
267
+ }
268
+ }
269
+ }
270
+
271
+ // ensure p is not out of bound
272
+ p = (p >= C14N_NS_LIMIT ? (C14N_NS_LIMIT-1) : p);
273
+
274
+ // API docs: "list of inclusive namespace prefixes ended with a NULL"
275
+ // Set last element to NULL
276
+ inc_ns_prefixes_ptr[p] = NULL;
277
+ }
278
+ //o_ns_prefixes will free at end of block
279
+
280
+ o_nodes = rb_hash_aref(option_hash, ID2SYM(rb_intern("nodes")));
281
+ if (!NIL_P(o_nodes))
282
+ {
283
+ int i;
284
+ int p = 0; // index of pointer array
285
+ VALUE * list_in = NULL;
286
+ int node_list_size = 0;
287
+
288
+ if (CLASS_OF(o_nodes) == cXMLXPathObject)
289
+ {
290
+ o_nodes = rb_funcall(o_nodes, rb_intern("to_a"), 0);
291
+ }
292
+ else
293
+ {
294
+ Check_Type(o_nodes, T_ARRAY);
295
+ }
296
+ list_in = RARRAY_PTR(o_nodes);
297
+ node_list_size = RARRAY_LEN(o_nodes);
298
+
299
+ for (i=0; i < node_list_size; ++i)
300
+ {
301
+ if (p >= C14N_NODESET_LIMIT) { break; }
302
+
303
+ if (RTEST(list_in[i]))
304
+ {
305
+ xmlNodePtr node_ptr;
306
+ Data_Get_Struct(list_in[i], xmlNode, node_ptr);
307
+ node_ptr_array[p] = node_ptr;
308
+ p++;
309
+ }
310
+ }
311
+
312
+ // Need to set values in nodeset struct
313
+ nodeset.nodeNr = (node_list_size > C14N_NODESET_LIMIT ?
314
+ C14N_NODESET_LIMIT :
315
+ node_list_size);
316
+ nodeset.nodeTab = node_ptr_array;
317
+ }
318
+ }//option_hash
167
319
 
168
- rb_scan_args(argc, argv, "01", &comments);
169
-
170
320
  Data_Get_Struct(self, xmlDoc, xdoc);
171
- length = xmlC14NDocDumpMemory(xdoc, NULL, XML_C14N_1_1, NULL,
172
- (comments == Qtrue ? 1 : 0),
173
- &buffer);
321
+ length = xmlC14NDocDumpMemory(
322
+ xdoc,
323
+ (nodeset.nodeNr == 0 ? NULL : &nodeset),
324
+ c14n_mode,
325
+ &inc_ns_prefixes_ptr,
326
+ comments,
327
+ &buffer
328
+ );
174
329
 
175
330
  if (buffer)
176
331
  {
@@ -180,8 +335,8 @@ static VALUE rxml_document_canonicalize(int argc, VALUE *argv, VALUE self)
180
335
 
181
336
  return result;
182
337
  }
183
-
184
-
338
+
339
+
185
340
  /*
186
341
  * call-seq:
187
342
  * document.compression -> num
@@ -356,7 +511,7 @@ static VALUE rxml_document_rb_encoding_get(VALUE self)
356
511
  rbencoding = rxml_xml_encoding_to_rb_encoding(mXMLEncoding, xmlParseCharEncoding(xencoding));
357
512
  return rb_enc_from_encoding(rbencoding);
358
513
  }
359
- #endif
514
+ #endif
360
515
 
361
516
  /*
362
517
  * call-seq:
@@ -615,7 +770,7 @@ static VALUE rxml_document_root_set(VALUE self, VALUE node)
615
770
  *
616
771
  * Saves a document to a file. You may provide an optional hash table
617
772
  * to control how the string is generated. Valid options are:
618
- *
773
+ *
619
774
  * :indent - Specifies if the string should be indented. The default value
620
775
  * is true. Note that indentation is only added if both :indent is
621
776
  * true and XML.indent_tree_output is true. If :indent is set to false,
@@ -626,7 +781,7 @@ static VALUE rxml_document_root_set(VALUE self, VALUE node)
626
781
  * #encoding. To override the orginal encoding, use one of the
627
782
  * XML::Encoding encoding constants. */
628
783
  static VALUE rxml_document_save(int argc, VALUE *argv, VALUE self)
629
- {
784
+ {
630
785
  VALUE options = Qnil;
631
786
  VALUE filename = Qnil;
632
787
  xmlDocPtr xdoc;
@@ -665,7 +820,7 @@ static VALUE rxml_document_save(int argc, VALUE *argv, VALUE self)
665
820
 
666
821
  if (length == -1)
667
822
  rxml_raise(&xmlLastError);
668
-
823
+
669
824
  return (INT2NUM(length));
670
825
  }
671
826
 
@@ -692,9 +847,9 @@ static VALUE rxml_document_standalone_q(VALUE self)
692
847
  * document.to_s(:indent => true, :encoding => XML::Encoding::UTF_8) -> "string"
693
848
  *
694
849
  * Converts a document, and all of its children, to a string representation.
695
- * You may provide an optional hash table to control how the string is
850
+ * You may provide an optional hash table to control how the string is
696
851
  * generated. Valid options are:
697
- *
852
+ *
698
853
  * :indent - Specifies if the string should be indented. The default value
699
854
  * is true. Note that indentation is only added if both :indent is
700
855
  * true and XML.indent_tree_output is true. If :indent is set to false,
@@ -704,13 +859,13 @@ static VALUE rxml_document_standalone_q(VALUE self)
704
859
  * defaults to XML::Encoding::UTF8. To change it, use one of the
705
860
  * XML::Encoding encoding constants. */
706
861
  static VALUE rxml_document_to_s(int argc, VALUE *argv, VALUE self)
707
- {
862
+ {
708
863
  VALUE result;
709
864
  VALUE options = Qnil;
710
865
  xmlDocPtr xdoc;
711
866
  int indent = 1;
712
867
  const char *xencoding = "UTF-8";
713
- xmlChar *buffer;
868
+ xmlChar *buffer;
714
869
  int length;
715
870
 
716
871
  rb_scan_args(argc, argv, "01", &options);
@@ -826,10 +981,10 @@ static VALUE rxml_document_xinclude(VALUE self)
826
981
 
827
982
  /*
828
983
  * call-seq:
829
- * document.order_elements!
830
- *
984
+ * document.order_elements!
985
+ *
831
986
  * Call this routine to speed up XPath computation on static documents.
832
- * This stamps all the element nodes with the document order.
987
+ * This stamps all the element nodes with the document order.
833
988
  */
834
989
  static VALUE rxml_document_order_elements(VALUE self)
835
990
  {
@@ -841,7 +996,7 @@ static VALUE rxml_document_order_elements(VALUE self)
841
996
 
842
997
  /*
843
998
  * call-seq:
844
- * document.validate_schema(schema)
999
+ * document.validate_schema(schema)
845
1000
  *
846
1001
  * Validate this document against the specified XML::Schema.
847
1002
  * If the document is valid the method returns true. Otherwise an
@@ -874,7 +1029,7 @@ static VALUE rxml_document_validate_schema(VALUE self, VALUE schema)
874
1029
 
875
1030
  /*
876
1031
  * call-seq:
877
- * document.validate_relaxng(relaxng)
1032
+ * document.validate_relaxng(relaxng)
878
1033
  *
879
1034
  * Validate this document against the specified XML::RelaxNG.
880
1035
  * If the document is valid the method returns true. Otherwise an
@@ -941,6 +1096,13 @@ void rxml_init_document(void)
941
1096
  cXMLDocument = rb_define_class_under(mXML, "Document", rb_cObject);
942
1097
  rb_define_alloc_func(cXMLDocument, rxml_document_alloc);
943
1098
 
1099
+ /* Original C14N 1.0 spec */
1100
+ rb_define_const(cXMLDocument, "XML_C14N_1_0", INT2NUM(XML_C14N_1_0));
1101
+ /* Exclusive C14N 1.0 spec */
1102
+ rb_define_const(cXMLDocument, "XML_C14N_EXCLUSIVE_1_0", INT2NUM(XML_C14N_EXCLUSIVE_1_0));
1103
+ /* C14N 1.1 spec */
1104
+ rb_define_const(cXMLDocument, "XML_C14N_1_1", INT2NUM(XML_C14N_1_1));
1105
+
944
1106
  rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1);
945
1107
  rb_define_method(cXMLDocument, "canonicalize", rxml_document_canonicalize, -1);
946
1108
  rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0);
@@ -7,4 +7,5 @@ extern VALUE cXMLDocument;
7
7
  void rxml_init_document();
8
8
  VALUE rxml_document_wrap(xmlDocPtr xnode);
9
9
 
10
+ typedef xmlChar * xmlCharPtr;
10
11
  #endif
@@ -164,27 +164,41 @@ VALUE rxml_encoding_to_rb_encoding(VALUE klass, VALUE encoding)
164
164
  rb_encoding* rbencoding = rxml_xml_encoding_to_rb_encoding(klass, xmlEncoding);
165
165
  return rb_enc_from_encoding(rbencoding);
166
166
  }
167
- #endif
168
-
169
167
 
170
- VALUE rxml_new_cstr(const char* xstr, const char* xencoding)
168
+ rb_encoding* rxml_figure_encoding(const char* xencoding)
171
169
  {
172
- #ifdef HAVE_RUBY_ENCODING_H
173
- rb_encoding* rbencoding;
170
+ rb_encoding* result;
174
171
  if (xencoding)
175
172
  {
176
173
  xmlCharEncoding xmlEncoding = xmlParseCharEncoding(xencoding);
177
- rbencoding = rxml_xml_encoding_to_rb_encoding(mXMLEncoding, xmlEncoding);
174
+ result = rxml_xml_encoding_to_rb_encoding(mXMLEncoding, xmlEncoding);
178
175
  }
179
176
  else
180
177
  {
181
- rbencoding = rb_utf8_encoding();
178
+ result = rb_utf8_encoding();
182
179
  }
180
+ return result;
181
+ }
182
+ #endif
183
+
184
+ VALUE rxml_new_cstr(const char* xstr, const char* xencoding)
185
+ {
186
+ #ifdef HAVE_RUBY_ENCODING_H
187
+ rb_encoding *rbencoding = rxml_figure_encoding(xencoding);
183
188
  return rb_external_str_new_with_enc(xstr, strlen(xstr), rbencoding);
184
189
  #endif
185
190
  return rb_str_new2(xstr);
186
191
  }
187
192
 
193
+ VALUE rxml_new_cstr_len(const char* xstr, const int length, const char* xencoding)
194
+ {
195
+ #ifdef HAVE_RUBY_ENCODING_H
196
+ rb_encoding *rbencoding = rxml_figure_encoding(xencoding);
197
+ return rb_external_str_new_with_enc(xstr, length, rbencoding);
198
+ #endif
199
+ return rb_str_new(xstr, length);
200
+ }
201
+
188
202
  void rxml_init_encoding(void)
189
203
  {
190
204
  mXMLEncoding = rb_define_module_under(mXML, "Encoding");
@@ -9,6 +9,7 @@ void rxml_init_encoding();
9
9
 
10
10
  // Ruby 1.8/1.9 encoding compatibility
11
11
  VALUE rxml_new_cstr(const char* xstr, const char* xencoding);
12
+ VALUE rxml_new_cstr_len(const char* xstr, const int length, const char* xencoding);
12
13
 
13
14
  #ifdef HAVE_RUBY_ENCODING_H
14
15
  rb_encoding* rxml_xml_encoding_to_rb_encoding(VALUE klass, xmlCharEncoding xmlEncoding);
@@ -188,6 +188,43 @@ static VALUE rxml_node_new_comment(int argc, VALUE *argv, VALUE klass)
188
188
  return rxml_node_wrap(xnode);
189
189
  }
190
190
 
191
+ /*
192
+ * call-seq:
193
+ * XML::Node.new_pi(name, content = nil) -> XML::Node
194
+ *
195
+ * Create a new pi node, optionally setting
196
+ * the node's content.
197
+ *
198
+ */
199
+ static VALUE rxml_node_new_pi(int argc, VALUE *argv, VALUE klass)
200
+ {
201
+ VALUE name = Qnil;
202
+ VALUE content = Qnil;
203
+ xmlNodePtr xnode;
204
+
205
+ rb_scan_args(argc, argv, "11", &name, &content);
206
+
207
+ if (NIL_P(name))
208
+ {
209
+ rb_raise(rb_eRuntimeError, "You must provide me with a name for a PI.");
210
+ }
211
+ name = rb_obj_as_string(name);
212
+ if (NIL_P(content))
213
+ {
214
+ xnode = xmlNewPI((xmlChar*) StringValuePtr(name), NULL);
215
+ }
216
+ else
217
+ {
218
+ content = rb_obj_as_string(content);
219
+ xnode = xmlNewPI((xmlChar*) StringValuePtr(name), (xmlChar*) StringValueCStr(content));
220
+ }
221
+
222
+ if (xnode == NULL)
223
+ rxml_raise(&xmlLastError);
224
+
225
+ return rxml_node_wrap(xnode);
226
+ }
227
+
191
228
  /*
192
229
  * call-seq:
193
230
  * XML::Node.new_text(content) -> XML::Node
@@ -1342,6 +1379,7 @@ void rxml_init_node(void)
1342
1379
 
1343
1380
  rb_define_singleton_method(cXMLNode, "new_cdata", rxml_node_new_cdata, -1);
1344
1381
  rb_define_singleton_method(cXMLNode, "new_comment", rxml_node_new_comment, -1);
1382
+ rb_define_singleton_method(cXMLNode, "new_pi", rxml_node_new_pi, -1);
1345
1383
  rb_define_singleton_method(cXMLNode, "new_text", rxml_node_new_text, 1);
1346
1384
 
1347
1385
  /* Initialization */