libxml-ruby 0.9.3-x86-mswin32-60 → 0.9.4-x86-mswin32-60

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.
@@ -1,1057 +1,1084 @@
1
- /* $Id: ruby_xml_document.c 614 2008-11-22 08:04:39Z cfis $ */
2
-
3
- /*
4
- * Document-class: LibXML::XML::Document
5
- *
6
- * The XML::Document class provides a tree based API for working
7
- * with xml documents. You may directly create a document and
8
- * manipulate it, or create a document from a data source by
9
- * using an XML::Parser object.
10
- *
11
- * To create a document from scratch:
12
- *
13
- * doc = XML::Document.new()
14
- * doc.root = XML::Node.new('root_node')
15
- * doc.root << XML::Node.new('elem1')
16
- * doc.save('output.xml', format)
17
- *
18
- * To read a document
19
- *
20
- * doc = XML::Document.file('my_file')
21
- *
22
- * To use a parser to read a document:
23
- *
24
- * parser = XML::Parser.new
25
- * parser.file = 'my_file'
26
- * doc = parser.parse
27
- */
28
-
29
- #include <stdarg.h>
30
- #include <st.h>
31
- #include "ruby_libxml.h"
32
- #include "ruby_xml_document.h"
33
-
34
-
35
- VALUE cXMLDocument;
36
-
37
- void
38
- rxml_document_free(xmlDocPtr xdoc) {
39
- xdoc->_private = NULL;
40
- xmlFreeDoc(xdoc);
41
- }
42
-
43
- void
44
- rxml_document_mark(xmlDocPtr xdoc) {
45
- rb_gc_mark(LIBXML_STATE);
46
- }
47
-
48
- VALUE
49
- rxml_document_wrap(xmlDocPtr xdoc) {
50
- VALUE result;
51
-
52
- // This node is already wrapped
53
- if (xdoc->_private != NULL)
54
- {
55
- result = (VALUE)xdoc->_private;
56
- }
57
- else
58
- {
59
- result = Data_Wrap_Struct(cXMLDocument, rxml_document_mark, rxml_document_free, xdoc);
60
- xdoc->_private = (void*)result;
61
- }
62
-
63
- return result;
64
- }
65
-
66
-
67
- /*
68
- * call-seq:
69
- * XML::Document.alloc(xml_version = 1.0) -> document
70
- *
71
- * Alocates a new XML::Document, optionally specifying the
72
- * XML version.
73
- */
74
- static VALUE
75
- rxml_document_alloc(VALUE klass) {
76
- return Data_Wrap_Struct(klass, rxml_document_mark, rxml_document_free, NULL);
77
- }
78
-
79
- /*
80
- * call-seq:
81
- * XML::Document.initialize(xml_version = 1.0) -> document
82
- *
83
- * Initializes a new XML::Document, optionally specifying the
84
- * XML version.
85
- */
86
- static VALUE
87
- rxml_document_initialize(int argc, VALUE *argv, VALUE self) {
88
- xmlDocPtr xdoc;
89
- VALUE xmlver;
90
-
91
- switch (argc) {
92
- case 0:
93
- xmlver = rb_str_new2("1.0");
94
- break;
95
- case 1:
96
- rb_scan_args(argc, argv, "01", &xmlver);
97
- break;
98
- default:
99
- rb_raise(rb_eArgError, "wrong number of arguments (need 0 or 1)");
100
- }
101
-
102
- Check_Type(xmlver, T_STRING);
103
- xdoc = xmlNewDoc((xmlChar*)StringValuePtr(xmlver));
104
- xdoc->_private = (void*)self;
105
- DATA_PTR(self) = xdoc;
106
-
107
- return self;
108
- }
109
-
110
-
111
- /*
112
- * call-seq:
113
- * document.compression -> num
114
- *
115
- * Obtain this document's compression mode identifier.
116
- */
117
- static VALUE
118
- rxml_document_compression_get(VALUE self) {
119
- #ifdef HAVE_ZLIB_H
120
- xmlDocPtr xdoc;
121
-
122
- int compmode;
123
- Data_Get_Struct(self, xmlDoc, xdoc);
124
-
125
- compmode = xmlGetDocCompressMode(xdoc);
126
- if (compmode == -1)
127
- return(Qnil);
128
- else
129
- return(INT2NUM(compmode));
130
- #else
131
- rb_warn("libxml not compiled with zlib support");
132
- return(Qfalse);
133
- #endif
134
- }
135
-
136
-
137
- /*
138
- * call-seq:
139
- * document.compression = num
140
- *
141
- * Set this document's compression mode.
142
- */
143
- static VALUE
144
- rxml_document_compression_set(VALUE self, VALUE num) {
145
- #ifdef HAVE_ZLIB_H
146
- xmlDocPtr xdoc;
147
-
148
- int compmode;
149
- Check_Type(num, T_FIXNUM);
150
- Data_Get_Struct(self, xmlDoc, xdoc);
151
-
152
- if (xdoc == NULL) {
153
- return(Qnil);
154
- } else {
155
- xmlSetDocCompressMode(xdoc, NUM2INT(num));
156
-
157
- compmode = xmlGetDocCompressMode(xdoc);
158
- if (compmode == -1)
159
- return(Qnil);
160
- else
161
- return(INT2NUM(compmode));
162
- }
163
- #else
164
- rb_warn("libxml compiled without zlib support");
165
- return(Qfalse);
166
- #endif
167
- }
168
-
169
-
170
- /*
171
- * call-seq:
172
- * document.compression? -> (true|false)
173
- *
174
- * Determine whether this document is compressed.
175
- */
176
- static VALUE
177
- rxml_document_compression_q(VALUE self) {
178
- #ifdef HAVE_ZLIB_H
179
- xmlDocPtr xdoc;
180
-
181
- Data_Get_Struct(self, xmlDoc, xdoc);
182
-
183
- if (xdoc->compression != -1)
184
- return(Qtrue);
185
- else
186
- return(Qfalse);
187
- #else
188
- rb_warn("libxml compiled without zlib support");
189
- return(Qfalse);
190
- #endif
191
- }
192
-
193
-
194
- /*
195
- * call-seq:
196
- * document.child -> node
197
- *
198
- * Get this document's child node.
199
- */
200
- static VALUE
201
- rxml_document_child_get(VALUE self) {
202
- xmlDocPtr xdoc;
203
- Data_Get_Struct(self, xmlDoc, xdoc);
204
-
205
- if (xdoc->children == NULL)
206
- return(Qnil);
207
-
208
- return rxml_node2_wrap(cXMLNode, xdoc->children);
209
- }
210
-
211
-
212
- /*
213
- * call-seq:
214
- * document.child? -> (true|false)
215
- *
216
- * Determine whether this document has a child node.
217
- */
218
- static VALUE
219
- rxml_document_child_q(VALUE self) {
220
- xmlDocPtr xdoc;
221
- Data_Get_Struct(self, xmlDoc, xdoc);
222
-
223
- if (xdoc->children == NULL)
224
- return(Qfalse);
225
- else
226
- return(Qtrue);
227
- }
228
-
229
-
230
- /*
231
- * call-seq:
232
- * document.dump([stream]) -> true
233
- *
234
- * Dump this document's XML to the specified IO stream.
235
- * If no stream is specified, stdout is used.
236
- */
237
- static VALUE
238
- rxml_document_dump(int argc, VALUE *argv, VALUE self) {
239
- OpenFile *fptr;
240
- VALUE io;
241
- FILE *out;
242
- xmlDocPtr xdoc;
243
-
244
- Data_Get_Struct(self, xmlDoc, xdoc);
245
- if (xdoc == NULL)
246
- return(Qnil);
247
-
248
- switch (argc) {
249
- case 0:
250
- io = rb_stdout;
251
- break;
252
- case 1:
253
- io = argv[0];
254
- if (!rb_obj_is_kind_of(io, rb_cIO))
255
- rb_raise(rb_eTypeError, "need an IO object");
256
- break;
257
- default:
258
- rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
259
- }
260
-
261
- GetOpenFile(io, fptr);
262
- rb_io_check_writable(fptr);
263
- out = GetWriteFile(fptr);
264
- xmlDocDump(out, xdoc);
265
- return(Qtrue);
266
- }
267
-
268
-
269
- /*
270
- * call-seq:
271
- * document.debug_dump([stream]) -> true
272
- *
273
- * Debug version of dump.
274
- */
275
- static VALUE
276
- rxml_document_debug_dump(int argc, VALUE *argv, VALUE self) {
277
- #ifdef LIBXML_DEBUG_ENABLED
278
- OpenFile *fptr;
279
- VALUE io;
280
- FILE *out;
281
- xmlDocPtr xdoc;
282
-
283
- Data_Get_Struct(self, xmlDoc, xdoc);
284
- if (xdoc == NULL)
285
- return(Qnil);
286
-
287
- switch (argc) {
288
- case 0:
289
- io = rb_stderr;
290
- break;
291
- case 1:
292
- io = argv[0];
293
- if (!rb_obj_is_kind_of(io, rb_cIO))
294
- rb_raise(rb_eTypeError, "need an IO object");
295
- break;
296
- default:
297
- rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
298
- }
299
-
300
- GetOpenFile(io, fptr);
301
- rb_io_check_writable(fptr);
302
- out = GetWriteFile(fptr);
303
- xmlDebugDumpDocument(out, xdoc);
304
- return(Qtrue);
305
- #else
306
- rb_warn("libxml was compiled without debugging support. Please recompile libxml and ruby-libxml");
307
- return(Qfalse);
308
- #endif
309
- }
310
-
311
-
312
- /*
313
- * call-seq:
314
- * document.debug_dump_head([stream]) -> true
315
- *
316
- * Debug-dump this document's header to the specified IO stream.
317
- * If no stream is specified, stdout is used.
318
- */
319
- static VALUE
320
- rxml_document_debug_dump_head(int argc, VALUE *argv, VALUE self) {
321
- #ifdef LIBXML_DEBUG_ENABLED
322
- OpenFile *fptr;
323
- VALUE io;
324
- FILE *out;
325
- xmlDocPtr xdoc;
326
-
327
-
328
- Data_Get_Struct(self, xmlDoc, xdoc);
329
- if (xdoc == NULL)
330
- return(Qnil);
331
-
332
- switch (argc) {
333
- case 0:
334
- io = rb_stdout;
335
- break;
336
- case 1:
337
- io = argv[0];
338
- if (!rb_obj_is_kind_of(io, rb_cIO))
339
- rb_raise(rb_eTypeError, "need an IO object");
340
- break;
341
- default:
342
- rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
343
- }
344
-
345
- GetOpenFile(io, fptr);
346
- rb_io_check_writable(fptr);
347
- out = GetWriteFile(fptr);
348
- xmlDebugDumpDocumentHead(out, xdoc);
349
- return(Qtrue);
350
- #else
351
- rb_warn("libxml was compiled without debugging support. Please recompile libxml and ruby-libxml");
352
- return(Qfalse);
353
- #endif
354
- }
355
-
356
-
357
- /*
358
- * call-seq:
359
- * document.format_dump([stream], [spacing]) -> true
360
- *
361
- * Dump this document's formatted XML to the specified IO stream.
362
- * If no stream is specified, stdout is used. If spacing is
363
- * specified, it must be a boolean that determines whether
364
- * spacing is used.
365
- */
366
- static VALUE
367
- rxml_document_format_dump(int argc, VALUE *argv, VALUE self) {
368
- OpenFile *fptr;
369
- VALUE bool, io;
370
- FILE *out;
371
- xmlDocPtr xdoc;
372
-
373
- int size, spacing;
374
-
375
- Data_Get_Struct(self, xmlDoc, xdoc);
376
- if (xdoc == NULL)
377
- return(Qnil);
378
-
379
- switch (argc) {
380
- case 0:
381
- io = rb_stdout;
382
- spacing = 1;
383
- break;
384
- case 1:
385
- io = argv[0];
386
- if (!rb_obj_is_kind_of(io, rb_cIO))
387
- rb_raise(rb_eTypeError, "need an IO object");
388
- spacing = 1;
389
- break;
390
- case 2:
391
- io = argv[0];
392
- if (!rb_obj_is_kind_of(io, rb_cIO))
393
- rb_raise(rb_eTypeError, "need an IO object");
394
- bool = argv[1];
395
- if (TYPE(bool) == T_TRUE)
396
- spacing = 1;
397
- else if (TYPE(bool) == T_FALSE)
398
- spacing = 0;
399
- else
400
- rb_raise(rb_eTypeError, "incorect argument type, second argument must be bool");
401
-
402
- break;
403
- default:
404
- rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
405
- }
406
-
407
- GetOpenFile(io, fptr);
408
- rb_io_check_writable(fptr);
409
- out = GetWriteFile(fptr);
410
- size = xmlDocFormatDump(out, xdoc, spacing);
411
- return(INT2NUM(size));
412
- }
413
-
414
-
415
- /*
416
- * call-seq:
417
- * document.debug_format_dump([stream]) -> true
418
- *
419
- * *Deprecated* in favour of format_dump.
420
- */
421
- static VALUE
422
- rxml_document_debug_format_dump(int argc, VALUE *argv, VALUE self) {
423
- rb_warn("debug_format_dump has been deprecaited, use format_dump instead");
424
- return(rxml_document_format_dump(argc, argv, self));
425
- }
426
-
427
-
428
- /*
429
- * call-seq:
430
- * document.encoding -> "encoding"
431
- *
432
- * Obtain the encoding specified by this document.
433
- */
434
- static VALUE
435
- rxml_document_encoding_get(VALUE self) {
436
- xmlDocPtr xdoc;
437
-
438
- Data_Get_Struct(self, xmlDoc, xdoc);
439
- if (xdoc->encoding == NULL)
440
- return(Qnil);
441
- else
442
- return(rb_str_new2((const char*)xdoc->encoding));
443
- }
444
-
445
-
446
- /*
447
- * call-seq:
448
- * document.encoding = "encoding"
449
- *
450
- * Set the encoding for this document.
451
- */
452
- static VALUE
453
- rxml_document_encoding_set(VALUE self, VALUE encoding) {
454
- xmlDocPtr xdoc;
455
-
456
-
457
- Check_Type(encoding, T_STRING);
458
- Data_Get_Struct(self, xmlDoc, xdoc);
459
- xdoc->encoding = xmlStrdup(StringValuePtr(encoding));
460
- return(rxml_document_encoding_get(self));
461
- }
462
-
463
- /*
464
- * call-seq:
465
- * document.last -> node
466
- *
467
- * Obtain the last node.
468
- */
469
- static VALUE
470
- rxml_document_last_get(VALUE self) {
471
- xmlDocPtr xdoc;
472
-
473
-
474
- Data_Get_Struct(self, xmlDoc, xdoc);
475
-
476
- if (xdoc->last == NULL)
477
- return(Qnil);
478
-
479
- return rxml_node2_wrap(cXMLNode, xdoc->last);
480
- }
481
-
482
-
483
- /*
484
- * call-seq:
485
- * document.last? -> (true|false)
486
- *
487
- * Determine whether there is a last node.
488
- */
489
- static VALUE
490
- rxml_document_last_q(VALUE self) {
491
- xmlDocPtr xdoc;
492
-
493
- Data_Get_Struct(self, xmlDoc, xdoc);
494
-
495
- if (xdoc->last == NULL)
496
- return(Qfalse);
497
- else
498
- return(Qtrue);
499
- }
500
-
501
-
502
- /*
503
- * call-seq:
504
- * document.next -> node
505
- *
506
- * Obtain the next node.
507
- */
508
- static VALUE
509
- rxml_document_next_get(VALUE self) {
510
- xmlDocPtr xdoc;
511
-
512
-
513
- Data_Get_Struct(self, xmlDoc, xdoc);
514
-
515
- if (xdoc->next == NULL)
516
- return(Qnil);
517
-
518
- return rxml_node2_wrap(cXMLNode, xdoc->next);
519
- }
520
-
521
-
522
- /*
523
- * call-seq:
524
- * document.next? -> (true|false)
525
- *
526
- * Determine whether there is a next node.
527
- */
528
- static VALUE
529
- rxml_document_next_q(VALUE self) {
530
- xmlDocPtr xdoc;
531
-
532
- Data_Get_Struct(self, xmlDoc, xdoc);
533
-
534
- if (xdoc->next == NULL)
535
- return(Qfalse);
536
- else
537
- return(Qtrue);
538
- }
539
-
540
-
541
- /*
542
- * call-seq:
543
- * document.parent -> node
544
- *
545
- * Obtain the parent node.
546
- */
547
- static VALUE
548
- rxml_document_parent_get(VALUE self) {
549
- xmlDocPtr xdoc;
550
-
551
-
552
- Data_Get_Struct(self, xmlDoc, xdoc);
553
-
554
- if (xdoc->parent == NULL)
555
- return(Qnil);
556
-
557
- return rxml_node2_wrap(cXMLNode, xdoc->parent);
558
- }
559
-
560
-
561
- /*
562
- * call-seq:
563
- * document.parent? -> (true|false)
564
- *
565
- * Determine whether there is a parent node.
566
- */
567
- static VALUE
568
- rxml_document_parent_q(VALUE self) {
569
- xmlDocPtr xdoc;
570
-
571
- Data_Get_Struct(self, xmlDoc, xdoc);
572
-
573
- if (xdoc->parent == NULL)
574
- return(Qfalse);
575
- else
576
- return(Qtrue);
577
- }
578
-
579
-
580
- /*
581
- * call-seq:
582
- * document.prev -> node
583
- *
584
- * Obtain the previous node.
585
- */
586
- static VALUE
587
- rxml_document_prev_get(VALUE self) {
588
- xmlDocPtr xdoc;
589
-
590
-
591
- Data_Get_Struct(self, xmlDoc, xdoc);
592
-
593
- if (xdoc->prev == NULL)
594
- return(Qnil);
595
-
596
- return rxml_node2_wrap(cXMLNode, xdoc->prev);
597
- }
598
-
599
-
600
- /*
601
- * call-seq:
602
- * document.prev? -> (true|false)
603
- *
604
- * Determine whether there is a previous node.
605
- */
606
- static VALUE
607
- rxml_document_prev_q(VALUE self) {
608
- xmlDocPtr xdoc;
609
-
610
- Data_Get_Struct(self, xmlDoc, xdoc);
611
-
612
- if (xdoc->prev == NULL)
613
- return(Qfalse);
614
- else
615
- return(Qtrue);
616
- }
617
-
618
-
619
- /*
620
- * call-seq:
621
- * document.root -> node
622
- *
623
- * Obtain the root node.
624
- */
625
- static VALUE
626
- rxml_document_root_get(VALUE self) {
627
- xmlDocPtr xdoc;
628
-
629
- xmlNodePtr root;
630
-
631
- Data_Get_Struct(self, xmlDoc, xdoc);
632
- root = xmlDocGetRootElement(xdoc);
633
-
634
- if (root == NULL)
635
- return(Qnil);
636
-
637
- return rxml_node2_wrap(cXMLNode, root);
638
- }
639
-
640
-
641
- /*
642
- * call-seq:
643
- * document.root = node
644
- *
645
- * Set the root node.
646
- */
647
- static VALUE
648
- rxml_document_root_set(VALUE self, VALUE node) {
649
- xmlDocPtr xdoc;
650
- xmlNodePtr xroot, xnode;
651
-
652
- if (rb_obj_is_kind_of(node, cXMLNode) == Qfalse)
653
- rb_raise(rb_eTypeError, "must pass an XML::Node type object");
654
-
655
- Data_Get_Struct(self, xmlDoc, xdoc);
656
- Data_Get_Struct(node, xmlNode, xnode);
657
- xroot = xmlDocSetRootElement(xdoc, xnode);
658
- if (xroot == NULL)
659
- return(Qnil);
660
-
661
- return rxml_node2_wrap(cXMLNode, xroot);
662
- }
663
-
664
-
665
- /*
666
- * call-seq:
667
- * document.save(filename, format = false) -> int
668
- *
669
- * Save this document to the file given by filename,
670
- * optionally formatting the output.
671
-
672
- * Parameters:
673
- * filename: The filename or URL of the new document
674
- * format: Specifies whether formatting spaces should be added.
675
- * returns: The number of bytes written or -1 in case of error.
676
- */
677
- static VALUE
678
- rxml_document_save(int argc, VALUE *argv, VALUE self) {
679
- xmlDocPtr xdoc;
680
-
681
- const char *filename;
682
- int format = 0;
683
- int len;
684
-
685
- if (argc <1 || argc > 2)
686
- rb_raise(rb_eArgError, "wrong number of arguments (need 1 or 2)");
687
-
688
- Check_Type(argv[0], T_STRING);
689
- filename = StringValuePtr(argv[0]);
690
-
691
- if (argc == 2)
692
- {
693
- switch (TYPE(argv[1])) {
694
- case T_TRUE:
695
- format = 1;
696
- break;
697
- case T_FALSE:
698
- format = 0;
699
- break;
700
- default:
701
- rb_raise(rb_eArgError, "The second parameter (format) must be true or false");
702
- }
703
- }
704
-
705
- Data_Get_Struct(self, xmlDoc, xdoc);
706
- len = xmlSaveFormatFileEnc(filename, xdoc, (const char*)xdoc->encoding, format);
707
-
708
- if (len == -1)
709
- rb_raise(rb_eIOError, "Could not write document");
710
- else
711
- return(INT2NUM(len));
712
- }
713
-
714
-
715
- /*
716
- * call-seq:
717
- * document.standalone? -> (true|false)
718
- *
719
- * Determine whether this is a standalone document.
720
- */
721
- static VALUE
722
- rxml_document_standalone_q(VALUE self) {
723
- xmlDocPtr xdoc;
724
-
725
- Data_Get_Struct(self, xmlDoc, xdoc);
726
- if (xdoc->standalone)
727
- return(Qtrue);
728
- else
729
- return(Qfalse);
730
- }
731
-
732
-
733
- /*
734
- * call-seq:
735
- * document.to_s({format=true,encoding) -> "xml"
736
- *
737
- * Coerce this document to a string representation
738
- * of it's XML. The default is to pretty format, but this
739
- * depends Parser#indent_tree_output==true or
740
- * Parser#default_keep_blanks==false.
741
- *
742
- * The encoding is not applied to the document, but is
743
- * encoding target of the resulting string.
744
- */
745
- static VALUE
746
- rxml_document_to_s(int argc, VALUE *argv, VALUE self) {
747
- xmlDocPtr xdoc;
748
-
749
- xmlChar *result, *encoding=NULL;
750
- int format, len;
751
- VALUE rresult;
752
-
753
- switch (argc) {
754
- case 0:
755
- format = 1;
756
- break;
757
- case 2:
758
- if (TYPE(argv[1]) == T_STRING)
759
- encoding=(xmlChar *)StringValuePtr(argv[1]);
760
- case 1:
761
- if (TYPE(argv[0]) == T_TRUE)
762
- format = 1;
763
- else if (TYPE(argv[0]) == T_FALSE)
764
- format = 0;
765
- else
766
- rb_raise(rb_eTypeError, "wrong type of argument, must be bool");
767
- break;
768
- default:
769
- rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
770
- }
771
-
772
- Data_Get_Struct(self, xmlDoc, xdoc);
773
- if (xdoc == NULL) {
774
- return(Qnil);
775
- } else if (encoding != NULL) {
776
- if (format) {
777
- xmlDocDumpFormatMemoryEnc(xdoc, &result, &len,
778
- (const char*)encoding, format);
779
- } else {
780
- xmlDocDumpMemoryEnc(xdoc, &result, &len,
781
- (const char *)encoding);
782
- }
783
- } else {
784
- if (format)
785
- xmlDocDumpFormatMemory(xdoc, &result, &len, format);
786
- else
787
- xmlDocDumpMemory(xdoc, &result, &len);
788
- }
789
- rresult=rb_str_new((const char*)result,len);
790
- xmlFree(result);
791
- return rresult;
792
- }
793
-
794
-
795
- /*
796
- * call-seq:
797
- * document.url -> "url"
798
- *
799
- * Obtain this document's source URL, if any.
800
- */
801
- static VALUE
802
- rxml_document_url_get(VALUE self) {
803
- xmlDocPtr xdoc;
804
-
805
- Data_Get_Struct(self, xmlDoc, xdoc);
806
- if (xdoc->URL == NULL)
807
- return(Qnil);
808
- else
809
- return(rb_str_new2((const char*)xdoc->URL));
810
- }
811
-
812
-
813
- /*
814
- * call-seq:
815
- * document.version -> "version"
816
- *
817
- * Obtain the XML version specified by this document.
818
- */
819
- static VALUE
820
- rxml_document_version_get(VALUE self) {
821
- xmlDocPtr xdoc;
822
-
823
- Data_Get_Struct(self, xmlDoc, xdoc);
824
- if (xdoc->version == NULL)
825
- return(Qnil);
826
- else
827
- return(rb_str_new2((const char*)xdoc->version));
828
- }
829
-
830
-
831
- /*
832
- * call-seq:
833
- * document.xinclude -> num
834
- *
835
- * Process xinclude directives in this document.
836
- */
837
- static VALUE
838
- rxml_document_xinclude(VALUE self) {
839
- #ifdef LIBXML_XINCLUDE_ENABLED
840
- xmlDocPtr xdoc;
841
-
842
- int ret;
843
-
844
- Data_Get_Struct(self, xmlDoc, xdoc);
845
- ret = xmlXIncludeProcess(xdoc);
846
- if (ret >= 0)
847
- {
848
- return(INT2NUM(ret));
849
- }
850
- else
851
- {
852
- rxml_raise(&xmlLastError);
853
- return Qnil;
854
- }
855
- #else
856
- rb_warn("libxml was compiled without XInclude support. Please recompile libxml and ruby-libxml");
857
- return(Qfalse);
858
- #endif
859
- }
860
-
861
- void
862
- LibXML_validity_error(void * ctxt, const char * msg, va_list ap)
863
- {
864
- if (rb_block_given_p()) {
865
- char buff[1024];
866
- snprintf(buff, 1024, msg, ap);
867
- rb_yield(rb_ary_new3(2, rb_str_new2(buff), Qtrue));
868
- } else {
869
- fprintf(stderr, "error -- found validity error: ");
870
- fprintf(stderr, msg, ap);
871
- }
872
- }
873
-
874
- void
875
- LibXML_validity_warning(void * ctxt, const char * msg, va_list ap)
876
- {
877
- if (rb_block_given_p()) {
878
- char buff[1024];
879
- snprintf(buff, 1024, msg, ap);
880
- rb_yield(rb_ary_new3(2, rb_str_new2(buff), Qfalse));
881
- } else {
882
- fprintf(stderr, "warning -- found validity error: ");
883
- fprintf(stderr, msg, ap);
884
- }
885
- }
886
-
887
- /*
888
- * call-seq:
889
- * document.validate_schema(schema) -> (true|false)
890
- *
891
- * Validate this document against the specified XML::Schema.
892
- *
893
- * If a block is provided it is used as an error handler for validaten errors.
894
- * The block is called with two argument, the message and a flag indication
895
- * if the message is an error (true) or a warning (false).
896
- */
897
- static VALUE
898
- rxml_document_validate_schema(VALUE self, VALUE schema) {
899
- xmlSchemaValidCtxtPtr vptr;
900
- xmlDocPtr xdoc;
901
- xmlSchemaPtr xschema;
902
- int is_invalid;
903
-
904
- Data_Get_Struct(self, xmlDoc, xdoc);
905
- Data_Get_Struct(schema, xmlSchema, xschema);
906
-
907
- vptr = xmlSchemaNewValidCtxt(xschema);
908
-
909
- xmlSchemaSetValidErrors(vptr, (xmlSchemaValidityErrorFunc)LibXML_validity_error,
910
- (xmlSchemaValidityWarningFunc)LibXML_validity_warning, NULL);
911
-
912
- is_invalid = xmlSchemaValidateDoc(vptr, xdoc);
913
- xmlSchemaFreeValidCtxt(vptr);
914
- if (is_invalid)
915
- {
916
- rxml_raise(&xmlLastError);
917
- return Qfalse;
918
- }
919
- else
920
- {
921
- return Qtrue;
922
- }
923
- }
924
-
925
- /*
926
- * call-seq:
927
- * document.validate_schema(relaxng) -> (true|false)
928
- *
929
- * Validate this document against the specified XML::RelaxNG.
930
- *
931
- * If a block is provided it is used as an error handler for validaten errors.
932
- * The block is called with two argument, the message and a flag indication
933
- * if the message is an error (true) or a warning (false).
934
- */
935
- static VALUE
936
- rxml_document_validate_relaxng(VALUE self, VALUE relaxng) {
937
- xmlRelaxNGValidCtxtPtr vptr;
938
- xmlDocPtr xdoc;
939
- xmlRelaxNGPtr xrelaxng;
940
- int is_invalid;
941
-
942
- Data_Get_Struct(self, xmlDoc, xdoc);
943
- Data_Get_Struct(relaxng, xmlRelaxNG, xrelaxng);
944
-
945
- vptr = xmlRelaxNGNewValidCtxt(xrelaxng);
946
-
947
- xmlRelaxNGSetValidErrors(vptr, (xmlRelaxNGValidityErrorFunc)LibXML_validity_error,
948
- (xmlRelaxNGValidityWarningFunc)LibXML_validity_warning, NULL);
949
-
950
- is_invalid = xmlRelaxNGValidateDoc(vptr, xdoc);
951
- xmlRelaxNGFreeValidCtxt(vptr);
952
- if (is_invalid)
953
- {
954
- rxml_raise(&xmlLastError);
955
- return Qfalse;
956
- } else
957
- {
958
- return Qtrue;
959
- }
960
- }
961
-
962
-
963
- /*
964
- * call-seq:
965
- * document.validate(dtd) -> (true|false)
966
- *
967
- * Validate this document against the specified XML::DTD.
968
- */
969
- static VALUE
970
- rxml_document_validate_dtd(VALUE self, VALUE dtd) {
971
- VALUE error = Qnil;
972
- xmlValidCtxt ctxt;
973
- xmlDocPtr xdoc;
974
- xmlDtdPtr xdtd;
975
-
976
- Data_Get_Struct(self, xmlDoc, xdoc);
977
- Data_Get_Struct(dtd, xmlDtd, xdtd);
978
-
979
- ctxt.userData = &error;
980
- ctxt.error = (xmlValidityErrorFunc)LibXML_validity_error;
981
- ctxt.warning = (xmlValidityWarningFunc)LibXML_validity_warning;
982
-
983
- ctxt.nodeNr = 0;
984
- ctxt.nodeTab = NULL;
985
- ctxt.vstateNr = 0;
986
- ctxt.vstateTab = NULL;
987
-
988
- if (xmlValidateDtd(&ctxt, xdoc, xdtd))
989
- {
990
- return(Qtrue);
991
- }
992
- else
993
- {
994
- rxml_raise(&xmlLastError);
995
- return Qfalse;
996
- }
997
- }
998
-
999
-
1000
- /*
1001
- * call-seq:
1002
- * document.reader -> reader
1003
- *
1004
- * Create a XML::Reader from the document. This is a shortcut to
1005
- * XML::Reader.walker().
1006
- */
1007
- static VALUE
1008
- rxml_document_reader(VALUE self)
1009
- {
1010
- return rxml_reader_new_walker(cXMLReader, self);
1011
- }
1012
-
1013
- // Rdoc needs to know
1014
- #ifdef RDOC_NEVER_DEFINED
1015
- mLibXML = rb_define_module("LibXML");
1016
- mXML = rb_define_module_under(mLibXML, "XML");
1017
- #endif
1018
-
1019
- void
1020
- ruby_init_xml_document(void) {
1021
- cXMLDocument = rb_define_class_under(mXML, "Document", rb_cObject);
1022
- rb_define_alloc_func(cXMLDocument, rxml_document_alloc);
1023
-
1024
- rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1);
1025
- rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0);
1026
- rb_define_method(cXMLDocument, "child?", rxml_document_child_q, 0);
1027
- rb_define_method(cXMLDocument, "compression", rxml_document_compression_get, 0);
1028
- rb_define_method(cXMLDocument, "compression=", rxml_document_compression_set, 1);
1029
- rb_define_method(cXMLDocument, "compression?", rxml_document_compression_q, 0);
1030
- rb_define_method(cXMLDocument, "dump", rxml_document_dump, -1);
1031
- rb_define_method(cXMLDocument, "debug_dump", rxml_document_debug_dump, -1);
1032
- rb_define_method(cXMLDocument, "debug_dump_head", rxml_document_debug_dump_head, -1);
1033
- rb_define_method(cXMLDocument, "debug_format_dump", rxml_document_debug_format_dump, -1);
1034
- rb_define_method(cXMLDocument, "encoding", rxml_document_encoding_get, 0);
1035
- rb_define_method(cXMLDocument, "encoding=", rxml_document_encoding_set, 1);
1036
- rb_define_method(cXMLDocument, "format_dump", rxml_document_format_dump, -1);
1037
- rb_define_method(cXMLDocument, "last", rxml_document_last_get, 0);
1038
- rb_define_method(cXMLDocument, "last?", rxml_document_last_q, 0);
1039
- rb_define_method(cXMLDocument, "next", rxml_document_next_get, 0);
1040
- rb_define_method(cXMLDocument, "next?", rxml_document_next_q, 0);
1041
- rb_define_method(cXMLDocument, "parent", rxml_document_parent_get, 0);
1042
- rb_define_method(cXMLDocument, "parent?", rxml_document_parent_q, 0);
1043
- rb_define_method(cXMLDocument, "prev", rxml_document_prev_get, 0);
1044
- rb_define_method(cXMLDocument, "prev?", rxml_document_prev_q, 0);
1045
- rb_define_method(cXMLDocument, "root", rxml_document_root_get, 0);
1046
- rb_define_method(cXMLDocument, "root=", rxml_document_root_set, 1);
1047
- rb_define_method(cXMLDocument, "save", rxml_document_save, -1);
1048
- rb_define_method(cXMLDocument, "standalone?", rxml_document_standalone_q, 0);
1049
- rb_define_method(cXMLDocument, "to_s", rxml_document_to_s, -1);
1050
- rb_define_method(cXMLDocument, "url", rxml_document_url_get, 0);
1051
- rb_define_method(cXMLDocument, "version", rxml_document_version_get, 0);
1052
- rb_define_method(cXMLDocument, "xinclude", rxml_document_xinclude, 0);
1053
- rb_define_method(cXMLDocument, "validate", rxml_document_validate_dtd, 1);
1054
- rb_define_method(cXMLDocument, "validate_schema", rxml_document_validate_schema, 1);
1055
- rb_define_method(cXMLDocument, "validate_relaxng", rxml_document_validate_relaxng, 1);
1056
- rb_define_method(cXMLDocument, "reader", rxml_document_reader, 0);
1057
- }
1
+ /* $Id: ruby_xml_document.c 626 2008-11-22 20:47:07Z cfis $ */
2
+
3
+ /*
4
+ * Document-class: LibXML::XML::Document
5
+ *
6
+ * The XML::Document class provides a tree based API for working
7
+ * with xml documents. You may directly create a document and
8
+ * manipulate it, or create a document from a data source by
9
+ * using an XML::Parser object.
10
+ *
11
+ * To create a document from scratch:
12
+ *
13
+ * doc = XML::Document.new()
14
+ * doc.root = XML::Node.new('root_node')
15
+ * doc.root << XML::Node.new('elem1')
16
+ * doc.save('output.xml', format)
17
+ *
18
+ * To read a document from a file:
19
+ *
20
+ * doc = XML::Document.file('my_file')
21
+ *
22
+ * To use a parser to read a document:
23
+ *
24
+ * parser = XML::Parser.new
25
+ * parser.file = 'my_file'
26
+ * doc = parser.parse
27
+ *
28
+ * To write a file:
29
+ *
30
+ *
31
+ * doc = XML::Document.new()
32
+ * doc.root = XML::Node.new('root_node')
33
+ * root = doc.root
34
+ *
35
+ * root << elem1 = XML::Node.new('elem1')
36
+ * elem1['attr1'] = 'val1'
37
+ * elem1['attr2'] = 'val2'
38
+ *
39
+ * root << elem2 = XML::Node.new('elem2')
40
+ * elem2['attr1'] = 'val1'
41
+ * elem2['attr2'] = 'val2'
42
+ *
43
+ * root << elem3 = XML::Node.new('elem3')
44
+ * elem3 << elem4 = XML::Node.new('elem4')
45
+ * elem3 << elem5 = XML::Node.new('elem5')
46
+ *
47
+ * elem5 << elem6 = XML::Node.new('elem6')
48
+ * elem6 << 'Content for element 6'
49
+ *
50
+ * elem3['attr'] = 'baz'
51
+ *
52
+ * format = true
53
+ * doc.save('output.xml', format)
54
+ */
55
+
56
+ #include <stdarg.h>
57
+ #include <st.h>
58
+ #include "ruby_libxml.h"
59
+ #include "ruby_xml_document.h"
60
+
61
+
62
+ VALUE cXMLDocument;
63
+
64
+ void
65
+ rxml_document_free(xmlDocPtr xdoc) {
66
+ xdoc->_private = NULL;
67
+ xmlFreeDoc(xdoc);
68
+ }
69
+
70
+ void
71
+ rxml_document_mark(xmlDocPtr xdoc) {
72
+ rb_gc_mark(LIBXML_STATE);
73
+ }
74
+
75
+ VALUE
76
+ rxml_document_wrap(xmlDocPtr xdoc) {
77
+ VALUE result;
78
+
79
+ // This node is already wrapped
80
+ if (xdoc->_private != NULL)
81
+ {
82
+ result = (VALUE)xdoc->_private;
83
+ }
84
+ else
85
+ {
86
+ result = Data_Wrap_Struct(cXMLDocument, rxml_document_mark, rxml_document_free, xdoc);
87
+ xdoc->_private = (void*)result;
88
+ }
89
+
90
+ return result;
91
+ }
92
+
93
+
94
+ /*
95
+ * call-seq:
96
+ * XML::Document.alloc(xml_version = 1.0) -> document
97
+ *
98
+ * Alocates a new XML::Document, optionally specifying the
99
+ * XML version.
100
+ */
101
+ static VALUE
102
+ rxml_document_alloc(VALUE klass) {
103
+ return Data_Wrap_Struct(klass, rxml_document_mark, rxml_document_free, NULL);
104
+ }
105
+
106
+ /*
107
+ * call-seq:
108
+ * XML::Document.initialize(xml_version = 1.0) -> document
109
+ *
110
+ * Initializes a new XML::Document, optionally specifying the
111
+ * XML version.
112
+ */
113
+ static VALUE
114
+ rxml_document_initialize(int argc, VALUE *argv, VALUE self) {
115
+ xmlDocPtr xdoc;
116
+ VALUE xmlver;
117
+
118
+ switch (argc) {
119
+ case 0:
120
+ xmlver = rb_str_new2("1.0");
121
+ break;
122
+ case 1:
123
+ rb_scan_args(argc, argv, "01", &xmlver);
124
+ break;
125
+ default:
126
+ rb_raise(rb_eArgError, "wrong number of arguments (need 0 or 1)");
127
+ }
128
+
129
+ Check_Type(xmlver, T_STRING);
130
+ xdoc = xmlNewDoc((xmlChar*)StringValuePtr(xmlver));
131
+ xdoc->_private = (void*)self;
132
+ DATA_PTR(self) = xdoc;
133
+
134
+ return self;
135
+ }
136
+
137
+
138
+ /*
139
+ * call-seq:
140
+ * document.compression -> num
141
+ *
142
+ * Obtain this document's compression mode identifier.
143
+ */
144
+ static VALUE
145
+ rxml_document_compression_get(VALUE self) {
146
+ #ifdef HAVE_ZLIB_H
147
+ xmlDocPtr xdoc;
148
+
149
+ int compmode;
150
+ Data_Get_Struct(self, xmlDoc, xdoc);
151
+
152
+ compmode = xmlGetDocCompressMode(xdoc);
153
+ if (compmode == -1)
154
+ return(Qnil);
155
+ else
156
+ return(INT2NUM(compmode));
157
+ #else
158
+ rb_warn("libxml not compiled with zlib support");
159
+ return(Qfalse);
160
+ #endif
161
+ }
162
+
163
+
164
+ /*
165
+ * call-seq:
166
+ * document.compression = num
167
+ *
168
+ * Set this document's compression mode.
169
+ */
170
+ static VALUE
171
+ rxml_document_compression_set(VALUE self, VALUE num) {
172
+ #ifdef HAVE_ZLIB_H
173
+ xmlDocPtr xdoc;
174
+
175
+ int compmode;
176
+ Check_Type(num, T_FIXNUM);
177
+ Data_Get_Struct(self, xmlDoc, xdoc);
178
+
179
+ if (xdoc == NULL) {
180
+ return(Qnil);
181
+ } else {
182
+ xmlSetDocCompressMode(xdoc, NUM2INT(num));
183
+
184
+ compmode = xmlGetDocCompressMode(xdoc);
185
+ if (compmode == -1)
186
+ return(Qnil);
187
+ else
188
+ return(INT2NUM(compmode));
189
+ }
190
+ #else
191
+ rb_warn("libxml compiled without zlib support");
192
+ return(Qfalse);
193
+ #endif
194
+ }
195
+
196
+
197
+ /*
198
+ * call-seq:
199
+ * document.compression? -> (true|false)
200
+ *
201
+ * Determine whether this document is compressed.
202
+ */
203
+ static VALUE
204
+ rxml_document_compression_q(VALUE self) {
205
+ #ifdef HAVE_ZLIB_H
206
+ xmlDocPtr xdoc;
207
+
208
+ Data_Get_Struct(self, xmlDoc, xdoc);
209
+
210
+ if (xdoc->compression != -1)
211
+ return(Qtrue);
212
+ else
213
+ return(Qfalse);
214
+ #else
215
+ rb_warn("libxml compiled without zlib support");
216
+ return(Qfalse);
217
+ #endif
218
+ }
219
+
220
+
221
+ /*
222
+ * call-seq:
223
+ * document.child -> node
224
+ *
225
+ * Get this document's child node.
226
+ */
227
+ static VALUE
228
+ rxml_document_child_get(VALUE self) {
229
+ xmlDocPtr xdoc;
230
+ Data_Get_Struct(self, xmlDoc, xdoc);
231
+
232
+ if (xdoc->children == NULL)
233
+ return(Qnil);
234
+
235
+ return rxml_node2_wrap(cXMLNode, xdoc->children);
236
+ }
237
+
238
+
239
+ /*
240
+ * call-seq:
241
+ * document.child? -> (true|false)
242
+ *
243
+ * Determine whether this document has a child node.
244
+ */
245
+ static VALUE
246
+ rxml_document_child_q(VALUE self) {
247
+ xmlDocPtr xdoc;
248
+ Data_Get_Struct(self, xmlDoc, xdoc);
249
+
250
+ if (xdoc->children == NULL)
251
+ return(Qfalse);
252
+ else
253
+ return(Qtrue);
254
+ }
255
+
256
+
257
+ /*
258
+ * call-seq:
259
+ * document.dump([stream]) -> true
260
+ *
261
+ * Dump this document's XML to the specified IO stream.
262
+ * If no stream is specified, stdout is used.
263
+ */
264
+ static VALUE
265
+ rxml_document_dump(int argc, VALUE *argv, VALUE self) {
266
+ OpenFile *fptr;
267
+ VALUE io;
268
+ FILE *out;
269
+ xmlDocPtr xdoc;
270
+
271
+ Data_Get_Struct(self, xmlDoc, xdoc);
272
+ if (xdoc == NULL)
273
+ return(Qnil);
274
+
275
+ switch (argc) {
276
+ case 0:
277
+ io = rb_stdout;
278
+ break;
279
+ case 1:
280
+ io = argv[0];
281
+ if (!rb_obj_is_kind_of(io, rb_cIO))
282
+ rb_raise(rb_eTypeError, "need an IO object");
283
+ break;
284
+ default:
285
+ rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
286
+ }
287
+
288
+ GetOpenFile(io, fptr);
289
+ rb_io_check_writable(fptr);
290
+ out = GetWriteFile(fptr);
291
+ xmlDocDump(out, xdoc);
292
+ return(Qtrue);
293
+ }
294
+
295
+
296
+ /*
297
+ * call-seq:
298
+ * document.debug_dump([stream]) -> true
299
+ *
300
+ * Debug version of dump.
301
+ */
302
+ static VALUE
303
+ rxml_document_debug_dump(int argc, VALUE *argv, VALUE self) {
304
+ #ifdef LIBXML_DEBUG_ENABLED
305
+ OpenFile *fptr;
306
+ VALUE io;
307
+ FILE *out;
308
+ xmlDocPtr xdoc;
309
+
310
+ Data_Get_Struct(self, xmlDoc, xdoc);
311
+ if (xdoc == NULL)
312
+ return(Qnil);
313
+
314
+ switch (argc) {
315
+ case 0:
316
+ io = rb_stderr;
317
+ break;
318
+ case 1:
319
+ io = argv[0];
320
+ if (!rb_obj_is_kind_of(io, rb_cIO))
321
+ rb_raise(rb_eTypeError, "need an IO object");
322
+ break;
323
+ default:
324
+ rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
325
+ }
326
+
327
+ GetOpenFile(io, fptr);
328
+ rb_io_check_writable(fptr);
329
+ out = GetWriteFile(fptr);
330
+ xmlDebugDumpDocument(out, xdoc);
331
+ return(Qtrue);
332
+ #else
333
+ rb_warn("libxml was compiled without debugging support. Please recompile libxml and ruby-libxml");
334
+ return(Qfalse);
335
+ #endif
336
+ }
337
+
338
+
339
+ /*
340
+ * call-seq:
341
+ * document.debug_dump_head([stream]) -> true
342
+ *
343
+ * Debug-dump this document's header to the specified IO stream.
344
+ * If no stream is specified, stdout is used.
345
+ */
346
+ static VALUE
347
+ rxml_document_debug_dump_head(int argc, VALUE *argv, VALUE self) {
348
+ #ifdef LIBXML_DEBUG_ENABLED
349
+ OpenFile *fptr;
350
+ VALUE io;
351
+ FILE *out;
352
+ xmlDocPtr xdoc;
353
+
354
+
355
+ Data_Get_Struct(self, xmlDoc, xdoc);
356
+ if (xdoc == NULL)
357
+ return(Qnil);
358
+
359
+ switch (argc) {
360
+ case 0:
361
+ io = rb_stdout;
362
+ break;
363
+ case 1:
364
+ io = argv[0];
365
+ if (!rb_obj_is_kind_of(io, rb_cIO))
366
+ rb_raise(rb_eTypeError, "need an IO object");
367
+ break;
368
+ default:
369
+ rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
370
+ }
371
+
372
+ GetOpenFile(io, fptr);
373
+ rb_io_check_writable(fptr);
374
+ out = GetWriteFile(fptr);
375
+ xmlDebugDumpDocumentHead(out, xdoc);
376
+ return(Qtrue);
377
+ #else
378
+ rb_warn("libxml was compiled without debugging support. Please recompile libxml and ruby-libxml");
379
+ return(Qfalse);
380
+ #endif
381
+ }
382
+
383
+
384
+ /*
385
+ * call-seq:
386
+ * document.format_dump([stream], [spacing]) -> true
387
+ *
388
+ * Dump this document's formatted XML to the specified IO stream.
389
+ * If no stream is specified, stdout is used. If spacing is
390
+ * specified, it must be a boolean that determines whether
391
+ * spacing is used.
392
+ */
393
+ static VALUE
394
+ rxml_document_format_dump(int argc, VALUE *argv, VALUE self) {
395
+ OpenFile *fptr;
396
+ VALUE bool, io;
397
+ FILE *out;
398
+ xmlDocPtr xdoc;
399
+
400
+ int size, spacing;
401
+
402
+ Data_Get_Struct(self, xmlDoc, xdoc);
403
+ if (xdoc == NULL)
404
+ return(Qnil);
405
+
406
+ switch (argc) {
407
+ case 0:
408
+ io = rb_stdout;
409
+ spacing = 1;
410
+ break;
411
+ case 1:
412
+ io = argv[0];
413
+ if (!rb_obj_is_kind_of(io, rb_cIO))
414
+ rb_raise(rb_eTypeError, "need an IO object");
415
+ spacing = 1;
416
+ break;
417
+ case 2:
418
+ io = argv[0];
419
+ if (!rb_obj_is_kind_of(io, rb_cIO))
420
+ rb_raise(rb_eTypeError, "need an IO object");
421
+ bool = argv[1];
422
+ if (TYPE(bool) == T_TRUE)
423
+ spacing = 1;
424
+ else if (TYPE(bool) == T_FALSE)
425
+ spacing = 0;
426
+ else
427
+ rb_raise(rb_eTypeError, "incorect argument type, second argument must be bool");
428
+
429
+ break;
430
+ default:
431
+ rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
432
+ }
433
+
434
+ GetOpenFile(io, fptr);
435
+ rb_io_check_writable(fptr);
436
+ out = GetWriteFile(fptr);
437
+ size = xmlDocFormatDump(out, xdoc, spacing);
438
+ return(INT2NUM(size));
439
+ }
440
+
441
+
442
+ /*
443
+ * call-seq:
444
+ * document.debug_format_dump([stream]) -> true
445
+ *
446
+ * *Deprecated* in favour of format_dump.
447
+ */
448
+ static VALUE
449
+ rxml_document_debug_format_dump(int argc, VALUE *argv, VALUE self) {
450
+ rb_warn("debug_format_dump has been deprecaited, use format_dump instead");
451
+ return(rxml_document_format_dump(argc, argv, self));
452
+ }
453
+
454
+
455
+ /*
456
+ * call-seq:
457
+ * document.encoding -> "encoding"
458
+ *
459
+ * Obtain the encoding specified by this document.
460
+ */
461
+ static VALUE
462
+ rxml_document_encoding_get(VALUE self) {
463
+ xmlDocPtr xdoc;
464
+
465
+ Data_Get_Struct(self, xmlDoc, xdoc);
466
+ if (xdoc->encoding == NULL)
467
+ return(Qnil);
468
+ else
469
+ return(rb_str_new2((const char*)xdoc->encoding));
470
+ }
471
+
472
+
473
+ /*
474
+ * call-seq:
475
+ * document.encoding = "encoding"
476
+ *
477
+ * Set the encoding for this document.
478
+ */
479
+ static VALUE
480
+ rxml_document_encoding_set(VALUE self, VALUE encoding) {
481
+ xmlDocPtr xdoc;
482
+
483
+
484
+ Check_Type(encoding, T_STRING);
485
+ Data_Get_Struct(self, xmlDoc, xdoc);
486
+ xdoc->encoding = xmlStrdup(StringValuePtr(encoding));
487
+ return(rxml_document_encoding_get(self));
488
+ }
489
+
490
+ /*
491
+ * call-seq:
492
+ * document.last -> node
493
+ *
494
+ * Obtain the last node.
495
+ */
496
+ static VALUE
497
+ rxml_document_last_get(VALUE self) {
498
+ xmlDocPtr xdoc;
499
+
500
+
501
+ Data_Get_Struct(self, xmlDoc, xdoc);
502
+
503
+ if (xdoc->last == NULL)
504
+ return(Qnil);
505
+
506
+ return rxml_node2_wrap(cXMLNode, xdoc->last);
507
+ }
508
+
509
+
510
+ /*
511
+ * call-seq:
512
+ * document.last? -> (true|false)
513
+ *
514
+ * Determine whether there is a last node.
515
+ */
516
+ static VALUE
517
+ rxml_document_last_q(VALUE self) {
518
+ xmlDocPtr xdoc;
519
+
520
+ Data_Get_Struct(self, xmlDoc, xdoc);
521
+
522
+ if (xdoc->last == NULL)
523
+ return(Qfalse);
524
+ else
525
+ return(Qtrue);
526
+ }
527
+
528
+
529
+ /*
530
+ * call-seq:
531
+ * document.next -> node
532
+ *
533
+ * Obtain the next node.
534
+ */
535
+ static VALUE
536
+ rxml_document_next_get(VALUE self) {
537
+ xmlDocPtr xdoc;
538
+
539
+
540
+ Data_Get_Struct(self, xmlDoc, xdoc);
541
+
542
+ if (xdoc->next == NULL)
543
+ return(Qnil);
544
+
545
+ return rxml_node2_wrap(cXMLNode, xdoc->next);
546
+ }
547
+
548
+
549
+ /*
550
+ * call-seq:
551
+ * document.next? -> (true|false)
552
+ *
553
+ * Determine whether there is a next node.
554
+ */
555
+ static VALUE
556
+ rxml_document_next_q(VALUE self) {
557
+ xmlDocPtr xdoc;
558
+
559
+ Data_Get_Struct(self, xmlDoc, xdoc);
560
+
561
+ if (xdoc->next == NULL)
562
+ return(Qfalse);
563
+ else
564
+ return(Qtrue);
565
+ }
566
+
567
+
568
+ /*
569
+ * call-seq:
570
+ * document.parent -> node
571
+ *
572
+ * Obtain the parent node.
573
+ */
574
+ static VALUE
575
+ rxml_document_parent_get(VALUE self) {
576
+ xmlDocPtr xdoc;
577
+
578
+
579
+ Data_Get_Struct(self, xmlDoc, xdoc);
580
+
581
+ if (xdoc->parent == NULL)
582
+ return(Qnil);
583
+
584
+ return rxml_node2_wrap(cXMLNode, xdoc->parent);
585
+ }
586
+
587
+
588
+ /*
589
+ * call-seq:
590
+ * document.parent? -> (true|false)
591
+ *
592
+ * Determine whether there is a parent node.
593
+ */
594
+ static VALUE
595
+ rxml_document_parent_q(VALUE self) {
596
+ xmlDocPtr xdoc;
597
+
598
+ Data_Get_Struct(self, xmlDoc, xdoc);
599
+
600
+ if (xdoc->parent == NULL)
601
+ return(Qfalse);
602
+ else
603
+ return(Qtrue);
604
+ }
605
+
606
+
607
+ /*
608
+ * call-seq:
609
+ * document.prev -> node
610
+ *
611
+ * Obtain the previous node.
612
+ */
613
+ static VALUE
614
+ rxml_document_prev_get(VALUE self) {
615
+ xmlDocPtr xdoc;
616
+
617
+
618
+ Data_Get_Struct(self, xmlDoc, xdoc);
619
+
620
+ if (xdoc->prev == NULL)
621
+ return(Qnil);
622
+
623
+ return rxml_node2_wrap(cXMLNode, xdoc->prev);
624
+ }
625
+
626
+
627
+ /*
628
+ * call-seq:
629
+ * document.prev? -> (true|false)
630
+ *
631
+ * Determine whether there is a previous node.
632
+ */
633
+ static VALUE
634
+ rxml_document_prev_q(VALUE self) {
635
+ xmlDocPtr xdoc;
636
+
637
+ Data_Get_Struct(self, xmlDoc, xdoc);
638
+
639
+ if (xdoc->prev == NULL)
640
+ return(Qfalse);
641
+ else
642
+ return(Qtrue);
643
+ }
644
+
645
+
646
+ /*
647
+ * call-seq:
648
+ * document.root -> node
649
+ *
650
+ * Obtain the root node.
651
+ */
652
+ static VALUE
653
+ rxml_document_root_get(VALUE self) {
654
+ xmlDocPtr xdoc;
655
+
656
+ xmlNodePtr root;
657
+
658
+ Data_Get_Struct(self, xmlDoc, xdoc);
659
+ root = xmlDocGetRootElement(xdoc);
660
+
661
+ if (root == NULL)
662
+ return(Qnil);
663
+
664
+ return rxml_node2_wrap(cXMLNode, root);
665
+ }
666
+
667
+
668
+ /*
669
+ * call-seq:
670
+ * document.root = node
671
+ *
672
+ * Set the root node.
673
+ */
674
+ static VALUE
675
+ rxml_document_root_set(VALUE self, VALUE node) {
676
+ xmlDocPtr xdoc;
677
+ xmlNodePtr xroot, xnode;
678
+
679
+ if (rb_obj_is_kind_of(node, cXMLNode) == Qfalse)
680
+ rb_raise(rb_eTypeError, "must pass an XML::Node type object");
681
+
682
+ Data_Get_Struct(self, xmlDoc, xdoc);
683
+ Data_Get_Struct(node, xmlNode, xnode);
684
+ xroot = xmlDocSetRootElement(xdoc, xnode);
685
+ if (xroot == NULL)
686
+ return(Qnil);
687
+
688
+ return rxml_node2_wrap(cXMLNode, xroot);
689
+ }
690
+
691
+
692
+ /*
693
+ * call-seq:
694
+ * document.save(filename, format = false) -> int
695
+ *
696
+ * Save this document to the file given by filename,
697
+ * optionally formatting the output.
698
+
699
+ * Parameters:
700
+ * filename: The filename or URL of the new document
701
+ * format: Specifies whether formatting spaces should be added.
702
+ * returns: The number of bytes written or -1 in case of error.
703
+ */
704
+ static VALUE
705
+ rxml_document_save(int argc, VALUE *argv, VALUE self) {
706
+ xmlDocPtr xdoc;
707
+
708
+ const char *filename;
709
+ int format = 0;
710
+ int len;
711
+
712
+ if (argc <1 || argc > 2)
713
+ rb_raise(rb_eArgError, "wrong number of arguments (need 1 or 2)");
714
+
715
+ Check_Type(argv[0], T_STRING);
716
+ filename = StringValuePtr(argv[0]);
717
+
718
+ if (argc == 2)
719
+ {
720
+ switch (TYPE(argv[1])) {
721
+ case T_TRUE:
722
+ format = 1;
723
+ break;
724
+ case T_FALSE:
725
+ format = 0;
726
+ break;
727
+ default:
728
+ rb_raise(rb_eArgError, "The second parameter (format) must be true or false");
729
+ }
730
+ }
731
+
732
+ Data_Get_Struct(self, xmlDoc, xdoc);
733
+ len = xmlSaveFormatFileEnc(filename, xdoc, (const char*)xdoc->encoding, format);
734
+
735
+ if (len == -1)
736
+ rb_raise(rb_eIOError, "Could not write document");
737
+ else
738
+ return(INT2NUM(len));
739
+ }
740
+
741
+
742
+ /*
743
+ * call-seq:
744
+ * document.standalone? -> (true|false)
745
+ *
746
+ * Determine whether this is a standalone document.
747
+ */
748
+ static VALUE
749
+ rxml_document_standalone_q(VALUE self) {
750
+ xmlDocPtr xdoc;
751
+
752
+ Data_Get_Struct(self, xmlDoc, xdoc);
753
+ if (xdoc->standalone)
754
+ return(Qtrue);
755
+ else
756
+ return(Qfalse);
757
+ }
758
+
759
+
760
+ /*
761
+ * call-seq:
762
+ * document.to_s({format=true,encoding) -> "xml"
763
+ *
764
+ * Coerce this document to a string representation
765
+ * of it's XML. The default is to pretty format, but this
766
+ * depends Parser#indent_tree_output==true or
767
+ * Parser#default_keep_blanks==false.
768
+ *
769
+ * The encoding is not applied to the document, but is
770
+ * encoding target of the resulting string.
771
+ */
772
+ static VALUE
773
+ rxml_document_to_s(int argc, VALUE *argv, VALUE self) {
774
+ xmlDocPtr xdoc;
775
+
776
+ xmlChar *result, *encoding=NULL;
777
+ int format, len;
778
+ VALUE rresult;
779
+
780
+ switch (argc) {
781
+ case 0:
782
+ format = 1;
783
+ break;
784
+ case 2:
785
+ if (TYPE(argv[1]) == T_STRING)
786
+ encoding=(xmlChar *)StringValuePtr(argv[1]);
787
+ case 1:
788
+ if (TYPE(argv[0]) == T_TRUE)
789
+ format = 1;
790
+ else if (TYPE(argv[0]) == T_FALSE)
791
+ format = 0;
792
+ else
793
+ rb_raise(rb_eTypeError, "wrong type of argument, must be bool");
794
+ break;
795
+ default:
796
+ rb_raise(rb_eArgError, "wrong number of arguments (0 or 1)");
797
+ }
798
+
799
+ Data_Get_Struct(self, xmlDoc, xdoc);
800
+ if (xdoc == NULL) {
801
+ return(Qnil);
802
+ } else if (encoding != NULL) {
803
+ if (format) {
804
+ xmlDocDumpFormatMemoryEnc(xdoc, &result, &len,
805
+ (const char*)encoding, format);
806
+ } else {
807
+ xmlDocDumpMemoryEnc(xdoc, &result, &len,
808
+ (const char *)encoding);
809
+ }
810
+ } else {
811
+ if (format)
812
+ xmlDocDumpFormatMemory(xdoc, &result, &len, format);
813
+ else
814
+ xmlDocDumpMemory(xdoc, &result, &len);
815
+ }
816
+ rresult=rb_str_new((const char*)result,len);
817
+ xmlFree(result);
818
+ return rresult;
819
+ }
820
+
821
+
822
+ /*
823
+ * call-seq:
824
+ * document.url -> "url"
825
+ *
826
+ * Obtain this document's source URL, if any.
827
+ */
828
+ static VALUE
829
+ rxml_document_url_get(VALUE self) {
830
+ xmlDocPtr xdoc;
831
+
832
+ Data_Get_Struct(self, xmlDoc, xdoc);
833
+ if (xdoc->URL == NULL)
834
+ return(Qnil);
835
+ else
836
+ return(rb_str_new2((const char*)xdoc->URL));
837
+ }
838
+
839
+
840
+ /*
841
+ * call-seq:
842
+ * document.version -> "version"
843
+ *
844
+ * Obtain the XML version specified by this document.
845
+ */
846
+ static VALUE
847
+ rxml_document_version_get(VALUE self) {
848
+ xmlDocPtr xdoc;
849
+
850
+ Data_Get_Struct(self, xmlDoc, xdoc);
851
+ if (xdoc->version == NULL)
852
+ return(Qnil);
853
+ else
854
+ return(rb_str_new2((const char*)xdoc->version));
855
+ }
856
+
857
+
858
+ /*
859
+ * call-seq:
860
+ * document.xinclude -> num
861
+ *
862
+ * Process xinclude directives in this document.
863
+ */
864
+ static VALUE
865
+ rxml_document_xinclude(VALUE self) {
866
+ #ifdef LIBXML_XINCLUDE_ENABLED
867
+ xmlDocPtr xdoc;
868
+
869
+ int ret;
870
+
871
+ Data_Get_Struct(self, xmlDoc, xdoc);
872
+ ret = xmlXIncludeProcess(xdoc);
873
+ if (ret >= 0)
874
+ {
875
+ return(INT2NUM(ret));
876
+ }
877
+ else
878
+ {
879
+ rxml_raise(&xmlLastError);
880
+ return Qnil;
881
+ }
882
+ #else
883
+ rb_warn("libxml was compiled without XInclude support. Please recompile libxml and ruby-libxml");
884
+ return(Qfalse);
885
+ #endif
886
+ }
887
+
888
+ void
889
+ LibXML_validity_error(void * ctxt, const char * msg, va_list ap)
890
+ {
891
+ if (rb_block_given_p()) {
892
+ char buff[1024];
893
+ snprintf(buff, 1024, msg, ap);
894
+ rb_yield(rb_ary_new3(2, rb_str_new2(buff), Qtrue));
895
+ } else {
896
+ fprintf(stderr, "error -- found validity error: ");
897
+ fprintf(stderr, msg, ap);
898
+ }
899
+ }
900
+
901
+ void
902
+ LibXML_validity_warning(void * ctxt, const char * msg, va_list ap)
903
+ {
904
+ if (rb_block_given_p()) {
905
+ char buff[1024];
906
+ snprintf(buff, 1024, msg, ap);
907
+ rb_yield(rb_ary_new3(2, rb_str_new2(buff), Qfalse));
908
+ } else {
909
+ fprintf(stderr, "warning -- found validity error: ");
910
+ fprintf(stderr, msg, ap);
911
+ }
912
+ }
913
+
914
+ /*
915
+ * call-seq:
916
+ * document.validate_schema(schema) -> (true|false)
917
+ *
918
+ * Validate this document against the specified XML::Schema.
919
+ *
920
+ * If a block is provided it is used as an error handler for validaten errors.
921
+ * The block is called with two argument, the message and a flag indication
922
+ * if the message is an error (true) or a warning (false).
923
+ */
924
+ static VALUE
925
+ rxml_document_validate_schema(VALUE self, VALUE schema) {
926
+ xmlSchemaValidCtxtPtr vptr;
927
+ xmlDocPtr xdoc;
928
+ xmlSchemaPtr xschema;
929
+ int is_invalid;
930
+
931
+ Data_Get_Struct(self, xmlDoc, xdoc);
932
+ Data_Get_Struct(schema, xmlSchema, xschema);
933
+
934
+ vptr = xmlSchemaNewValidCtxt(xschema);
935
+
936
+ xmlSchemaSetValidErrors(vptr, (xmlSchemaValidityErrorFunc)LibXML_validity_error,
937
+ (xmlSchemaValidityWarningFunc)LibXML_validity_warning, NULL);
938
+
939
+ is_invalid = xmlSchemaValidateDoc(vptr, xdoc);
940
+ xmlSchemaFreeValidCtxt(vptr);
941
+ if (is_invalid)
942
+ {
943
+ rxml_raise(&xmlLastError);
944
+ return Qfalse;
945
+ }
946
+ else
947
+ {
948
+ return Qtrue;
949
+ }
950
+ }
951
+
952
+ /*
953
+ * call-seq:
954
+ * document.validate_schema(relaxng) -> (true|false)
955
+ *
956
+ * Validate this document against the specified XML::RelaxNG.
957
+ *
958
+ * If a block is provided it is used as an error handler for validaten errors.
959
+ * The block is called with two argument, the message and a flag indication
960
+ * if the message is an error (true) or a warning (false).
961
+ */
962
+ static VALUE
963
+ rxml_document_validate_relaxng(VALUE self, VALUE relaxng) {
964
+ xmlRelaxNGValidCtxtPtr vptr;
965
+ xmlDocPtr xdoc;
966
+ xmlRelaxNGPtr xrelaxng;
967
+ int is_invalid;
968
+
969
+ Data_Get_Struct(self, xmlDoc, xdoc);
970
+ Data_Get_Struct(relaxng, xmlRelaxNG, xrelaxng);
971
+
972
+ vptr = xmlRelaxNGNewValidCtxt(xrelaxng);
973
+
974
+ xmlRelaxNGSetValidErrors(vptr, (xmlRelaxNGValidityErrorFunc)LibXML_validity_error,
975
+ (xmlRelaxNGValidityWarningFunc)LibXML_validity_warning, NULL);
976
+
977
+ is_invalid = xmlRelaxNGValidateDoc(vptr, xdoc);
978
+ xmlRelaxNGFreeValidCtxt(vptr);
979
+ if (is_invalid)
980
+ {
981
+ rxml_raise(&xmlLastError);
982
+ return Qfalse;
983
+ } else
984
+ {
985
+ return Qtrue;
986
+ }
987
+ }
988
+
989
+
990
+ /*
991
+ * call-seq:
992
+ * document.validate(dtd) -> (true|false)
993
+ *
994
+ * Validate this document against the specified XML::DTD.
995
+ */
996
+ static VALUE
997
+ rxml_document_validate_dtd(VALUE self, VALUE dtd) {
998
+ VALUE error = Qnil;
999
+ xmlValidCtxt ctxt;
1000
+ xmlDocPtr xdoc;
1001
+ xmlDtdPtr xdtd;
1002
+
1003
+ Data_Get_Struct(self, xmlDoc, xdoc);
1004
+ Data_Get_Struct(dtd, xmlDtd, xdtd);
1005
+
1006
+ ctxt.userData = &error;
1007
+ ctxt.error = (xmlValidityErrorFunc)LibXML_validity_error;
1008
+ ctxt.warning = (xmlValidityWarningFunc)LibXML_validity_warning;
1009
+
1010
+ ctxt.nodeNr = 0;
1011
+ ctxt.nodeTab = NULL;
1012
+ ctxt.vstateNr = 0;
1013
+ ctxt.vstateTab = NULL;
1014
+
1015
+ if (xmlValidateDtd(&ctxt, xdoc, xdtd))
1016
+ {
1017
+ return(Qtrue);
1018
+ }
1019
+ else
1020
+ {
1021
+ rxml_raise(&xmlLastError);
1022
+ return Qfalse;
1023
+ }
1024
+ }
1025
+
1026
+
1027
+ /*
1028
+ * call-seq:
1029
+ * document.reader -> reader
1030
+ *
1031
+ * Create a XML::Reader from the document. This is a shortcut to
1032
+ * XML::Reader.walker().
1033
+ */
1034
+ static VALUE
1035
+ rxml_document_reader(VALUE self)
1036
+ {
1037
+ return rxml_reader_new_walker(cXMLReader, self);
1038
+ }
1039
+
1040
+ // Rdoc needs to know
1041
+ #ifdef RDOC_NEVER_DEFINED
1042
+ mLibXML = rb_define_module("LibXML");
1043
+ mXML = rb_define_module_under(mLibXML, "XML");
1044
+ #endif
1045
+
1046
+ void
1047
+ ruby_init_xml_document(void) {
1048
+ cXMLDocument = rb_define_class_under(mXML, "Document", rb_cObject);
1049
+ rb_define_alloc_func(cXMLDocument, rxml_document_alloc);
1050
+
1051
+ rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1);
1052
+ rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0);
1053
+ rb_define_method(cXMLDocument, "child?", rxml_document_child_q, 0);
1054
+ rb_define_method(cXMLDocument, "compression", rxml_document_compression_get, 0);
1055
+ rb_define_method(cXMLDocument, "compression=", rxml_document_compression_set, 1);
1056
+ rb_define_method(cXMLDocument, "compression?", rxml_document_compression_q, 0);
1057
+ rb_define_method(cXMLDocument, "dump", rxml_document_dump, -1);
1058
+ rb_define_method(cXMLDocument, "debug_dump", rxml_document_debug_dump, -1);
1059
+ rb_define_method(cXMLDocument, "debug_dump_head", rxml_document_debug_dump_head, -1);
1060
+ rb_define_method(cXMLDocument, "debug_format_dump", rxml_document_debug_format_dump, -1);
1061
+ rb_define_method(cXMLDocument, "encoding", rxml_document_encoding_get, 0);
1062
+ rb_define_method(cXMLDocument, "encoding=", rxml_document_encoding_set, 1);
1063
+ rb_define_method(cXMLDocument, "format_dump", rxml_document_format_dump, -1);
1064
+ rb_define_method(cXMLDocument, "last", rxml_document_last_get, 0);
1065
+ rb_define_method(cXMLDocument, "last?", rxml_document_last_q, 0);
1066
+ rb_define_method(cXMLDocument, "next", rxml_document_next_get, 0);
1067
+ rb_define_method(cXMLDocument, "next?", rxml_document_next_q, 0);
1068
+ rb_define_method(cXMLDocument, "parent", rxml_document_parent_get, 0);
1069
+ rb_define_method(cXMLDocument, "parent?", rxml_document_parent_q, 0);
1070
+ rb_define_method(cXMLDocument, "prev", rxml_document_prev_get, 0);
1071
+ rb_define_method(cXMLDocument, "prev?", rxml_document_prev_q, 0);
1072
+ rb_define_method(cXMLDocument, "root", rxml_document_root_get, 0);
1073
+ rb_define_method(cXMLDocument, "root=", rxml_document_root_set, 1);
1074
+ rb_define_method(cXMLDocument, "save", rxml_document_save, -1);
1075
+ rb_define_method(cXMLDocument, "standalone?", rxml_document_standalone_q, 0);
1076
+ rb_define_method(cXMLDocument, "to_s", rxml_document_to_s, -1);
1077
+ rb_define_method(cXMLDocument, "url", rxml_document_url_get, 0);
1078
+ rb_define_method(cXMLDocument, "version", rxml_document_version_get, 0);
1079
+ rb_define_method(cXMLDocument, "xinclude", rxml_document_xinclude, 0);
1080
+ rb_define_method(cXMLDocument, "validate", rxml_document_validate_dtd, 1);
1081
+ rb_define_method(cXMLDocument, "validate_schema", rxml_document_validate_schema, 1);
1082
+ rb_define_method(cXMLDocument, "validate_relaxng", rxml_document_validate_relaxng, 1);
1083
+ rb_define_method(cXMLDocument, "reader", rxml_document_reader, 0);
1084
+ }