libxml-ruby 5.0.5 → 6.0.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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/{HISTORY → CHANGELOG.md} +875 -923
  3. data/LICENSE +20 -20
  4. data/README.md +67 -0
  5. data/Rakefile +77 -98
  6. data/ext/libxml/extconf.rb +34 -20
  7. data/ext/libxml/libxml.c +67 -79
  8. data/ext/libxml/ruby_libxml.h +1 -1
  9. data/ext/libxml/ruby_xml_attr.c +338 -333
  10. data/ext/libxml/ruby_xml_attr.h +13 -12
  11. data/ext/libxml/ruby_xml_attr_decl.c +19 -12
  12. data/ext/libxml/ruby_xml_attr_decl.h +11 -11
  13. data/ext/libxml/ruby_xml_attributes.c +18 -9
  14. data/ext/libxml/ruby_xml_document.c +111 -98
  15. data/ext/libxml/ruby_xml_document.h +1 -0
  16. data/ext/libxml/ruby_xml_dtd.c +49 -19
  17. data/ext/libxml/ruby_xml_dtd.h +10 -9
  18. data/ext/libxml/ruby_xml_html_parser.c +91 -91
  19. data/ext/libxml/ruby_xml_html_parser.h +10 -10
  20. data/ext/libxml/ruby_xml_html_parser_context.c +19 -6
  21. data/ext/libxml/ruby_xml_html_parser_context.h +11 -10
  22. data/ext/libxml/ruby_xml_html_parser_options.c +48 -48
  23. data/ext/libxml/ruby_xml_html_parser_options.h +10 -10
  24. data/ext/libxml/ruby_xml_input_cbg.c +45 -17
  25. data/ext/libxml/ruby_xml_input_cbg.h +20 -20
  26. data/ext/libxml/ruby_xml_io.c +49 -47
  27. data/ext/libxml/ruby_xml_io.h +10 -10
  28. data/ext/libxml/ruby_xml_namespace.c +20 -12
  29. data/ext/libxml/ruby_xml_namespace.h +11 -10
  30. data/ext/libxml/ruby_xml_namespaces.c +313 -293
  31. data/ext/libxml/ruby_xml_namespaces.h +9 -9
  32. data/ext/libxml/ruby_xml_node.c +71 -32
  33. data/ext/libxml/ruby_xml_node.h +15 -13
  34. data/ext/libxml/ruby_xml_parser.c +91 -91
  35. data/ext/libxml/ruby_xml_parser_context.c +54 -47
  36. data/ext/libxml/ruby_xml_parser_context.h +11 -10
  37. data/ext/libxml/ruby_xml_reader.c +25 -15
  38. data/ext/libxml/ruby_xml_reader.h +14 -14
  39. data/ext/libxml/ruby_xml_registry.c +31 -0
  40. data/ext/libxml/ruby_xml_registry.h +22 -0
  41. data/ext/libxml/ruby_xml_relaxng.c +21 -5
  42. data/ext/libxml/ruby_xml_relaxng.h +9 -8
  43. data/ext/libxml/ruby_xml_sax2_handler.h +10 -10
  44. data/ext/libxml/ruby_xml_sax_parser.c +1 -1
  45. data/ext/libxml/ruby_xml_sax_parser.h +10 -10
  46. data/ext/libxml/ruby_xml_schema.c +18 -11
  47. data/ext/libxml/ruby_xml_schema.h +26 -25
  48. data/ext/libxml/ruby_xml_schema_attribute.c +7 -7
  49. data/ext/libxml/ruby_xml_schema_attribute.h +37 -37
  50. data/ext/libxml/ruby_xml_schema_element.c +8 -8
  51. data/ext/libxml/ruby_xml_schema_element.h +11 -11
  52. data/ext/libxml/ruby_xml_schema_facet.c +50 -50
  53. data/ext/libxml/ruby_xml_schema_facet.h +9 -9
  54. data/ext/libxml/ruby_xml_schema_type.c +12 -19
  55. data/ext/libxml/ruby_xml_schema_type.h +9 -9
  56. data/ext/libxml/ruby_xml_version.h +4 -4
  57. data/ext/libxml/ruby_xml_writer.c +1136 -1124
  58. data/ext/libxml/ruby_xml_writer.h +6 -6
  59. data/ext/libxml/ruby_xml_xinclude.c +20 -20
  60. data/ext/libxml/ruby_xml_xinclude.h +11 -11
  61. data/ext/libxml/ruby_xml_xpath.c +195 -195
  62. data/ext/libxml/ruby_xml_xpath.h +15 -15
  63. data/ext/libxml/ruby_xml_xpath_context.c +408 -362
  64. data/ext/libxml/ruby_xml_xpath_context.h +9 -9
  65. data/ext/libxml/ruby_xml_xpath_expression.c +11 -5
  66. data/ext/libxml/ruby_xml_xpath_expression.h +11 -10
  67. data/ext/libxml/ruby_xml_xpath_object.c +69 -54
  68. data/ext/libxml/ruby_xml_xpath_object.h +19 -17
  69. data/ext/vc/libxml_ruby/libxml_ruby.vcxproj +271 -0
  70. data/ext/xcode/libxml-ruby.xcodeproj/project.pbxproj +633 -0
  71. data/ext/xcode/libxml-ruby.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  72. data/ext/xcode/libxml-ruby.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  73. data/ext/xcode/libxml-ruby.xcodeproj/xcshareddata/xcschemes/libxml-ruby.xcscheme +80 -0
  74. data/lib/libxml/document.rb +0 -29
  75. data/lib/libxml/error.rb +30 -3
  76. data/lib/libxml/html_parser.rb +0 -16
  77. data/lib/libxml/node.rb +1 -3
  78. data/lib/libxml/parser.rb +0 -8
  79. data/lib/libxml/schema/attribute.rb +27 -19
  80. data/lib/libxml/schema/element.rb +20 -0
  81. data/lib/libxml/schema/type.rb +44 -21
  82. data/lib/libxml/schema.rb +47 -47
  83. data/lib/libxml-ruby.rb +30 -30
  84. data/libxml-ruby.gemspec +12 -16
  85. data/test/c14n/result/1-1-without-comments/example-1 +3 -3
  86. data/test/c14n/result/1-1-without-comments/example-2 +10 -10
  87. data/test/c14n/result/1-1-without-comments/example-3 +13 -13
  88. data/test/c14n/result/1-1-without-comments/example-4 +8 -8
  89. data/test/c14n/result/1-1-without-comments/example-5 +2 -2
  90. data/test/c14n/result/with-comments/example-1 +5 -5
  91. data/test/c14n/result/with-comments/example-2 +10 -10
  92. data/test/c14n/result/with-comments/example-3 +13 -13
  93. data/test/c14n/result/with-comments/example-4 +8 -8
  94. data/test/c14n/result/with-comments/example-5 +3 -3
  95. data/test/c14n/result/without-comments/example-1 +3 -3
  96. data/test/c14n/result/without-comments/example-2 +10 -10
  97. data/test/c14n/result/without-comments/example-3 +13 -13
  98. data/test/c14n/result/without-comments/example-4 +8 -8
  99. data/test/c14n/result/without-comments/example-5 +2 -2
  100. data/test/test_attr.rb +179 -180
  101. data/test/test_attr_decl.rb +131 -131
  102. data/test/test_attributes.rb +135 -135
  103. data/test/test_canonicalize.rb +122 -120
  104. data/test/test_document.rb +2 -4
  105. data/test/test_dtd.rb +12 -4
  106. data/test/test_encoding_sax.rb +114 -114
  107. data/test/test_error.rb +6 -3
  108. data/test/test_helper.rb +1 -0
  109. data/test/test_html_parser.rb +6 -2
  110. data/test/test_html_parser_context.rb +22 -22
  111. data/test/test_input_callbacks.rb +36 -0
  112. data/test/test_namespace.rb +1 -1
  113. data/test/test_namespaces.rb +200 -200
  114. data/test/test_node.rb +16 -0
  115. data/test/test_node_cdata.rb +50 -50
  116. data/test/test_node_comment.rb +32 -32
  117. data/test/test_node_copy.rb +40 -40
  118. data/test/test_node_edit.rb +176 -158
  119. data/test/test_node_pi.rb +37 -37
  120. data/test/test_node_text.rb +69 -69
  121. data/test/test_node_xlink.rb +28 -28
  122. data/test/test_parser.rb +5 -41
  123. data/test/test_parser_context.rb +198 -198
  124. data/test/test_properties.rb +38 -38
  125. data/test/test_reader.rb +55 -6
  126. data/test/test_relaxng.rb +59 -53
  127. data/test/test_sax_parser.rb +345 -345
  128. data/test/test_schema.rb +28 -0
  129. data/test/test_traversal.rb +152 -152
  130. data/test/test_writer.rb +469 -468
  131. data/test/test_xinclude.rb +20 -20
  132. data/test/test_xml.rb +3 -7
  133. data/test/test_xpath.rb +244 -244
  134. data/test/test_xpath_context.rb +87 -87
  135. data/test/test_xpath_expression.rb +37 -37
  136. metadata +33 -27
  137. data/README.rdoc +0 -208
  138. data/ext/libxml/extconf.h +0 -3
  139. data/ext/libxml/ruby_xml_cbg.c +0 -85
  140. data/lib/libxml/hpricot.rb +0 -78
  141. data/lib/libxml.rb +0 -5
  142. data/lib/xml/libxml.rb +0 -10
  143. data/lib/xml.rb +0 -14
  144. data/script/benchmark/depixelate +0 -634
  145. data/script/benchmark/hamlet.xml +0 -9055
  146. data/script/benchmark/parsecount +0 -170
  147. data/script/benchmark/sock_entries.xml +0 -507
  148. data/script/benchmark/throughput +0 -41
  149. data/script/test +0 -6
  150. data/test/test.rb +0 -5
  151. data/test/test_deprecated_require.rb +0 -12
@@ -1,1124 +1,1136 @@
1
- #include "ruby_libxml.h"
2
- #include "ruby_xml_writer.h"
3
-
4
- #ifdef LIBXML_WRITER_ENABLED
5
- #include <libxml/xmlwriter.h>
6
- #endif
7
-
8
- VALUE cXMLWriter;
9
- static VALUE sEncoding, sStandalone;
10
-
11
- #ifdef LIBXML_WRITER_ENABLED
12
-
13
- /*
14
- * Document-class: LibXML::XML::Writer
15
- *
16
- * The XML::Writer class provides a simpler, alternative way to build a valid
17
- * XML document from scratch (forward-only) compared to a DOM approach (based
18
- * on XML::Document class).
19
- *
20
- * For a more in depth tutorial, albeit in C, see http://xmlsoft.org/xmlwriter.html
21
- */
22
-
23
- #include <libxml/xmlwriter.h>
24
-
25
-
26
- typedef enum
27
- {
28
- RXMLW_OUTPUT_NONE,
29
- RXMLW_OUTPUT_IO,
30
- RXMLW_OUTPUT_DOC,
31
- RXMLW_OUTPUT_STRING
32
- } rxmlw_output_type;
33
-
34
- typedef struct
35
- {
36
- VALUE output;
37
- rb_encoding* encoding;
38
- xmlBufferPtr buffer;
39
- xmlTextWriterPtr writer;
40
- rxmlw_output_type output_type;
41
- int closed;
42
- } rxml_writer_object;
43
-
44
- static void rxml_writer_free(rxml_writer_object* rwo)
45
- {
46
- #if 0 /* seems to be done by xmlFreeTextWriter */
47
- if (NULL != rwo->buffer)
48
- {
49
- xmlBufferFree(rwo->buffer);
50
- }
51
- #endif
52
-
53
- rwo->closed = 1;
54
- xmlFreeTextWriter(rwo->writer);
55
- xfree(rwo);
56
- }
57
-
58
- static void rxml_writer_mark(rxml_writer_object* rwo)
59
- {
60
- if (!NIL_P(rwo->output))
61
- {
62
- rb_gc_mark(rwo->output);
63
- }
64
- }
65
-
66
- static VALUE rxml_writer_wrap(rxml_writer_object* rwo)
67
- {
68
- return Data_Wrap_Struct(cXMLWriter, rxml_writer_mark, rxml_writer_free, rwo);
69
- }
70
-
71
- static rxml_writer_object* rxml_textwriter_get(VALUE obj)
72
- {
73
- rxml_writer_object* rwo;
74
-
75
- Data_Get_Struct(obj, rxml_writer_object, rwo);
76
-
77
- return rwo;
78
- }
79
-
80
- int rxml_writer_write_callback(void* context, const char* buffer, int len)
81
- {
82
- rxml_writer_object* rwo = context;
83
-
84
- if (rwo->closed)
85
- {
86
- return 0;
87
- }
88
- else
89
- {
90
- return rxml_write_callback(rwo->output, buffer, len);
91
- }
92
- }
93
-
94
- /* ===== public class methods ===== */
95
-
96
- /* call-seq:
97
- * XML::Writer::io(io) -> XML::Writer
98
- *
99
- * Creates a XML::Writer which will write XML directly into an IO object.
100
- */
101
- static VALUE rxml_writer_io(VALUE klass, VALUE io)
102
- {
103
- xmlOutputBufferPtr out;
104
- rxml_writer_object* rwo;
105
-
106
- rwo = ALLOC(rxml_writer_object);
107
- rwo->output = io;
108
- rwo->buffer = NULL;
109
- rwo->closed = 0;
110
- rwo->encoding = rb_enc_get(io);
111
- if (!rwo->encoding)
112
- rwo->encoding = rb_utf8_encoding();
113
-
114
- rwo->output_type = RXMLW_OUTPUT_IO;
115
-
116
- xmlCharEncodingHandlerPtr encodingHdlr = xmlFindCharEncodingHandler(rwo->encoding->name);
117
- if (NULL == (out = xmlOutputBufferCreateIO(rxml_writer_write_callback, NULL, (void*)rwo, encodingHdlr)))
118
- {
119
- rxml_raise(xmlGetLastError());
120
- }
121
- if (NULL == (rwo->writer = xmlNewTextWriter(out)))
122
- {
123
- rxml_raise(xmlGetLastError());
124
- }
125
-
126
- return rxml_writer_wrap(rwo);
127
- }
128
-
129
-
130
- /* call-seq:
131
- * XML::Writer::file(path) -> XML::Writer
132
- *
133
- * Creates a XML::Writer object which will write XML into the file with
134
- * the given name.
135
- */
136
- static VALUE rxml_writer_file(VALUE klass, VALUE filename)
137
- {
138
- rxml_writer_object* rwo;
139
-
140
- rwo = ALLOC(rxml_writer_object);
141
- rwo->output = Qnil;
142
- rwo->buffer = NULL;
143
- rwo->closed = 0;
144
- rwo->encoding = rb_utf8_encoding();
145
- rwo->output_type = RXMLW_OUTPUT_NONE;
146
- if (NULL == (rwo->writer = xmlNewTextWriterFilename(StringValueCStr(filename), 0)))
147
- {
148
- rxml_raise(xmlGetLastError());
149
- }
150
-
151
- return rxml_writer_wrap(rwo);
152
- }
153
-
154
- /* call-seq:
155
- * XML::Writer::string -> XML::Writer
156
- *
157
- * Creates a XML::Writer which will write XML into memory, as string.
158
- */
159
- static VALUE rxml_writer_string(VALUE klass)
160
- {
161
- rxml_writer_object* rwo;
162
-
163
- rwo = ALLOC(rxml_writer_object);
164
- rwo->output = Qnil;
165
- rwo->closed = 0;
166
- rwo->encoding = rb_utf8_encoding();
167
- rwo->output_type = RXMLW_OUTPUT_STRING;
168
- if (NULL == (rwo->buffer = xmlBufferCreate()))
169
- {
170
- rxml_raise(xmlGetLastError());
171
- }
172
- if (NULL == (rwo->writer = xmlNewTextWriterMemory(rwo->buffer, 0)))
173
- {
174
- xmlBufferFree(rwo->buffer);
175
- rxml_raise(xmlGetLastError());
176
- }
177
-
178
- return rxml_writer_wrap(rwo);
179
- }
180
-
181
- /* call-seq:
182
- * XML::Writer::document -> XML::Writer
183
- *
184
- * Creates a XML::Writer which will write into an in memory XML::Document
185
- */
186
- static VALUE rxml_writer_doc(VALUE klass)
187
- {
188
- xmlDocPtr doc;
189
- rxml_writer_object* rwo;
190
-
191
- rwo = ALLOC(rxml_writer_object);
192
- rwo->buffer = NULL;
193
- rwo->output = Qnil;
194
- rwo->closed = 0;
195
- rwo->encoding = rb_utf8_encoding();
196
- rwo->output_type = RXMLW_OUTPUT_DOC;
197
- if (NULL == (rwo->writer = xmlNewTextWriterDoc(&doc, 0)))
198
- {
199
- rxml_raise(xmlGetLastError());
200
- }
201
- rwo->output = rxml_document_wrap(doc);
202
-
203
- return rxml_writer_wrap(rwo);
204
- }
205
-
206
- /* ===== public instance methods ===== */
207
-
208
- /* call-seq:
209
- * writer.flush(empty? = true) -> (num|string)
210
- *
211
- * Flushes the output buffer. Returns the number of written bytes or
212
- * the current content of the internal buffer for a in memory XML::Writer.
213
- * If +empty?+ is +true+, and for a in memory XML::Writer, this internel
214
- * buffer is empty.
215
- */
216
- static VALUE rxml_writer_flush(int argc, VALUE* argv, VALUE self)
217
- {
218
- int ret;
219
- VALUE empty;
220
- rxml_writer_object* rwo;
221
-
222
- rb_scan_args(argc, argv, "01", &empty);
223
-
224
- rwo = rxml_textwriter_get(self);
225
- if (-1 == (ret = xmlTextWriterFlush(rwo->writer)))
226
- {
227
- rxml_raise(xmlGetLastError());
228
- }
229
-
230
- if (NULL != rwo->buffer)
231
- {
232
- VALUE content;
233
-
234
- content = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding);
235
- if (NIL_P(empty) || RTEST(empty))
236
- { /* nil = default value = true */
237
- xmlBufferEmpty(rwo->buffer);
238
- }
239
-
240
- return content;
241
- }
242
- else
243
- {
244
- return INT2NUM(ret);
245
- }
246
- }
247
-
248
- /* call-seq:
249
- * writer.result -> (XML::Document|"string"|nil)
250
- *
251
- * Returns the associated result object to the XML::Writer creation.
252
- * A String for a XML::Writer object created with XML::Writer::string,
253
- * a XML::Document with XML::Writer::document, etc.
254
- */
255
- static VALUE rxml_writer_result(VALUE self)
256
- {
257
- VALUE ret = Qnil;
258
- rxml_writer_object* rwo = rxml_textwriter_get(self);
259
- int bytesWritten = xmlTextWriterFlush(rwo->writer);
260
-
261
- if (bytesWritten == -1)
262
- {
263
- rxml_raise(xmlGetLastError());
264
- }
265
-
266
- switch (rwo->output_type)
267
- {
268
- case RXMLW_OUTPUT_DOC:
269
- ret = rwo->output;
270
- break;
271
- case RXMLW_OUTPUT_STRING:
272
- ret = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding);
273
- break;
274
- case RXMLW_OUTPUT_IO:
275
- case RXMLW_OUTPUT_NONE:
276
- break;
277
- default:
278
- rb_bug("unexpected output");
279
- break;
280
- }
281
-
282
- return ret;
283
- }
284
-
285
- /* ===== private helpers ===== */
286
- static void encodeStrings(rb_encoding* encoding, int count, VALUE* strings, const xmlChar** encoded_strings)
287
- {
288
- for (int i = 0; i < count; i++)
289
- {
290
- VALUE string = strings[i];
291
-
292
- if (NIL_P(string))
293
- {
294
- encoded_strings[i] = NULL;
295
- }
296
- else
297
- {
298
- VALUE encoded = rb_str_conv_enc(strings[i], rb_enc_get(string), encoding);
299
- encoded_strings[i] = BAD_CAST StringValueCStr(encoded);
300
- }
301
- }
302
- }
303
-
304
- static VALUE invoke_void_arg_function(VALUE self, int (*fn)(xmlTextWriterPtr))
305
- {
306
- rxml_writer_object* rwo = rxml_textwriter_get(self);
307
- int result = fn(rwo->writer);
308
- return (result == -1 ? Qfalse : Qtrue);
309
- }
310
-
311
- static VALUE invoke_single_arg_function(VALUE self, int (*fn)(xmlTextWriterPtr, const xmlChar *), VALUE value)
312
- {
313
- rxml_writer_object* rwo = rxml_textwriter_get(self);
314
-
315
- VALUE rubyStrings[] = { value };
316
- const xmlChar* xmlStrings[] = { NULL };
317
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
318
-
319
- int result = fn(rwo->writer, xmlStrings[0]);
320
- return (result == -1 ? Qfalse : Qtrue);
321
- }
322
-
323
-
324
- /* ===== public instance methods ===== */
325
-
326
- #if LIBXML_VERSION >= 20605
327
- /* call-seq:
328
- * writer.set_indent(indentation) -> (true|false)
329
- *
330
- * Toggles indentation on or off. Returns +false+ on failure.
331
- *
332
- * Availability: libxml2 >= 2.6.5
333
- */
334
- static VALUE rxml_writer_set_indent(VALUE self, VALUE indentation)
335
- {
336
- int ret;
337
- rxml_writer_object* rwo;
338
-
339
- rwo = rxml_textwriter_get(self);
340
- ret = xmlTextWriterSetIndent(rwo->writer, RTEST(indentation));
341
-
342
- return (-1 == ret ? Qfalse : Qtrue);
343
- }
344
-
345
- /* call-seq:
346
- * writer.set_indent_string(string) -> (true|false)
347
- *
348
- * Sets the string to use to indent each element of the document.
349
- * Don't forget to enable indentation with set_indent. Returns
350
- * +false+ on failure.
351
- *
352
- * Availability: libxml2 >= 2.6.5
353
- */
354
- static VALUE rxml_writer_set_indent_string(VALUE self, VALUE indentation)
355
- {
356
- return invoke_single_arg_function(self, xmlTextWriterSetIndentString, indentation);
357
- }
358
- #endif /* LIBXML_VERSION >= 20605 */
359
-
360
- /* ===== public full tag interface ===== */
361
-
362
- /* write_<X> = start_<X> + write_string + end_<X> */
363
-
364
- /* call-seq:
365
- * writer.write_comment(content) -> (true|false)
366
- *
367
- * Writes a full comment tag, all at once. Returns +false+ on failure.
368
- * This is equivalent to start_comment + write_string(content) + end_comment.
369
- */
370
- static VALUE rxml_writer_write_comment(VALUE self, VALUE content)
371
- {
372
- return invoke_single_arg_function(self, xmlTextWriterWriteComment, content);
373
- }
374
-
375
- /* call-seq:
376
- * writer.write_cdata(content) -> (true|false)
377
- *
378
- * Writes a full CDATA section, all at once. Returns +false+ on failure.
379
- * This is equivalent to start_cdata + write_string(content) + end_cdata.
380
- */
381
- static VALUE rxml_writer_write_cdata(VALUE self, VALUE content)
382
- {
383
- return invoke_single_arg_function(self, xmlTextWriterWriteCDATA, content);
384
- }
385
-
386
- static VALUE rxml_writer_start_element(VALUE, VALUE);
387
- static VALUE rxml_writer_start_element_ns(int, VALUE*, VALUE);
388
- static VALUE rxml_writer_end_element(VALUE);
389
-
390
- /* call-seq:
391
- * writer.write_element(name, content) -> (true|false)
392
- *
393
- * Writes a full element tag, all at once. Returns +false+ on failure.
394
- * This is equivalent to start_element(name) + write_string(content) +
395
- * end_element.
396
- */
397
- static VALUE rxml_writer_write_element(int argc, VALUE* argv, VALUE self)
398
- {
399
- VALUE name, content;
400
-
401
- rb_scan_args(argc, argv, "11", &name, &content);
402
- if (Qnil == content)
403
- {
404
- if (Qfalse == rxml_writer_start_element(self, name))
405
- {
406
- return Qfalse;
407
- }
408
- return rxml_writer_end_element(self);
409
- }
410
- else
411
- {
412
- rxml_writer_object* rwo = rxml_textwriter_get(self);
413
- VALUE rubyStrings[] = {name, content};
414
- const xmlChar* xmlStrings[] = {NULL, NULL};
415
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
416
-
417
- int result = xmlTextWriterWriteElement(rwo->writer, xmlStrings[0], xmlStrings[1]);
418
- return (result == -1 ? Qfalse : Qtrue);
419
- }
420
- }
421
-
422
- #define ARRAY_SIZE(array) \
423
- (sizeof(array) / sizeof((array)[0]))
424
-
425
- /* call-seq:
426
- * writer.write_element_ns(prefix, name, namespaceURI, content) -> (true|false)
427
- *
428
- * Writes a full namespaced element tag, all at once. Returns +false+ on failure.
429
- * This is a shortcut for start_element_ns(prefix, name, namespaceURI) +
430
- * write_string(content) + end_element.
431
- *
432
- * Notes:
433
- * - by default, the xmlns: definition is repeated on every element. If you want
434
- * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+
435
- * to nil or omit it. Don't forget to declare the namespace prefix somewhere
436
- * earlier.
437
- * - +content+ can be omitted for an empty tag
438
- */
439
- static VALUE rxml_writer_write_element_ns(int argc, VALUE* argv, VALUE self)
440
- {
441
- VALUE prefix, name, namespaceURI, content;
442
-
443
- rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
444
- if (Qnil == content)
445
- {
446
- VALUE argv[3] = { prefix, name, namespaceURI };
447
-
448
- if (Qfalse == rxml_writer_start_element_ns(ARRAY_SIZE(argv), argv, self))
449
- {
450
- return Qfalse;
451
- }
452
- return rxml_writer_end_element(self);
453
- }
454
- else
455
- {
456
- rxml_writer_object* rwo = rxml_textwriter_get(self);
457
- VALUE rubyStrings[] = {prefix, name, namespaceURI, content};
458
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL};
459
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
460
- int result = xmlTextWriterWriteElementNS(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3]);
461
- return (result == -1 ? Qfalse : Qtrue);
462
- }
463
- }
464
-
465
- /* call-seq:
466
- * writer.write_attribute(name, content) -> (true|false)
467
- *
468
- * Writes a full attribute, all at once. Returns +false+ on failure.
469
- * Same as start_attribute(name) + write_string(content) + end_attribute.
470
- */
471
- static VALUE rxml_writer_write_attribute(VALUE self, VALUE name, VALUE content)
472
- {
473
- rxml_writer_object* rwo = rxml_textwriter_get(self);
474
- VALUE rubyStrings[] = {name, content};
475
- const xmlChar* xmlStrings[] = {NULL, NULL};
476
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
477
- int result = xmlTextWriterWriteAttribute(rwo->writer, xmlStrings[0], xmlStrings[1]);
478
- return (result == -1 ? Qfalse : Qtrue);
479
- }
480
-
481
- /* call-seq:
482
- * writer.write_attribute_ns(prefix, name, namespaceURI, content) -> (true|false)
483
- *
484
- * Writes a full namespaced attribute, all at once. Returns +false+ on failure.
485
- * Same as start_attribute_ns(prefix, name, namespaceURI) +
486
- * write_string(content) + end_attribute.
487
- *
488
- * Notes:
489
- * - by default, the xmlns: definition is repeated on every element. If you want
490
- * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+
491
- * to nil or omit it. Don't forget to declare the namespace prefix somewhere
492
- * earlier.
493
- * - +content+ can be omitted too for an empty attribute
494
- */
495
- static VALUE rxml_writer_write_attribute_ns(int argc, VALUE* argv, VALUE self)
496
- {
497
- VALUE prefix, name, namespaceURI, content;
498
- rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
499
-
500
- rxml_writer_object* rwo = rxml_textwriter_get(self);
501
- VALUE rubyStrings[] = {prefix, name, namespaceURI, content};
502
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL};
503
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
504
- int result = xmlTextWriterWriteAttributeNS(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3]);
505
- return (result == -1 ? Qfalse : Qtrue);
506
- }
507
-
508
- /* call-seq:
509
- * writer.write_pi(target, content) -> (true|false)
510
- *
511
- * Writes a full CDATA tag, all at once. Returns +false+ on failure.
512
- * This is a shortcut for start_pi(target) + write_string(content) + end_pi.
513
- */
514
- static VALUE rxml_writer_write_pi(VALUE self, VALUE target, VALUE content)
515
- {
516
- rxml_writer_object* rwo = rxml_textwriter_get(self);
517
- VALUE rubyStrings[] = {target, content};
518
- const xmlChar* xmlStrings[] = {NULL, NULL};
519
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
520
- int result = xmlTextWriterWritePI(rwo->writer, xmlStrings[0], xmlStrings[1]);
521
- return (result == -1 ? Qfalse : Qtrue);
522
- }
523
-
524
- /* ===== public start/end interface ===== */
525
-
526
- /* call-seq:
527
- * writer.write_string(content) -> (true|false)
528
- *
529
- * Safely (problematic characters are internally translated to their
530
- * associated named entities) writes a string into the current node
531
- * (attribute, element, comment, ...). Returns +false+ on failure.
532
- */
533
- static VALUE rxml_writer_write_string(VALUE self, VALUE content)
534
- {
535
- return invoke_single_arg_function(self, xmlTextWriterWriteString, content);
536
- }
537
-
538
- /* call-seq:
539
- * writer.write_raw(content) -> (true|false)
540
- *
541
- * Writes the string +content+ as is, reserved characters are not
542
- * translated to their associated entities. Returns +false+ on failure.
543
- * Consider write_string to handle them.
544
- */
545
- static VALUE rxml_writer_write_raw(VALUE self, VALUE content)
546
- {
547
- return invoke_single_arg_function(self, xmlTextWriterWriteRaw, content);
548
- }
549
-
550
- /* call-seq:
551
- * writer.start_attribute(name) -> (true|false)
552
- *
553
- * Starts an attribute. Returns +false+ on failure.
554
- */
555
- static VALUE rxml_writer_start_attribute(VALUE self, VALUE name)
556
- {
557
- return invoke_single_arg_function(self, xmlTextWriterStartAttribute, name);
558
- }
559
-
560
- /* call-seq:
561
- * writer.start_attribute_ns(prefix, name, namespaceURI) -> (true|false)
562
- *
563
- * Starts a namespaced attribute. Returns +false+ on failure.
564
- *
565
- * Note: by default, the xmlns: definition is repeated on every element. If
566
- * you want the prefix, but don't want the xmlns: declaration repeated, set
567
- * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace
568
- * prefix somewhere earlier.
569
- */
570
- static VALUE rxml_writer_start_attribute_ns(int argc, VALUE* argv, VALUE self)
571
- {
572
- VALUE prefix, name, namespaceURI;
573
- rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
574
-
575
- rxml_writer_object* rwo = rxml_textwriter_get(self);
576
- VALUE rubyStrings[] = {prefix, name, namespaceURI};
577
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
578
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
579
- int result = xmlTextWriterStartAttributeNS(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
580
- return (result == -1 ? Qfalse : Qtrue);
581
- }
582
-
583
- /* call-seq:
584
- * writer.end_attribute -> (true|false)
585
- *
586
- * Ends an attribute, namespaced or not. Returns +false+ on failure.
587
- */
588
- static VALUE rxml_writer_end_attribute(VALUE self)
589
- {
590
- return invoke_void_arg_function(self, xmlTextWriterEndAttribute);
591
- }
592
-
593
- #if LIBXML_VERSION >= 20607
594
- /* call-seq:
595
- * writer.start_comment -> (true|false)
596
- *
597
- * Starts a comment. Returns +false+ on failure.
598
- * Note: libxml2 >= 2.6.7 required
599
- */
600
- static VALUE rxml_writer_start_comment(VALUE self)
601
- {
602
- return invoke_void_arg_function(self, xmlTextWriterStartComment);
603
- }
604
-
605
- /* call-seq:
606
- * writer.end_comment -> (true|false)
607
- *
608
- * Ends current comment, returns +false+ on failure.
609
- * Note: libxml2 >= 2.6.7 required
610
- */
611
- static VALUE rxml_writer_end_comment(VALUE self)
612
- {
613
- return invoke_void_arg_function(self, xmlTextWriterEndComment);
614
- }
615
- #endif /* LIBXML_VERSION >= 20607 */
616
-
617
- /* call-seq:
618
- * writer.start_element(name) -> (true|false)
619
- *
620
- * Starts a new element. Returns +false+ on failure.
621
- */
622
- static VALUE rxml_writer_start_element(VALUE self, VALUE name)
623
- {
624
- return invoke_single_arg_function(self, xmlTextWriterStartElement, name);
625
- }
626
-
627
- /* call-seq:
628
- * writer.start_element_ns(prefix, name, namespaceURI) -> (true|false)
629
- *
630
- * Starts a new namespaced element. Returns +false+ on failure.
631
- *
632
- * Note: by default, the xmlns: definition is repeated on every element. If
633
- * you want the prefix, but don't want the xmlns: declaration repeated, set
634
- * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace
635
- * prefix somewhere earlier.
636
- */
637
- static VALUE rxml_writer_start_element_ns(int argc, VALUE* argv, VALUE self)
638
- {
639
- VALUE prefix, name, namespaceURI;
640
- rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
641
-
642
- rxml_writer_object* rwo = rxml_textwriter_get(self);
643
- VALUE rubyStrings[] = {prefix, name, namespaceURI};
644
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
645
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
646
- int result = xmlTextWriterStartElementNS(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
647
- return (result == -1 ? Qfalse : Qtrue);
648
- }
649
-
650
- /* call-seq:
651
- * writer.end_element -> (true|false)
652
- *
653
- * Ends current element, namespaced or not. Returns +false+ on failure.
654
- */
655
- static VALUE rxml_writer_end_element(VALUE self)
656
- {
657
- return invoke_void_arg_function(self, xmlTextWriterEndElement);
658
- }
659
-
660
- /* call-seq:
661
- * writer.write_full_end_element -> (true|false)
662
- *
663
- * Ends current element, namespaced or not. Returns +false+ on failure.
664
- * This method writes an end tag even if the element is empty (<foo></foo>),
665
- * end_element does not (<foo/>).
666
- */
667
- static VALUE rxml_writer_full_end_element(VALUE self)
668
- {
669
- return invoke_void_arg_function(self, xmlTextWriterFullEndElement);
670
- }
671
-
672
- /* call-seq:
673
- * writer.start_cdata -> (true|false)
674
- *
675
- * Starts a new CDATA section. Returns +false+ on failure.
676
- */
677
- static VALUE rxml_writer_start_cdata(VALUE self)
678
- {
679
- return invoke_void_arg_function(self, xmlTextWriterStartCDATA);
680
- }
681
-
682
- /* call-seq:
683
- * writer.end_cdata -> (true|false)
684
- *
685
- * Ends current CDATA section. Returns +false+ on failure.
686
- */
687
- static VALUE rxml_writer_end_cdata(VALUE self)
688
- {
689
- return invoke_void_arg_function(self, xmlTextWriterEndCDATA);
690
- }
691
-
692
- /* call-seq:
693
- * writer.start_document -> (true|false)
694
- * writer.start_document(:encoding => XML::Encoding::UTF_8,
695
- * :standalone => true) -> (true|false)
696
- *
697
- * Starts a new document. Returns +false+ on failure.
698
- *
699
- * You may provide an optional hash table to control XML header that will be
700
- * generated. Valid options are:
701
- * - encoding: the output document encoding, defaults to nil (= UTF-8). Valid
702
- * values are the encoding constants defined on XML::Encoding
703
- * - standalone: nil (default) or a boolean to indicate if the document is
704
- * standalone or not
705
- */
706
- static VALUE rxml_writer_start_document(int argc, VALUE* argv, VALUE self)
707
- {
708
- int ret;
709
- VALUE options = Qnil;
710
- rxml_writer_object* rwo;
711
- const xmlChar* xencoding = NULL;
712
- const char* xstandalone = NULL;
713
-
714
- rb_scan_args(argc, argv, "01", &options);
715
- if (!NIL_P(options))
716
- {
717
- VALUE encoding, standalone;
718
-
719
- encoding = standalone = Qnil;
720
- Check_Type(options, T_HASH);
721
- encoding = rb_hash_aref(options, sEncoding);
722
- xencoding = NIL_P(encoding) ? NULL : (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding));
723
- standalone = rb_hash_aref(options, sStandalone);
724
- if (NIL_P(standalone))
725
- {
726
- xstandalone = NULL;
727
- }
728
- else
729
- {
730
- xstandalone = RTEST(standalone) ? "yes" : "no";
731
- }
732
- }
733
- rwo = rxml_textwriter_get(self);
734
- rwo->encoding = rxml_figure_encoding(xencoding);
735
- ret = xmlTextWriterStartDocument(rwo->writer, NULL, (const char*)xencoding, xstandalone);
736
-
737
- return (-1 == ret ? Qfalse : Qtrue);
738
- }
739
-
740
- /* call-seq:
741
- * writer.end_document -> (true|false)
742
- *
743
- * Ends current document. Returns +false+ on failure.
744
- */
745
- static VALUE rxml_writer_end_document(VALUE self)
746
- {
747
- return invoke_void_arg_function(self, xmlTextWriterEndDocument);
748
- }
749
-
750
- /* call-seq:
751
- * writer.start_pi(target) -> (true|false)
752
- *
753
- * Starts a new processing instruction. Returns +false+ on failure.
754
- */
755
- static VALUE rxml_writer_start_pi(VALUE self, VALUE target)
756
- {
757
- return invoke_single_arg_function(self, xmlTextWriterStartPI, target);
758
- }
759
-
760
- /* call-seq:
761
- * writer.end_pi -> (true|false)
762
- *
763
- * Ends current processing instruction. Returns +false+ on failure.
764
- */
765
- static VALUE rxml_writer_end_pi(VALUE self)
766
- {
767
- return invoke_void_arg_function(self, xmlTextWriterEndPI);
768
- }
769
-
770
- /* call-seq:
771
- * writer.start_dtd(qualifiedName, publicId, systemId) -> (true|false)
772
- *
773
- * Starts a DTD. Returns +false+ on failure.
774
- */
775
- static VALUE rxml_writer_start_dtd(int argc, VALUE* argv, VALUE self)
776
- {
777
- VALUE name, pubid, sysid;
778
- rb_scan_args(argc, argv, "12", &name, &pubid, &sysid);
779
-
780
- rxml_writer_object* rwo = rxml_textwriter_get(self);
781
- VALUE rubyStrings[] = {name, pubid, sysid};
782
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
783
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
784
- int result = xmlTextWriterStartDTD(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
785
- return (result == -1 ? Qfalse : Qtrue);
786
- }
787
-
788
- /* call-seq:
789
- * writer.start_dtd_element(qualifiedName) -> (true|false)
790
- *
791
- * Starts a DTD element (<!ELEMENT ... >). Returns +false+ on failure.
792
- */
793
- static VALUE rxml_writer_start_dtd_element(VALUE self, VALUE name)
794
- {
795
- return invoke_single_arg_function(self, xmlTextWriterStartDTDElement, name);
796
- }
797
-
798
- /* call-seq:
799
- * writer.start_dtd_entity(name, pe = false) -> (true|false)
800
- *
801
- * Starts a DTD entity (<!ENTITY ... >). Returns +false+ on failure.
802
- */
803
- static VALUE rxml_writer_start_dtd_entity(int argc, VALUE* argv, VALUE self)
804
- {
805
- VALUE name, pe;
806
- rb_scan_args(argc, argv, "11", &name, &pe);
807
-
808
- rxml_writer_object* rwo = rxml_textwriter_get(self);
809
- VALUE rubyStrings[] = {name};
810
- const xmlChar* xmlStrings[] = {NULL};
811
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
812
- int result = xmlTextWriterStartDTDEntity(rwo->writer, RB_TEST(pe), xmlStrings[0]);
813
- return (result == -1 ? Qfalse : Qtrue);
814
- }
815
-
816
- /* call-seq:
817
- * writer.start_dtd_attlist(name) -> (true|false)
818
- *
819
- * Starts a DTD attribute list (<!ATTLIST ... >). Returns +false+ on failure.
820
- */
821
- static VALUE rxml_writer_start_dtd_attlist(VALUE self, VALUE name)
822
- {
823
- return invoke_single_arg_function(self, xmlTextWriterStartDTDAttlist, name);
824
- }
825
-
826
- /* call-seq:
827
- * writer.end_dtd -> (true|false)
828
- *
829
- * Ends current DTD, returns +false+ on failure.
830
- */
831
- static VALUE rxml_writer_end_dtd(VALUE self)
832
- {
833
- return invoke_void_arg_function(self, xmlTextWriterEndDTD);
834
- }
835
-
836
- /* call-seq:
837
- * writer.end_dtd_entity -> (true|false)
838
- *
839
- * Ends current DTD entity, returns +false+ on failure.
840
- */
841
- static VALUE rxml_writer_end_dtd_entity(VALUE self)
842
- {
843
- return invoke_void_arg_function(self, xmlTextWriterEndDTDEntity);
844
- }
845
-
846
- /* call-seq:
847
- * writer.end_dtd_attlist -> (true|false)
848
- *
849
- * Ends current DTD attribute list, returns +false+ on failure.
850
- */
851
- static VALUE rxml_writer_end_dtd_attlist(VALUE self)
852
- {
853
- return invoke_void_arg_function(self, xmlTextWriterEndDTDAttlist);
854
- }
855
-
856
- /* call-seq:
857
- * writer.end_dtd_element -> (true|false)
858
- *
859
- * Ends current DTD element, returns +false+ on failure.
860
- */
861
- static VALUE rxml_writer_end_dtd_element(VALUE self)
862
- {
863
- return invoke_void_arg_function(self, xmlTextWriterEndDTDElement);
864
- }
865
-
866
- /* call-seq:
867
- * writer.write_dtd(name [ [ [, publicId ], systemId ], subset ]) -> (true|false)
868
- *
869
- * Writes a DTD, all at once. Returns +false+ on failure.
870
- * - name: dtd name
871
- * - publicId: external subset public identifier, use nil for a SYSTEM doctype
872
- * - systemId: external subset system identifier
873
- * - subset: content
874
- *
875
- * Examples:
876
- * writer.write_dtd 'html'
877
- * #=> <!DOCTYPE html>
878
- * writer.write_dtd 'docbook', nil, 'http://www.docbook.org/xml/5.0/dtd/docbook.dtd'
879
- * #=> <!DOCTYPE docbook SYSTEM "http://www.docbook.org/xml/5.0/dtd/docbook.dtd">
880
- * writer.write_dtd 'html', '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
881
- * #=> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
882
- * writer.write_dtd 'person', nil, nil, '<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>'
883
- * #=> <!DOCTYPE person [<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>]>
884
- */
885
- static VALUE rxml_writer_write_dtd(int argc, VALUE* argv, VALUE self)
886
- {
887
- VALUE name, pubid, sysid, subset;
888
- rb_scan_args(argc, argv, "13", &name, &pubid, &sysid, &subset);
889
-
890
- rxml_writer_object* rwo = rxml_textwriter_get(self);
891
- VALUE rubyStrings[] = {name, pubid, sysid, subset};
892
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL};
893
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
894
- int result = xmlTextWriterWriteDTD(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3]);
895
- return (result == -1 ? Qfalse : Qtrue);
896
- }
897
-
898
- /* call-seq:
899
- * writer.write_dtd_attlist(name, content) -> (true|false)
900
- *
901
- * Writes a DTD attribute list, all at once. Returns +false+ on failure.
902
- * writer.write_dtd_attlist 'id', 'ID #IMPLIED'
903
- * #=> <!ATTLIST id ID #IMPLIED>
904
- */
905
- static VALUE rxml_writer_write_dtd_attlist(VALUE self, VALUE name, VALUE content)
906
- {
907
- rxml_writer_object* rwo = rxml_textwriter_get(self);
908
- VALUE rubyStrings[] = {name, content};
909
- const xmlChar* xmlStrings[] = {NULL, NULL};
910
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
911
- int result = xmlTextWriterWriteDTDAttlist(rwo->writer, xmlStrings[0], xmlStrings[1]);
912
- return (result == -1 ? Qfalse : Qtrue);
913
- }
914
-
915
- /* call-seq:
916
- * writer.write_dtd_element(name, content) -> (true|false)
917
- *
918
- * Writes a full DTD element, all at once. Returns +false+ on failure.
919
- * writer.write_dtd_element 'person', '(firstname,lastname)'
920
- * #=> <!ELEMENT person (firstname,lastname)>
921
- */
922
- static VALUE rxml_writer_write_dtd_element(VALUE self, VALUE name, VALUE content)
923
- {
924
- rxml_writer_object* rwo = rxml_textwriter_get(self);
925
- VALUE rubyStrings[] = {name, content};
926
- const xmlChar* xmlStrings[] = {NULL, NULL};
927
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
928
- int result = xmlTextWriterWriteDTDElement(rwo->writer, xmlStrings[0], xmlStrings[1]);
929
- return (result == -1 ? Qfalse : Qtrue);
930
- }
931
-
932
- /* call-seq:
933
- * writer.write_dtd_entity(name, publicId, systemId, ndataid, content, pe) -> (true|false)
934
- *
935
- * Writes a DTD entity, all at once. Returns +false+ on failure.
936
- */
937
- static VALUE rxml_writer_write_dtd_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE content, VALUE pe)
938
- {
939
- rxml_writer_object* rwo = rxml_textwriter_get(self);
940
- VALUE rubyStrings[] = {name, pubid, sysid, ndataid, content};
941
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL, NULL};
942
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
943
- int result = xmlTextWriterWriteDTDEntity(rwo->writer, RB_TEST(pe), xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3], xmlStrings[4]);
944
- return (result == -1 ? Qfalse : Qtrue);
945
- }
946
-
947
- /* call-seq:
948
- * writer.write_dtd_external_entity(name, publicId, systemId, ndataid, pe) -> (true|false)
949
- *
950
- * Writes a DTD external entity. The entity must have been started
951
- * with start_dtd_entity. Returns +false+ on failure.
952
- * - name: the name of the DTD entity
953
- * - publicId: the public identifier, which is an alternative to the system identifier
954
- * - systemId: the system identifier, which is the URI of the DTD
955
- * - ndataid: the xml notation name
956
- * - pe: +true+ if this is a parameter entity (to be used only in the DTD
957
- * itself), +false+ if not
958
- */
959
- static VALUE rxml_writer_write_dtd_external_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE pe)
960
- {
961
- rxml_writer_object* rwo = rxml_textwriter_get(self);
962
- VALUE rubyStrings[] = {name, pubid, sysid, ndataid};
963
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL};
964
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
965
- int result = xmlTextWriterWriteDTDExternalEntity(rwo->writer, RB_TEST(pe), xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3]);
966
- return (result == -1 ? Qfalse : Qtrue);
967
- }
968
-
969
- /* call-seq:
970
- * writer.write_dtd_external_entity_contents(publicId, systemId, ndataid) -> (true|false)
971
- *
972
- * Writes the contents of a DTD external entity, all at once. Returns +false+ on failure.
973
- */
974
- static VALUE rxml_writer_write_dtd_external_entity_contents(VALUE self, VALUE pubid, VALUE sysid, VALUE ndataid)
975
- {
976
- rxml_writer_object* rwo = rxml_textwriter_get(self);
977
- VALUE rubyStrings[] = {pubid, sysid, ndataid,};
978
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
979
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
980
- int result = xmlTextWriterWriteDTDExternalEntityContents(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
981
- return (result == -1 ? Qfalse : Qtrue);
982
- }
983
-
984
- /* call-seq:
985
- * writer.write_dtd_internal_entity(name, content, pe) -> (true|false)
986
- *
987
- * Writes a DTD internal entity, all at once. Returns +false+ on failure.
988
- *
989
- * Examples:
990
- * writer.write_dtd_entity 'Shape', '(rect|circle|poly|default)', true
991
- * #=> <!ENTITY % Shape "(rect|circle|poly|default)">
992
- * writer.write_dtd_entity 'delta', '&#948;', false
993
- * #=> <!ENTITY delta "&#948;">
994
- */
995
- static VALUE rxml_writer_write_dtd_internal_entity(VALUE self, VALUE name, VALUE content, VALUE pe)
996
- {
997
- rxml_writer_object* rwo = rxml_textwriter_get(self);
998
- VALUE rubyStrings[] = {name, content};
999
- const xmlChar* xmlStrings[] = {NULL, NULL};
1000
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
1001
- int result = xmlTextWriterWriteDTDInternalEntity(rwo->writer, RB_TEST(pe), xmlStrings[0], xmlStrings[1]);
1002
- return (result == -1 ? Qfalse : Qtrue);
1003
- }
1004
-
1005
- /* call-seq:
1006
- * writer.write_dtd_notation(name, publicId, systemId) -> (true|false)
1007
- *
1008
- * Writes a DTD entity, all at once. Returns +false+ on failure.
1009
- */
1010
- static VALUE rxml_writer_write_dtd_notation(VALUE self, VALUE name, VALUE pubid, VALUE sysid)
1011
- {
1012
- rxml_writer_object* rwo = rxml_textwriter_get(self);
1013
- VALUE rubyStrings[] = {name, pubid, sysid};
1014
- const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
1015
- encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
1016
- int result = xmlTextWriterWriteDTDNotation(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
1017
- return (result == -1 ? Qfalse : Qtrue);
1018
- }
1019
-
1020
- #if LIBXML_VERSION >= 20900
1021
- /* call-seq:
1022
- * writer.set_quote_char(...) -> (true|false)
1023
- *
1024
- * Sets the character used to quote attributes. Returns +false+ on failure.
1025
- *
1026
- * Notes:
1027
- * - only " (default) and ' characters are valid
1028
- * - availability: libxml2 >= 2.9.0
1029
- */
1030
- static VALUE rxml_writer_set_quote_char(VALUE self, VALUE quotechar)
1031
- {
1032
- int ret;
1033
- const char* xquotechar;
1034
- rxml_writer_object* rwo;
1035
-
1036
- rwo = rxml_textwriter_get(self);
1037
- xquotechar = StringValueCStr(quotechar);
1038
- ret = xmlTextWriterSetQuoteChar(rwo->writer, (xmlChar)xquotechar[0]);
1039
-
1040
- return (-1 == ret ? Qfalse : Qtrue);
1041
- }
1042
- #endif /* LIBXML_VERSION >= 20900 */
1043
-
1044
- #endif /* LIBXML_WRITER_ENABLED */
1045
-
1046
-
1047
- /* grep -P 'xmlTextWriter(Start|End|Write)(?!DTD|V?Format)[^(]+' /usr/include/libxml2/libxml/xmlwriter.h */
1048
- void rxml_init_writer(void)
1049
- {
1050
- sEncoding = ID2SYM(rb_intern("encoding"));
1051
- sStandalone = ID2SYM(rb_intern("standalone"));
1052
-
1053
- cXMLWriter = rb_define_class_under(mXML, "Writer", rb_cObject);
1054
- rb_undef_alloc_func(cXMLWriter);
1055
-
1056
- #ifdef LIBXML_WRITER_ENABLED
1057
- rb_define_singleton_method(cXMLWriter, "io", rxml_writer_io, 1);
1058
- rb_define_singleton_method(cXMLWriter, "file", rxml_writer_file, 1);
1059
- rb_define_singleton_method(cXMLWriter, "document", rxml_writer_doc, 0);
1060
- rb_define_singleton_method(cXMLWriter, "string", rxml_writer_string, 0);
1061
-
1062
- /* misc */
1063
- #if LIBXML_VERSION >= 20605
1064
- rb_define_method(cXMLWriter, "set_indent", rxml_writer_set_indent, 1);
1065
- rb_define_method(cXMLWriter, "set_indent_string", rxml_writer_set_indent_string, 1);
1066
- #endif /* LIBXML_VERSION >= 20605 */
1067
- #if LIBXML_VERSION >= 20900
1068
- rb_define_method(cXMLWriter, "set_quote_char", rxml_writer_set_quote_char, 1);
1069
- #endif /* LIBXML_VERSION >= 20900 */
1070
- rb_define_method(cXMLWriter, "flush", rxml_writer_flush, -1);
1071
- rb_define_method(cXMLWriter, "start_dtd", rxml_writer_start_dtd, -1);
1072
- rb_define_method(cXMLWriter, "start_dtd_entity", rxml_writer_start_dtd_entity, -1);
1073
- rb_define_method(cXMLWriter, "start_dtd_attlist", rxml_writer_start_dtd_attlist, 1);
1074
- rb_define_method(cXMLWriter, "start_dtd_element", rxml_writer_start_dtd_element, 1);
1075
- rb_define_method(cXMLWriter, "write_dtd", rxml_writer_write_dtd, -1);
1076
- rb_define_method(cXMLWriter, "write_dtd_attlist", rxml_writer_write_dtd_attlist, 2);
1077
- rb_define_method(cXMLWriter, "write_dtd_element", rxml_writer_write_dtd_element, 2);
1078
- rb_define_method(cXMLWriter, "write_dtd_entity", rxml_writer_write_dtd_entity, 6);
1079
- rb_define_method(cXMLWriter, "write_dtd_external_entity", rxml_writer_write_dtd_external_entity, 5);
1080
- rb_define_method(cXMLWriter, "write_dtd_external_entity_contents", rxml_writer_write_dtd_external_entity_contents, 3);
1081
- rb_define_method(cXMLWriter, "write_dtd_internal_entity", rxml_writer_write_dtd_internal_entity, 3);
1082
- rb_define_method(cXMLWriter, "write_dtd_notation", rxml_writer_write_dtd_notation, 3);
1083
- rb_define_method(cXMLWriter, "end_dtd", rxml_writer_end_dtd, 0);
1084
- rb_define_method(cXMLWriter, "end_dtd_entity", rxml_writer_end_dtd_entity, 0);
1085
- rb_define_method(cXMLWriter, "end_dtd_attlist", rxml_writer_end_dtd_attlist, 0);
1086
- rb_define_method(cXMLWriter, "end_dtd_element", rxml_writer_end_dtd_element, 0);
1087
-
1088
- /* tag by parts */
1089
- rb_define_method(cXMLWriter, "write_raw", rxml_writer_write_raw, 1);
1090
- rb_define_method(cXMLWriter, "write_string", rxml_writer_write_string, 1);
1091
-
1092
- rb_define_method(cXMLWriter, "start_cdata", rxml_writer_start_cdata, 0);
1093
- rb_define_method(cXMLWriter, "end_cdata", rxml_writer_end_cdata, 0);
1094
- rb_define_method(cXMLWriter, "start_attribute", rxml_writer_start_attribute, 1);
1095
- rb_define_method(cXMLWriter, "start_attribute_ns", rxml_writer_start_attribute_ns, -1);
1096
- rb_define_method(cXMLWriter, "end_attribute", rxml_writer_end_attribute, 0);
1097
- rb_define_method(cXMLWriter, "start_element", rxml_writer_start_element, 1);
1098
- rb_define_method(cXMLWriter, "start_element_ns", rxml_writer_start_element_ns, -1);
1099
- rb_define_method(cXMLWriter, "end_element", rxml_writer_end_element, 0);
1100
- rb_define_method(cXMLWriter, "full_end_element", rxml_writer_full_end_element, 0);
1101
- rb_define_method(cXMLWriter, "start_document", rxml_writer_start_document, -1);
1102
- rb_define_method(cXMLWriter, "end_document", rxml_writer_end_document, 0);
1103
- #if LIBXML_VERSION >= 20607
1104
- rb_define_method(cXMLWriter, "start_comment", rxml_writer_start_comment, 0);
1105
- rb_define_method(cXMLWriter, "end_comment", rxml_writer_end_comment, 0);
1106
- #endif /* LIBXML_VERSION >= 20607 */
1107
- rb_define_method(cXMLWriter, "start_pi", rxml_writer_start_pi, 1);
1108
- rb_define_method(cXMLWriter, "end_pi", rxml_writer_end_pi, 0);
1109
-
1110
- /* full tag at once */
1111
- rb_define_method(cXMLWriter, "write_attribute", rxml_writer_write_attribute, 2);
1112
- rb_define_method(cXMLWriter, "write_attribute_ns", rxml_writer_write_attribute_ns, -1);
1113
- rb_define_method(cXMLWriter, "write_comment", rxml_writer_write_comment, 1);
1114
- rb_define_method(cXMLWriter, "write_cdata", rxml_writer_write_cdata, 1);
1115
- rb_define_method(cXMLWriter, "write_element", rxml_writer_write_element, -1);
1116
- rb_define_method(cXMLWriter, "write_element_ns", rxml_writer_write_element_ns, -1);
1117
- rb_define_method(cXMLWriter, "write_pi", rxml_writer_write_pi, 2);
1118
-
1119
- rb_define_method(cXMLWriter, "result", rxml_writer_result, 0);
1120
-
1121
- rb_undef_method(CLASS_OF(cXMLWriter), "new");
1122
- #endif
1123
- }
1124
-
1
+ #include "ruby_libxml.h"
2
+ #include "ruby_xml_writer.h"
3
+
4
+ #ifdef LIBXML_WRITER_ENABLED
5
+ #include <libxml/xmlwriter.h>
6
+ #endif
7
+
8
+ VALUE cXMLWriter;
9
+ static VALUE sEncoding, sStandalone;
10
+
11
+ #ifdef LIBXML_WRITER_ENABLED
12
+
13
+ /*
14
+ * Document-class: LibXML::XML::Writer
15
+ *
16
+ * The XML::Writer class provides a simpler, alternative way to build a valid
17
+ * XML document from scratch (forward-only) compared to a DOM approach (based
18
+ * on XML::Document class).
19
+ *
20
+ * For a more in depth tutorial, albeit in C, see http://xmlsoft.org/xmlwriter.html
21
+ */
22
+
23
+ #include <libxml/xmlwriter.h>
24
+
25
+
26
+ typedef enum
27
+ {
28
+ RXMLW_OUTPUT_NONE,
29
+ RXMLW_OUTPUT_IO,
30
+ RXMLW_OUTPUT_DOC,
31
+ RXMLW_OUTPUT_STRING
32
+ } rxmlw_output_type;
33
+
34
+ typedef struct
35
+ {
36
+ VALUE output;
37
+ rb_encoding* encoding;
38
+ xmlBufferPtr buffer;
39
+ xmlTextWriterPtr writer;
40
+ rxmlw_output_type output_type;
41
+ int closed;
42
+ } rxml_writer_object;
43
+
44
+ static void rxml_writer_free(void* data)
45
+ {
46
+ rxml_writer_object* rwo = (rxml_writer_object*)data;
47
+ xmlBufferPtr buffer = rwo->buffer;
48
+
49
+ rwo->closed = 1;
50
+ xmlFreeTextWriter(rwo->writer);
51
+
52
+ if (NULL != buffer)
53
+ {
54
+ xmlBufferFree(buffer);
55
+ }
56
+
57
+ xfree(rwo);
58
+ }
59
+
60
+ static void rxml_writer_mark(void* data)
61
+ {
62
+ rxml_writer_object* rwo = (rxml_writer_object*)data;
63
+ if (!NIL_P(rwo->output))
64
+ {
65
+ rb_gc_mark(rwo->output);
66
+ }
67
+ }
68
+
69
+ static const rb_data_type_t rxml_writer_data_type = {
70
+ .wrap_struct_name = "LibXML::XML::Writer",
71
+ .function = { .dmark = rxml_writer_mark, .dfree = rxml_writer_free },
72
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
73
+ };
74
+
75
+ static VALUE rxml_writer_wrap(rxml_writer_object* rwo)
76
+ {
77
+ return TypedData_Wrap_Struct(cXMLWriter, &rxml_writer_data_type, rwo);
78
+ }
79
+
80
+ static rxml_writer_object* rxml_textwriter_get(VALUE obj)
81
+ {
82
+ rxml_writer_object* rwo;
83
+
84
+ TypedData_Get_Struct(obj, rxml_writer_object, &rxml_writer_data_type, rwo);
85
+
86
+ return rwo;
87
+ }
88
+
89
+ int rxml_writer_write_callback(void* context, const char* buffer, int len)
90
+ {
91
+ rxml_writer_object* rwo = context;
92
+
93
+ if (rwo->closed)
94
+ {
95
+ return 0;
96
+ }
97
+ else
98
+ {
99
+ return rxml_write_callback(rwo->output, buffer, len);
100
+ }
101
+ }
102
+
103
+ /* ===== public class methods ===== */
104
+
105
+ /* call-seq:
106
+ * XML::Writer::io(io) -> XML::Writer
107
+ *
108
+ * Creates a XML::Writer which will write XML directly into an IO object.
109
+ */
110
+ static VALUE rxml_writer_io(VALUE klass, VALUE io)
111
+ {
112
+ xmlOutputBufferPtr out;
113
+ rxml_writer_object* rwo;
114
+
115
+ rwo = ALLOC(rxml_writer_object);
116
+ rwo->output = io;
117
+ rwo->buffer = NULL;
118
+ rwo->closed = 0;
119
+ rwo->encoding = rb_enc_get(io);
120
+ if (!rwo->encoding)
121
+ rwo->encoding = rb_utf8_encoding();
122
+
123
+ rwo->output_type = RXMLW_OUTPUT_IO;
124
+
125
+ xmlCharEncodingHandlerPtr encodingHdlr = xmlFindCharEncodingHandler(rwo->encoding->name);
126
+ if (NULL == (out = xmlOutputBufferCreateIO(rxml_writer_write_callback, NULL, (void*)rwo, encodingHdlr)))
127
+ {
128
+ rxml_raise(xmlGetLastError());
129
+ }
130
+ if (NULL == (rwo->writer = xmlNewTextWriter(out)))
131
+ {
132
+ rxml_raise(xmlGetLastError());
133
+ }
134
+
135
+ return rxml_writer_wrap(rwo);
136
+ }
137
+
138
+
139
+ /* call-seq:
140
+ * XML::Writer::file(path) -> XML::Writer
141
+ *
142
+ * Creates a XML::Writer object which will write XML into the file with
143
+ * the given name.
144
+ */
145
+ static VALUE rxml_writer_file(VALUE klass, VALUE filename)
146
+ {
147
+ rxml_writer_object* rwo;
148
+
149
+ rwo = ALLOC(rxml_writer_object);
150
+ rwo->output = Qnil;
151
+ rwo->buffer = NULL;
152
+ rwo->closed = 0;
153
+ rwo->encoding = rb_utf8_encoding();
154
+ rwo->output_type = RXMLW_OUTPUT_NONE;
155
+ if (NULL == (rwo->writer = xmlNewTextWriterFilename(StringValueCStr(filename), 0)))
156
+ {
157
+ rxml_raise(xmlGetLastError());
158
+ }
159
+
160
+ return rxml_writer_wrap(rwo);
161
+ }
162
+
163
+ /* call-seq:
164
+ * XML::Writer::string -> XML::Writer
165
+ *
166
+ * Creates a XML::Writer which will write XML into memory, as string.
167
+ */
168
+ static VALUE rxml_writer_string(VALUE klass)
169
+ {
170
+ rxml_writer_object* rwo;
171
+
172
+ rwo = ALLOC(rxml_writer_object);
173
+ rwo->output = Qnil;
174
+ rwo->closed = 0;
175
+ rwo->encoding = rb_utf8_encoding();
176
+ rwo->output_type = RXMLW_OUTPUT_STRING;
177
+ if (NULL == (rwo->buffer = xmlBufferCreate()))
178
+ {
179
+ rxml_raise(xmlGetLastError());
180
+ }
181
+ if (NULL == (rwo->writer = xmlNewTextWriterMemory(rwo->buffer, 0)))
182
+ {
183
+ xmlBufferFree(rwo->buffer);
184
+ rxml_raise(xmlGetLastError());
185
+ }
186
+
187
+ return rxml_writer_wrap(rwo);
188
+ }
189
+
190
+ /* call-seq:
191
+ * XML::Writer::document -> XML::Writer
192
+ *
193
+ * Creates a XML::Writer which will write into an in memory XML::Document
194
+ */
195
+ static VALUE rxml_writer_doc(VALUE klass)
196
+ {
197
+ xmlDocPtr doc;
198
+ rxml_writer_object* rwo;
199
+ VALUE output, result;
200
+
201
+ rwo = ALLOC(rxml_writer_object);
202
+ rwo->buffer = NULL;
203
+ rwo->output = Qnil;
204
+ rwo->closed = 0;
205
+ rwo->encoding = rb_utf8_encoding();
206
+ rwo->output_type = RXMLW_OUTPUT_DOC;
207
+ if (NULL == (rwo->writer = xmlNewTextWriterDoc(&doc, 0)))
208
+ {
209
+ rxml_raise(xmlGetLastError());
210
+ }
211
+ output = rxml_document_wrap(doc);
212
+ rwo->output = output;
213
+
214
+ result = rxml_writer_wrap(rwo);
215
+ RB_GC_GUARD(output);
216
+ return result;
217
+ }
218
+
219
+ /* ===== public instance methods ===== */
220
+
221
+ /* call-seq:
222
+ * writer.flush(empty? = true) -> (num|string)
223
+ *
224
+ * Flushes the output buffer. Returns the number of written bytes or
225
+ * the current content of the internal buffer for a in memory XML::Writer.
226
+ * If +empty?+ is +true+, and for a in memory XML::Writer, this internel
227
+ * buffer is empty.
228
+ */
229
+ static VALUE rxml_writer_flush(int argc, VALUE* argv, VALUE self)
230
+ {
231
+ int ret;
232
+ VALUE empty;
233
+ rxml_writer_object* rwo;
234
+
235
+ rb_scan_args(argc, argv, "01", &empty);
236
+
237
+ rwo = rxml_textwriter_get(self);
238
+ if (-1 == (ret = xmlTextWriterFlush(rwo->writer)))
239
+ {
240
+ rxml_raise(xmlGetLastError());
241
+ }
242
+
243
+ if (NULL != rwo->buffer)
244
+ {
245
+ VALUE content;
246
+
247
+ content = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding);
248
+ if (NIL_P(empty) || RTEST(empty))
249
+ { /* nil = default value = true */
250
+ xmlBufferEmpty(rwo->buffer);
251
+ }
252
+
253
+ return content;
254
+ }
255
+ else
256
+ {
257
+ return INT2NUM(ret);
258
+ }
259
+ }
260
+
261
+ /* call-seq:
262
+ * writer.result -> (XML::Document|"string"|nil)
263
+ *
264
+ * Returns the associated result object to the XML::Writer creation.
265
+ * A String for a XML::Writer object created with XML::Writer::string,
266
+ * a XML::Document with XML::Writer::document, etc.
267
+ */
268
+ static VALUE rxml_writer_result(VALUE self)
269
+ {
270
+ VALUE ret = Qnil;
271
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
272
+ int bytesWritten = xmlTextWriterFlush(rwo->writer);
273
+
274
+ if (bytesWritten == -1)
275
+ {
276
+ rxml_raise(xmlGetLastError());
277
+ }
278
+
279
+ switch (rwo->output_type)
280
+ {
281
+ case RXMLW_OUTPUT_DOC:
282
+ ret = rwo->output;
283
+ break;
284
+ case RXMLW_OUTPUT_STRING:
285
+ ret = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding);
286
+ break;
287
+ case RXMLW_OUTPUT_IO:
288
+ case RXMLW_OUTPUT_NONE:
289
+ break;
290
+ default:
291
+ rb_bug("unexpected output");
292
+ break;
293
+ }
294
+
295
+ return ret;
296
+ }
297
+
298
+ /* ===== private helpers ===== */
299
+ static void encodeStrings(rb_encoding* encoding, int count, VALUE* strings, const xmlChar** encoded_strings)
300
+ {
301
+ for (int i = 0; i < count; i++)
302
+ {
303
+ VALUE string = strings[i];
304
+
305
+ if (NIL_P(string))
306
+ {
307
+ encoded_strings[i] = NULL;
308
+ }
309
+ else
310
+ {
311
+ VALUE encoded = rb_str_conv_enc(strings[i], rb_enc_get(string), encoding);
312
+ encoded_strings[i] = BAD_CAST StringValueCStr(encoded);
313
+ }
314
+ }
315
+ }
316
+
317
+ static VALUE invoke_void_arg_function(VALUE self, int (*fn)(xmlTextWriterPtr))
318
+ {
319
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
320
+ int result = fn(rwo->writer);
321
+ return (result == -1 ? Qfalse : Qtrue);
322
+ }
323
+
324
+ static VALUE invoke_single_arg_function(VALUE self, int (*fn)(xmlTextWriterPtr, const xmlChar *), VALUE value)
325
+ {
326
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
327
+
328
+ VALUE rubyStrings[] = { value };
329
+ const xmlChar* xmlStrings[] = { NULL };
330
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
331
+
332
+ int result = fn(rwo->writer, xmlStrings[0]);
333
+ return (result == -1 ? Qfalse : Qtrue);
334
+ }
335
+
336
+
337
+ /* ===== public instance methods ===== */
338
+
339
+ #if LIBXML_VERSION >= 20605
340
+ /* call-seq:
341
+ * writer.set_indent(indentation) -> (true|false)
342
+ *
343
+ * Toggles indentation on or off. Returns +false+ on failure.
344
+ *
345
+ * Availability: libxml2 >= 2.6.5
346
+ */
347
+ static VALUE rxml_writer_set_indent(VALUE self, VALUE indentation)
348
+ {
349
+ int ret;
350
+ rxml_writer_object* rwo;
351
+
352
+ rwo = rxml_textwriter_get(self);
353
+ ret = xmlTextWriterSetIndent(rwo->writer, RTEST(indentation));
354
+
355
+ return (-1 == ret ? Qfalse : Qtrue);
356
+ }
357
+
358
+ /* call-seq:
359
+ * writer.set_indent_string(string) -> (true|false)
360
+ *
361
+ * Sets the string to use to indent each element of the document.
362
+ * Don't forget to enable indentation with set_indent. Returns
363
+ * +false+ on failure.
364
+ *
365
+ * Availability: libxml2 >= 2.6.5
366
+ */
367
+ static VALUE rxml_writer_set_indent_string(VALUE self, VALUE indentation)
368
+ {
369
+ return invoke_single_arg_function(self, xmlTextWriterSetIndentString, indentation);
370
+ }
371
+ #endif /* LIBXML_VERSION >= 20605 */
372
+
373
+ /* ===== public full tag interface ===== */
374
+
375
+ /* write_<X> = start_<X> + write_string + end_<X> */
376
+
377
+ /* call-seq:
378
+ * writer.write_comment(content) -> (true|false)
379
+ *
380
+ * Writes a full comment tag, all at once. Returns +false+ on failure.
381
+ * This is equivalent to start_comment + write_string(content) + end_comment.
382
+ */
383
+ static VALUE rxml_writer_write_comment(VALUE self, VALUE content)
384
+ {
385
+ return invoke_single_arg_function(self, xmlTextWriterWriteComment, content);
386
+ }
387
+
388
+ /* call-seq:
389
+ * writer.write_cdata(content) -> (true|false)
390
+ *
391
+ * Writes a full CDATA section, all at once. Returns +false+ on failure.
392
+ * This is equivalent to start_cdata + write_string(content) + end_cdata.
393
+ */
394
+ static VALUE rxml_writer_write_cdata(VALUE self, VALUE content)
395
+ {
396
+ return invoke_single_arg_function(self, xmlTextWriterWriteCDATA, content);
397
+ }
398
+
399
+ static VALUE rxml_writer_start_element(VALUE, VALUE);
400
+ static VALUE rxml_writer_start_element_ns(int, VALUE*, VALUE);
401
+ static VALUE rxml_writer_end_element(VALUE);
402
+
403
+ /* call-seq:
404
+ * writer.write_element(name, content) -> (true|false)
405
+ *
406
+ * Writes a full element tag, all at once. Returns +false+ on failure.
407
+ * This is equivalent to start_element(name) + write_string(content) +
408
+ * end_element.
409
+ */
410
+ static VALUE rxml_writer_write_element(int argc, VALUE* argv, VALUE self)
411
+ {
412
+ VALUE name, content;
413
+
414
+ rb_scan_args(argc, argv, "11", &name, &content);
415
+ if (Qnil == content)
416
+ {
417
+ if (Qfalse == rxml_writer_start_element(self, name))
418
+ {
419
+ return Qfalse;
420
+ }
421
+ return rxml_writer_end_element(self);
422
+ }
423
+ else
424
+ {
425
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
426
+ VALUE rubyStrings[] = {name, content};
427
+ const xmlChar* xmlStrings[] = {NULL, NULL};
428
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
429
+
430
+ int result = xmlTextWriterWriteElement(rwo->writer, xmlStrings[0], xmlStrings[1]);
431
+ return (result == -1 ? Qfalse : Qtrue);
432
+ }
433
+ }
434
+
435
+ #define ARRAY_SIZE(array) \
436
+ (sizeof(array) / sizeof((array)[0]))
437
+
438
+ /* call-seq:
439
+ * writer.write_element_ns(prefix, name, namespaceURI, content) -> (true|false)
440
+ *
441
+ * Writes a full namespaced element tag, all at once. Returns +false+ on failure.
442
+ * This is a shortcut for start_element_ns(prefix, name, namespaceURI) +
443
+ * write_string(content) + end_element.
444
+ *
445
+ * Notes:
446
+ * - by default, the xmlns: definition is repeated on every element. If you want
447
+ * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+
448
+ * to nil or omit it. Don't forget to declare the namespace prefix somewhere
449
+ * earlier.
450
+ * - +content+ can be omitted for an empty tag
451
+ */
452
+ static VALUE rxml_writer_write_element_ns(int argc, VALUE* argv, VALUE self)
453
+ {
454
+ VALUE prefix, name, namespaceURI, content;
455
+
456
+ rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
457
+ if (Qnil == content)
458
+ {
459
+ VALUE argv[3] = { prefix, name, namespaceURI };
460
+
461
+ if (Qfalse == rxml_writer_start_element_ns(ARRAY_SIZE(argv), argv, self))
462
+ {
463
+ return Qfalse;
464
+ }
465
+ return rxml_writer_end_element(self);
466
+ }
467
+ else
468
+ {
469
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
470
+ VALUE rubyStrings[] = {prefix, name, namespaceURI, content};
471
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL};
472
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
473
+ int result = xmlTextWriterWriteElementNS(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3]);
474
+ return (result == -1 ? Qfalse : Qtrue);
475
+ }
476
+ }
477
+
478
+ /* call-seq:
479
+ * writer.write_attribute(name, content) -> (true|false)
480
+ *
481
+ * Writes a full attribute, all at once. Returns +false+ on failure.
482
+ * Same as start_attribute(name) + write_string(content) + end_attribute.
483
+ */
484
+ static VALUE rxml_writer_write_attribute(VALUE self, VALUE name, VALUE content)
485
+ {
486
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
487
+ VALUE rubyStrings[] = {name, content};
488
+ const xmlChar* xmlStrings[] = {NULL, NULL};
489
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
490
+ int result = xmlTextWriterWriteAttribute(rwo->writer, xmlStrings[0], xmlStrings[1]);
491
+ return (result == -1 ? Qfalse : Qtrue);
492
+ }
493
+
494
+ /* call-seq:
495
+ * writer.write_attribute_ns(prefix, name, namespaceURI, content) -> (true|false)
496
+ *
497
+ * Writes a full namespaced attribute, all at once. Returns +false+ on failure.
498
+ * Same as start_attribute_ns(prefix, name, namespaceURI) +
499
+ * write_string(content) + end_attribute.
500
+ *
501
+ * Notes:
502
+ * - by default, the xmlns: definition is repeated on every element. If you want
503
+ * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+
504
+ * to nil or omit it. Don't forget to declare the namespace prefix somewhere
505
+ * earlier.
506
+ * - +content+ can be omitted too for an empty attribute
507
+ */
508
+ static VALUE rxml_writer_write_attribute_ns(int argc, VALUE* argv, VALUE self)
509
+ {
510
+ VALUE prefix, name, namespaceURI, content;
511
+ rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
512
+
513
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
514
+ VALUE rubyStrings[] = {prefix, name, namespaceURI, content};
515
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL};
516
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
517
+ int result = xmlTextWriterWriteAttributeNS(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3]);
518
+ return (result == -1 ? Qfalse : Qtrue);
519
+ }
520
+
521
+ /* call-seq:
522
+ * writer.write_pi(target, content) -> (true|false)
523
+ *
524
+ * Writes a full CDATA tag, all at once. Returns +false+ on failure.
525
+ * This is a shortcut for start_pi(target) + write_string(content) + end_pi.
526
+ */
527
+ static VALUE rxml_writer_write_pi(VALUE self, VALUE target, VALUE content)
528
+ {
529
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
530
+ VALUE rubyStrings[] = {target, content};
531
+ const xmlChar* xmlStrings[] = {NULL, NULL};
532
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
533
+ int result = xmlTextWriterWritePI(rwo->writer, xmlStrings[0], xmlStrings[1]);
534
+ return (result == -1 ? Qfalse : Qtrue);
535
+ }
536
+
537
+ /* ===== public start/end interface ===== */
538
+
539
+ /* call-seq:
540
+ * writer.write_string(content) -> (true|false)
541
+ *
542
+ * Safely (problematic characters are internally translated to their
543
+ * associated named entities) writes a string into the current node
544
+ * (attribute, element, comment, ...). Returns +false+ on failure.
545
+ */
546
+ static VALUE rxml_writer_write_string(VALUE self, VALUE content)
547
+ {
548
+ return invoke_single_arg_function(self, xmlTextWriterWriteString, content);
549
+ }
550
+
551
+ /* call-seq:
552
+ * writer.write_raw(content) -> (true|false)
553
+ *
554
+ * Writes the string +content+ as is, reserved characters are not
555
+ * translated to their associated entities. Returns +false+ on failure.
556
+ * Consider write_string to handle them.
557
+ */
558
+ static VALUE rxml_writer_write_raw(VALUE self, VALUE content)
559
+ {
560
+ return invoke_single_arg_function(self, xmlTextWriterWriteRaw, content);
561
+ }
562
+
563
+ /* call-seq:
564
+ * writer.start_attribute(name) -> (true|false)
565
+ *
566
+ * Starts an attribute. Returns +false+ on failure.
567
+ */
568
+ static VALUE rxml_writer_start_attribute(VALUE self, VALUE name)
569
+ {
570
+ return invoke_single_arg_function(self, xmlTextWriterStartAttribute, name);
571
+ }
572
+
573
+ /* call-seq:
574
+ * writer.start_attribute_ns(prefix, name, namespaceURI) -> (true|false)
575
+ *
576
+ * Starts a namespaced attribute. Returns +false+ on failure.
577
+ *
578
+ * Note: by default, the xmlns: definition is repeated on every element. If
579
+ * you want the prefix, but don't want the xmlns: declaration repeated, set
580
+ * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace
581
+ * prefix somewhere earlier.
582
+ */
583
+ static VALUE rxml_writer_start_attribute_ns(int argc, VALUE* argv, VALUE self)
584
+ {
585
+ VALUE prefix, name, namespaceURI;
586
+ rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
587
+
588
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
589
+ VALUE rubyStrings[] = {prefix, name, namespaceURI};
590
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
591
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
592
+ int result = xmlTextWriterStartAttributeNS(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
593
+ return (result == -1 ? Qfalse : Qtrue);
594
+ }
595
+
596
+ /* call-seq:
597
+ * writer.end_attribute -> (true|false)
598
+ *
599
+ * Ends an attribute, namespaced or not. Returns +false+ on failure.
600
+ */
601
+ static VALUE rxml_writer_end_attribute(VALUE self)
602
+ {
603
+ return invoke_void_arg_function(self, xmlTextWriterEndAttribute);
604
+ }
605
+
606
+ #if LIBXML_VERSION >= 20607
607
+ /* call-seq:
608
+ * writer.start_comment -> (true|false)
609
+ *
610
+ * Starts a comment. Returns +false+ on failure.
611
+ * Note: libxml2 >= 2.6.7 required
612
+ */
613
+ static VALUE rxml_writer_start_comment(VALUE self)
614
+ {
615
+ return invoke_void_arg_function(self, xmlTextWriterStartComment);
616
+ }
617
+
618
+ /* call-seq:
619
+ * writer.end_comment -> (true|false)
620
+ *
621
+ * Ends current comment, returns +false+ on failure.
622
+ * Note: libxml2 >= 2.6.7 required
623
+ */
624
+ static VALUE rxml_writer_end_comment(VALUE self)
625
+ {
626
+ return invoke_void_arg_function(self, xmlTextWriterEndComment);
627
+ }
628
+ #endif /* LIBXML_VERSION >= 20607 */
629
+
630
+ /* call-seq:
631
+ * writer.start_element(name) -> (true|false)
632
+ *
633
+ * Starts a new element. Returns +false+ on failure.
634
+ */
635
+ static VALUE rxml_writer_start_element(VALUE self, VALUE name)
636
+ {
637
+ return invoke_single_arg_function(self, xmlTextWriterStartElement, name);
638
+ }
639
+
640
+ /* call-seq:
641
+ * writer.start_element_ns(prefix, name, namespaceURI) -> (true|false)
642
+ *
643
+ * Starts a new namespaced element. Returns +false+ on failure.
644
+ *
645
+ * Note: by default, the xmlns: definition is repeated on every element. If
646
+ * you want the prefix, but don't want the xmlns: declaration repeated, set
647
+ * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace
648
+ * prefix somewhere earlier.
649
+ */
650
+ static VALUE rxml_writer_start_element_ns(int argc, VALUE* argv, VALUE self)
651
+ {
652
+ VALUE prefix, name, namespaceURI;
653
+ rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
654
+
655
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
656
+ VALUE rubyStrings[] = {prefix, name, namespaceURI};
657
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
658
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
659
+ int result = xmlTextWriterStartElementNS(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
660
+ return (result == -1 ? Qfalse : Qtrue);
661
+ }
662
+
663
+ /* call-seq:
664
+ * writer.end_element -> (true|false)
665
+ *
666
+ * Ends current element, namespaced or not. Returns +false+ on failure.
667
+ */
668
+ static VALUE rxml_writer_end_element(VALUE self)
669
+ {
670
+ return invoke_void_arg_function(self, xmlTextWriterEndElement);
671
+ }
672
+
673
+ /* call-seq:
674
+ * writer.write_full_end_element -> (true|false)
675
+ *
676
+ * Ends current element, namespaced or not. Returns +false+ on failure.
677
+ * This method writes an end tag even if the element is empty (<foo></foo>),
678
+ * end_element does not (<foo/>).
679
+ */
680
+ static VALUE rxml_writer_full_end_element(VALUE self)
681
+ {
682
+ return invoke_void_arg_function(self, xmlTextWriterFullEndElement);
683
+ }
684
+
685
+ /* call-seq:
686
+ * writer.start_cdata -> (true|false)
687
+ *
688
+ * Starts a new CDATA section. Returns +false+ on failure.
689
+ */
690
+ static VALUE rxml_writer_start_cdata(VALUE self)
691
+ {
692
+ return invoke_void_arg_function(self, xmlTextWriterStartCDATA);
693
+ }
694
+
695
+ /* call-seq:
696
+ * writer.end_cdata -> (true|false)
697
+ *
698
+ * Ends current CDATA section. Returns +false+ on failure.
699
+ */
700
+ static VALUE rxml_writer_end_cdata(VALUE self)
701
+ {
702
+ return invoke_void_arg_function(self, xmlTextWriterEndCDATA);
703
+ }
704
+
705
+ /* call-seq:
706
+ * writer.start_document -> (true|false)
707
+ * writer.start_document(:encoding => XML::Encoding::UTF_8,
708
+ * :standalone => true) -> (true|false)
709
+ *
710
+ * Starts a new document. Returns +false+ on failure.
711
+ *
712
+ * You may provide an optional hash table to control XML header that will be
713
+ * generated. Valid options are:
714
+ * - encoding: the output document encoding, defaults to nil (= UTF-8). Valid
715
+ * values are the encoding constants defined on XML::Encoding
716
+ * - standalone: nil (default) or a boolean to indicate if the document is
717
+ * standalone or not
718
+ */
719
+ static VALUE rxml_writer_start_document(int argc, VALUE* argv, VALUE self)
720
+ {
721
+ int ret;
722
+ VALUE options = Qnil;
723
+ rxml_writer_object* rwo;
724
+ const xmlChar* xencoding = NULL;
725
+ const char* xstandalone = NULL;
726
+
727
+ rb_scan_args(argc, argv, "01", &options);
728
+ if (!NIL_P(options))
729
+ {
730
+ VALUE encoding, standalone;
731
+
732
+ encoding = standalone = Qnil;
733
+ Check_Type(options, T_HASH);
734
+ encoding = rb_hash_aref(options, sEncoding);
735
+ xencoding = NIL_P(encoding) ? NULL : (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding));
736
+ standalone = rb_hash_aref(options, sStandalone);
737
+ if (NIL_P(standalone))
738
+ {
739
+ xstandalone = NULL;
740
+ }
741
+ else
742
+ {
743
+ xstandalone = RTEST(standalone) ? "yes" : "no";
744
+ }
745
+ }
746
+ rwo = rxml_textwriter_get(self);
747
+ rwo->encoding = rxml_figure_encoding(xencoding);
748
+ ret = xmlTextWriterStartDocument(rwo->writer, NULL, (const char*)xencoding, xstandalone);
749
+
750
+ return (-1 == ret ? Qfalse : Qtrue);
751
+ }
752
+
753
+ /* call-seq:
754
+ * writer.end_document -> (true|false)
755
+ *
756
+ * Ends current document. Returns +false+ on failure.
757
+ */
758
+ static VALUE rxml_writer_end_document(VALUE self)
759
+ {
760
+ return invoke_void_arg_function(self, xmlTextWriterEndDocument);
761
+ }
762
+
763
+ /* call-seq:
764
+ * writer.start_pi(target) -> (true|false)
765
+ *
766
+ * Starts a new processing instruction. Returns +false+ on failure.
767
+ */
768
+ static VALUE rxml_writer_start_pi(VALUE self, VALUE target)
769
+ {
770
+ return invoke_single_arg_function(self, xmlTextWriterStartPI, target);
771
+ }
772
+
773
+ /* call-seq:
774
+ * writer.end_pi -> (true|false)
775
+ *
776
+ * Ends current processing instruction. Returns +false+ on failure.
777
+ */
778
+ static VALUE rxml_writer_end_pi(VALUE self)
779
+ {
780
+ return invoke_void_arg_function(self, xmlTextWriterEndPI);
781
+ }
782
+
783
+ /* call-seq:
784
+ * writer.start_dtd(qualifiedName, publicId, systemId) -> (true|false)
785
+ *
786
+ * Starts a DTD. Returns +false+ on failure.
787
+ */
788
+ static VALUE rxml_writer_start_dtd(int argc, VALUE* argv, VALUE self)
789
+ {
790
+ VALUE name, pubid, sysid;
791
+ rb_scan_args(argc, argv, "12", &name, &pubid, &sysid);
792
+
793
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
794
+ VALUE rubyStrings[] = {name, pubid, sysid};
795
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
796
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
797
+ int result = xmlTextWriterStartDTD(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
798
+ return (result == -1 ? Qfalse : Qtrue);
799
+ }
800
+
801
+ /* call-seq:
802
+ * writer.start_dtd_element(qualifiedName) -> (true|false)
803
+ *
804
+ * Starts a DTD element (<!ELEMENT ... >). Returns +false+ on failure.
805
+ */
806
+ static VALUE rxml_writer_start_dtd_element(VALUE self, VALUE name)
807
+ {
808
+ return invoke_single_arg_function(self, xmlTextWriterStartDTDElement, name);
809
+ }
810
+
811
+ /* call-seq:
812
+ * writer.start_dtd_entity(name, pe = false) -> (true|false)
813
+ *
814
+ * Starts a DTD entity (<!ENTITY ... >). Returns +false+ on failure.
815
+ */
816
+ static VALUE rxml_writer_start_dtd_entity(int argc, VALUE* argv, VALUE self)
817
+ {
818
+ VALUE name, pe;
819
+ rb_scan_args(argc, argv, "11", &name, &pe);
820
+
821
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
822
+ VALUE rubyStrings[] = {name};
823
+ const xmlChar* xmlStrings[] = {NULL};
824
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
825
+ int result = xmlTextWriterStartDTDEntity(rwo->writer, RB_TEST(pe), xmlStrings[0]);
826
+ return (result == -1 ? Qfalse : Qtrue);
827
+ }
828
+
829
+ /* call-seq:
830
+ * writer.start_dtd_attlist(name) -> (true|false)
831
+ *
832
+ * Starts a DTD attribute list (<!ATTLIST ... >). Returns +false+ on failure.
833
+ */
834
+ static VALUE rxml_writer_start_dtd_attlist(VALUE self, VALUE name)
835
+ {
836
+ return invoke_single_arg_function(self, xmlTextWriterStartDTDAttlist, name);
837
+ }
838
+
839
+ /* call-seq:
840
+ * writer.end_dtd -> (true|false)
841
+ *
842
+ * Ends current DTD, returns +false+ on failure.
843
+ */
844
+ static VALUE rxml_writer_end_dtd(VALUE self)
845
+ {
846
+ return invoke_void_arg_function(self, xmlTextWriterEndDTD);
847
+ }
848
+
849
+ /* call-seq:
850
+ * writer.end_dtd_entity -> (true|false)
851
+ *
852
+ * Ends current DTD entity, returns +false+ on failure.
853
+ */
854
+ static VALUE rxml_writer_end_dtd_entity(VALUE self)
855
+ {
856
+ return invoke_void_arg_function(self, xmlTextWriterEndDTDEntity);
857
+ }
858
+
859
+ /* call-seq:
860
+ * writer.end_dtd_attlist -> (true|false)
861
+ *
862
+ * Ends current DTD attribute list, returns +false+ on failure.
863
+ */
864
+ static VALUE rxml_writer_end_dtd_attlist(VALUE self)
865
+ {
866
+ return invoke_void_arg_function(self, xmlTextWriterEndDTDAttlist);
867
+ }
868
+
869
+ /* call-seq:
870
+ * writer.end_dtd_element -> (true|false)
871
+ *
872
+ * Ends current DTD element, returns +false+ on failure.
873
+ */
874
+ static VALUE rxml_writer_end_dtd_element(VALUE self)
875
+ {
876
+ return invoke_void_arg_function(self, xmlTextWriterEndDTDElement);
877
+ }
878
+
879
+ /* call-seq:
880
+ * writer.write_dtd(name [ [ [, publicId ], systemId ], subset ]) -> (true|false)
881
+ *
882
+ * Writes a DTD, all at once. Returns +false+ on failure.
883
+ * - name: dtd name
884
+ * - publicId: external subset public identifier, use nil for a SYSTEM doctype
885
+ * - systemId: external subset system identifier
886
+ * - subset: content
887
+ *
888
+ * Examples:
889
+ * writer.write_dtd 'html'
890
+ * #=> <!DOCTYPE html>
891
+ * writer.write_dtd 'docbook', nil, 'http://www.docbook.org/xml/5.0/dtd/docbook.dtd'
892
+ * #=> <!DOCTYPE docbook SYSTEM "http://www.docbook.org/xml/5.0/dtd/docbook.dtd">
893
+ * writer.write_dtd 'html', '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
894
+ * #=> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
895
+ * writer.write_dtd 'person', nil, nil, '<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>'
896
+ * #=> <!DOCTYPE person [<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>]>
897
+ */
898
+ static VALUE rxml_writer_write_dtd(int argc, VALUE* argv, VALUE self)
899
+ {
900
+ VALUE name, pubid, sysid, subset;
901
+ rb_scan_args(argc, argv, "13", &name, &pubid, &sysid, &subset);
902
+
903
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
904
+ VALUE rubyStrings[] = {name, pubid, sysid, subset};
905
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL};
906
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
907
+ int result = xmlTextWriterWriteDTD(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3]);
908
+ return (result == -1 ? Qfalse : Qtrue);
909
+ }
910
+
911
+ /* call-seq:
912
+ * writer.write_dtd_attlist(name, content) -> (true|false)
913
+ *
914
+ * Writes a DTD attribute list, all at once. Returns +false+ on failure.
915
+ * writer.write_dtd_attlist 'id', 'ID #IMPLIED'
916
+ * #=> <!ATTLIST id ID #IMPLIED>
917
+ */
918
+ static VALUE rxml_writer_write_dtd_attlist(VALUE self, VALUE name, VALUE content)
919
+ {
920
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
921
+ VALUE rubyStrings[] = {name, content};
922
+ const xmlChar* xmlStrings[] = {NULL, NULL};
923
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
924
+ int result = xmlTextWriterWriteDTDAttlist(rwo->writer, xmlStrings[0], xmlStrings[1]);
925
+ return (result == -1 ? Qfalse : Qtrue);
926
+ }
927
+
928
+ /* call-seq:
929
+ * writer.write_dtd_element(name, content) -> (true|false)
930
+ *
931
+ * Writes a full DTD element, all at once. Returns +false+ on failure.
932
+ * writer.write_dtd_element 'person', '(firstname,lastname)'
933
+ * #=> <!ELEMENT person (firstname,lastname)>
934
+ */
935
+ static VALUE rxml_writer_write_dtd_element(VALUE self, VALUE name, VALUE content)
936
+ {
937
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
938
+ VALUE rubyStrings[] = {name, content};
939
+ const xmlChar* xmlStrings[] = {NULL, NULL};
940
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
941
+ int result = xmlTextWriterWriteDTDElement(rwo->writer, xmlStrings[0], xmlStrings[1]);
942
+ return (result == -1 ? Qfalse : Qtrue);
943
+ }
944
+
945
+ /* call-seq:
946
+ * writer.write_dtd_entity(name, publicId, systemId, ndataid, content, pe) -> (true|false)
947
+ *
948
+ * Writes a DTD entity, all at once. Returns +false+ on failure.
949
+ */
950
+ static VALUE rxml_writer_write_dtd_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE content, VALUE pe)
951
+ {
952
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
953
+ VALUE rubyStrings[] = {name, pubid, sysid, ndataid, content};
954
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL, NULL};
955
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
956
+ int result = xmlTextWriterWriteDTDEntity(rwo->writer, RB_TEST(pe), xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3], xmlStrings[4]);
957
+ return (result == -1 ? Qfalse : Qtrue);
958
+ }
959
+
960
+ /* call-seq:
961
+ * writer.write_dtd_external_entity(name, publicId, systemId, ndataid, pe) -> (true|false)
962
+ *
963
+ * Writes a DTD external entity. The entity must have been started
964
+ * with start_dtd_entity. Returns +false+ on failure.
965
+ * - name: the name of the DTD entity
966
+ * - publicId: the public identifier, which is an alternative to the system identifier
967
+ * - systemId: the system identifier, which is the URI of the DTD
968
+ * - ndataid: the xml notation name
969
+ * - pe: +true+ if this is a parameter entity (to be used only in the DTD
970
+ * itself), +false+ if not
971
+ */
972
+ static VALUE rxml_writer_write_dtd_external_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE pe)
973
+ {
974
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
975
+ VALUE rubyStrings[] = {name, pubid, sysid, ndataid};
976
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL, NULL};
977
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
978
+ int result = xmlTextWriterWriteDTDExternalEntity(rwo->writer, RB_TEST(pe), xmlStrings[0], xmlStrings[1], xmlStrings[2], xmlStrings[3]);
979
+ return (result == -1 ? Qfalse : Qtrue);
980
+ }
981
+
982
+ /* call-seq:
983
+ * writer.write_dtd_external_entity_contents(publicId, systemId, ndataid) -> (true|false)
984
+ *
985
+ * Writes the contents of a DTD external entity, all at once. Returns +false+ on failure.
986
+ */
987
+ static VALUE rxml_writer_write_dtd_external_entity_contents(VALUE self, VALUE pubid, VALUE sysid, VALUE ndataid)
988
+ {
989
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
990
+ VALUE rubyStrings[] = {pubid, sysid, ndataid,};
991
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
992
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
993
+ int result = xmlTextWriterWriteDTDExternalEntityContents(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
994
+ return (result == -1 ? Qfalse : Qtrue);
995
+ }
996
+
997
+ /* call-seq:
998
+ * writer.write_dtd_internal_entity(name, content, pe) -> (true|false)
999
+ *
1000
+ * Writes a DTD internal entity, all at once. Returns +false+ on failure.
1001
+ *
1002
+ * Examples:
1003
+ * writer.write_dtd_entity 'Shape', '(rect|circle|poly|default)', true
1004
+ * #=> <!ENTITY % Shape "(rect|circle|poly|default)">
1005
+ * writer.write_dtd_entity 'delta', '&#948;', false
1006
+ * #=> <!ENTITY delta "&#948;">
1007
+ */
1008
+ static VALUE rxml_writer_write_dtd_internal_entity(VALUE self, VALUE name, VALUE content, VALUE pe)
1009
+ {
1010
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
1011
+ VALUE rubyStrings[] = {name, content};
1012
+ const xmlChar* xmlStrings[] = {NULL, NULL};
1013
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
1014
+ int result = xmlTextWriterWriteDTDInternalEntity(rwo->writer, RB_TEST(pe), xmlStrings[0], xmlStrings[1]);
1015
+ return (result == -1 ? Qfalse : Qtrue);
1016
+ }
1017
+
1018
+ /* call-seq:
1019
+ * writer.write_dtd_notation(name, publicId, systemId) -> (true|false)
1020
+ *
1021
+ * Writes a DTD entity, all at once. Returns +false+ on failure.
1022
+ */
1023
+ static VALUE rxml_writer_write_dtd_notation(VALUE self, VALUE name, VALUE pubid, VALUE sysid)
1024
+ {
1025
+ rxml_writer_object* rwo = rxml_textwriter_get(self);
1026
+ VALUE rubyStrings[] = {name, pubid, sysid};
1027
+ const xmlChar* xmlStrings[] = {NULL, NULL, NULL};
1028
+ encodeStrings(rwo->encoding, sizeof(rubyStrings)/sizeof(VALUE), rubyStrings, xmlStrings);
1029
+ int result = xmlTextWriterWriteDTDNotation(rwo->writer, xmlStrings[0], xmlStrings[1], xmlStrings[2]);
1030
+ return (result == -1 ? Qfalse : Qtrue);
1031
+ }
1032
+
1033
+ #if LIBXML_VERSION >= 20900
1034
+ /* call-seq:
1035
+ * writer.set_quote_char(...) -> (true|false)
1036
+ *
1037
+ * Sets the character used to quote attributes. Returns +false+ on failure.
1038
+ *
1039
+ * Notes:
1040
+ * - only " (default) and ' characters are valid
1041
+ * - availability: libxml2 >= 2.9.0
1042
+ */
1043
+ static VALUE rxml_writer_set_quote_char(VALUE self, VALUE quotechar)
1044
+ {
1045
+ int ret;
1046
+ const char* xquotechar;
1047
+ rxml_writer_object* rwo;
1048
+
1049
+ rwo = rxml_textwriter_get(self);
1050
+ xquotechar = StringValueCStr(quotechar);
1051
+ ret = xmlTextWriterSetQuoteChar(rwo->writer, (xmlChar)xquotechar[0]);
1052
+
1053
+ return (-1 == ret ? Qfalse : Qtrue);
1054
+ }
1055
+ #endif /* LIBXML_VERSION >= 20900 */
1056
+
1057
+ #endif /* LIBXML_WRITER_ENABLED */
1058
+
1059
+
1060
+ /* grep -P 'xmlTextWriter(Start|End|Write)(?!DTD|V?Format)[^(]+' /usr/include/libxml2/libxml/xmlwriter.h */
1061
+ void rxml_init_writer(void)
1062
+ {
1063
+ sEncoding = ID2SYM(rb_intern("encoding"));
1064
+ sStandalone = ID2SYM(rb_intern("standalone"));
1065
+
1066
+ cXMLWriter = rb_define_class_under(mXML, "Writer", rb_cObject);
1067
+ rb_undef_alloc_func(cXMLWriter);
1068
+
1069
+ #ifdef LIBXML_WRITER_ENABLED
1070
+ rb_define_singleton_method(cXMLWriter, "io", rxml_writer_io, 1);
1071
+ rb_define_singleton_method(cXMLWriter, "file", rxml_writer_file, 1);
1072
+ rb_define_singleton_method(cXMLWriter, "document", rxml_writer_doc, 0);
1073
+ rb_define_singleton_method(cXMLWriter, "string", rxml_writer_string, 0);
1074
+
1075
+ /* misc */
1076
+ #if LIBXML_VERSION >= 20605
1077
+ rb_define_method(cXMLWriter, "set_indent", rxml_writer_set_indent, 1);
1078
+ rb_define_method(cXMLWriter, "set_indent_string", rxml_writer_set_indent_string, 1);
1079
+ #endif /* LIBXML_VERSION >= 20605 */
1080
+ #if LIBXML_VERSION >= 20900
1081
+ rb_define_method(cXMLWriter, "set_quote_char", rxml_writer_set_quote_char, 1);
1082
+ #endif /* LIBXML_VERSION >= 20900 */
1083
+ rb_define_method(cXMLWriter, "flush", rxml_writer_flush, -1);
1084
+ rb_define_method(cXMLWriter, "start_dtd", rxml_writer_start_dtd, -1);
1085
+ rb_define_method(cXMLWriter, "start_dtd_entity", rxml_writer_start_dtd_entity, -1);
1086
+ rb_define_method(cXMLWriter, "start_dtd_attlist", rxml_writer_start_dtd_attlist, 1);
1087
+ rb_define_method(cXMLWriter, "start_dtd_element", rxml_writer_start_dtd_element, 1);
1088
+ rb_define_method(cXMLWriter, "write_dtd", rxml_writer_write_dtd, -1);
1089
+ rb_define_method(cXMLWriter, "write_dtd_attlist", rxml_writer_write_dtd_attlist, 2);
1090
+ rb_define_method(cXMLWriter, "write_dtd_element", rxml_writer_write_dtd_element, 2);
1091
+ rb_define_method(cXMLWriter, "write_dtd_entity", rxml_writer_write_dtd_entity, 6);
1092
+ rb_define_method(cXMLWriter, "write_dtd_external_entity", rxml_writer_write_dtd_external_entity, 5);
1093
+ rb_define_method(cXMLWriter, "write_dtd_external_entity_contents", rxml_writer_write_dtd_external_entity_contents, 3);
1094
+ rb_define_method(cXMLWriter, "write_dtd_internal_entity", rxml_writer_write_dtd_internal_entity, 3);
1095
+ rb_define_method(cXMLWriter, "write_dtd_notation", rxml_writer_write_dtd_notation, 3);
1096
+ rb_define_method(cXMLWriter, "end_dtd", rxml_writer_end_dtd, 0);
1097
+ rb_define_method(cXMLWriter, "end_dtd_entity", rxml_writer_end_dtd_entity, 0);
1098
+ rb_define_method(cXMLWriter, "end_dtd_attlist", rxml_writer_end_dtd_attlist, 0);
1099
+ rb_define_method(cXMLWriter, "end_dtd_element", rxml_writer_end_dtd_element, 0);
1100
+
1101
+ /* tag by parts */
1102
+ rb_define_method(cXMLWriter, "write_raw", rxml_writer_write_raw, 1);
1103
+ rb_define_method(cXMLWriter, "write_string", rxml_writer_write_string, 1);
1104
+
1105
+ rb_define_method(cXMLWriter, "start_cdata", rxml_writer_start_cdata, 0);
1106
+ rb_define_method(cXMLWriter, "end_cdata", rxml_writer_end_cdata, 0);
1107
+ rb_define_method(cXMLWriter, "start_attribute", rxml_writer_start_attribute, 1);
1108
+ rb_define_method(cXMLWriter, "start_attribute_ns", rxml_writer_start_attribute_ns, -1);
1109
+ rb_define_method(cXMLWriter, "end_attribute", rxml_writer_end_attribute, 0);
1110
+ rb_define_method(cXMLWriter, "start_element", rxml_writer_start_element, 1);
1111
+ rb_define_method(cXMLWriter, "start_element_ns", rxml_writer_start_element_ns, -1);
1112
+ rb_define_method(cXMLWriter, "end_element", rxml_writer_end_element, 0);
1113
+ rb_define_method(cXMLWriter, "full_end_element", rxml_writer_full_end_element, 0);
1114
+ rb_define_method(cXMLWriter, "start_document", rxml_writer_start_document, -1);
1115
+ rb_define_method(cXMLWriter, "end_document", rxml_writer_end_document, 0);
1116
+ #if LIBXML_VERSION >= 20607
1117
+ rb_define_method(cXMLWriter, "start_comment", rxml_writer_start_comment, 0);
1118
+ rb_define_method(cXMLWriter, "end_comment", rxml_writer_end_comment, 0);
1119
+ #endif /* LIBXML_VERSION >= 20607 */
1120
+ rb_define_method(cXMLWriter, "start_pi", rxml_writer_start_pi, 1);
1121
+ rb_define_method(cXMLWriter, "end_pi", rxml_writer_end_pi, 0);
1122
+
1123
+ /* full tag at once */
1124
+ rb_define_method(cXMLWriter, "write_attribute", rxml_writer_write_attribute, 2);
1125
+ rb_define_method(cXMLWriter, "write_attribute_ns", rxml_writer_write_attribute_ns, -1);
1126
+ rb_define_method(cXMLWriter, "write_comment", rxml_writer_write_comment, 1);
1127
+ rb_define_method(cXMLWriter, "write_cdata", rxml_writer_write_cdata, 1);
1128
+ rb_define_method(cXMLWriter, "write_element", rxml_writer_write_element, -1);
1129
+ rb_define_method(cXMLWriter, "write_element_ns", rxml_writer_write_element_ns, -1);
1130
+ rb_define_method(cXMLWriter, "write_pi", rxml_writer_write_pi, 2);
1131
+
1132
+ rb_define_method(cXMLWriter, "result", rxml_writer_result, 0);
1133
+
1134
+ rb_undef_method(CLASS_OF(cXMLWriter), "new");
1135
+ #endif
1136
+ }