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

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