libxml-ruby 2.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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 */