libxml-ruby 4.0.0-x64-mingw-ucrt → 4.1.2-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1137 +1,1138 @@
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(&xmlLastError);
120
- }
121
- if (NULL == (rwo->writer = xmlNewTextWriter(out)))
122
- {
123
- rxml_raise(&xmlLastError);
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(&xmlLastError);
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(&xmlLastError);
171
- }
172
- if (NULL == (rwo->writer = xmlNewTextWriterMemory(rwo->buffer, 0)))
173
- {
174
- xmlBufferFree(rwo->buffer);
175
- rxml_raise(&xmlLastError);
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(&xmlLastError);
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(&xmlLastError);
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(&xmlLastError);
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
-
287
- static VALUE numeric_rxml_writer_void(VALUE obj, int (*fn)(xmlTextWriterPtr))
288
- {
289
- int ret;
290
- rxml_writer_object* rwo;
291
-
292
- rwo = rxml_textwriter_get(obj);
293
- ret = fn(rwo->writer);
294
-
295
- return (-1 == ret ? Qfalse : Qtrue);
296
- }
297
-
298
- #define numeric_rxml_writer_string(/*VALUE*/ obj, /*VALUE*/ name_or_content, /*int (**/fn/*)(xmlTextWriterPtr, const xmlChar *)*/) \
299
- numeric_rxml_writer_va_strings(obj, Qundef, 1, fn, name_or_content)
300
-
301
- /**
302
- * This is quite ugly but thanks to libxml2 coding style, all xmlTextWriter*
303
- * calls can be redirected to a single function. This can be convenient to:
304
- * - avoid repeating yourself
305
- * - convert strings to UTF-8
306
- * - validate names
307
- * and so on
308
- **/
309
- #define XMLWRITER_MAX_STRING_ARGS 5
310
- static VALUE numeric_rxml_writer_va_strings(VALUE obj, VALUE pe, size_t strings_count, int (*fn)(ANYARGS), ...)
311
- {
312
- va_list ap;
313
- size_t argc;
314
- int ret = -1;
315
- rxml_writer_object* rwo;
316
- const xmlChar* argv[XMLWRITER_MAX_STRING_ARGS];
317
- VALUE utf8[XMLWRITER_MAX_STRING_ARGS], orig[XMLWRITER_MAX_STRING_ARGS];
318
-
319
- if (strings_count > XMLWRITER_MAX_STRING_ARGS)
320
- {
321
- rb_bug("more arguments than expected");
322
- }
323
- va_start(ap, fn);
324
- rwo = rxml_textwriter_get(obj);
325
- for (argc = 0; argc < strings_count; argc++)
326
- {
327
- VALUE arg;
328
-
329
- arg = va_arg(ap, VALUE);
330
- orig[argc] = arg;
331
- if (NIL_P(arg))
332
- {
333
- utf8[argc] = Qnil;
334
- argv[argc] = NULL;
335
- }
336
- else
337
- {
338
- utf8[argc] = rb_str_conv_enc(orig[argc], rb_enc_get(orig[argc]), rwo->encoding);
339
- argv[argc] = BAD_CAST StringValueCStr(utf8[argc]);
340
- }
341
- }
342
- va_end(ap);
343
-
344
- if (Qundef == pe)
345
- {
346
- switch (strings_count)
347
- {
348
- case 0:
349
- ret = fn(rwo->writer);
350
- break;
351
- case 1:
352
- ret = fn(rwo->writer, argv[0]);
353
- break;
354
- case 2:
355
- ret = fn(rwo->writer, argv[0], argv[1]);
356
- break;
357
- case 3:
358
- ret = fn(rwo->writer, argv[0], argv[1], argv[2]);
359
- break;
360
- case 4:
361
- ret = fn(rwo->writer, argv[0], argv[1], argv[2], argv[3]);
362
- break;
363
- case 5:
364
- ret = fn(rwo->writer, argv[0], argv[1], argv[2], argv[3], argv[4]);
365
- break;
366
- default:
367
- break;
368
- }
369
- }
370
- else
371
- {
372
- int xpe;
373
-
374
- xpe = RTEST(pe);
375
- switch (strings_count)
376
- { /* strings_count doesn't include pe */
377
- case 0:
378
- ret = fn(rwo->writer, xpe);
379
- break;
380
- case 1:
381
- ret = fn(rwo->writer, xpe, argv[0]);
382
- break;
383
- case 2:
384
- ret = fn(rwo->writer, xpe, argv[0], argv[1]);
385
- break;
386
- case 3:
387
- ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2]);
388
- break;
389
- case 4:
390
- ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2], argv[3]);
391
- break;
392
- case 5:
393
- ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2], argv[3], argv[4]);
394
- break;
395
- default:
396
- break;
397
- }
398
- }
399
-
400
- while (--strings_count > 0)
401
- {
402
- if (!NIL_P(orig[strings_count]))
403
- {
404
- if (orig[strings_count] != utf8[strings_count])
405
- {
406
- rb_str_free(utf8[strings_count]);
407
- }
408
- }
409
- }
410
-
411
- return (-1 == ret ? Qfalse : Qtrue);
412
- }
413
-
414
- /* ===== public instance methods ===== */
415
-
416
- #if LIBXML_VERSION >= 20605
417
- /* call-seq:
418
- * writer.set_indent(indentation) -> (true|false)
419
- *
420
- * Toggles indentation on or off. Returns +false+ on failure.
421
- *
422
- * Availability: libxml2 >= 2.6.5
423
- */
424
- static VALUE rxml_writer_set_indent(VALUE self, VALUE indentation)
425
- {
426
- int ret;
427
- rxml_writer_object* rwo;
428
-
429
- rwo = rxml_textwriter_get(self);
430
- ret = xmlTextWriterSetIndent(rwo->writer, RTEST(indentation));
431
-
432
- return (-1 == ret ? Qfalse : Qtrue);
433
- }
434
-
435
- /* call-seq:
436
- * writer.set_indent_string(string) -> (true|false)
437
- *
438
- * Sets the string to use to indent each element of the document.
439
- * Don't forget to enable indentation with set_indent. Returns
440
- * +false+ on failure.
441
- *
442
- * Availability: libxml2 >= 2.6.5
443
- */
444
- static VALUE rxml_writer_set_indent_string(VALUE self, VALUE indentation)
445
- {
446
- return numeric_rxml_writer_string(self, indentation, xmlTextWriterSetIndentString);
447
- }
448
- #endif /* LIBXML_VERSION >= 20605 */
449
-
450
- /* ===== public full tag interface ===== */
451
-
452
- /* write_<X> = start_<X> + write_string + end_<X> */
453
-
454
- /* call-seq:
455
- * writer.write_comment(content) -> (true|false)
456
- *
457
- * Writes a full comment tag, all at once. Returns +false+ on failure.
458
- * This is equivalent to start_comment + write_string(content) + end_comment.
459
- */
460
- static VALUE rxml_writer_write_comment(VALUE self, VALUE content)
461
- {
462
- return numeric_rxml_writer_string(self, content, xmlTextWriterWriteComment);
463
- }
464
-
465
- /* call-seq:
466
- * writer.write_cdata(content) -> (true|false)
467
- *
468
- * Writes a full CDATA section, all at once. Returns +false+ on failure.
469
- * This is equivalent to start_cdata + write_string(content) + end_cdata.
470
- */
471
- static VALUE rxml_writer_write_cdata(VALUE self, VALUE content)
472
- {
473
- return numeric_rxml_writer_string(self, content, xmlTextWriterWriteCDATA);
474
- }
475
-
476
- static VALUE rxml_writer_start_element(VALUE, VALUE);
477
- static VALUE rxml_writer_start_element_ns(int, VALUE*, VALUE);
478
- static VALUE rxml_writer_end_element(VALUE);
479
-
480
- /* call-seq:
481
- * writer.write_element(name, content) -> (true|false)
482
- *
483
- * Writes a full element tag, all at once. Returns +false+ on failure.
484
- * This is equivalent to start_element(name) + write_string(content) +
485
- * end_element.
486
- */
487
- static VALUE rxml_writer_write_element(int argc, VALUE* argv, VALUE self)
488
- {
489
- VALUE name, content;
490
-
491
- rb_scan_args(argc, argv, "11", &name, &content);
492
- if (Qnil == content)
493
- {
494
- if (Qfalse == rxml_writer_start_element(self, name))
495
- {
496
- return Qfalse;
497
- }
498
- return rxml_writer_end_element(self);
499
- }
500
- else
501
- {
502
- return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteElement, name, content);
503
- }
504
- }
505
-
506
- #define ARRAY_SIZE(array) \
507
- (sizeof(array) / sizeof((array)[0]))
508
-
509
- /* call-seq:
510
- * writer.write_element_ns(prefix, name, namespaceURI, content) -> (true|false)
511
- *
512
- * Writes a full namespaced element tag, all at once. Returns +false+ on failure.
513
- * This is a shortcut for start_element_ns(prefix, name, namespaceURI) +
514
- * write_string(content) + end_element.
515
- *
516
- * Notes:
517
- * - by default, the xmlns: definition is repeated on every element. If you want
518
- * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+
519
- * to nil or omit it. Don't forget to declare the namespace prefix somewhere
520
- * earlier.
521
- * - +content+ can be omitted for an empty tag
522
- */
523
- static VALUE rxml_writer_write_element_ns(int argc, VALUE* argv, VALUE self)
524
- {
525
- VALUE prefix, name, namespaceURI, content;
526
-
527
- rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
528
- if (Qnil == content)
529
- {
530
- VALUE argv[3] = { prefix, name, namespaceURI };
531
-
532
- if (Qfalse == rxml_writer_start_element_ns(ARRAY_SIZE(argv), argv, self))
533
- {
534
- return Qfalse;
535
- }
536
- return rxml_writer_end_element(self);
537
- }
538
- else
539
- {
540
- return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteElementNS, prefix, name, namespaceURI, content);
541
- }
542
- }
543
-
544
- /* call-seq:
545
- * writer.write_attribute(name, content) -> (true|false)
546
- *
547
- * Writes a full attribute, all at once. Returns +false+ on failure.
548
- * Same as start_attribute(name) + write_string(content) + end_attribute.
549
- */
550
- static VALUE rxml_writer_write_attribute(VALUE self, VALUE name, VALUE content)
551
- {
552
- return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteAttribute, name, content);
553
- }
554
-
555
- /* call-seq:
556
- * writer.write_attribute_ns(prefix, name, namespaceURI, content) -> (true|false)
557
- *
558
- * Writes a full namespaced attribute, all at once. Returns +false+ on failure.
559
- * Same as start_attribute_ns(prefix, name, namespaceURI) +
560
- * write_string(content) + end_attribute.
561
- *
562
- * Notes:
563
- * - by default, the xmlns: definition is repeated on every element. If you want
564
- * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+
565
- * to nil or omit it. Don't forget to declare the namespace prefix somewhere
566
- * earlier.
567
- * - +content+ can be omitted too for an empty attribute
568
- */
569
- static VALUE rxml_writer_write_attribute_ns(int argc, VALUE* argv, VALUE self)
570
- {
571
- VALUE prefix, name, namespaceURI, content;
572
-
573
- rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
574
-
575
- return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteAttributeNS, prefix, name, namespaceURI, content);
576
- }
577
-
578
- /* call-seq:
579
- * writer.write_pi(target, content) -> (true|false)
580
- *
581
- * Writes a full CDATA tag, all at once. Returns +false+ on failure.
582
- * This is a shortcut for start_pi(target) + write_string(content) + end_pi.
583
- */
584
- static VALUE rxml_writer_write_pi(VALUE self, VALUE target, VALUE content)
585
- {
586
- return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWritePI, target, content);
587
- }
588
-
589
- /* ===== public start/end interface ===== */
590
-
591
- /* call-seq:
592
- * writer.write_string(content) -> (true|false)
593
- *
594
- * Safely (problematic characters are internally translated to their
595
- * associated named entities) writes a string into the current node
596
- * (attribute, element, comment, ...). Returns +false+ on failure.
597
- */
598
- static VALUE rxml_writer_write_string(VALUE self, VALUE content)
599
- {
600
- return numeric_rxml_writer_string(self, content, xmlTextWriterWriteString);
601
- }
602
-
603
- /* call-seq:
604
- * writer.write_raw(content) -> (true|false)
605
- *
606
- * Writes the string +content+ as is, reserved characters are not
607
- * translated to their associated entities. Returns +false+ on failure.
608
- * Consider write_string to handle them.
609
- */
610
- static VALUE rxml_writer_write_raw(VALUE self, VALUE content)
611
- {
612
- return numeric_rxml_writer_string(self, content, xmlTextWriterWriteRaw);
613
- }
614
-
615
- /* call-seq:
616
- * writer.start_attribute(name) -> (true|false)
617
- *
618
- * Starts an attribute. Returns +false+ on failure.
619
- */
620
- static VALUE rxml_writer_start_attribute(VALUE self, VALUE name)
621
- {
622
- return numeric_rxml_writer_string(self, name, xmlTextWriterStartAttribute);
623
- }
624
-
625
- /* call-seq:
626
- * writer.start_attribute_ns(prefix, name, namespaceURI) -> (true|false)
627
- *
628
- * Starts a namespaced attribute. Returns +false+ on failure.
629
- *
630
- * Note: by default, the xmlns: definition is repeated on every element. If
631
- * you want the prefix, but don't want the xmlns: declaration repeated, set
632
- * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace
633
- * prefix somewhere earlier.
634
- */
635
- static VALUE rxml_writer_start_attribute_ns(int argc, VALUE* argv, VALUE self)
636
- {
637
- VALUE prefix, name, namespaceURI;
638
-
639
- rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
640
-
641
- return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartAttributeNS, prefix, name, namespaceURI);
642
- }
643
-
644
- /* call-seq:
645
- * writer.end_attribute -> (true|false)
646
- *
647
- * Ends an attribute, namespaced or not. Returns +false+ on failure.
648
- */
649
- static VALUE rxml_writer_end_attribute(VALUE self)
650
- {
651
- return numeric_rxml_writer_void(self, xmlTextWriterEndAttribute);
652
- }
653
-
654
- #if LIBXML_VERSION >= 20607
655
- /* call-seq:
656
- * writer.start_comment -> (true|false)
657
- *
658
- * Starts a comment. Returns +false+ on failure.
659
- * Note: libxml2 >= 2.6.7 required
660
- */
661
- static VALUE rxml_writer_start_comment(VALUE self)
662
- {
663
- return numeric_rxml_writer_void(self, xmlTextWriterStartComment);
664
- }
665
-
666
- /* call-seq:
667
- * writer.end_comment -> (true|false)
668
- *
669
- * Ends current comment, returns +false+ on failure.
670
- * Note: libxml2 >= 2.6.7 required
671
- */
672
- static VALUE rxml_writer_end_comment(VALUE self)
673
- {
674
- return numeric_rxml_writer_void(self, xmlTextWriterEndComment);
675
- }
676
- #endif /* LIBXML_VERSION >= 20607 */
677
-
678
- /* call-seq:
679
- * writer.start_element(name) -> (true|false)
680
- *
681
- * Starts a new element. Returns +false+ on failure.
682
- */
683
- static VALUE rxml_writer_start_element(VALUE self, VALUE name)
684
- {
685
- return numeric_rxml_writer_string(self, name, xmlTextWriterStartElement);
686
- }
687
-
688
- /* call-seq:
689
- * writer.start_element_ns(prefix, name, namespaceURI) -> (true|false)
690
- *
691
- * Starts a new namespaced element. Returns +false+ on failure.
692
- *
693
- * Note: by default, the xmlns: definition is repeated on every element. If
694
- * you want the prefix, but don't want the xmlns: declaration repeated, set
695
- * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace
696
- * prefix somewhere earlier.
697
- */
698
- static VALUE rxml_writer_start_element_ns(int argc, VALUE* argv, VALUE self)
699
- {
700
- VALUE prefix, name, namespaceURI;
701
-
702
- rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
703
-
704
- return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartElementNS, prefix, name, namespaceURI);
705
- }
706
-
707
- /* call-seq:
708
- * writer.end_element -> (true|false)
709
- *
710
- * Ends current element, namespaced or not. Returns +false+ on failure.
711
- */
712
- static VALUE rxml_writer_end_element(VALUE self)
713
- {
714
- return numeric_rxml_writer_void(self, xmlTextWriterEndElement);
715
- }
716
-
717
- /* call-seq:
718
- * writer.write_full_end_element -> (true|false)
719
- *
720
- * Ends current element, namespaced or not. Returns +false+ on failure.
721
- * This method writes an end tag even if the element is empty (<foo></foo>),
722
- * end_element does not (<foo/>).
723
- */
724
- static VALUE rxml_writer_full_end_element(VALUE self)
725
- {
726
- return numeric_rxml_writer_void(self, xmlTextWriterFullEndElement);
727
- }
728
-
729
- /* call-seq:
730
- * writer.start_cdata -> (true|false)
731
- *
732
- * Starts a new CDATA section. Returns +false+ on failure.
733
- */
734
- static VALUE rxml_writer_start_cdata(VALUE self)
735
- {
736
- return numeric_rxml_writer_void(self, xmlTextWriterStartCDATA);
737
- }
738
-
739
- /* call-seq:
740
- * writer.end_cdata -> (true|false)
741
- *
742
- * Ends current CDATA section. Returns +false+ on failure.
743
- */
744
- static VALUE rxml_writer_end_cdata(VALUE self)
745
- {
746
- return numeric_rxml_writer_void(self, xmlTextWriterEndCDATA);
747
- }
748
-
749
- /* call-seq:
750
- * writer.start_document -> (true|false)
751
- * writer.start_document(:encoding => XML::Encoding::UTF_8,
752
- * :standalone => true) -> (true|false)
753
- *
754
- * Starts a new document. Returns +false+ on failure.
755
- *
756
- * You may provide an optional hash table to control XML header that will be
757
- * generated. Valid options are:
758
- * - encoding: the output document encoding, defaults to nil (= UTF-8). Valid
759
- * values are the encoding constants defined on XML::Encoding
760
- * - standalone: nil (default) or a boolean to indicate if the document is
761
- * standalone or not
762
- */
763
- static VALUE rxml_writer_start_document(int argc, VALUE* argv, VALUE self)
764
- {
765
- int ret;
766
- VALUE options = Qnil;
767
- rxml_writer_object* rwo;
768
- const xmlChar* xencoding = NULL;
769
- const char* xstandalone = NULL;
770
-
771
- rb_scan_args(argc, argv, "01", &options);
772
- if (!NIL_P(options))
773
- {
774
- VALUE encoding, standalone;
775
-
776
- encoding = standalone = Qnil;
777
- Check_Type(options, T_HASH);
778
- encoding = rb_hash_aref(options, sEncoding);
779
- xencoding = NIL_P(encoding) ? NULL : (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding));
780
- standalone = rb_hash_aref(options, sStandalone);
781
- if (NIL_P(standalone))
782
- {
783
- xstandalone = NULL;
784
- }
785
- else
786
- {
787
- xstandalone = RTEST(standalone) ? "yes" : "no";
788
- }
789
- }
790
- rwo = rxml_textwriter_get(self);
791
- rwo->encoding = rxml_figure_encoding(xencoding);
792
- ret = xmlTextWriterStartDocument(rwo->writer, NULL, (const char*)xencoding, xstandalone);
793
-
794
- return (-1 == ret ? Qfalse : Qtrue);
795
- }
796
-
797
- /* call-seq:
798
- * writer.end_document -> (true|false)
799
- *
800
- * Ends current document. Returns +false+ on failure.
801
- */
802
- static VALUE rxml_writer_end_document(VALUE self)
803
- {
804
- return numeric_rxml_writer_void(self, xmlTextWriterEndDocument);
805
- }
806
-
807
- /* call-seq:
808
- * writer.start_pi(target) -> (true|false)
809
- *
810
- * Starts a new processing instruction. Returns +false+ on failure.
811
- */
812
- static VALUE rxml_writer_start_pi(VALUE self, VALUE target)
813
- {
814
- return numeric_rxml_writer_string(self, target, xmlTextWriterStartPI);
815
- }
816
-
817
- /* call-seq:
818
- * writer.end_pi -> (true|false)
819
- *
820
- * Ends current processing instruction. Returns +false+ on failure.
821
- */
822
- static VALUE rxml_writer_end_pi(VALUE self)
823
- {
824
- return numeric_rxml_writer_void(self, xmlTextWriterEndPI);
825
- }
826
-
827
- /* call-seq:
828
- * writer.start_dtd(qualifiedName, publicId, systemId) -> (true|false)
829
- *
830
- * Starts a DTD. Returns +false+ on failure.
831
- */
832
- static VALUE rxml_writer_start_dtd(int argc, VALUE* argv, VALUE self)
833
- {
834
- VALUE name, pubid, sysid;
835
-
836
- rb_scan_args(argc, argv, "12", &name, &pubid, &sysid);
837
-
838
- return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartDTD, name, pubid, sysid);
839
- }
840
-
841
- /* call-seq:
842
- * writer.start_dtd_element(qualifiedName) -> (true|false)
843
- *
844
- * Starts a DTD element (<!ELEMENT ... >). Returns +false+ on failure.
845
- */
846
- static VALUE rxml_writer_start_dtd_element(VALUE self, VALUE name)
847
- {
848
- return numeric_rxml_writer_string(self, name, xmlTextWriterStartDTDElement);
849
- }
850
-
851
- /* call-seq:
852
- * writer.start_dtd_entity(name, pe = false) -> (true|false)
853
- *
854
- * Starts a DTD entity (<!ENTITY ... >). Returns +false+ on failure.
855
- */
856
- static VALUE rxml_writer_start_dtd_entity(int argc, VALUE* argv, VALUE self)
857
- {
858
- VALUE name, pe;
859
-
860
- rb_scan_args(argc, argv, "11", &name, &pe);
861
- if (NIL_P(pe))
862
- {
863
- pe = Qfalse;
864
- }
865
-
866
- return numeric_rxml_writer_va_strings(self, pe, 1, xmlTextWriterStartDTDEntity, name);
867
- }
868
-
869
- /* call-seq:
870
- * writer.start_dtd_attlist(name) -> (true|false)
871
- *
872
- * Starts a DTD attribute list (<!ATTLIST ... >). Returns +false+ on failure.
873
- */
874
- static VALUE rxml_writer_start_dtd_attlist(VALUE self, VALUE name)
875
- {
876
- return numeric_rxml_writer_string(self, name, xmlTextWriterStartDTDAttlist);
877
- }
878
-
879
- /* call-seq:
880
- * writer.end_dtd -> (true|false)
881
- *
882
- * Ends current DTD, returns +false+ on failure.
883
- */
884
- static VALUE rxml_writer_end_dtd(VALUE self)
885
- {
886
- return numeric_rxml_writer_void(self, xmlTextWriterEndDTD);
887
- }
888
-
889
- /* call-seq:
890
- * writer.end_dtd_entity -> (true|false)
891
- *
892
- * Ends current DTD entity, returns +false+ on failure.
893
- */
894
- static VALUE rxml_writer_end_dtd_entity(VALUE self)
895
- {
896
- return numeric_rxml_writer_void(self, xmlTextWriterEndDTDEntity);
897
- }
898
-
899
- /* call-seq:
900
- * writer.end_dtd_attlist -> (true|false)
901
- *
902
- * Ends current DTD attribute list, returns +false+ on failure.
903
- */
904
- static VALUE rxml_writer_end_dtd_attlist(VALUE self)
905
- {
906
- return numeric_rxml_writer_void(self, xmlTextWriterEndDTDAttlist);
907
- }
908
-
909
- /* call-seq:
910
- * writer.end_dtd_element -> (true|false)
911
- *
912
- * Ends current DTD element, returns +false+ on failure.
913
- */
914
- static VALUE rxml_writer_end_dtd_element(VALUE self)
915
- {
916
- return numeric_rxml_writer_void(self, xmlTextWriterEndDTDElement);
917
- }
918
-
919
- /* call-seq:
920
- * writer.write_dtd(name [ [ [, publicId ], systemId ], subset ]) -> (true|false)
921
- *
922
- * Writes a DTD, all at once. Returns +false+ on failure.
923
- * - name: dtd name
924
- * - publicId: external subset public identifier, use nil for a SYSTEM doctype
925
- * - systemId: external subset system identifier
926
- * - subset: content
927
- *
928
- * Examples:
929
- * writer.write_dtd 'html'
930
- * #=> <!DOCTYPE html>
931
- * writer.write_dtd 'docbook', nil, 'http://www.docbook.org/xml/5.0/dtd/docbook.dtd'
932
- * #=> <!DOCTYPE docbook SYSTEM "http://www.docbook.org/xml/5.0/dtd/docbook.dtd">
933
- * writer.write_dtd 'html', '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
934
- * #=> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
935
- * writer.write_dtd 'person', nil, nil, '<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>'
936
- * #=> <!DOCTYPE person [<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>]>
937
- */
938
- static VALUE rxml_writer_write_dtd(int argc, VALUE* argv, VALUE self)
939
- {
940
- VALUE name, pubid, sysid, subset;
941
-
942
- rb_scan_args(argc, argv, "13", &name, &pubid, &sysid, &subset);
943
-
944
- return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteDTD, name, pubid, sysid, subset);
945
- }
946
-
947
- /* call-seq:
948
- * writer.write_dtd_attlist(name, content) -> (true|false)
949
- *
950
- * Writes a DTD attribute list, all at once. Returns +false+ on failure.
951
- * writer.write_dtd_attlist 'id', 'ID #IMPLIED'
952
- * #=> <!ATTLIST id ID #IMPLIED>
953
- */
954
- static VALUE rxml_writer_write_dtd_attlist(VALUE self, VALUE name, VALUE content)
955
- {
956
- return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteDTDAttlist, name, content);
957
- }
958
-
959
- /* call-seq:
960
- * writer.write_dtd_element(name, content) -> (true|false)
961
- *
962
- * Writes a full DTD element, all at once. Returns +false+ on failure.
963
- * writer.write_dtd_element 'person', '(firstname,lastname)'
964
- * #=> <!ELEMENT person (firstname,lastname)>
965
- */
966
- static VALUE rxml_writer_write_dtd_element(VALUE self, VALUE name, VALUE content)
967
- {
968
- return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteDTDElement, name, content);
969
- }
970
-
971
- /* call-seq:
972
- * writer.write_dtd_entity(name, publicId, systemId, ndataid, content, pe) -> (true|false)
973
- *
974
- * Writes a DTD entity, all at once. Returns +false+ on failure.
975
- */
976
- static VALUE rxml_writer_write_dtd_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE content, VALUE pe)
977
- {
978
- return numeric_rxml_writer_va_strings(self, pe, 5, xmlTextWriterWriteDTDEntity, name, pubid, sysid, ndataid, content);
979
- }
980
-
981
- /* call-seq:
982
- * writer.write_dtd_external_entity(name, publicId, systemId, ndataid, pe) -> (true|false)
983
- *
984
- * Writes a DTD external entity. The entity must have been started
985
- * with start_dtd_entity. Returns +false+ on failure.
986
- * - name: the name of the DTD entity
987
- * - publicId: the public identifier, which is an alternative to the system identifier
988
- * - systemId: the system identifier, which is the URI of the DTD
989
- * - ndataid: the xml notation name
990
- * - pe: +true+ if this is a parameter entity (to be used only in the DTD
991
- * itself), +false+ if not
992
- */
993
- static VALUE rxml_writer_write_dtd_external_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE pe)
994
- {
995
- return numeric_rxml_writer_va_strings(self, pe, 4, xmlTextWriterWriteDTDExternalEntity, name, pubid, sysid, ndataid);
996
- }
997
-
998
- /* call-seq:
999
- * writer.write_dtd_external_entity_contents(publicId, systemId, ndataid) -> (true|false)
1000
- *
1001
- * Writes the contents of a DTD external entity, all at once. Returns +false+ on failure.
1002
- */
1003
- static VALUE rxml_writer_write_dtd_external_entity_contents(VALUE self, VALUE pubid, VALUE sysid, VALUE ndataid)
1004
- {
1005
- return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterWriteDTDExternalEntityContents, pubid, sysid, ndataid);
1006
- }
1007
-
1008
- /* call-seq:
1009
- * writer.write_dtd_internal_entity(name, content, pe) -> (true|false)
1010
- *
1011
- * Writes a DTD internal entity, all at once. Returns +false+ on failure.
1012
- *
1013
- * Examples:
1014
- * writer.write_dtd_entity 'Shape', '(rect|circle|poly|default)', true
1015
- * #=> <!ENTITY % Shape "(rect|circle|poly|default)">
1016
- * writer.write_dtd_entity 'delta', '&#948;', false
1017
- * #=> <!ENTITY delta "&#948;">
1018
- */
1019
- static VALUE rxml_writer_write_dtd_internal_entity(VALUE self, VALUE name, VALUE content, VALUE pe)
1020
- {
1021
- return numeric_rxml_writer_va_strings(self, pe, 2, xmlTextWriterWriteDTDInternalEntity, name, content);
1022
- }
1023
-
1024
- /* call-seq:
1025
- * writer.write_dtd_notation(name, publicId, systemId) -> (true|false)
1026
- *
1027
- * Writes a DTD entity, all at once. Returns +false+ on failure.
1028
- */
1029
- static VALUE rxml_writer_write_dtd_notation(VALUE self, VALUE name, VALUE pubid, VALUE sysid)
1030
- {
1031
- return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterWriteDTDNotation, name, pubid, sysid);
1032
- }
1033
-
1034
- #if LIBXML_VERSION >= 20900
1035
- /* call-seq:
1036
- * writer.set_quote_char(...) -> (true|false)
1037
- *
1038
- * Sets the character used to quote attributes. Returns +false+ on failure.
1039
- *
1040
- * Notes:
1041
- * - only " (default) and ' characters are valid
1042
- * - availability: libxml2 >= 2.9.0
1043
- */
1044
- static VALUE rxml_writer_set_quote_char(VALUE self, VALUE quotechar)
1045
- {
1046
- int ret;
1047
- const char* xquotechar;
1048
- rxml_writer_object* rwo;
1049
-
1050
- rwo = rxml_textwriter_get(self);
1051
- xquotechar = StringValueCStr(quotechar);
1052
- ret = xmlTextWriterSetQuoteChar(rwo->writer, (xmlChar)xquotechar[0]);
1053
-
1054
- return (-1 == ret ? Qfalse : Qtrue);
1055
- }
1056
- #endif /* LIBXML_VERSION >= 20900 */
1057
-
1058
- #endif /* LIBXML_WRITER_ENABLED */
1059
-
1060
-
1061
- /* grep -P 'xmlTextWriter(Start|End|Write)(?!DTD|V?Format)[^(]+' /usr/include/libxml2/libxml/xmlwriter.h */
1062
- void rxml_init_writer(void)
1063
- {
1064
- sEncoding = ID2SYM(rb_intern("encoding"));
1065
- sStandalone = ID2SYM(rb_intern("standalone"));
1066
-
1067
- cXMLWriter = rb_define_class_under(mXML, "Writer", rb_cObject);
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
- }
1137
-
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(&xmlLastError);
120
+ }
121
+ if (NULL == (rwo->writer = xmlNewTextWriter(out)))
122
+ {
123
+ rxml_raise(&xmlLastError);
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(&xmlLastError);
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(&xmlLastError);
171
+ }
172
+ if (NULL == (rwo->writer = xmlNewTextWriterMemory(rwo->buffer, 0)))
173
+ {
174
+ xmlBufferFree(rwo->buffer);
175
+ rxml_raise(&xmlLastError);
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(&xmlLastError);
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(&xmlLastError);
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(&xmlLastError);
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
+
287
+ static VALUE numeric_rxml_writer_void(VALUE obj, int (*fn)(xmlTextWriterPtr))
288
+ {
289
+ int ret;
290
+ rxml_writer_object* rwo;
291
+
292
+ rwo = rxml_textwriter_get(obj);
293
+ ret = fn(rwo->writer);
294
+
295
+ return (-1 == ret ? Qfalse : Qtrue);
296
+ }
297
+
298
+ #define numeric_rxml_writer_string(/*VALUE*/ obj, /*VALUE*/ name_or_content, /*int (**/fn/*)(xmlTextWriterPtr, const xmlChar *)*/) \
299
+ numeric_rxml_writer_va_strings(obj, Qundef, 1, fn, name_or_content)
300
+
301
+ /**
302
+ * This is quite ugly but thanks to libxml2 coding style, all xmlTextWriter*
303
+ * calls can be redirected to a single function. This can be convenient to:
304
+ * - avoid repeating yourself
305
+ * - convert strings to UTF-8
306
+ * - validate names
307
+ * and so on
308
+ **/
309
+ #define XMLWRITER_MAX_STRING_ARGS 5
310
+ static VALUE numeric_rxml_writer_va_strings(VALUE obj, VALUE pe, size_t strings_count, int (*fn)(ANYARGS), ...)
311
+ {
312
+ va_list ap;
313
+ size_t argc;
314
+ int ret = -1;
315
+ rxml_writer_object* rwo;
316
+ const xmlChar* argv[XMLWRITER_MAX_STRING_ARGS];
317
+ VALUE utf8[XMLWRITER_MAX_STRING_ARGS], orig[XMLWRITER_MAX_STRING_ARGS];
318
+
319
+ if (strings_count > XMLWRITER_MAX_STRING_ARGS)
320
+ {
321
+ rb_bug("more arguments than expected");
322
+ }
323
+ va_start(ap, fn);
324
+ rwo = rxml_textwriter_get(obj);
325
+ for (argc = 0; argc < strings_count; argc++)
326
+ {
327
+ VALUE arg;
328
+
329
+ arg = va_arg(ap, VALUE);
330
+ orig[argc] = arg;
331
+ if (NIL_P(arg))
332
+ {
333
+ utf8[argc] = Qnil;
334
+ argv[argc] = NULL;
335
+ }
336
+ else
337
+ {
338
+ utf8[argc] = rb_str_conv_enc(orig[argc], rb_enc_get(orig[argc]), rwo->encoding);
339
+ argv[argc] = BAD_CAST StringValueCStr(utf8[argc]);
340
+ }
341
+ }
342
+ va_end(ap);
343
+
344
+ if (Qundef == pe)
345
+ {
346
+ switch (strings_count)
347
+ {
348
+ case 0:
349
+ ret = fn(rwo->writer);
350
+ break;
351
+ case 1:
352
+ ret = fn(rwo->writer, argv[0]);
353
+ break;
354
+ case 2:
355
+ ret = fn(rwo->writer, argv[0], argv[1]);
356
+ break;
357
+ case 3:
358
+ ret = fn(rwo->writer, argv[0], argv[1], argv[2]);
359
+ break;
360
+ case 4:
361
+ ret = fn(rwo->writer, argv[0], argv[1], argv[2], argv[3]);
362
+ break;
363
+ case 5:
364
+ ret = fn(rwo->writer, argv[0], argv[1], argv[2], argv[3], argv[4]);
365
+ break;
366
+ default:
367
+ break;
368
+ }
369
+ }
370
+ else
371
+ {
372
+ int xpe;
373
+
374
+ xpe = RTEST(pe);
375
+ switch (strings_count)
376
+ { /* strings_count doesn't include pe */
377
+ case 0:
378
+ ret = fn(rwo->writer, xpe);
379
+ break;
380
+ case 1:
381
+ ret = fn(rwo->writer, xpe, argv[0]);
382
+ break;
383
+ case 2:
384
+ ret = fn(rwo->writer, xpe, argv[0], argv[1]);
385
+ break;
386
+ case 3:
387
+ ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2]);
388
+ break;
389
+ case 4:
390
+ ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2], argv[3]);
391
+ break;
392
+ case 5:
393
+ ret = fn(rwo->writer, xpe, argv[0], argv[1], argv[2], argv[3], argv[4]);
394
+ break;
395
+ default:
396
+ break;
397
+ }
398
+ }
399
+
400
+ while (--strings_count > 0)
401
+ {
402
+ if (!NIL_P(orig[strings_count]))
403
+ {
404
+ if (orig[strings_count] != utf8[strings_count])
405
+ {
406
+ rb_str_free(utf8[strings_count]);
407
+ }
408
+ }
409
+ }
410
+
411
+ return (-1 == ret ? Qfalse : Qtrue);
412
+ }
413
+
414
+ /* ===== public instance methods ===== */
415
+
416
+ #if LIBXML_VERSION >= 20605
417
+ /* call-seq:
418
+ * writer.set_indent(indentation) -> (true|false)
419
+ *
420
+ * Toggles indentation on or off. Returns +false+ on failure.
421
+ *
422
+ * Availability: libxml2 >= 2.6.5
423
+ */
424
+ static VALUE rxml_writer_set_indent(VALUE self, VALUE indentation)
425
+ {
426
+ int ret;
427
+ rxml_writer_object* rwo;
428
+
429
+ rwo = rxml_textwriter_get(self);
430
+ ret = xmlTextWriterSetIndent(rwo->writer, RTEST(indentation));
431
+
432
+ return (-1 == ret ? Qfalse : Qtrue);
433
+ }
434
+
435
+ /* call-seq:
436
+ * writer.set_indent_string(string) -> (true|false)
437
+ *
438
+ * Sets the string to use to indent each element of the document.
439
+ * Don't forget to enable indentation with set_indent. Returns
440
+ * +false+ on failure.
441
+ *
442
+ * Availability: libxml2 >= 2.6.5
443
+ */
444
+ static VALUE rxml_writer_set_indent_string(VALUE self, VALUE indentation)
445
+ {
446
+ return numeric_rxml_writer_string(self, indentation, xmlTextWriterSetIndentString);
447
+ }
448
+ #endif /* LIBXML_VERSION >= 20605 */
449
+
450
+ /* ===== public full tag interface ===== */
451
+
452
+ /* write_<X> = start_<X> + write_string + end_<X> */
453
+
454
+ /* call-seq:
455
+ * writer.write_comment(content) -> (true|false)
456
+ *
457
+ * Writes a full comment tag, all at once. Returns +false+ on failure.
458
+ * This is equivalent to start_comment + write_string(content) + end_comment.
459
+ */
460
+ static VALUE rxml_writer_write_comment(VALUE self, VALUE content)
461
+ {
462
+ return numeric_rxml_writer_string(self, content, xmlTextWriterWriteComment);
463
+ }
464
+
465
+ /* call-seq:
466
+ * writer.write_cdata(content) -> (true|false)
467
+ *
468
+ * Writes a full CDATA section, all at once. Returns +false+ on failure.
469
+ * This is equivalent to start_cdata + write_string(content) + end_cdata.
470
+ */
471
+ static VALUE rxml_writer_write_cdata(VALUE self, VALUE content)
472
+ {
473
+ return numeric_rxml_writer_string(self, content, xmlTextWriterWriteCDATA);
474
+ }
475
+
476
+ static VALUE rxml_writer_start_element(VALUE, VALUE);
477
+ static VALUE rxml_writer_start_element_ns(int, VALUE*, VALUE);
478
+ static VALUE rxml_writer_end_element(VALUE);
479
+
480
+ /* call-seq:
481
+ * writer.write_element(name, content) -> (true|false)
482
+ *
483
+ * Writes a full element tag, all at once. Returns +false+ on failure.
484
+ * This is equivalent to start_element(name) + write_string(content) +
485
+ * end_element.
486
+ */
487
+ static VALUE rxml_writer_write_element(int argc, VALUE* argv, VALUE self)
488
+ {
489
+ VALUE name, content;
490
+
491
+ rb_scan_args(argc, argv, "11", &name, &content);
492
+ if (Qnil == content)
493
+ {
494
+ if (Qfalse == rxml_writer_start_element(self, name))
495
+ {
496
+ return Qfalse;
497
+ }
498
+ return rxml_writer_end_element(self);
499
+ }
500
+ else
501
+ {
502
+ return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteElement, name, content);
503
+ }
504
+ }
505
+
506
+ #define ARRAY_SIZE(array) \
507
+ (sizeof(array) / sizeof((array)[0]))
508
+
509
+ /* call-seq:
510
+ * writer.write_element_ns(prefix, name, namespaceURI, content) -> (true|false)
511
+ *
512
+ * Writes a full namespaced element tag, all at once. Returns +false+ on failure.
513
+ * This is a shortcut for start_element_ns(prefix, name, namespaceURI) +
514
+ * write_string(content) + end_element.
515
+ *
516
+ * Notes:
517
+ * - by default, the xmlns: definition is repeated on every element. If you want
518
+ * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+
519
+ * to nil or omit it. Don't forget to declare the namespace prefix somewhere
520
+ * earlier.
521
+ * - +content+ can be omitted for an empty tag
522
+ */
523
+ static VALUE rxml_writer_write_element_ns(int argc, VALUE* argv, VALUE self)
524
+ {
525
+ VALUE prefix, name, namespaceURI, content;
526
+
527
+ rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
528
+ if (Qnil == content)
529
+ {
530
+ VALUE argv[3] = { prefix, name, namespaceURI };
531
+
532
+ if (Qfalse == rxml_writer_start_element_ns(ARRAY_SIZE(argv), argv, self))
533
+ {
534
+ return Qfalse;
535
+ }
536
+ return rxml_writer_end_element(self);
537
+ }
538
+ else
539
+ {
540
+ return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteElementNS, prefix, name, namespaceURI, content);
541
+ }
542
+ }
543
+
544
+ /* call-seq:
545
+ * writer.write_attribute(name, content) -> (true|false)
546
+ *
547
+ * Writes a full attribute, all at once. Returns +false+ on failure.
548
+ * Same as start_attribute(name) + write_string(content) + end_attribute.
549
+ */
550
+ static VALUE rxml_writer_write_attribute(VALUE self, VALUE name, VALUE content)
551
+ {
552
+ return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteAttribute, name, content);
553
+ }
554
+
555
+ /* call-seq:
556
+ * writer.write_attribute_ns(prefix, name, namespaceURI, content) -> (true|false)
557
+ *
558
+ * Writes a full namespaced attribute, all at once. Returns +false+ on failure.
559
+ * Same as start_attribute_ns(prefix, name, namespaceURI) +
560
+ * write_string(content) + end_attribute.
561
+ *
562
+ * Notes:
563
+ * - by default, the xmlns: definition is repeated on every element. If you want
564
+ * the prefix, but don't want the xmlns: declaration repeated, set +namespaceURI+
565
+ * to nil or omit it. Don't forget to declare the namespace prefix somewhere
566
+ * earlier.
567
+ * - +content+ can be omitted too for an empty attribute
568
+ */
569
+ static VALUE rxml_writer_write_attribute_ns(int argc, VALUE* argv, VALUE self)
570
+ {
571
+ VALUE prefix, name, namespaceURI, content;
572
+
573
+ rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
574
+
575
+ return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteAttributeNS, prefix, name, namespaceURI, content);
576
+ }
577
+
578
+ /* call-seq:
579
+ * writer.write_pi(target, content) -> (true|false)
580
+ *
581
+ * Writes a full CDATA tag, all at once. Returns +false+ on failure.
582
+ * This is a shortcut for start_pi(target) + write_string(content) + end_pi.
583
+ */
584
+ static VALUE rxml_writer_write_pi(VALUE self, VALUE target, VALUE content)
585
+ {
586
+ return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWritePI, target, content);
587
+ }
588
+
589
+ /* ===== public start/end interface ===== */
590
+
591
+ /* call-seq:
592
+ * writer.write_string(content) -> (true|false)
593
+ *
594
+ * Safely (problematic characters are internally translated to their
595
+ * associated named entities) writes a string into the current node
596
+ * (attribute, element, comment, ...). Returns +false+ on failure.
597
+ */
598
+ static VALUE rxml_writer_write_string(VALUE self, VALUE content)
599
+ {
600
+ return numeric_rxml_writer_string(self, content, xmlTextWriterWriteString);
601
+ }
602
+
603
+ /* call-seq:
604
+ * writer.write_raw(content) -> (true|false)
605
+ *
606
+ * Writes the string +content+ as is, reserved characters are not
607
+ * translated to their associated entities. Returns +false+ on failure.
608
+ * Consider write_string to handle them.
609
+ */
610
+ static VALUE rxml_writer_write_raw(VALUE self, VALUE content)
611
+ {
612
+ return numeric_rxml_writer_string(self, content, xmlTextWriterWriteRaw);
613
+ }
614
+
615
+ /* call-seq:
616
+ * writer.start_attribute(name) -> (true|false)
617
+ *
618
+ * Starts an attribute. Returns +false+ on failure.
619
+ */
620
+ static VALUE rxml_writer_start_attribute(VALUE self, VALUE name)
621
+ {
622
+ return numeric_rxml_writer_string(self, name, xmlTextWriterStartAttribute);
623
+ }
624
+
625
+ /* call-seq:
626
+ * writer.start_attribute_ns(prefix, name, namespaceURI) -> (true|false)
627
+ *
628
+ * Starts a namespaced attribute. Returns +false+ on failure.
629
+ *
630
+ * Note: by default, the xmlns: definition is repeated on every element. If
631
+ * you want the prefix, but don't want the xmlns: declaration repeated, set
632
+ * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace
633
+ * prefix somewhere earlier.
634
+ */
635
+ static VALUE rxml_writer_start_attribute_ns(int argc, VALUE* argv, VALUE self)
636
+ {
637
+ VALUE prefix, name, namespaceURI;
638
+
639
+ rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
640
+
641
+ return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartAttributeNS, prefix, name, namespaceURI);
642
+ }
643
+
644
+ /* call-seq:
645
+ * writer.end_attribute -> (true|false)
646
+ *
647
+ * Ends an attribute, namespaced or not. Returns +false+ on failure.
648
+ */
649
+ static VALUE rxml_writer_end_attribute(VALUE self)
650
+ {
651
+ return numeric_rxml_writer_void(self, xmlTextWriterEndAttribute);
652
+ }
653
+
654
+ #if LIBXML_VERSION >= 20607
655
+ /* call-seq:
656
+ * writer.start_comment -> (true|false)
657
+ *
658
+ * Starts a comment. Returns +false+ on failure.
659
+ * Note: libxml2 >= 2.6.7 required
660
+ */
661
+ static VALUE rxml_writer_start_comment(VALUE self)
662
+ {
663
+ return numeric_rxml_writer_void(self, xmlTextWriterStartComment);
664
+ }
665
+
666
+ /* call-seq:
667
+ * writer.end_comment -> (true|false)
668
+ *
669
+ * Ends current comment, returns +false+ on failure.
670
+ * Note: libxml2 >= 2.6.7 required
671
+ */
672
+ static VALUE rxml_writer_end_comment(VALUE self)
673
+ {
674
+ return numeric_rxml_writer_void(self, xmlTextWriterEndComment);
675
+ }
676
+ #endif /* LIBXML_VERSION >= 20607 */
677
+
678
+ /* call-seq:
679
+ * writer.start_element(name) -> (true|false)
680
+ *
681
+ * Starts a new element. Returns +false+ on failure.
682
+ */
683
+ static VALUE rxml_writer_start_element(VALUE self, VALUE name)
684
+ {
685
+ return numeric_rxml_writer_string(self, name, xmlTextWriterStartElement);
686
+ }
687
+
688
+ /* call-seq:
689
+ * writer.start_element_ns(prefix, name, namespaceURI) -> (true|false)
690
+ *
691
+ * Starts a new namespaced element. Returns +false+ on failure.
692
+ *
693
+ * Note: by default, the xmlns: definition is repeated on every element. If
694
+ * you want the prefix, but don't want the xmlns: declaration repeated, set
695
+ * +namespaceURI+ to nil or omit it. Don't forget to declare the namespace
696
+ * prefix somewhere earlier.
697
+ */
698
+ static VALUE rxml_writer_start_element_ns(int argc, VALUE* argv, VALUE self)
699
+ {
700
+ VALUE prefix, name, namespaceURI;
701
+
702
+ rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
703
+
704
+ return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartElementNS, prefix, name, namespaceURI);
705
+ }
706
+
707
+ /* call-seq:
708
+ * writer.end_element -> (true|false)
709
+ *
710
+ * Ends current element, namespaced or not. Returns +false+ on failure.
711
+ */
712
+ static VALUE rxml_writer_end_element(VALUE self)
713
+ {
714
+ return numeric_rxml_writer_void(self, xmlTextWriterEndElement);
715
+ }
716
+
717
+ /* call-seq:
718
+ * writer.write_full_end_element -> (true|false)
719
+ *
720
+ * Ends current element, namespaced or not. Returns +false+ on failure.
721
+ * This method writes an end tag even if the element is empty (<foo></foo>),
722
+ * end_element does not (<foo/>).
723
+ */
724
+ static VALUE rxml_writer_full_end_element(VALUE self)
725
+ {
726
+ return numeric_rxml_writer_void(self, xmlTextWriterFullEndElement);
727
+ }
728
+
729
+ /* call-seq:
730
+ * writer.start_cdata -> (true|false)
731
+ *
732
+ * Starts a new CDATA section. Returns +false+ on failure.
733
+ */
734
+ static VALUE rxml_writer_start_cdata(VALUE self)
735
+ {
736
+ return numeric_rxml_writer_void(self, xmlTextWriterStartCDATA);
737
+ }
738
+
739
+ /* call-seq:
740
+ * writer.end_cdata -> (true|false)
741
+ *
742
+ * Ends current CDATA section. Returns +false+ on failure.
743
+ */
744
+ static VALUE rxml_writer_end_cdata(VALUE self)
745
+ {
746
+ return numeric_rxml_writer_void(self, xmlTextWriterEndCDATA);
747
+ }
748
+
749
+ /* call-seq:
750
+ * writer.start_document -> (true|false)
751
+ * writer.start_document(:encoding => XML::Encoding::UTF_8,
752
+ * :standalone => true) -> (true|false)
753
+ *
754
+ * Starts a new document. Returns +false+ on failure.
755
+ *
756
+ * You may provide an optional hash table to control XML header that will be
757
+ * generated. Valid options are:
758
+ * - encoding: the output document encoding, defaults to nil (= UTF-8). Valid
759
+ * values are the encoding constants defined on XML::Encoding
760
+ * - standalone: nil (default) or a boolean to indicate if the document is
761
+ * standalone or not
762
+ */
763
+ static VALUE rxml_writer_start_document(int argc, VALUE* argv, VALUE self)
764
+ {
765
+ int ret;
766
+ VALUE options = Qnil;
767
+ rxml_writer_object* rwo;
768
+ const xmlChar* xencoding = NULL;
769
+ const char* xstandalone = NULL;
770
+
771
+ rb_scan_args(argc, argv, "01", &options);
772
+ if (!NIL_P(options))
773
+ {
774
+ VALUE encoding, standalone;
775
+
776
+ encoding = standalone = Qnil;
777
+ Check_Type(options, T_HASH);
778
+ encoding = rb_hash_aref(options, sEncoding);
779
+ xencoding = NIL_P(encoding) ? NULL : (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding));
780
+ standalone = rb_hash_aref(options, sStandalone);
781
+ if (NIL_P(standalone))
782
+ {
783
+ xstandalone = NULL;
784
+ }
785
+ else
786
+ {
787
+ xstandalone = RTEST(standalone) ? "yes" : "no";
788
+ }
789
+ }
790
+ rwo = rxml_textwriter_get(self);
791
+ rwo->encoding = rxml_figure_encoding(xencoding);
792
+ ret = xmlTextWriterStartDocument(rwo->writer, NULL, (const char*)xencoding, xstandalone);
793
+
794
+ return (-1 == ret ? Qfalse : Qtrue);
795
+ }
796
+
797
+ /* call-seq:
798
+ * writer.end_document -> (true|false)
799
+ *
800
+ * Ends current document. Returns +false+ on failure.
801
+ */
802
+ static VALUE rxml_writer_end_document(VALUE self)
803
+ {
804
+ return numeric_rxml_writer_void(self, xmlTextWriterEndDocument);
805
+ }
806
+
807
+ /* call-seq:
808
+ * writer.start_pi(target) -> (true|false)
809
+ *
810
+ * Starts a new processing instruction. Returns +false+ on failure.
811
+ */
812
+ static VALUE rxml_writer_start_pi(VALUE self, VALUE target)
813
+ {
814
+ return numeric_rxml_writer_string(self, target, xmlTextWriterStartPI);
815
+ }
816
+
817
+ /* call-seq:
818
+ * writer.end_pi -> (true|false)
819
+ *
820
+ * Ends current processing instruction. Returns +false+ on failure.
821
+ */
822
+ static VALUE rxml_writer_end_pi(VALUE self)
823
+ {
824
+ return numeric_rxml_writer_void(self, xmlTextWriterEndPI);
825
+ }
826
+
827
+ /* call-seq:
828
+ * writer.start_dtd(qualifiedName, publicId, systemId) -> (true|false)
829
+ *
830
+ * Starts a DTD. Returns +false+ on failure.
831
+ */
832
+ static VALUE rxml_writer_start_dtd(int argc, VALUE* argv, VALUE self)
833
+ {
834
+ VALUE name, pubid, sysid;
835
+
836
+ rb_scan_args(argc, argv, "12", &name, &pubid, &sysid);
837
+
838
+ return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartDTD, name, pubid, sysid);
839
+ }
840
+
841
+ /* call-seq:
842
+ * writer.start_dtd_element(qualifiedName) -> (true|false)
843
+ *
844
+ * Starts a DTD element (<!ELEMENT ... >). Returns +false+ on failure.
845
+ */
846
+ static VALUE rxml_writer_start_dtd_element(VALUE self, VALUE name)
847
+ {
848
+ return numeric_rxml_writer_string(self, name, xmlTextWriterStartDTDElement);
849
+ }
850
+
851
+ /* call-seq:
852
+ * writer.start_dtd_entity(name, pe = false) -> (true|false)
853
+ *
854
+ * Starts a DTD entity (<!ENTITY ... >). Returns +false+ on failure.
855
+ */
856
+ static VALUE rxml_writer_start_dtd_entity(int argc, VALUE* argv, VALUE self)
857
+ {
858
+ VALUE name, pe;
859
+
860
+ rb_scan_args(argc, argv, "11", &name, &pe);
861
+ if (NIL_P(pe))
862
+ {
863
+ pe = Qfalse;
864
+ }
865
+
866
+ return numeric_rxml_writer_va_strings(self, pe, 1, xmlTextWriterStartDTDEntity, name);
867
+ }
868
+
869
+ /* call-seq:
870
+ * writer.start_dtd_attlist(name) -> (true|false)
871
+ *
872
+ * Starts a DTD attribute list (<!ATTLIST ... >). Returns +false+ on failure.
873
+ */
874
+ static VALUE rxml_writer_start_dtd_attlist(VALUE self, VALUE name)
875
+ {
876
+ return numeric_rxml_writer_string(self, name, xmlTextWriterStartDTDAttlist);
877
+ }
878
+
879
+ /* call-seq:
880
+ * writer.end_dtd -> (true|false)
881
+ *
882
+ * Ends current DTD, returns +false+ on failure.
883
+ */
884
+ static VALUE rxml_writer_end_dtd(VALUE self)
885
+ {
886
+ return numeric_rxml_writer_void(self, xmlTextWriterEndDTD);
887
+ }
888
+
889
+ /* call-seq:
890
+ * writer.end_dtd_entity -> (true|false)
891
+ *
892
+ * Ends current DTD entity, returns +false+ on failure.
893
+ */
894
+ static VALUE rxml_writer_end_dtd_entity(VALUE self)
895
+ {
896
+ return numeric_rxml_writer_void(self, xmlTextWriterEndDTDEntity);
897
+ }
898
+
899
+ /* call-seq:
900
+ * writer.end_dtd_attlist -> (true|false)
901
+ *
902
+ * Ends current DTD attribute list, returns +false+ on failure.
903
+ */
904
+ static VALUE rxml_writer_end_dtd_attlist(VALUE self)
905
+ {
906
+ return numeric_rxml_writer_void(self, xmlTextWriterEndDTDAttlist);
907
+ }
908
+
909
+ /* call-seq:
910
+ * writer.end_dtd_element -> (true|false)
911
+ *
912
+ * Ends current DTD element, returns +false+ on failure.
913
+ */
914
+ static VALUE rxml_writer_end_dtd_element(VALUE self)
915
+ {
916
+ return numeric_rxml_writer_void(self, xmlTextWriterEndDTDElement);
917
+ }
918
+
919
+ /* call-seq:
920
+ * writer.write_dtd(name [ [ [, publicId ], systemId ], subset ]) -> (true|false)
921
+ *
922
+ * Writes a DTD, all at once. Returns +false+ on failure.
923
+ * - name: dtd name
924
+ * - publicId: external subset public identifier, use nil for a SYSTEM doctype
925
+ * - systemId: external subset system identifier
926
+ * - subset: content
927
+ *
928
+ * Examples:
929
+ * writer.write_dtd 'html'
930
+ * #=> <!DOCTYPE html>
931
+ * writer.write_dtd 'docbook', nil, 'http://www.docbook.org/xml/5.0/dtd/docbook.dtd'
932
+ * #=> <!DOCTYPE docbook SYSTEM "http://www.docbook.org/xml/5.0/dtd/docbook.dtd">
933
+ * writer.write_dtd 'html', '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
934
+ * #=> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
935
+ * writer.write_dtd 'person', nil, nil, '<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>'
936
+ * #=> <!DOCTYPE person [<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>]>
937
+ */
938
+ static VALUE rxml_writer_write_dtd(int argc, VALUE* argv, VALUE self)
939
+ {
940
+ VALUE name, pubid, sysid, subset;
941
+
942
+ rb_scan_args(argc, argv, "13", &name, &pubid, &sysid, &subset);
943
+
944
+ return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteDTD, name, pubid, sysid, subset);
945
+ }
946
+
947
+ /* call-seq:
948
+ * writer.write_dtd_attlist(name, content) -> (true|false)
949
+ *
950
+ * Writes a DTD attribute list, all at once. Returns +false+ on failure.
951
+ * writer.write_dtd_attlist 'id', 'ID #IMPLIED'
952
+ * #=> <!ATTLIST id ID #IMPLIED>
953
+ */
954
+ static VALUE rxml_writer_write_dtd_attlist(VALUE self, VALUE name, VALUE content)
955
+ {
956
+ return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteDTDAttlist, name, content);
957
+ }
958
+
959
+ /* call-seq:
960
+ * writer.write_dtd_element(name, content) -> (true|false)
961
+ *
962
+ * Writes a full DTD element, all at once. Returns +false+ on failure.
963
+ * writer.write_dtd_element 'person', '(firstname,lastname)'
964
+ * #=> <!ELEMENT person (firstname,lastname)>
965
+ */
966
+ static VALUE rxml_writer_write_dtd_element(VALUE self, VALUE name, VALUE content)
967
+ {
968
+ return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteDTDElement, name, content);
969
+ }
970
+
971
+ /* call-seq:
972
+ * writer.write_dtd_entity(name, publicId, systemId, ndataid, content, pe) -> (true|false)
973
+ *
974
+ * Writes a DTD entity, all at once. Returns +false+ on failure.
975
+ */
976
+ static VALUE rxml_writer_write_dtd_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE content, VALUE pe)
977
+ {
978
+ return numeric_rxml_writer_va_strings(self, pe, 5, xmlTextWriterWriteDTDEntity, name, pubid, sysid, ndataid, content);
979
+ }
980
+
981
+ /* call-seq:
982
+ * writer.write_dtd_external_entity(name, publicId, systemId, ndataid, pe) -> (true|false)
983
+ *
984
+ * Writes a DTD external entity. The entity must have been started
985
+ * with start_dtd_entity. Returns +false+ on failure.
986
+ * - name: the name of the DTD entity
987
+ * - publicId: the public identifier, which is an alternative to the system identifier
988
+ * - systemId: the system identifier, which is the URI of the DTD
989
+ * - ndataid: the xml notation name
990
+ * - pe: +true+ if this is a parameter entity (to be used only in the DTD
991
+ * itself), +false+ if not
992
+ */
993
+ static VALUE rxml_writer_write_dtd_external_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE pe)
994
+ {
995
+ return numeric_rxml_writer_va_strings(self, pe, 4, xmlTextWriterWriteDTDExternalEntity, name, pubid, sysid, ndataid);
996
+ }
997
+
998
+ /* call-seq:
999
+ * writer.write_dtd_external_entity_contents(publicId, systemId, ndataid) -> (true|false)
1000
+ *
1001
+ * Writes the contents of a DTD external entity, all at once. Returns +false+ on failure.
1002
+ */
1003
+ static VALUE rxml_writer_write_dtd_external_entity_contents(VALUE self, VALUE pubid, VALUE sysid, VALUE ndataid)
1004
+ {
1005
+ return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterWriteDTDExternalEntityContents, pubid, sysid, ndataid);
1006
+ }
1007
+
1008
+ /* call-seq:
1009
+ * writer.write_dtd_internal_entity(name, content, pe) -> (true|false)
1010
+ *
1011
+ * Writes a DTD internal entity, all at once. Returns +false+ on failure.
1012
+ *
1013
+ * Examples:
1014
+ * writer.write_dtd_entity 'Shape', '(rect|circle|poly|default)', true
1015
+ * #=> <!ENTITY % Shape "(rect|circle|poly|default)">
1016
+ * writer.write_dtd_entity 'delta', '&#948;', false
1017
+ * #=> <!ENTITY delta "&#948;">
1018
+ */
1019
+ static VALUE rxml_writer_write_dtd_internal_entity(VALUE self, VALUE name, VALUE content, VALUE pe)
1020
+ {
1021
+ return numeric_rxml_writer_va_strings(self, pe, 2, xmlTextWriterWriteDTDInternalEntity, name, content);
1022
+ }
1023
+
1024
+ /* call-seq:
1025
+ * writer.write_dtd_notation(name, publicId, systemId) -> (true|false)
1026
+ *
1027
+ * Writes a DTD entity, all at once. Returns +false+ on failure.
1028
+ */
1029
+ static VALUE rxml_writer_write_dtd_notation(VALUE self, VALUE name, VALUE pubid, VALUE sysid)
1030
+ {
1031
+ return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterWriteDTDNotation, name, pubid, sysid);
1032
+ }
1033
+
1034
+ #if LIBXML_VERSION >= 20900
1035
+ /* call-seq:
1036
+ * writer.set_quote_char(...) -> (true|false)
1037
+ *
1038
+ * Sets the character used to quote attributes. Returns +false+ on failure.
1039
+ *
1040
+ * Notes:
1041
+ * - only " (default) and ' characters are valid
1042
+ * - availability: libxml2 >= 2.9.0
1043
+ */
1044
+ static VALUE rxml_writer_set_quote_char(VALUE self, VALUE quotechar)
1045
+ {
1046
+ int ret;
1047
+ const char* xquotechar;
1048
+ rxml_writer_object* rwo;
1049
+
1050
+ rwo = rxml_textwriter_get(self);
1051
+ xquotechar = StringValueCStr(quotechar);
1052
+ ret = xmlTextWriterSetQuoteChar(rwo->writer, (xmlChar)xquotechar[0]);
1053
+
1054
+ return (-1 == ret ? Qfalse : Qtrue);
1055
+ }
1056
+ #endif /* LIBXML_VERSION >= 20900 */
1057
+
1058
+ #endif /* LIBXML_WRITER_ENABLED */
1059
+
1060
+
1061
+ /* grep -P 'xmlTextWriter(Start|End|Write)(?!DTD|V?Format)[^(]+' /usr/include/libxml2/libxml/xmlwriter.h */
1062
+ void rxml_init_writer(void)
1063
+ {
1064
+ sEncoding = ID2SYM(rb_intern("encoding"));
1065
+ sStandalone = ID2SYM(rb_intern("standalone"));
1066
+
1067
+ cXMLWriter = rb_define_class_under(mXML, "Writer", rb_cObject);
1068
+ rb_undef_alloc_func(cXMLWriter);
1069
+
1070
+ #ifdef LIBXML_WRITER_ENABLED
1071
+ rb_define_singleton_method(cXMLWriter, "io", rxml_writer_io, 1);
1072
+ rb_define_singleton_method(cXMLWriter, "file", rxml_writer_file, 1);
1073
+ rb_define_singleton_method(cXMLWriter, "document", rxml_writer_doc, 0);
1074
+ rb_define_singleton_method(cXMLWriter, "string", rxml_writer_string, 0);
1075
+
1076
+ /* misc */
1077
+ #if LIBXML_VERSION >= 20605
1078
+ rb_define_method(cXMLWriter, "set_indent", rxml_writer_set_indent, 1);
1079
+ rb_define_method(cXMLWriter, "set_indent_string", rxml_writer_set_indent_string, 1);
1080
+ #endif /* LIBXML_VERSION >= 20605 */
1081
+ #if LIBXML_VERSION >= 20900
1082
+ rb_define_method(cXMLWriter, "set_quote_char", rxml_writer_set_quote_char, 1);
1083
+ #endif /* LIBXML_VERSION >= 20900 */
1084
+ rb_define_method(cXMLWriter, "flush", rxml_writer_flush, -1);
1085
+ rb_define_method(cXMLWriter, "start_dtd", rxml_writer_start_dtd, -1);
1086
+ rb_define_method(cXMLWriter, "start_dtd_entity", rxml_writer_start_dtd_entity, -1);
1087
+ rb_define_method(cXMLWriter, "start_dtd_attlist", rxml_writer_start_dtd_attlist, 1);
1088
+ rb_define_method(cXMLWriter, "start_dtd_element", rxml_writer_start_dtd_element, 1);
1089
+ rb_define_method(cXMLWriter, "write_dtd", rxml_writer_write_dtd, -1);
1090
+ rb_define_method(cXMLWriter, "write_dtd_attlist", rxml_writer_write_dtd_attlist, 2);
1091
+ rb_define_method(cXMLWriter, "write_dtd_element", rxml_writer_write_dtd_element, 2);
1092
+ rb_define_method(cXMLWriter, "write_dtd_entity", rxml_writer_write_dtd_entity, 6);
1093
+ rb_define_method(cXMLWriter, "write_dtd_external_entity", rxml_writer_write_dtd_external_entity, 5);
1094
+ rb_define_method(cXMLWriter, "write_dtd_external_entity_contents", rxml_writer_write_dtd_external_entity_contents, 3);
1095
+ rb_define_method(cXMLWriter, "write_dtd_internal_entity", rxml_writer_write_dtd_internal_entity, 3);
1096
+ rb_define_method(cXMLWriter, "write_dtd_notation", rxml_writer_write_dtd_notation, 3);
1097
+ rb_define_method(cXMLWriter, "end_dtd", rxml_writer_end_dtd, 0);
1098
+ rb_define_method(cXMLWriter, "end_dtd_entity", rxml_writer_end_dtd_entity, 0);
1099
+ rb_define_method(cXMLWriter, "end_dtd_attlist", rxml_writer_end_dtd_attlist, 0);
1100
+ rb_define_method(cXMLWriter, "end_dtd_element", rxml_writer_end_dtd_element, 0);
1101
+
1102
+ /* tag by parts */
1103
+ rb_define_method(cXMLWriter, "write_raw", rxml_writer_write_raw, 1);
1104
+ rb_define_method(cXMLWriter, "write_string", rxml_writer_write_string, 1);
1105
+
1106
+ rb_define_method(cXMLWriter, "start_cdata", rxml_writer_start_cdata, 0);
1107
+ rb_define_method(cXMLWriter, "end_cdata", rxml_writer_end_cdata, 0);
1108
+ rb_define_method(cXMLWriter, "start_attribute", rxml_writer_start_attribute, 1);
1109
+ rb_define_method(cXMLWriter, "start_attribute_ns", rxml_writer_start_attribute_ns, -1);
1110
+ rb_define_method(cXMLWriter, "end_attribute", rxml_writer_end_attribute, 0);
1111
+ rb_define_method(cXMLWriter, "start_element", rxml_writer_start_element, 1);
1112
+ rb_define_method(cXMLWriter, "start_element_ns", rxml_writer_start_element_ns, -1);
1113
+ rb_define_method(cXMLWriter, "end_element", rxml_writer_end_element, 0);
1114
+ rb_define_method(cXMLWriter, "full_end_element", rxml_writer_full_end_element, 0);
1115
+ rb_define_method(cXMLWriter, "start_document", rxml_writer_start_document, -1);
1116
+ rb_define_method(cXMLWriter, "end_document", rxml_writer_end_document, 0);
1117
+ #if LIBXML_VERSION >= 20607
1118
+ rb_define_method(cXMLWriter, "start_comment", rxml_writer_start_comment, 0);
1119
+ rb_define_method(cXMLWriter, "end_comment", rxml_writer_end_comment, 0);
1120
+ #endif /* LIBXML_VERSION >= 20607 */
1121
+ rb_define_method(cXMLWriter, "start_pi", rxml_writer_start_pi, 1);
1122
+ rb_define_method(cXMLWriter, "end_pi", rxml_writer_end_pi, 0);
1123
+
1124
+ /* full tag at once */
1125
+ rb_define_method(cXMLWriter, "write_attribute", rxml_writer_write_attribute, 2);
1126
+ rb_define_method(cXMLWriter, "write_attribute_ns", rxml_writer_write_attribute_ns, -1);
1127
+ rb_define_method(cXMLWriter, "write_comment", rxml_writer_write_comment, 1);
1128
+ rb_define_method(cXMLWriter, "write_cdata", rxml_writer_write_cdata, 1);
1129
+ rb_define_method(cXMLWriter, "write_element", rxml_writer_write_element, -1);
1130
+ rb_define_method(cXMLWriter, "write_element_ns", rxml_writer_write_element_ns, -1);
1131
+ rb_define_method(cXMLWriter, "write_pi", rxml_writer_write_pi, 2);
1132
+
1133
+ rb_define_method(cXMLWriter, "result", rxml_writer_result, 0);
1134
+
1135
+ rb_undef_method(CLASS_OF(cXMLWriter), "new");
1136
+ #endif
1137
+ }
1138
+