libxml-ruby 5.0.4 → 5.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY +10 -6
  3. data/README.rdoc +1 -1
  4. data/ext/libxml/extconf.rb +5 -0
  5. data/ext/libxml/ruby_xml.c +556 -556
  6. data/ext/libxml/ruby_xml_attributes.h +17 -17
  7. data/ext/libxml/ruby_xml_document.c +1129 -1129
  8. data/ext/libxml/ruby_xml_dtd.c +257 -257
  9. data/ext/libxml/ruby_xml_encoding.c +250 -250
  10. data/ext/libxml/ruby_xml_error.c +1003 -1003
  11. data/ext/libxml/ruby_xml_error.h +14 -14
  12. data/ext/libxml/ruby_xml_html_parser_context.c +351 -351
  13. data/ext/libxml/ruby_xml_input_cbg.c +188 -188
  14. data/ext/libxml/ruby_xml_namespace.c +151 -151
  15. data/ext/libxml/ruby_xml_parser.h +10 -10
  16. data/ext/libxml/ruby_xml_parser_context.c +1009 -1009
  17. data/ext/libxml/ruby_xml_parser_options.c +74 -74
  18. data/ext/libxml/ruby_xml_parser_options.h +10 -10
  19. data/ext/libxml/ruby_xml_sax2_handler.c +326 -326
  20. data/ext/libxml/ruby_xml_sax_parser.c +108 -108
  21. data/ext/libxml/ruby_xml_version.h +9 -9
  22. data/lib/libxml/attr.rb +122 -122
  23. data/lib/libxml/attr_decl.rb +80 -80
  24. data/lib/libxml/attributes.rb +13 -13
  25. data/lib/libxml/document.rb +194 -194
  26. data/lib/libxml/error.rb +95 -95
  27. data/lib/libxml/hpricot.rb +77 -77
  28. data/lib/libxml/html_parser.rb +96 -96
  29. data/lib/libxml/namespace.rb +61 -61
  30. data/lib/libxml/namespaces.rb +37 -37
  31. data/lib/libxml/node.rb +323 -323
  32. data/lib/libxml/parser.rb +102 -102
  33. data/lib/libxml/sax_callbacks.rb +179 -179
  34. data/lib/libxml/sax_parser.rb +40 -40
  35. data/lib/libxml/tree.rb +28 -28
  36. data/lib/libxml.rb +4 -4
  37. data/lib/xml/libxml.rb +10 -10
  38. data/lib/xml.rb +13 -13
  39. data/libxml-ruby.gemspec +50 -49
  40. data/test/test_document.rb +140 -140
  41. data/test/test_document_write.rb +142 -142
  42. data/test/test_dtd.rb +126 -126
  43. data/test/test_encoding.rb +126 -126
  44. data/test/test_error.rb +194 -194
  45. data/test/test_helper.rb +20 -20
  46. data/test/test_namespace.rb +58 -58
  47. data/test/test_node.rb +235 -235
  48. data/test/test_node_write.rb +93 -93
  49. data/test/test_parser.rb +333 -333
  50. data/test/test_reader.rb +364 -364
  51. data/test/test_xml.rb +168 -168
  52. metadata +5 -4
@@ -1,1129 +1,1129 @@
1
- /*
2
- * Document-class: LibXML::XML::Document
3
- *
4
- * The XML::Document class provides a tree based API for working
5
- * with xml documents. You may directly create a document and
6
- * manipulate it, or create a document from a data source by
7
- * using an XML::Parser object.
8
- *
9
- * To read a document from a file:
10
- *
11
- * doc = XML::Document.file('my_file')
12
- *
13
- * To use a parser to read a document:
14
- *
15
- * parser = XML::Parser.file('my_file')
16
- * doc = parser.parse
17
- *
18
- * To create a document from scratch:
19
- *
20
- * doc = XML::Document.new()
21
- * doc.root = XML::Node.new('root_node')
22
- * doc.root << XML::Node.new('elem1')
23
- * doc.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8)
24
- *
25
- * To write a document to a file:
26
- *
27
- * doc = XML::Document.new()
28
- * doc.root = XML::Node.new('root_node')
29
- * root = doc.root
30
- *
31
- * root << elem1 = XML::Node.new('elem1')
32
- * elem1['attr1'] = 'val1'
33
- * elem1['attr2'] = 'val2'
34
- *
35
- * root << elem2 = XML::Node.new('elem2')
36
- * elem2['attr1'] = 'val1'
37
- * elem2['attr2'] = 'val2'
38
- *
39
- * root << elem3 = XML::Node.new('elem3')
40
- * elem3 << elem4 = XML::Node.new('elem4')
41
- * elem3 << elem5 = XML::Node.new('elem5')
42
- *
43
- * elem5 << elem6 = XML::Node.new('elem6')
44
- * elem6 << 'Content for element 6'
45
- *
46
- * elem3['attr'] = 'baz'
47
- *
48
- * doc.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8)
49
- */
50
-
51
- #include <stdarg.h>
52
- #include "ruby_libxml.h"
53
- #include "ruby_xml_document.h"
54
-
55
- #include <libxml/c14n.h>
56
- #include <libxml/debugXML.h>
57
- #include <libxml/relaxng.h>
58
- #include <libxml/xmlschemas.h>
59
- #include <libxml/xinclude.h>
60
-
61
- VALUE cXMLDocument;
62
-
63
- void rxml_document_free(xmlDocPtr xdoc)
64
- {
65
- xdoc->_private = NULL;
66
- xmlFreeDoc(xdoc);
67
- }
68
-
69
- VALUE rxml_document_wrap(xmlDocPtr xdoc)
70
- {
71
- VALUE result = Qnil;
72
-
73
- // Is this node is already wrapped?
74
- if (xdoc->_private != NULL)
75
- {
76
- result = (VALUE)xdoc->_private;
77
- }
78
- else
79
- {
80
- result = Data_Wrap_Struct(cXMLDocument, NULL, rxml_document_free, xdoc);
81
- xdoc->_private = (void*)result;
82
- }
83
-
84
- return result;
85
- }
86
-
87
- /*
88
- * call-seq:
89
- * XML::Document.alloc(xml_version = 1.0) -> document
90
- *
91
- * Alocates a new XML::Document, optionally specifying the
92
- * XML version.
93
- */
94
- static VALUE rxml_document_alloc(VALUE klass)
95
- {
96
- return Data_Wrap_Struct(klass, NULL, rxml_document_free, NULL);
97
- }
98
-
99
- /*
100
- * call-seq:
101
- * XML::Document.initialize(xml_version = 1.0) -> document
102
- *
103
- * Initializes a new XML::Document, optionally specifying the
104
- * XML version.
105
- */
106
- static VALUE rxml_document_initialize(int argc, VALUE *argv, VALUE self)
107
- {
108
- xmlDocPtr xdoc;
109
- VALUE xmlver;
110
-
111
- switch (argc)
112
- {
113
- case 0:
114
- xmlver = rb_str_new2("1.0");
115
- break;
116
- case 1:
117
- rb_scan_args(argc, argv, "01", &xmlver);
118
- break;
119
- default:
120
- rb_raise(rb_eArgError, "wrong number of arguments (need 0 or 1)");
121
- }
122
-
123
- Check_Type(xmlver, T_STRING);
124
- xdoc = xmlNewDoc((xmlChar*) StringValuePtr(xmlver));
125
-
126
- // Link the ruby object to the document and the document to the ruby object
127
- RDATA(self)->data = xdoc;
128
- xdoc->_private = (void*)self;
129
-
130
- return self;
131
- }
132
-
133
- /* XML_C14N_1* constants are not defined until libxml 1.1.25, so if they
134
- are not defined then define these constants to map to zero,
135
- the same value as XML_C14N_1_0. */
136
-
137
- /* XML_C14N* constants are not defined until libxml 1.1.25, so define them
138
- if needed so things compile. */
139
- #ifndef XML_C14N_1_0
140
- #define XML_C14N_1_0 0
141
- #define XML_C14N_EXCLUSIVE_1_0 XML_C14N_1_0
142
- #define XML_C14N_1_1 XML_C14N_1_0
143
- #endif
144
-
145
- /*
146
- * :call-seq:
147
- * document.canonicalize -> String
148
- * document.canonicalize(options) -> String
149
- *
150
- * Returns a string containing the canonicalized form of the document.
151
- * Implemented to include all of the functionality of the libxml2
152
- * {xmlC14NDocDumpMemory}[http://xmlsoft.org/html/libxml-c14n.html#xmlC14NDocDumpMemory]
153
- * method.
154
- *
155
- * === Options
156
- * [comments]
157
- * * *Type:* Boolean
158
- * * *Default:* false
159
- * Specifies if comments should be output.
160
- * * Must be boolean, otherwise defaults to false.
161
- * [inclusive_ns_prefixes]
162
- * * *Type:* Array of strings
163
- * * *Default:* empty array
164
- * Array of namespace prefixes to include in exclusive canonicalization only.
165
- * * The last item in the list is reserved for a NULL value because the C method demands it, therefore
166
- * up to the first 255 valid entries will be used.
167
- * * <em>Only used for *XML_C14N_EXCLUSIVE_1_0* mode. Ignored otherwise.</em>
168
- * [mode]
169
- * * *Type:* XML::Document Constant
170
- * * *Default:* XML_C14N_1_0
171
- * Specifies the mode of canonicalization.
172
- * * *NOTE:* XML_C14N_1_1 may not be fully implemented upon compilation due to C library compatibility.
173
- * Please check if XML_C14N_1_0 and XML_C14N_1_1 are the same value prior to using XML_C14N_1_1.
174
- * [nodes]
175
- * * *Type:* Array of XML::Node objects
176
- * * *Default:* empty array
177
- * XML::Nodes to include in the canonicalization process
178
- * * For large lists of more than 256 valid namespaces, up to the first 256 valid entries will be used.
179
- */
180
- #define C14N_NS_LIMIT 256
181
- #define C14N_NODESET_LIMIT 256
182
-
183
- static VALUE
184
- rxml_document_canonicalize(int argc, VALUE *argv, VALUE self)
185
- {
186
- VALUE result = Qnil;
187
- xmlDocPtr xdoc;
188
- xmlChar *buffer = NULL;
189
- VALUE option_hash = Qnil;
190
- VALUE o_nodes = Qnil;
191
-
192
- // :comments option
193
- int comments = 0;
194
- // :mode option
195
- int c14n_mode = XML_C14N_1_0;
196
- // :inclusive_ns_prefixes option (ARRAY)
197
-
198
- xmlChar * inc_ns_prefixes_ptr[C14N_NS_LIMIT];
199
-
200
- // :nodes option (ARRAY)
201
- xmlNodePtr node_ptr_array[C14N_NODESET_LIMIT];
202
- xmlNodeSet nodeset = {
203
- 0, C14N_NODESET_LIMIT, NULL
204
- };
205
-
206
- /* At least one NULL value must be defined in the array or the extension will
207
- * segfault when using XML_C14N_EXCLUSIVE_1_0 mode.
208
- * API docs: "list of inclusive namespace prefixes ended with a NULL"
209
- */
210
- inc_ns_prefixes_ptr[0] = NULL;
211
-
212
- rb_scan_args(argc, argv, "01", &option_hash);
213
- // Do stuff if ruby hash passed as argument
214
- if (!NIL_P(option_hash))
215
- {
216
- VALUE o_comments = Qnil;
217
- VALUE o_mode = Qnil;
218
- VALUE o_i_ns_prefixes = Qnil;
219
-
220
- Check_Type(option_hash, T_HASH);
221
-
222
- o_comments = rb_hash_aref(option_hash, ID2SYM(rb_intern("comments")));
223
- comments = (RTEST(o_comments) ? 1 : 0);
224
-
225
- o_mode = rb_hash_aref(option_hash, ID2SYM(rb_intern("mode")));
226
- if (!NIL_P(o_mode))
227
- {
228
- Check_Type(o_mode, T_FIXNUM);
229
- c14n_mode = NUM2INT(o_mode);
230
- //TODO: clean this up
231
- //if (c14n_mode > 2) { c14n_mode = 0; }
232
- //mode_int = (NUM2INT(o_mode) > 2 ? 0 : NUM2INT(o_mode));
233
- }
234
-
235
- o_i_ns_prefixes = rb_hash_aref(option_hash, ID2SYM(rb_intern("inclusive_ns_prefixes")));
236
- if (!NIL_P(o_i_ns_prefixes))
237
- {
238
- int i;
239
- int p = 0; //pointer array index
240
- VALUE *list_in = NULL;
241
- long list_size = 0;
242
-
243
- Check_Type(o_i_ns_prefixes, T_ARRAY);
244
- list_in = RARRAY_PTR(o_i_ns_prefixes);
245
- list_size = RARRAY_LEN(o_i_ns_prefixes);
246
-
247
- if (list_size > 0)
248
- {
249
- for(i=0; i < list_size; ++i) {
250
- if (p >= C14N_NS_LIMIT) { break; }
251
-
252
- if (RTEST(list_in[i]))
253
- {
254
- if (TYPE(list_in[i]) == T_STRING)
255
- {
256
- inc_ns_prefixes_ptr[p] = (xmlChar *)StringValueCStr(list_in[i]);
257
- p++;
258
- }
259
- }
260
- }
261
- }
262
-
263
- // ensure p is not out of bound
264
- p = (p >= C14N_NS_LIMIT ? (C14N_NS_LIMIT-1) : p);
265
-
266
- // API docs: "list of inclusive namespace prefixes ended with a NULL"
267
- // Set last element to NULL
268
- inc_ns_prefixes_ptr[p] = NULL;
269
- }
270
- //o_ns_prefixes will free at end of block
271
-
272
- o_nodes = rb_hash_aref(option_hash, ID2SYM(rb_intern("nodes")));
273
- if (!NIL_P(o_nodes))
274
- {
275
- int i;
276
- int p = 0; // index of pointer array
277
- VALUE * list_in = NULL;
278
- long node_list_size = 0;
279
-
280
- if (CLASS_OF(o_nodes) == cXMLXPathObject)
281
- {
282
- o_nodes = rb_funcall(o_nodes, rb_intern("to_a"), 0);
283
- }
284
- else
285
- {
286
- Check_Type(o_nodes, T_ARRAY);
287
- }
288
- list_in = RARRAY_PTR(o_nodes);
289
- node_list_size = RARRAY_LEN(o_nodes);
290
-
291
- for (i=0; i < node_list_size; ++i)
292
- {
293
- if (p >= C14N_NODESET_LIMIT) { break; }
294
-
295
- if (RTEST(list_in[i]))
296
- {
297
- xmlNodePtr node_ptr;
298
- Data_Get_Struct(list_in[i], xmlNode, node_ptr);
299
- node_ptr_array[p] = node_ptr;
300
- p++;
301
- }
302
- }
303
-
304
- // Need to set values in nodeset struct
305
- nodeset.nodeNr = (node_list_size > C14N_NODESET_LIMIT ?
306
- C14N_NODESET_LIMIT :
307
- (int)node_list_size);
308
- nodeset.nodeTab = node_ptr_array;
309
- }
310
- }//option_hash
311
-
312
- Data_Get_Struct(self, xmlDoc, xdoc);
313
- xmlC14NDocDumpMemory(xdoc,
314
- (nodeset.nodeNr == 0 ? NULL : &nodeset),
315
- c14n_mode,
316
- inc_ns_prefixes_ptr,
317
- comments,
318
- &buffer);
319
-
320
- if (buffer)
321
- {
322
- result = rxml_new_cstr( buffer, NULL);
323
- xmlFree(buffer);
324
- }
325
-
326
- return result;
327
- }
328
-
329
-
330
- /*
331
- * call-seq:
332
- * document.compression -> num
333
- *
334
- * Obtain this document's compression mode identifier.
335
- */
336
- static VALUE rxml_document_compression_get(VALUE self)
337
- {
338
- #ifdef HAVE_ZLIB_H
339
- xmlDocPtr xdoc;
340
-
341
- int compmode;
342
- Data_Get_Struct(self, xmlDoc, xdoc);
343
-
344
- compmode = xmlGetDocCompressMode(xdoc);
345
- if (compmode == -1)
346
- return(Qnil);
347
- else
348
- return(INT2NUM(compmode));
349
- #else
350
- rb_warn("libxml not compiled with zlib support");
351
- return (Qfalse);
352
- #endif
353
- }
354
-
355
- /*
356
- * call-seq:
357
- * document.compression = num
358
- *
359
- * Set this document's compression mode.
360
- */
361
- static VALUE rxml_document_compression_set(VALUE self, VALUE num)
362
- {
363
- #ifdef HAVE_ZLIB_H
364
- xmlDocPtr xdoc;
365
-
366
- int compmode;
367
- Check_Type(num, T_FIXNUM);
368
- Data_Get_Struct(self, xmlDoc, xdoc);
369
-
370
- if (xdoc == NULL)
371
- {
372
- return(Qnil);
373
- }
374
- else
375
- {
376
- xmlSetDocCompressMode(xdoc, NUM2INT(num));
377
-
378
- compmode = xmlGetDocCompressMode(xdoc);
379
- if (compmode == -1)
380
- return(Qnil);
381
- else
382
- return(INT2NUM(compmode));
383
- }
384
- #else
385
- rb_warn("libxml compiled without zlib support");
386
- return (Qfalse);
387
- #endif
388
- }
389
-
390
- /*
391
- * call-seq:
392
- * document.compression? -> (true|false)
393
- *
394
- * Determine whether this document is compressed.
395
- */
396
- static VALUE rxml_document_compression_q(VALUE self)
397
- {
398
- #ifdef HAVE_ZLIB_H
399
- xmlDocPtr xdoc;
400
-
401
- Data_Get_Struct(self, xmlDoc, xdoc);
402
-
403
- if (xdoc->compression != -1)
404
- return(Qtrue);
405
- else
406
- return(Qfalse);
407
- #else
408
- rb_warn("libxml compiled without zlib support");
409
- return (Qfalse);
410
- #endif
411
- }
412
-
413
- /*
414
- * call-seq:
415
- * document.child -> node
416
- *
417
- * Get this document's child node.
418
- */
419
- static VALUE rxml_document_child_get(VALUE self)
420
- {
421
- xmlDocPtr xdoc;
422
- Data_Get_Struct(self, xmlDoc, xdoc);
423
-
424
- if (xdoc->children == NULL)
425
- return (Qnil);
426
-
427
- return rxml_node_wrap(xdoc->children);
428
- }
429
-
430
- /*
431
- * call-seq:
432
- * document.child? -> (true|false)
433
- *
434
- * Determine whether this document has a child node.
435
- */
436
- static VALUE rxml_document_child_q(VALUE self)
437
- {
438
- xmlDocPtr xdoc;
439
- Data_Get_Struct(self, xmlDoc, xdoc);
440
-
441
- if (xdoc->children == NULL)
442
- return (Qfalse);
443
- else
444
- return (Qtrue);
445
- }
446
-
447
-
448
- /*
449
- * call-seq:
450
- * node.debug -> true|false
451
- *
452
- * Print libxml debugging information to stdout.
453
- * Requires that libxml was compiled with debugging enabled.
454
- */
455
- static VALUE rxml_document_debug(VALUE self)
456
- {
457
- #ifdef LIBXML_DEBUG_ENABLED
458
- xmlDocPtr xdoc;
459
- Data_Get_Struct(self, xmlDoc, xdoc);
460
- xmlDebugDumpDocument(NULL, xdoc);
461
- return Qtrue;
462
- #else
463
- rb_warn("libxml was compiled without debugging support.");
464
- return Qfalse;
465
- #endif
466
- }
467
-
468
- /*
469
- * call-seq:
470
- * document.encoding -> XML::Encoding::UTF_8
471
- *
472
- * Returns the LibXML encoding constant specified by this document.
473
- */
474
- static VALUE rxml_document_encoding_get(VALUE self)
475
- {
476
- xmlDocPtr xdoc;
477
- const char *xencoding;
478
- Data_Get_Struct(self, xmlDoc, xdoc);
479
-
480
- xencoding = (const char*)xdoc->encoding;
481
- return INT2NUM(xmlParseCharEncoding(xencoding));
482
- }
483
-
484
-
485
- /*
486
- * call-seq:
487
- * document.rb_encoding -> Encoding
488
- *
489
- * Returns the Ruby encoding specified by this document
490
- * (available on Ruby 1.9.x and higher).
491
- */
492
- static VALUE rxml_document_rb_encoding_get(VALUE self)
493
- {
494
- xmlDocPtr xdoc;
495
- rb_encoding* rbencoding;
496
- Data_Get_Struct(self, xmlDoc, xdoc);
497
-
498
- rbencoding = rxml_xml_encoding_to_rb_encoding(mXMLEncoding, xmlParseCharEncoding((const char*)xdoc->encoding));
499
- return rb_enc_from_encoding(rbencoding);
500
- }
501
-
502
- /*
503
- * call-seq:
504
- * document.encoding = XML::Encoding::UTF_8
505
- *
506
- * Set the encoding for this document.
507
- */
508
- static VALUE rxml_document_encoding_set(VALUE self, VALUE encoding)
509
- {
510
- xmlDocPtr xdoc;
511
- const char* xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(encoding));
512
-
513
- Data_Get_Struct(self, xmlDoc, xdoc);
514
-
515
- if (xdoc->encoding != NULL)
516
- xmlFree((xmlChar *) xdoc->encoding);
517
-
518
- xdoc->encoding = xmlStrdup((xmlChar *)xencoding);
519
- return self;
520
- }
521
-
522
- /*
523
- * call-seq:
524
- * document.import(node) -> XML::Node
525
- *
526
- * Creates a copy of the node that can be inserted into the
527
- * current document.
528
- *
529
- * IMPORTANT - The returned node MUST be inserted into the document.
530
- * This is because the returned node refereces internal LibXML data
531
- * structures owned by the document. Therefore, if the document is
532
- * is freed before the the node is freed a segmentation fault will occur.
533
- */
534
- static VALUE rxml_document_import(VALUE self, VALUE node)
535
- {
536
- xmlDocPtr xdoc;
537
- xmlNodePtr xnode, xresult;
538
-
539
- Data_Get_Struct(self, xmlDoc, xdoc);
540
- Data_Get_Struct(node, xmlNode, xnode);
541
-
542
- xresult = xmlDocCopyNode(xnode, xdoc, 1);
543
-
544
- if (xresult == NULL)
545
- rxml_raise(xmlGetLastError());
546
-
547
- return rxml_node_wrap(xresult);
548
- }
549
-
550
- /*
551
- * call-seq:
552
- * document.last -> node
553
- *
554
- * Obtain the last node.
555
- */
556
- static VALUE rxml_document_last_get(VALUE self)
557
- {
558
- xmlDocPtr xdoc;
559
-
560
- Data_Get_Struct(self, xmlDoc, xdoc);
561
-
562
- if (xdoc->last == NULL)
563
- return (Qnil);
564
-
565
- return rxml_node_wrap(xdoc->last);
566
- }
567
-
568
- /*
569
- * call-seq:
570
- * document.last? -> (true|false)
571
- *
572
- * Determine whether there is a last node.
573
- */
574
- static VALUE rxml_document_last_q(VALUE self)
575
- {
576
- xmlDocPtr xdoc;
577
-
578
- Data_Get_Struct(self, xmlDoc, xdoc);
579
-
580
- if (xdoc->last == NULL)
581
- return (Qfalse);
582
- else
583
- return (Qtrue);
584
- }
585
-
586
- /*
587
- * call-seq:
588
- * document.next -> node
589
- *
590
- * Obtain the next node.
591
- */
592
- static VALUE rxml_document_next_get(VALUE self)
593
- {
594
- xmlDocPtr xdoc;
595
-
596
- Data_Get_Struct(self, xmlDoc, xdoc);
597
-
598
- if (xdoc->next == NULL)
599
- return (Qnil);
600
-
601
- return rxml_node_wrap(xdoc->next);
602
- }
603
-
604
- /*
605
- * call-seq:
606
- * document.next? -> (true|false)
607
- *
608
- * Determine whether there is a next node.
609
- */
610
- static VALUE rxml_document_next_q(VALUE self)
611
- {
612
- xmlDocPtr xdoc;
613
-
614
- Data_Get_Struct(self, xmlDoc, xdoc);
615
-
616
- if (xdoc->next == NULL)
617
- return (Qfalse);
618
- else
619
- return (Qtrue);
620
- }
621
-
622
- /*
623
- * call-seq:
624
- * node.type -> num
625
- *
626
- * Obtain this node's type identifier.
627
- */
628
- static VALUE rxml_document_node_type(VALUE self)
629
- {
630
- xmlNodePtr xnode;
631
- Data_Get_Struct(self, xmlNode, xnode);
632
- return (INT2NUM(xnode->type));
633
- }
634
-
635
- /*
636
- * call-seq:
637
- * document.parent -> node
638
- *
639
- * Obtain the parent node.
640
- */
641
- static VALUE rxml_document_parent_get(VALUE self)
642
- {
643
- xmlDocPtr xdoc;
644
-
645
- Data_Get_Struct(self, xmlDoc, xdoc);
646
-
647
- if (xdoc->parent == NULL)
648
- return (Qnil);
649
-
650
- return rxml_node_wrap(xdoc->parent);
651
- }
652
-
653
- /*
654
- * call-seq:
655
- * document.parent? -> (true|false)
656
- *
657
- * Determine whether there is a parent node.
658
- */
659
- static VALUE rxml_document_parent_q(VALUE self)
660
- {
661
- xmlDocPtr xdoc;
662
-
663
- Data_Get_Struct(self, xmlDoc, xdoc);
664
-
665
- if (xdoc->parent == NULL)
666
- return (Qfalse);
667
- else
668
- return (Qtrue);
669
- }
670
-
671
- /*
672
- * call-seq:
673
- * document.prev -> node
674
- *
675
- * Obtain the previous node.
676
- */
677
- static VALUE rxml_document_prev_get(VALUE self)
678
- {
679
- xmlDocPtr xdoc;
680
-
681
- Data_Get_Struct(self, xmlDoc, xdoc);
682
-
683
- if (xdoc->prev == NULL)
684
- return (Qnil);
685
-
686
- return rxml_node_wrap(xdoc->prev);
687
- }
688
-
689
- /*
690
- * call-seq:
691
- * document.prev? -> (true|false)
692
- *
693
- * Determine whether there is a previous node.
694
- */
695
- static VALUE rxml_document_prev_q(VALUE self)
696
- {
697
- xmlDocPtr xdoc;
698
-
699
- Data_Get_Struct(self, xmlDoc, xdoc);
700
-
701
- if (xdoc->prev == NULL)
702
- return (Qfalse);
703
- else
704
- return (Qtrue);
705
- }
706
-
707
- /*
708
- * call-seq:
709
- * document.root -> node
710
- *
711
- * Obtain the root node.
712
- */
713
- static VALUE rxml_document_root_get(VALUE self)
714
- {
715
- xmlDocPtr xdoc;
716
- xmlNodePtr root;
717
-
718
- Data_Get_Struct(self, xmlDoc, xdoc);
719
- root = xmlDocGetRootElement(xdoc);
720
-
721
- if (root == NULL)
722
- return (Qnil);
723
-
724
- return rxml_node_wrap(root);
725
- }
726
-
727
- /*
728
- * call-seq:
729
- * document.root = node
730
- *
731
- * Set the root node.
732
- */
733
- static VALUE rxml_document_root_set(VALUE self, VALUE node)
734
- {
735
- xmlDocPtr xdoc;
736
- xmlNodePtr xnode;
737
-
738
- if (rb_obj_is_kind_of(node, cXMLNode) == Qfalse)
739
- rb_raise(rb_eTypeError, "must pass an XML::Node type object");
740
-
741
- Data_Get_Struct(self, xmlDoc, xdoc);
742
- Data_Get_Struct(node, xmlNode, xnode);
743
-
744
- if (xnode->doc != NULL && xnode->doc != xdoc)
745
- rb_raise(eXMLError, "Nodes belong to different documents. You must first import the node by calling LibXML::XML::Document.import");
746
-
747
- xmlDocSetRootElement(xdoc, xnode);
748
-
749
- // Ruby no longer manages this nodes memory
750
- rxml_node_unmanage(xnode, node);
751
-
752
- return node;
753
- }
754
-
755
- /*
756
- * call-seq:
757
- * document.save(filename) -> int
758
- * document.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8) -> int
759
- *
760
- * Saves a document to a file. You may provide an optional hash table
761
- * to control how the string is generated. Valid options are:
762
- *
763
- * :indent - Specifies if the string should be indented. The default value
764
- * is true. Note that indentation is only added if both :indent is
765
- * true and XML.indent_tree_output is true. If :indent is set to false,
766
- * then both indentation and line feeds are removed from the result.
767
- *
768
- * :encoding - Specifies the output encoding of the string. It
769
- * defaults to the original encoding of the document (see
770
- * #encoding. To override the orginal encoding, use one of the
771
- * XML::Encoding encoding constants. */
772
- static VALUE rxml_document_save(int argc, VALUE *argv, VALUE self)
773
- {
774
- VALUE options = Qnil;
775
- VALUE filename = Qnil;
776
- xmlDocPtr xdoc;
777
- int indent = 1;
778
- const char *xfilename;
779
- const xmlChar *xencoding;
780
- int length;
781
-
782
- rb_scan_args(argc, argv, "11", &filename, &options);
783
-
784
- Check_Type(filename, T_STRING);
785
- xfilename = StringValuePtr(filename);
786
-
787
- Data_Get_Struct(self, xmlDoc, xdoc);
788
- xencoding = xdoc->encoding;
789
-
790
- if (!NIL_P(options))
791
- {
792
- VALUE rencoding, rindent;
793
- Check_Type(options, T_HASH);
794
- rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
795
- rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
796
-
797
- if (rindent == Qfalse)
798
- indent = 0;
799
-
800
- if (rencoding != Qnil)
801
- {
802
- xencoding = (const xmlChar*)xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
803
- if (!xencoding)
804
- rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
805
- }
806
- }
807
-
808
- length = xmlSaveFormatFileEnc(xfilename, xdoc, (const char*)xencoding, indent);
809
-
810
- if (length == -1)
811
- rxml_raise(xmlGetLastError());
812
-
813
- return (INT2NUM(length));
814
- }
815
-
816
- /*
817
- * call-seq:
818
- * document.standalone? -> (true|false)
819
- *
820
- * Determine whether this is a standalone document.
821
- */
822
- static VALUE rxml_document_standalone_q(VALUE self)
823
- {
824
- xmlDocPtr xdoc;
825
-
826
- Data_Get_Struct(self, xmlDoc, xdoc);
827
- if (xdoc->standalone)
828
- return (Qtrue);
829
- else
830
- return (Qfalse);
831
- }
832
-
833
- /*
834
- * call-seq:
835
- * document.to_s -> "string"
836
- * document.to_s(:indent => true, :encoding => XML::Encoding::UTF_8) -> "string"
837
- *
838
- * Converts a document, and all of its children, to a string representation.
839
- * You may provide an optional hash table to control how the string is
840
- * generated. Valid options are:
841
- *
842
- * :indent - Specifies if the string should be indented. The default value
843
- * is true. Note that indentation is only added if both :indent is
844
- * true and XML.indent_tree_output is true. If :indent is set to false,
845
- * then both indentation and line feeds are removed from the result.
846
- *
847
- * :encoding - Specifies the output encoding of the string. It
848
- * defaults to XML::Encoding::UTF8. To change it, use one of the
849
- * XML::Encoding encoding constants. */
850
- static VALUE rxml_document_to_s(int argc, VALUE *argv, VALUE self)
851
- {
852
- VALUE result;
853
- VALUE options = Qnil;
854
- xmlDocPtr xdoc;
855
- int indent = 1;
856
- const xmlChar *xencoding = (const xmlChar*) "UTF-8";
857
- xmlChar *buffer;
858
- int length;
859
-
860
- rb_scan_args(argc, argv, "01", &options);
861
-
862
- if (!NIL_P(options))
863
- {
864
- VALUE rencoding, rindent;
865
- Check_Type(options, T_HASH);
866
- rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
867
- rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
868
-
869
- if (rindent == Qfalse)
870
- indent = 0;
871
-
872
- if (rencoding != Qnil)
873
- {
874
- xencoding = (const xmlChar*)xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
875
- if (!xencoding)
876
- rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
877
- }
878
- }
879
-
880
- Data_Get_Struct(self, xmlDoc, xdoc);
881
- xmlDocDumpFormatMemoryEnc(xdoc, &buffer, &length, (const char*)xencoding, indent);
882
-
883
- result = rxml_new_cstr(buffer, xencoding);
884
- xmlFree(buffer);
885
- return result;
886
- }
887
-
888
- /*
889
- * call-seq:
890
- * document.url -> "url"
891
- *
892
- * Obtain this document's source URL, if any.
893
- */
894
- static VALUE rxml_document_url_get(VALUE self)
895
- {
896
- xmlDocPtr xdoc;
897
-
898
- Data_Get_Struct(self, xmlDoc, xdoc);
899
- if (xdoc->URL == NULL)
900
- return (Qnil);
901
- else
902
- return (rxml_new_cstr( xdoc->URL, NULL));
903
- }
904
-
905
- /*
906
- * call-seq:
907
- * document.version -> "version"
908
- *
909
- * Obtain the XML version specified by this document.
910
- */
911
- static VALUE rxml_document_version_get(VALUE self)
912
- {
913
- xmlDocPtr xdoc;
914
-
915
- Data_Get_Struct(self, xmlDoc, xdoc);
916
- if (xdoc->version == NULL)
917
- return (Qnil);
918
- else
919
- return (rxml_new_cstr( xdoc->version, NULL));
920
- }
921
-
922
- /*
923
- * call-seq:
924
- * document.xhtml? -> (true|false)
925
- *
926
- * Determine whether this is an XHTML document.
927
- */
928
- static VALUE rxml_document_xhtml_q(VALUE self)
929
- {
930
- xmlDocPtr xdoc;
931
- xmlDtdPtr xdtd;
932
- Data_Get_Struct(self, xmlDoc, xdoc);
933
- xdtd = xmlGetIntSubset(xdoc);
934
- if (xdtd != NULL && xmlIsXHTML(xdtd->SystemID, xdtd->ExternalID) > 0)
935
- return (Qtrue);
936
- else
937
- return (Qfalse);
938
- }
939
-
940
- /*
941
- * call-seq:
942
- * document.xinclude -> num
943
- *
944
- * Process xinclude directives in this document.
945
- */
946
- static VALUE rxml_document_xinclude(VALUE self)
947
- {
948
- #ifdef LIBXML_XINCLUDE_ENABLED
949
- xmlDocPtr xdoc;
950
-
951
- int ret;
952
-
953
- Data_Get_Struct(self, xmlDoc, xdoc);
954
- ret = xmlXIncludeProcess(xdoc);
955
- if (ret >= 0)
956
- {
957
- return(INT2NUM(ret));
958
- }
959
- else
960
- {
961
- rxml_raise(xmlGetLastError());
962
- return Qnil;
963
- }
964
- #else
965
- rb_warn(
966
- "libxml was compiled without XInclude support. Please recompile libxml and ruby-libxml");
967
- return (Qfalse);
968
- #endif
969
- }
970
-
971
- /*
972
- * call-seq:
973
- * document.order_elements!
974
- *
975
- * Call this routine to speed up XPath computation on static documents.
976
- * This stamps all the element nodes with the document order.
977
- */
978
- static VALUE rxml_document_order_elements(VALUE self)
979
- {
980
- xmlDocPtr xdoc;
981
-
982
- Data_Get_Struct(self, xmlDoc, xdoc);
983
- return LONG2FIX(xmlXPathOrderDocElems(xdoc));
984
- }
985
-
986
- /*
987
- * call-seq:
988
- * document.validate_schema(schema)
989
- *
990
- * Validate this document against the specified XML::Schema.
991
- * If the document is valid the method returns true. Otherwise an
992
- * exception is raised with validation information.
993
- */
994
- static VALUE rxml_document_validate_schema(VALUE self, VALUE schema)
995
- {
996
- xmlSchemaValidCtxtPtr vptr;
997
- xmlDocPtr xdoc;
998
- xmlSchemaPtr xschema;
999
- int is_invalid;
1000
-
1001
- Data_Get_Struct(self, xmlDoc, xdoc);
1002
- Data_Get_Struct(schema, xmlSchema, xschema);
1003
-
1004
- vptr = xmlSchemaNewValidCtxt(xschema);
1005
-
1006
- is_invalid = xmlSchemaValidateDoc(vptr, xdoc);
1007
- xmlSchemaFreeValidCtxt(vptr);
1008
- if (is_invalid)
1009
- {
1010
- rxml_raise(xmlGetLastError());
1011
- return Qfalse;
1012
- }
1013
- else
1014
- {
1015
- return Qtrue;
1016
- }
1017
- }
1018
-
1019
- /*
1020
- * call-seq:
1021
- * document.validate_relaxng(relaxng)
1022
- *
1023
- * Validate this document against the specified XML::RelaxNG.
1024
- * If the document is valid the method returns true. Otherwise an
1025
- * exception is raised with validation information.
1026
- */
1027
- static VALUE rxml_document_validate_relaxng(VALUE self, VALUE relaxng)
1028
- {
1029
- xmlRelaxNGValidCtxtPtr vptr;
1030
- xmlDocPtr xdoc;
1031
- xmlRelaxNGPtr xrelaxng;
1032
- int is_invalid;
1033
-
1034
- Data_Get_Struct(self, xmlDoc, xdoc);
1035
- Data_Get_Struct(relaxng, xmlRelaxNG, xrelaxng);
1036
-
1037
- vptr = xmlRelaxNGNewValidCtxt(xrelaxng);
1038
-
1039
- is_invalid = xmlRelaxNGValidateDoc(vptr, xdoc);
1040
- xmlRelaxNGFreeValidCtxt(vptr);
1041
- if (is_invalid)
1042
- {
1043
- rxml_raise(xmlGetLastError());
1044
- return Qfalse;
1045
- }
1046
- else
1047
- {
1048
- return Qtrue;
1049
- }
1050
- }
1051
-
1052
- /*
1053
- * call-seq:
1054
- * document.validate(dtd) -> (true|false)
1055
- *
1056
- * Validate this document against the specified XML::DTD.
1057
- * If the document is valid the method returns true. Otherwise an
1058
- * exception is raised with validation information.
1059
- */
1060
- static VALUE rxml_document_validate_dtd(VALUE self, VALUE dtd)
1061
- {
1062
- xmlValidCtxt ctxt;
1063
- xmlDocPtr xdoc;
1064
- xmlDtdPtr xdtd;
1065
-
1066
- Data_Get_Struct(self, xmlDoc, xdoc);
1067
- Data_Get_Struct(dtd, xmlDtd, xdtd);
1068
-
1069
- /* Setup context */
1070
- memset(&ctxt, 0, sizeof(xmlValidCtxt));
1071
-
1072
- if (xmlValidateDtd(&ctxt, xdoc, xdtd))
1073
- {
1074
- return Qtrue;
1075
- }
1076
- else
1077
- {
1078
- rxml_raise(xmlGetLastError());
1079
- return Qfalse;
1080
- }
1081
- }
1082
-
1083
- void rxml_init_document(void)
1084
- {
1085
- cXMLDocument = rb_define_class_under(mXML, "Document", rb_cObject);
1086
- rb_define_alloc_func(cXMLDocument, rxml_document_alloc);
1087
-
1088
- /* Original C14N 1.0 spec */
1089
- rb_define_const(cXMLDocument, "XML_C14N_1_0", INT2NUM(XML_C14N_1_0));
1090
- /* Exclusive C14N 1.0 spec */
1091
- rb_define_const(cXMLDocument, "XML_C14N_EXCLUSIVE_1_0", INT2NUM(XML_C14N_EXCLUSIVE_1_0));
1092
- /* C14N 1.1 spec */
1093
- rb_define_const(cXMLDocument, "XML_C14N_1_1", INT2NUM(XML_C14N_1_1));
1094
-
1095
- rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1);
1096
- rb_define_method(cXMLDocument, "canonicalize", rxml_document_canonicalize, -1);
1097
- rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0);
1098
- rb_define_method(cXMLDocument, "child?", rxml_document_child_q, 0);
1099
- rb_define_method(cXMLDocument, "compression", rxml_document_compression_get, 0);
1100
- rb_define_method(cXMLDocument, "compression=", rxml_document_compression_set, 1);
1101
- rb_define_method(cXMLDocument, "compression?", rxml_document_compression_q, 0);
1102
- rb_define_method(cXMLDocument, "debug", rxml_document_debug, 0);
1103
- rb_define_method(cXMLDocument, "encoding", rxml_document_encoding_get, 0);
1104
- rb_define_method(cXMLDocument, "rb_encoding", rxml_document_rb_encoding_get, 0);
1105
- rb_define_method(cXMLDocument, "encoding=", rxml_document_encoding_set, 1);
1106
- rb_define_method(cXMLDocument, "import", rxml_document_import, 1);
1107
- rb_define_method(cXMLDocument, "last", rxml_document_last_get, 0);
1108
- rb_define_method(cXMLDocument, "last?", rxml_document_last_q, 0);
1109
- rb_define_method(cXMLDocument, "next", rxml_document_next_get, 0);
1110
- rb_define_method(cXMLDocument, "next?", rxml_document_next_q, 0);
1111
- rb_define_method(cXMLDocument, "node_type", rxml_document_node_type, 0);
1112
- rb_define_method(cXMLDocument, "order_elements!", rxml_document_order_elements, 0);
1113
- rb_define_method(cXMLDocument, "parent", rxml_document_parent_get, 0);
1114
- rb_define_method(cXMLDocument, "parent?", rxml_document_parent_q, 0);
1115
- rb_define_method(cXMLDocument, "prev", rxml_document_prev_get, 0);
1116
- rb_define_method(cXMLDocument, "prev?", rxml_document_prev_q, 0);
1117
- rb_define_method(cXMLDocument, "root", rxml_document_root_get, 0);
1118
- rb_define_method(cXMLDocument, "root=", rxml_document_root_set, 1);
1119
- rb_define_method(cXMLDocument, "save", rxml_document_save, -1);
1120
- rb_define_method(cXMLDocument, "standalone?", rxml_document_standalone_q, 0);
1121
- rb_define_method(cXMLDocument, "to_s", rxml_document_to_s, -1);
1122
- rb_define_method(cXMLDocument, "url", rxml_document_url_get, 0);
1123
- rb_define_method(cXMLDocument, "version", rxml_document_version_get, 0);
1124
- rb_define_method(cXMLDocument, "xhtml?", rxml_document_xhtml_q, 0);
1125
- rb_define_method(cXMLDocument, "xinclude", rxml_document_xinclude, 0);
1126
- rb_define_method(cXMLDocument, "validate", rxml_document_validate_dtd, 1);
1127
- rb_define_method(cXMLDocument, "validate_schema", rxml_document_validate_schema, 1);
1128
- rb_define_method(cXMLDocument, "validate_relaxng", rxml_document_validate_relaxng, 1);
1129
- }
1
+ /*
2
+ * Document-class: LibXML::XML::Document
3
+ *
4
+ * The XML::Document class provides a tree based API for working
5
+ * with xml documents. You may directly create a document and
6
+ * manipulate it, or create a document from a data source by
7
+ * using an XML::Parser object.
8
+ *
9
+ * To read a document from a file:
10
+ *
11
+ * doc = XML::Document.file('my_file')
12
+ *
13
+ * To use a parser to read a document:
14
+ *
15
+ * parser = XML::Parser.file('my_file')
16
+ * doc = parser.parse
17
+ *
18
+ * To create a document from scratch:
19
+ *
20
+ * doc = XML::Document.new()
21
+ * doc.root = XML::Node.new('root_node')
22
+ * doc.root << XML::Node.new('elem1')
23
+ * doc.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8)
24
+ *
25
+ * To write a document to a file:
26
+ *
27
+ * doc = XML::Document.new()
28
+ * doc.root = XML::Node.new('root_node')
29
+ * root = doc.root
30
+ *
31
+ * root << elem1 = XML::Node.new('elem1')
32
+ * elem1['attr1'] = 'val1'
33
+ * elem1['attr2'] = 'val2'
34
+ *
35
+ * root << elem2 = XML::Node.new('elem2')
36
+ * elem2['attr1'] = 'val1'
37
+ * elem2['attr2'] = 'val2'
38
+ *
39
+ * root << elem3 = XML::Node.new('elem3')
40
+ * elem3 << elem4 = XML::Node.new('elem4')
41
+ * elem3 << elem5 = XML::Node.new('elem5')
42
+ *
43
+ * elem5 << elem6 = XML::Node.new('elem6')
44
+ * elem6 << 'Content for element 6'
45
+ *
46
+ * elem3['attr'] = 'baz'
47
+ *
48
+ * doc.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8)
49
+ */
50
+
51
+ #include <stdarg.h>
52
+ #include "ruby_libxml.h"
53
+ #include "ruby_xml_document.h"
54
+
55
+ #include <libxml/c14n.h>
56
+ #include <libxml/debugXML.h>
57
+ #include <libxml/relaxng.h>
58
+ #include <libxml/xmlschemas.h>
59
+ #include <libxml/xinclude.h>
60
+
61
+ VALUE cXMLDocument;
62
+
63
+ void rxml_document_free(xmlDocPtr xdoc)
64
+ {
65
+ xdoc->_private = NULL;
66
+ xmlFreeDoc(xdoc);
67
+ }
68
+
69
+ VALUE rxml_document_wrap(xmlDocPtr xdoc)
70
+ {
71
+ VALUE result = Qnil;
72
+
73
+ // Is this node is already wrapped?
74
+ if (xdoc->_private != NULL)
75
+ {
76
+ result = (VALUE)xdoc->_private;
77
+ }
78
+ else
79
+ {
80
+ result = Data_Wrap_Struct(cXMLDocument, NULL, rxml_document_free, xdoc);
81
+ xdoc->_private = (void*)result;
82
+ }
83
+
84
+ return result;
85
+ }
86
+
87
+ /*
88
+ * call-seq:
89
+ * XML::Document.alloc(xml_version = 1.0) -> document
90
+ *
91
+ * Alocates a new XML::Document, optionally specifying the
92
+ * XML version.
93
+ */
94
+ static VALUE rxml_document_alloc(VALUE klass)
95
+ {
96
+ return Data_Wrap_Struct(klass, NULL, rxml_document_free, NULL);
97
+ }
98
+
99
+ /*
100
+ * call-seq:
101
+ * XML::Document.initialize(xml_version = 1.0) -> document
102
+ *
103
+ * Initializes a new XML::Document, optionally specifying the
104
+ * XML version.
105
+ */
106
+ static VALUE rxml_document_initialize(int argc, VALUE *argv, VALUE self)
107
+ {
108
+ xmlDocPtr xdoc;
109
+ VALUE xmlver;
110
+
111
+ switch (argc)
112
+ {
113
+ case 0:
114
+ xmlver = rb_str_new2("1.0");
115
+ break;
116
+ case 1:
117
+ rb_scan_args(argc, argv, "01", &xmlver);
118
+ break;
119
+ default:
120
+ rb_raise(rb_eArgError, "wrong number of arguments (need 0 or 1)");
121
+ }
122
+
123
+ Check_Type(xmlver, T_STRING);
124
+ xdoc = xmlNewDoc((xmlChar*) StringValuePtr(xmlver));
125
+
126
+ // Link the ruby object to the document and the document to the ruby object
127
+ RDATA(self)->data = xdoc;
128
+ xdoc->_private = (void*)self;
129
+
130
+ return self;
131
+ }
132
+
133
+ /* XML_C14N_1* constants are not defined until libxml 1.1.25, so if they
134
+ are not defined then define these constants to map to zero,
135
+ the same value as XML_C14N_1_0. */
136
+
137
+ /* XML_C14N* constants are not defined until libxml 1.1.25, so define them
138
+ if needed so things compile. */
139
+ #ifndef XML_C14N_1_0
140
+ #define XML_C14N_1_0 0
141
+ #define XML_C14N_EXCLUSIVE_1_0 XML_C14N_1_0
142
+ #define XML_C14N_1_1 XML_C14N_1_0
143
+ #endif
144
+
145
+ /*
146
+ * :call-seq:
147
+ * document.canonicalize -> String
148
+ * document.canonicalize(options) -> String
149
+ *
150
+ * Returns a string containing the canonicalized form of the document.
151
+ * Implemented to include all of the functionality of the libxml2
152
+ * {xmlC14NDocDumpMemory}[http://xmlsoft.org/html/libxml-c14n.html#xmlC14NDocDumpMemory]
153
+ * method.
154
+ *
155
+ * === Options
156
+ * [comments]
157
+ * * *Type:* Boolean
158
+ * * *Default:* false
159
+ * Specifies if comments should be output.
160
+ * * Must be boolean, otherwise defaults to false.
161
+ * [inclusive_ns_prefixes]
162
+ * * *Type:* Array of strings
163
+ * * *Default:* empty array
164
+ * Array of namespace prefixes to include in exclusive canonicalization only.
165
+ * * The last item in the list is reserved for a NULL value because the C method demands it, therefore
166
+ * up to the first 255 valid entries will be used.
167
+ * * <em>Only used for *XML_C14N_EXCLUSIVE_1_0* mode. Ignored otherwise.</em>
168
+ * [mode]
169
+ * * *Type:* XML::Document Constant
170
+ * * *Default:* XML_C14N_1_0
171
+ * Specifies the mode of canonicalization.
172
+ * * *NOTE:* XML_C14N_1_1 may not be fully implemented upon compilation due to C library compatibility.
173
+ * Please check if XML_C14N_1_0 and XML_C14N_1_1 are the same value prior to using XML_C14N_1_1.
174
+ * [nodes]
175
+ * * *Type:* Array of XML::Node objects
176
+ * * *Default:* empty array
177
+ * XML::Nodes to include in the canonicalization process
178
+ * * For large lists of more than 256 valid namespaces, up to the first 256 valid entries will be used.
179
+ */
180
+ #define C14N_NS_LIMIT 256
181
+ #define C14N_NODESET_LIMIT 256
182
+
183
+ static VALUE
184
+ rxml_document_canonicalize(int argc, VALUE *argv, VALUE self)
185
+ {
186
+ VALUE result = Qnil;
187
+ xmlDocPtr xdoc;
188
+ xmlChar *buffer = NULL;
189
+ VALUE option_hash = Qnil;
190
+ VALUE o_nodes = Qnil;
191
+
192
+ // :comments option
193
+ int comments = 0;
194
+ // :mode option
195
+ int c14n_mode = XML_C14N_1_0;
196
+ // :inclusive_ns_prefixes option (ARRAY)
197
+
198
+ xmlChar * inc_ns_prefixes_ptr[C14N_NS_LIMIT];
199
+
200
+ // :nodes option (ARRAY)
201
+ xmlNodePtr node_ptr_array[C14N_NODESET_LIMIT];
202
+ xmlNodeSet nodeset = {
203
+ 0, C14N_NODESET_LIMIT, NULL
204
+ };
205
+
206
+ /* At least one NULL value must be defined in the array or the extension will
207
+ * segfault when using XML_C14N_EXCLUSIVE_1_0 mode.
208
+ * API docs: "list of inclusive namespace prefixes ended with a NULL"
209
+ */
210
+ inc_ns_prefixes_ptr[0] = NULL;
211
+
212
+ rb_scan_args(argc, argv, "01", &option_hash);
213
+ // Do stuff if ruby hash passed as argument
214
+ if (!NIL_P(option_hash))
215
+ {
216
+ VALUE o_comments = Qnil;
217
+ VALUE o_mode = Qnil;
218
+ VALUE o_i_ns_prefixes = Qnil;
219
+
220
+ Check_Type(option_hash, T_HASH);
221
+
222
+ o_comments = rb_hash_aref(option_hash, ID2SYM(rb_intern("comments")));
223
+ comments = (RTEST(o_comments) ? 1 : 0);
224
+
225
+ o_mode = rb_hash_aref(option_hash, ID2SYM(rb_intern("mode")));
226
+ if (!NIL_P(o_mode))
227
+ {
228
+ Check_Type(o_mode, T_FIXNUM);
229
+ c14n_mode = NUM2INT(o_mode);
230
+ //TODO: clean this up
231
+ //if (c14n_mode > 2) { c14n_mode = 0; }
232
+ //mode_int = (NUM2INT(o_mode) > 2 ? 0 : NUM2INT(o_mode));
233
+ }
234
+
235
+ o_i_ns_prefixes = rb_hash_aref(option_hash, ID2SYM(rb_intern("inclusive_ns_prefixes")));
236
+ if (!NIL_P(o_i_ns_prefixes))
237
+ {
238
+ int i;
239
+ int p = 0; //pointer array index
240
+ VALUE *list_in = NULL;
241
+ long list_size = 0;
242
+
243
+ Check_Type(o_i_ns_prefixes, T_ARRAY);
244
+ list_in = RARRAY_PTR(o_i_ns_prefixes);
245
+ list_size = RARRAY_LEN(o_i_ns_prefixes);
246
+
247
+ if (list_size > 0)
248
+ {
249
+ for(i=0; i < list_size; ++i) {
250
+ if (p >= C14N_NS_LIMIT) { break; }
251
+
252
+ if (RTEST(list_in[i]))
253
+ {
254
+ if (TYPE(list_in[i]) == T_STRING)
255
+ {
256
+ inc_ns_prefixes_ptr[p] = (xmlChar *)StringValueCStr(list_in[i]);
257
+ p++;
258
+ }
259
+ }
260
+ }
261
+ }
262
+
263
+ // ensure p is not out of bound
264
+ p = (p >= C14N_NS_LIMIT ? (C14N_NS_LIMIT-1) : p);
265
+
266
+ // API docs: "list of inclusive namespace prefixes ended with a NULL"
267
+ // Set last element to NULL
268
+ inc_ns_prefixes_ptr[p] = NULL;
269
+ }
270
+ //o_ns_prefixes will free at end of block
271
+
272
+ o_nodes = rb_hash_aref(option_hash, ID2SYM(rb_intern("nodes")));
273
+ if (!NIL_P(o_nodes))
274
+ {
275
+ int i;
276
+ int p = 0; // index of pointer array
277
+ VALUE * list_in = NULL;
278
+ long node_list_size = 0;
279
+
280
+ if (CLASS_OF(o_nodes) == cXMLXPathObject)
281
+ {
282
+ o_nodes = rb_funcall(o_nodes, rb_intern("to_a"), 0);
283
+ }
284
+ else
285
+ {
286
+ Check_Type(o_nodes, T_ARRAY);
287
+ }
288
+ list_in = RARRAY_PTR(o_nodes);
289
+ node_list_size = RARRAY_LEN(o_nodes);
290
+
291
+ for (i=0; i < node_list_size; ++i)
292
+ {
293
+ if (p >= C14N_NODESET_LIMIT) { break; }
294
+
295
+ if (RTEST(list_in[i]))
296
+ {
297
+ xmlNodePtr node_ptr;
298
+ Data_Get_Struct(list_in[i], xmlNode, node_ptr);
299
+ node_ptr_array[p] = node_ptr;
300
+ p++;
301
+ }
302
+ }
303
+
304
+ // Need to set values in nodeset struct
305
+ nodeset.nodeNr = (node_list_size > C14N_NODESET_LIMIT ?
306
+ C14N_NODESET_LIMIT :
307
+ (int)node_list_size);
308
+ nodeset.nodeTab = node_ptr_array;
309
+ }
310
+ }//option_hash
311
+
312
+ Data_Get_Struct(self, xmlDoc, xdoc);
313
+ xmlC14NDocDumpMemory(xdoc,
314
+ (nodeset.nodeNr == 0 ? NULL : &nodeset),
315
+ c14n_mode,
316
+ inc_ns_prefixes_ptr,
317
+ comments,
318
+ &buffer);
319
+
320
+ if (buffer)
321
+ {
322
+ result = rxml_new_cstr( buffer, NULL);
323
+ xmlFree(buffer);
324
+ }
325
+
326
+ return result;
327
+ }
328
+
329
+
330
+ /*
331
+ * call-seq:
332
+ * document.compression -> num
333
+ *
334
+ * Obtain this document's compression mode identifier.
335
+ */
336
+ static VALUE rxml_document_compression_get(VALUE self)
337
+ {
338
+ #ifdef HAVE_ZLIB_H
339
+ xmlDocPtr xdoc;
340
+
341
+ int compmode;
342
+ Data_Get_Struct(self, xmlDoc, xdoc);
343
+
344
+ compmode = xmlGetDocCompressMode(xdoc);
345
+ if (compmode == -1)
346
+ return(Qnil);
347
+ else
348
+ return(INT2NUM(compmode));
349
+ #else
350
+ rb_warn("libxml not compiled with zlib support");
351
+ return (Qfalse);
352
+ #endif
353
+ }
354
+
355
+ /*
356
+ * call-seq:
357
+ * document.compression = num
358
+ *
359
+ * Set this document's compression mode.
360
+ */
361
+ static VALUE rxml_document_compression_set(VALUE self, VALUE num)
362
+ {
363
+ #ifdef HAVE_ZLIB_H
364
+ xmlDocPtr xdoc;
365
+
366
+ int compmode;
367
+ Check_Type(num, T_FIXNUM);
368
+ Data_Get_Struct(self, xmlDoc, xdoc);
369
+
370
+ if (xdoc == NULL)
371
+ {
372
+ return(Qnil);
373
+ }
374
+ else
375
+ {
376
+ xmlSetDocCompressMode(xdoc, NUM2INT(num));
377
+
378
+ compmode = xmlGetDocCompressMode(xdoc);
379
+ if (compmode == -1)
380
+ return(Qnil);
381
+ else
382
+ return(INT2NUM(compmode));
383
+ }
384
+ #else
385
+ rb_warn("libxml compiled without zlib support");
386
+ return (Qfalse);
387
+ #endif
388
+ }
389
+
390
+ /*
391
+ * call-seq:
392
+ * document.compression? -> (true|false)
393
+ *
394
+ * Determine whether this document is compressed.
395
+ */
396
+ static VALUE rxml_document_compression_q(VALUE self)
397
+ {
398
+ #ifdef HAVE_ZLIB_H
399
+ xmlDocPtr xdoc;
400
+
401
+ Data_Get_Struct(self, xmlDoc, xdoc);
402
+
403
+ if (xdoc->compression != -1)
404
+ return(Qtrue);
405
+ else
406
+ return(Qfalse);
407
+ #else
408
+ rb_warn("libxml compiled without zlib support");
409
+ return (Qfalse);
410
+ #endif
411
+ }
412
+
413
+ /*
414
+ * call-seq:
415
+ * document.child -> node
416
+ *
417
+ * Get this document's child node.
418
+ */
419
+ static VALUE rxml_document_child_get(VALUE self)
420
+ {
421
+ xmlDocPtr xdoc;
422
+ Data_Get_Struct(self, xmlDoc, xdoc);
423
+
424
+ if (xdoc->children == NULL)
425
+ return (Qnil);
426
+
427
+ return rxml_node_wrap(xdoc->children);
428
+ }
429
+
430
+ /*
431
+ * call-seq:
432
+ * document.child? -> (true|false)
433
+ *
434
+ * Determine whether this document has a child node.
435
+ */
436
+ static VALUE rxml_document_child_q(VALUE self)
437
+ {
438
+ xmlDocPtr xdoc;
439
+ Data_Get_Struct(self, xmlDoc, xdoc);
440
+
441
+ if (xdoc->children == NULL)
442
+ return (Qfalse);
443
+ else
444
+ return (Qtrue);
445
+ }
446
+
447
+
448
+ /*
449
+ * call-seq:
450
+ * node.debug -> true|false
451
+ *
452
+ * Print libxml debugging information to stdout.
453
+ * Requires that libxml was compiled with debugging enabled.
454
+ */
455
+ static VALUE rxml_document_debug(VALUE self)
456
+ {
457
+ #ifdef LIBXML_DEBUG_ENABLED
458
+ xmlDocPtr xdoc;
459
+ Data_Get_Struct(self, xmlDoc, xdoc);
460
+ xmlDebugDumpDocument(NULL, xdoc);
461
+ return Qtrue;
462
+ #else
463
+ rb_warn("libxml was compiled without debugging support.");
464
+ return Qfalse;
465
+ #endif
466
+ }
467
+
468
+ /*
469
+ * call-seq:
470
+ * document.encoding -> XML::Encoding::UTF_8
471
+ *
472
+ * Returns the LibXML encoding constant specified by this document.
473
+ */
474
+ static VALUE rxml_document_encoding_get(VALUE self)
475
+ {
476
+ xmlDocPtr xdoc;
477
+ const char *xencoding;
478
+ Data_Get_Struct(self, xmlDoc, xdoc);
479
+
480
+ xencoding = (const char*)xdoc->encoding;
481
+ return INT2NUM(xmlParseCharEncoding(xencoding));
482
+ }
483
+
484
+
485
+ /*
486
+ * call-seq:
487
+ * document.rb_encoding -> Encoding
488
+ *
489
+ * Returns the Ruby encoding specified by this document
490
+ * (available on Ruby 1.9.x and higher).
491
+ */
492
+ static VALUE rxml_document_rb_encoding_get(VALUE self)
493
+ {
494
+ xmlDocPtr xdoc;
495
+ rb_encoding* rbencoding;
496
+ Data_Get_Struct(self, xmlDoc, xdoc);
497
+
498
+ rbencoding = rxml_xml_encoding_to_rb_encoding(mXMLEncoding, xmlParseCharEncoding((const char*)xdoc->encoding));
499
+ return rb_enc_from_encoding(rbencoding);
500
+ }
501
+
502
+ /*
503
+ * call-seq:
504
+ * document.encoding = XML::Encoding::UTF_8
505
+ *
506
+ * Set the encoding for this document.
507
+ */
508
+ static VALUE rxml_document_encoding_set(VALUE self, VALUE encoding)
509
+ {
510
+ xmlDocPtr xdoc;
511
+ const char* xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(encoding));
512
+
513
+ Data_Get_Struct(self, xmlDoc, xdoc);
514
+
515
+ if (xdoc->encoding != NULL)
516
+ xmlFree((xmlChar *) xdoc->encoding);
517
+
518
+ xdoc->encoding = xmlStrdup((xmlChar *)xencoding);
519
+ return self;
520
+ }
521
+
522
+ /*
523
+ * call-seq:
524
+ * document.import(node) -> XML::Node
525
+ *
526
+ * Creates a copy of the node that can be inserted into the
527
+ * current document.
528
+ *
529
+ * IMPORTANT - The returned node MUST be inserted into the document.
530
+ * This is because the returned node refereces internal LibXML data
531
+ * structures owned by the document. Therefore, if the document is
532
+ * is freed before the the node is freed a segmentation fault will occur.
533
+ */
534
+ static VALUE rxml_document_import(VALUE self, VALUE node)
535
+ {
536
+ xmlDocPtr xdoc;
537
+ xmlNodePtr xnode, xresult;
538
+
539
+ Data_Get_Struct(self, xmlDoc, xdoc);
540
+ Data_Get_Struct(node, xmlNode, xnode);
541
+
542
+ xresult = xmlDocCopyNode(xnode, xdoc, 1);
543
+
544
+ if (xresult == NULL)
545
+ rxml_raise(xmlGetLastError());
546
+
547
+ return rxml_node_wrap(xresult);
548
+ }
549
+
550
+ /*
551
+ * call-seq:
552
+ * document.last -> node
553
+ *
554
+ * Obtain the last node.
555
+ */
556
+ static VALUE rxml_document_last_get(VALUE self)
557
+ {
558
+ xmlDocPtr xdoc;
559
+
560
+ Data_Get_Struct(self, xmlDoc, xdoc);
561
+
562
+ if (xdoc->last == NULL)
563
+ return (Qnil);
564
+
565
+ return rxml_node_wrap(xdoc->last);
566
+ }
567
+
568
+ /*
569
+ * call-seq:
570
+ * document.last? -> (true|false)
571
+ *
572
+ * Determine whether there is a last node.
573
+ */
574
+ static VALUE rxml_document_last_q(VALUE self)
575
+ {
576
+ xmlDocPtr xdoc;
577
+
578
+ Data_Get_Struct(self, xmlDoc, xdoc);
579
+
580
+ if (xdoc->last == NULL)
581
+ return (Qfalse);
582
+ else
583
+ return (Qtrue);
584
+ }
585
+
586
+ /*
587
+ * call-seq:
588
+ * document.next -> node
589
+ *
590
+ * Obtain the next node.
591
+ */
592
+ static VALUE rxml_document_next_get(VALUE self)
593
+ {
594
+ xmlDocPtr xdoc;
595
+
596
+ Data_Get_Struct(self, xmlDoc, xdoc);
597
+
598
+ if (xdoc->next == NULL)
599
+ return (Qnil);
600
+
601
+ return rxml_node_wrap(xdoc->next);
602
+ }
603
+
604
+ /*
605
+ * call-seq:
606
+ * document.next? -> (true|false)
607
+ *
608
+ * Determine whether there is a next node.
609
+ */
610
+ static VALUE rxml_document_next_q(VALUE self)
611
+ {
612
+ xmlDocPtr xdoc;
613
+
614
+ Data_Get_Struct(self, xmlDoc, xdoc);
615
+
616
+ if (xdoc->next == NULL)
617
+ return (Qfalse);
618
+ else
619
+ return (Qtrue);
620
+ }
621
+
622
+ /*
623
+ * call-seq:
624
+ * node.type -> num
625
+ *
626
+ * Obtain this node's type identifier.
627
+ */
628
+ static VALUE rxml_document_node_type(VALUE self)
629
+ {
630
+ xmlNodePtr xnode;
631
+ Data_Get_Struct(self, xmlNode, xnode);
632
+ return (INT2NUM(xnode->type));
633
+ }
634
+
635
+ /*
636
+ * call-seq:
637
+ * document.parent -> node
638
+ *
639
+ * Obtain the parent node.
640
+ */
641
+ static VALUE rxml_document_parent_get(VALUE self)
642
+ {
643
+ xmlDocPtr xdoc;
644
+
645
+ Data_Get_Struct(self, xmlDoc, xdoc);
646
+
647
+ if (xdoc->parent == NULL)
648
+ return (Qnil);
649
+
650
+ return rxml_node_wrap(xdoc->parent);
651
+ }
652
+
653
+ /*
654
+ * call-seq:
655
+ * document.parent? -> (true|false)
656
+ *
657
+ * Determine whether there is a parent node.
658
+ */
659
+ static VALUE rxml_document_parent_q(VALUE self)
660
+ {
661
+ xmlDocPtr xdoc;
662
+
663
+ Data_Get_Struct(self, xmlDoc, xdoc);
664
+
665
+ if (xdoc->parent == NULL)
666
+ return (Qfalse);
667
+ else
668
+ return (Qtrue);
669
+ }
670
+
671
+ /*
672
+ * call-seq:
673
+ * document.prev -> node
674
+ *
675
+ * Obtain the previous node.
676
+ */
677
+ static VALUE rxml_document_prev_get(VALUE self)
678
+ {
679
+ xmlDocPtr xdoc;
680
+
681
+ Data_Get_Struct(self, xmlDoc, xdoc);
682
+
683
+ if (xdoc->prev == NULL)
684
+ return (Qnil);
685
+
686
+ return rxml_node_wrap(xdoc->prev);
687
+ }
688
+
689
+ /*
690
+ * call-seq:
691
+ * document.prev? -> (true|false)
692
+ *
693
+ * Determine whether there is a previous node.
694
+ */
695
+ static VALUE rxml_document_prev_q(VALUE self)
696
+ {
697
+ xmlDocPtr xdoc;
698
+
699
+ Data_Get_Struct(self, xmlDoc, xdoc);
700
+
701
+ if (xdoc->prev == NULL)
702
+ return (Qfalse);
703
+ else
704
+ return (Qtrue);
705
+ }
706
+
707
+ /*
708
+ * call-seq:
709
+ * document.root -> node
710
+ *
711
+ * Obtain the root node.
712
+ */
713
+ static VALUE rxml_document_root_get(VALUE self)
714
+ {
715
+ xmlDocPtr xdoc;
716
+ xmlNodePtr root;
717
+
718
+ Data_Get_Struct(self, xmlDoc, xdoc);
719
+ root = xmlDocGetRootElement(xdoc);
720
+
721
+ if (root == NULL)
722
+ return (Qnil);
723
+
724
+ return rxml_node_wrap(root);
725
+ }
726
+
727
+ /*
728
+ * call-seq:
729
+ * document.root = node
730
+ *
731
+ * Set the root node.
732
+ */
733
+ static VALUE rxml_document_root_set(VALUE self, VALUE node)
734
+ {
735
+ xmlDocPtr xdoc;
736
+ xmlNodePtr xnode;
737
+
738
+ if (rb_obj_is_kind_of(node, cXMLNode) == Qfalse)
739
+ rb_raise(rb_eTypeError, "must pass an XML::Node type object");
740
+
741
+ Data_Get_Struct(self, xmlDoc, xdoc);
742
+ Data_Get_Struct(node, xmlNode, xnode);
743
+
744
+ if (xnode->doc != NULL && xnode->doc != xdoc)
745
+ rb_raise(eXMLError, "Nodes belong to different documents. You must first import the node by calling LibXML::XML::Document.import");
746
+
747
+ xmlDocSetRootElement(xdoc, xnode);
748
+
749
+ // Ruby no longer manages this nodes memory
750
+ rxml_node_unmanage(xnode, node);
751
+
752
+ return node;
753
+ }
754
+
755
+ /*
756
+ * call-seq:
757
+ * document.save(filename) -> int
758
+ * document.save(filename, :indent => true, :encoding => XML::Encoding::UTF_8) -> int
759
+ *
760
+ * Saves a document to a file. You may provide an optional hash table
761
+ * to control how the string is generated. Valid options are:
762
+ *
763
+ * :indent - Specifies if the string should be indented. The default value
764
+ * is true. Note that indentation is only added if both :indent is
765
+ * true and XML.indent_tree_output is true. If :indent is set to false,
766
+ * then both indentation and line feeds are removed from the result.
767
+ *
768
+ * :encoding - Specifies the output encoding of the string. It
769
+ * defaults to the original encoding of the document (see
770
+ * #encoding. To override the orginal encoding, use one of the
771
+ * XML::Encoding encoding constants. */
772
+ static VALUE rxml_document_save(int argc, VALUE *argv, VALUE self)
773
+ {
774
+ VALUE options = Qnil;
775
+ VALUE filename = Qnil;
776
+ xmlDocPtr xdoc;
777
+ int indent = 1;
778
+ const char *xfilename;
779
+ const xmlChar *xencoding;
780
+ int length;
781
+
782
+ rb_scan_args(argc, argv, "11", &filename, &options);
783
+
784
+ Check_Type(filename, T_STRING);
785
+ xfilename = StringValuePtr(filename);
786
+
787
+ Data_Get_Struct(self, xmlDoc, xdoc);
788
+ xencoding = xdoc->encoding;
789
+
790
+ if (!NIL_P(options))
791
+ {
792
+ VALUE rencoding, rindent;
793
+ Check_Type(options, T_HASH);
794
+ rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
795
+ rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
796
+
797
+ if (rindent == Qfalse)
798
+ indent = 0;
799
+
800
+ if (rencoding != Qnil)
801
+ {
802
+ xencoding = (const xmlChar*)xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
803
+ if (!xencoding)
804
+ rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
805
+ }
806
+ }
807
+
808
+ length = xmlSaveFormatFileEnc(xfilename, xdoc, (const char*)xencoding, indent);
809
+
810
+ if (length == -1)
811
+ rxml_raise(xmlGetLastError());
812
+
813
+ return (INT2NUM(length));
814
+ }
815
+
816
+ /*
817
+ * call-seq:
818
+ * document.standalone? -> (true|false)
819
+ *
820
+ * Determine whether this is a standalone document.
821
+ */
822
+ static VALUE rxml_document_standalone_q(VALUE self)
823
+ {
824
+ xmlDocPtr xdoc;
825
+
826
+ Data_Get_Struct(self, xmlDoc, xdoc);
827
+ if (xdoc->standalone)
828
+ return (Qtrue);
829
+ else
830
+ return (Qfalse);
831
+ }
832
+
833
+ /*
834
+ * call-seq:
835
+ * document.to_s -> "string"
836
+ * document.to_s(:indent => true, :encoding => XML::Encoding::UTF_8) -> "string"
837
+ *
838
+ * Converts a document, and all of its children, to a string representation.
839
+ * You may provide an optional hash table to control how the string is
840
+ * generated. Valid options are:
841
+ *
842
+ * :indent - Specifies if the string should be indented. The default value
843
+ * is true. Note that indentation is only added if both :indent is
844
+ * true and XML.indent_tree_output is true. If :indent is set to false,
845
+ * then both indentation and line feeds are removed from the result.
846
+ *
847
+ * :encoding - Specifies the output encoding of the string. It
848
+ * defaults to XML::Encoding::UTF8. To change it, use one of the
849
+ * XML::Encoding encoding constants. */
850
+ static VALUE rxml_document_to_s(int argc, VALUE *argv, VALUE self)
851
+ {
852
+ VALUE result;
853
+ VALUE options = Qnil;
854
+ xmlDocPtr xdoc;
855
+ int indent = 1;
856
+ const xmlChar *xencoding = (const xmlChar*) "UTF-8";
857
+ xmlChar *buffer;
858
+ int length;
859
+
860
+ rb_scan_args(argc, argv, "01", &options);
861
+
862
+ if (!NIL_P(options))
863
+ {
864
+ VALUE rencoding, rindent;
865
+ Check_Type(options, T_HASH);
866
+ rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
867
+ rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
868
+
869
+ if (rindent == Qfalse)
870
+ indent = 0;
871
+
872
+ if (rencoding != Qnil)
873
+ {
874
+ xencoding = (const xmlChar*)xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
875
+ if (!xencoding)
876
+ rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
877
+ }
878
+ }
879
+
880
+ Data_Get_Struct(self, xmlDoc, xdoc);
881
+ xmlDocDumpFormatMemoryEnc(xdoc, &buffer, &length, (const char*)xencoding, indent);
882
+
883
+ result = rxml_new_cstr(buffer, xencoding);
884
+ xmlFree(buffer);
885
+ return result;
886
+ }
887
+
888
+ /*
889
+ * call-seq:
890
+ * document.url -> "url"
891
+ *
892
+ * Obtain this document's source URL, if any.
893
+ */
894
+ static VALUE rxml_document_url_get(VALUE self)
895
+ {
896
+ xmlDocPtr xdoc;
897
+
898
+ Data_Get_Struct(self, xmlDoc, xdoc);
899
+ if (xdoc->URL == NULL)
900
+ return (Qnil);
901
+ else
902
+ return (rxml_new_cstr( xdoc->URL, NULL));
903
+ }
904
+
905
+ /*
906
+ * call-seq:
907
+ * document.version -> "version"
908
+ *
909
+ * Obtain the XML version specified by this document.
910
+ */
911
+ static VALUE rxml_document_version_get(VALUE self)
912
+ {
913
+ xmlDocPtr xdoc;
914
+
915
+ Data_Get_Struct(self, xmlDoc, xdoc);
916
+ if (xdoc->version == NULL)
917
+ return (Qnil);
918
+ else
919
+ return (rxml_new_cstr( xdoc->version, NULL));
920
+ }
921
+
922
+ /*
923
+ * call-seq:
924
+ * document.xhtml? -> (true|false)
925
+ *
926
+ * Determine whether this is an XHTML document.
927
+ */
928
+ static VALUE rxml_document_xhtml_q(VALUE self)
929
+ {
930
+ xmlDocPtr xdoc;
931
+ xmlDtdPtr xdtd;
932
+ Data_Get_Struct(self, xmlDoc, xdoc);
933
+ xdtd = xmlGetIntSubset(xdoc);
934
+ if (xdtd != NULL && xmlIsXHTML(xdtd->SystemID, xdtd->ExternalID) > 0)
935
+ return (Qtrue);
936
+ else
937
+ return (Qfalse);
938
+ }
939
+
940
+ /*
941
+ * call-seq:
942
+ * document.xinclude -> num
943
+ *
944
+ * Process xinclude directives in this document.
945
+ */
946
+ static VALUE rxml_document_xinclude(VALUE self)
947
+ {
948
+ #ifdef LIBXML_XINCLUDE_ENABLED
949
+ xmlDocPtr xdoc;
950
+
951
+ int ret;
952
+
953
+ Data_Get_Struct(self, xmlDoc, xdoc);
954
+ ret = xmlXIncludeProcess(xdoc);
955
+ if (ret >= 0)
956
+ {
957
+ return(INT2NUM(ret));
958
+ }
959
+ else
960
+ {
961
+ rxml_raise(xmlGetLastError());
962
+ return Qnil;
963
+ }
964
+ #else
965
+ rb_warn(
966
+ "libxml was compiled without XInclude support. Please recompile libxml and ruby-libxml");
967
+ return (Qfalse);
968
+ #endif
969
+ }
970
+
971
+ /*
972
+ * call-seq:
973
+ * document.order_elements!
974
+ *
975
+ * Call this routine to speed up XPath computation on static documents.
976
+ * This stamps all the element nodes with the document order.
977
+ */
978
+ static VALUE rxml_document_order_elements(VALUE self)
979
+ {
980
+ xmlDocPtr xdoc;
981
+
982
+ Data_Get_Struct(self, xmlDoc, xdoc);
983
+ return LONG2FIX(xmlXPathOrderDocElems(xdoc));
984
+ }
985
+
986
+ /*
987
+ * call-seq:
988
+ * document.validate_schema(schema)
989
+ *
990
+ * Validate this document against the specified XML::Schema.
991
+ * If the document is valid the method returns true. Otherwise an
992
+ * exception is raised with validation information.
993
+ */
994
+ static VALUE rxml_document_validate_schema(VALUE self, VALUE schema)
995
+ {
996
+ xmlSchemaValidCtxtPtr vptr;
997
+ xmlDocPtr xdoc;
998
+ xmlSchemaPtr xschema;
999
+ int is_invalid;
1000
+
1001
+ Data_Get_Struct(self, xmlDoc, xdoc);
1002
+ Data_Get_Struct(schema, xmlSchema, xschema);
1003
+
1004
+ vptr = xmlSchemaNewValidCtxt(xschema);
1005
+
1006
+ is_invalid = xmlSchemaValidateDoc(vptr, xdoc);
1007
+ xmlSchemaFreeValidCtxt(vptr);
1008
+ if (is_invalid)
1009
+ {
1010
+ rxml_raise(xmlGetLastError());
1011
+ return Qfalse;
1012
+ }
1013
+ else
1014
+ {
1015
+ return Qtrue;
1016
+ }
1017
+ }
1018
+
1019
+ /*
1020
+ * call-seq:
1021
+ * document.validate_relaxng(relaxng)
1022
+ *
1023
+ * Validate this document against the specified XML::RelaxNG.
1024
+ * If the document is valid the method returns true. Otherwise an
1025
+ * exception is raised with validation information.
1026
+ */
1027
+ static VALUE rxml_document_validate_relaxng(VALUE self, VALUE relaxng)
1028
+ {
1029
+ xmlRelaxNGValidCtxtPtr vptr;
1030
+ xmlDocPtr xdoc;
1031
+ xmlRelaxNGPtr xrelaxng;
1032
+ int is_invalid;
1033
+
1034
+ Data_Get_Struct(self, xmlDoc, xdoc);
1035
+ Data_Get_Struct(relaxng, xmlRelaxNG, xrelaxng);
1036
+
1037
+ vptr = xmlRelaxNGNewValidCtxt(xrelaxng);
1038
+
1039
+ is_invalid = xmlRelaxNGValidateDoc(vptr, xdoc);
1040
+ xmlRelaxNGFreeValidCtxt(vptr);
1041
+ if (is_invalid)
1042
+ {
1043
+ rxml_raise(xmlGetLastError());
1044
+ return Qfalse;
1045
+ }
1046
+ else
1047
+ {
1048
+ return Qtrue;
1049
+ }
1050
+ }
1051
+
1052
+ /*
1053
+ * call-seq:
1054
+ * document.validate(dtd) -> (true|false)
1055
+ *
1056
+ * Validate this document against the specified XML::DTD.
1057
+ * If the document is valid the method returns true. Otherwise an
1058
+ * exception is raised with validation information.
1059
+ */
1060
+ static VALUE rxml_document_validate_dtd(VALUE self, VALUE dtd)
1061
+ {
1062
+ xmlValidCtxt ctxt;
1063
+ xmlDocPtr xdoc;
1064
+ xmlDtdPtr xdtd;
1065
+
1066
+ Data_Get_Struct(self, xmlDoc, xdoc);
1067
+ Data_Get_Struct(dtd, xmlDtd, xdtd);
1068
+
1069
+ /* Setup context */
1070
+ memset(&ctxt, 0, sizeof(xmlValidCtxt));
1071
+
1072
+ if (xmlValidateDtd(&ctxt, xdoc, xdtd))
1073
+ {
1074
+ return Qtrue;
1075
+ }
1076
+ else
1077
+ {
1078
+ rxml_raise(xmlGetLastError());
1079
+ return Qfalse;
1080
+ }
1081
+ }
1082
+
1083
+ void rxml_init_document(void)
1084
+ {
1085
+ cXMLDocument = rb_define_class_under(mXML, "Document", rb_cObject);
1086
+ rb_define_alloc_func(cXMLDocument, rxml_document_alloc);
1087
+
1088
+ /* Original C14N 1.0 spec */
1089
+ rb_define_const(cXMLDocument, "XML_C14N_1_0", INT2NUM(XML_C14N_1_0));
1090
+ /* Exclusive C14N 1.0 spec */
1091
+ rb_define_const(cXMLDocument, "XML_C14N_EXCLUSIVE_1_0", INT2NUM(XML_C14N_EXCLUSIVE_1_0));
1092
+ /* C14N 1.1 spec */
1093
+ rb_define_const(cXMLDocument, "XML_C14N_1_1", INT2NUM(XML_C14N_1_1));
1094
+
1095
+ rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1);
1096
+ rb_define_method(cXMLDocument, "canonicalize", rxml_document_canonicalize, -1);
1097
+ rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0);
1098
+ rb_define_method(cXMLDocument, "child?", rxml_document_child_q, 0);
1099
+ rb_define_method(cXMLDocument, "compression", rxml_document_compression_get, 0);
1100
+ rb_define_method(cXMLDocument, "compression=", rxml_document_compression_set, 1);
1101
+ rb_define_method(cXMLDocument, "compression?", rxml_document_compression_q, 0);
1102
+ rb_define_method(cXMLDocument, "debug", rxml_document_debug, 0);
1103
+ rb_define_method(cXMLDocument, "encoding", rxml_document_encoding_get, 0);
1104
+ rb_define_method(cXMLDocument, "rb_encoding", rxml_document_rb_encoding_get, 0);
1105
+ rb_define_method(cXMLDocument, "encoding=", rxml_document_encoding_set, 1);
1106
+ rb_define_method(cXMLDocument, "import", rxml_document_import, 1);
1107
+ rb_define_method(cXMLDocument, "last", rxml_document_last_get, 0);
1108
+ rb_define_method(cXMLDocument, "last?", rxml_document_last_q, 0);
1109
+ rb_define_method(cXMLDocument, "next", rxml_document_next_get, 0);
1110
+ rb_define_method(cXMLDocument, "next?", rxml_document_next_q, 0);
1111
+ rb_define_method(cXMLDocument, "node_type", rxml_document_node_type, 0);
1112
+ rb_define_method(cXMLDocument, "order_elements!", rxml_document_order_elements, 0);
1113
+ rb_define_method(cXMLDocument, "parent", rxml_document_parent_get, 0);
1114
+ rb_define_method(cXMLDocument, "parent?", rxml_document_parent_q, 0);
1115
+ rb_define_method(cXMLDocument, "prev", rxml_document_prev_get, 0);
1116
+ rb_define_method(cXMLDocument, "prev?", rxml_document_prev_q, 0);
1117
+ rb_define_method(cXMLDocument, "root", rxml_document_root_get, 0);
1118
+ rb_define_method(cXMLDocument, "root=", rxml_document_root_set, 1);
1119
+ rb_define_method(cXMLDocument, "save", rxml_document_save, -1);
1120
+ rb_define_method(cXMLDocument, "standalone?", rxml_document_standalone_q, 0);
1121
+ rb_define_method(cXMLDocument, "to_s", rxml_document_to_s, -1);
1122
+ rb_define_method(cXMLDocument, "url", rxml_document_url_get, 0);
1123
+ rb_define_method(cXMLDocument, "version", rxml_document_version_get, 0);
1124
+ rb_define_method(cXMLDocument, "xhtml?", rxml_document_xhtml_q, 0);
1125
+ rb_define_method(cXMLDocument, "xinclude", rxml_document_xinclude, 0);
1126
+ rb_define_method(cXMLDocument, "validate", rxml_document_validate_dtd, 1);
1127
+ rb_define_method(cXMLDocument, "validate_schema", rxml_document_validate_schema, 1);
1128
+ rb_define_method(cXMLDocument, "validate_relaxng", rxml_document_validate_relaxng, 1);
1129
+ }