libxml-ruby 1.1.2-x86-mswin32-60 → 1.1.3-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,7 +23,7 @@ void rxml_attr_decl_mark(xmlAttributePtr xattribute)
23
23
  return;
24
24
  }
25
25
 
26
- rxml_node_mark_common((xmlNodePtr) xattribute);
26
+ rxml_node_mark((xmlNodePtr) xattribute);
27
27
  }
28
28
 
29
29
  VALUE rxml_attr_decl_wrap(xmlAttributePtr xattribute)
@@ -36,7 +36,7 @@ VALUE cXMLAttributes;
36
36
 
37
37
  void rxml_attributes_mark(xmlNodePtr xnode)
38
38
  {
39
- rxml_node_mark_common(xnode);
39
+ rxml_node_mark(xnode);
40
40
  }
41
41
 
42
42
  /*
@@ -80,7 +80,7 @@ static VALUE rxml_attributes_get_attribute(VALUE self, VALUE name)
80
80
  xmlNodePtr xnode;
81
81
  xmlAttrPtr xattr;
82
82
 
83
- name = check_string_or_symbol(name);
83
+ name = rb_obj_as_string(name);
84
84
 
85
85
  Data_Get_Struct(self, xmlNode, xnode);
86
86
 
@@ -114,7 +114,7 @@ static VALUE rxml_attributes_get_attribute_ns(VALUE self, VALUE namespace,
114
114
  xmlNodePtr xnode;
115
115
  xmlAttrPtr xattr;
116
116
 
117
- name = check_string_or_symbol(name);
117
+ name = rb_obj_as_string(name);
118
118
 
119
119
  Data_Get_Struct(self, xmlNode, xnode);
120
120
 
@@ -1,86 +1,86 @@
1
- #include "ruby_libxml.h"
2
- #include <string.h>
3
- #include <libxml/xmlIO.h>
4
-
5
- /*
6
- int xmlRegisterInputCallbacks (xmlInputMatchCallback matchFunc,
7
- xmlInputOpenCallback openFunc,
8
- xmlInputReadCallback readFunc,
9
- xmlInputCloseCallback closeFunc);
10
-
11
-
12
- int (*xmlInputMatchCallback) (char const *filename);
13
- void* (*xmlInputOpenCallback) (char const *filename);
14
- int (*xmlInputReadCallback) (void *context,
15
- char *buffer,
16
- int len);
17
- int (*xmlInputCloseCallback) (void *context);
18
- */
19
-
20
- typedef struct deb_doc_context
21
- {
22
- char *buffer;
23
- char *bpos;
24
- int remaining;
25
- } deb_doc_context;
26
-
27
- int deb_Match(char const *filename)
28
- {
29
- fprintf(stderr, "deb_Match: %s\n", filename);
30
- if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "deb://", 6))
31
- {
32
- return (1);
33
- }
34
- return (0);
35
- }
36
-
37
- void* deb_Open(char const *filename)
38
- {
39
- deb_doc_context *deb_doc;
40
- VALUE res;
41
-
42
- deb_doc = (deb_doc_context*) malloc(sizeof(deb_doc_context));
43
-
44
- res = rb_funcall(rb_funcall(rb_mKernel, rb_intern("const_get"), 1,
45
- rb_str_new2("DEBSystem")), rb_intern("document_query"), 1, rb_str_new2(
46
- filename));
47
- deb_doc->buffer = strdup(StringValuePtr(res));
48
- //deb_doc->buffer = strdup("<serepes>serepes</serepes>");
49
-
50
- deb_doc->bpos = deb_doc->buffer;
51
- deb_doc->remaining = strlen(deb_doc->buffer);
52
- return deb_doc;
53
- }
54
-
55
- int deb_Read(void *context, char *buffer, int len)
56
- {
57
- deb_doc_context *deb_doc;
58
- int ret_len;
59
- deb_doc = (deb_doc_context*) context;
60
-
61
- if (len >= deb_doc->remaining)
62
- {
63
- ret_len = deb_doc->remaining;
64
- }
65
- else
66
- {
67
- ret_len = len;
68
- }
69
- deb_doc->remaining -= ret_len;
70
- strncpy(buffer, deb_doc->bpos, ret_len);
71
- deb_doc->bpos += ret_len;
72
-
73
- return ret_len;
74
- }
75
-
76
- int deb_Close(void *context)
77
- {
78
- free(((deb_doc_context*) context)->buffer);
79
- free(context);
80
- return 1;
81
- }
82
-
83
- void deb_register_cbg()
84
- {
85
- xmlRegisterInputCallbacks(deb_Match, deb_Open, deb_Read, deb_Close);
86
- }
1
+ #include "ruby_libxml.h"
2
+ #include <string.h>
3
+ #include <libxml/xmlIO.h>
4
+
5
+ /*
6
+ int xmlRegisterInputCallbacks (xmlInputMatchCallback matchFunc,
7
+ xmlInputOpenCallback openFunc,
8
+ xmlInputReadCallback readFunc,
9
+ xmlInputCloseCallback closeFunc);
10
+
11
+
12
+ int (*xmlInputMatchCallback) (char const *filename);
13
+ void* (*xmlInputOpenCallback) (char const *filename);
14
+ int (*xmlInputReadCallback) (void *context,
15
+ char *buffer,
16
+ int len);
17
+ int (*xmlInputCloseCallback) (void *context);
18
+ */
19
+
20
+ typedef struct deb_doc_context
21
+ {
22
+ char *buffer;
23
+ char *bpos;
24
+ int remaining;
25
+ } deb_doc_context;
26
+
27
+ int deb_Match(char const *filename)
28
+ {
29
+ fprintf(stderr, "deb_Match: %s\n", filename);
30
+ if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "deb://", 6))
31
+ {
32
+ return (1);
33
+ }
34
+ return (0);
35
+ }
36
+
37
+ void* deb_Open(char const *filename)
38
+ {
39
+ deb_doc_context *deb_doc;
40
+ VALUE res;
41
+
42
+ deb_doc = (deb_doc_context*) malloc(sizeof(deb_doc_context));
43
+
44
+ res = rb_funcall(rb_funcall(rb_mKernel, rb_intern("const_get"), 1,
45
+ rb_str_new2("DEBSystem")), rb_intern("document_query"), 1, rb_str_new2(
46
+ filename));
47
+ deb_doc->buffer = strdup(StringValuePtr(res));
48
+ //deb_doc->buffer = strdup("<serepes>serepes</serepes>");
49
+
50
+ deb_doc->bpos = deb_doc->buffer;
51
+ deb_doc->remaining = strlen(deb_doc->buffer);
52
+ return deb_doc;
53
+ }
54
+
55
+ int deb_Read(void *context, char *buffer, int len)
56
+ {
57
+ deb_doc_context *deb_doc;
58
+ int ret_len;
59
+ deb_doc = (deb_doc_context*) context;
60
+
61
+ if (len >= deb_doc->remaining)
62
+ {
63
+ ret_len = deb_doc->remaining;
64
+ }
65
+ else
66
+ {
67
+ ret_len = len;
68
+ }
69
+ deb_doc->remaining -= ret_len;
70
+ strncpy(buffer, deb_doc->bpos, ret_len);
71
+ deb_doc->bpos += ret_len;
72
+
73
+ return ret_len;
74
+ }
75
+
76
+ int deb_Close(void *context)
77
+ {
78
+ free(((deb_doc_context*) context)->buffer);
79
+ free(context);
80
+ return 1;
81
+ }
82
+
83
+ void deb_register_cbg()
84
+ {
85
+ xmlRegisterInputCallbacks(deb_Match, deb_Open, deb_Read, deb_Close);
86
+ }
@@ -1,915 +1,936 @@
1
- /* $Id: ruby_xml_document.c 804 2009-03-05 08:30:56Z 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 read a document from a file:
12
- *
13
- * doc = XML::Document.file('my_file')
14
- *
15
- * To use a parser to read a document:
16
- *
17
- * parser = XML::Parser.file('my_file')
18
- * doc = parser.parse
19
- *
20
- * To create a document from scratch:
21
- *
22
- * doc = XML::Document.new()
23
- * doc.root = XML::Node.new('root_node')
24
- * doc.root << XML::Node.new('elem1')
25
- * doc.save(filename, :indent => true, :encoding => 'UTF-8')
26
- *
27
- * To write a document to a file:
28
- *
29
- * doc = XML::Document.new()
30
- * doc.root = XML::Node.new('root_node')
31
- * root = doc.root
32
- *
33
- * root << elem1 = XML::Node.new('elem1')
34
- * elem1['attr1'] = 'val1'
35
- * elem1['attr2'] = 'val2'
36
- *
37
- * root << elem2 = XML::Node.new('elem2')
38
- * elem2['attr1'] = 'val1'
39
- * elem2['attr2'] = 'val2'
40
- *
41
- * root << elem3 = XML::Node.new('elem3')
42
- * elem3 << elem4 = XML::Node.new('elem4')
43
- * elem3 << elem5 = XML::Node.new('elem5')
44
- *
45
- * elem5 << elem6 = XML::Node.new('elem6')
46
- * elem6 << 'Content for element 6'
47
- *
48
- * elem3['attr'] = 'baz'
49
- *
50
- * doc.save(filename, :indent => true, :encoding => 'UTF-8')
51
- */
52
-
53
- #include <stdarg.h>
54
- #include "ruby_libxml.h"
55
- #include "ruby_xml_document.h"
56
-
57
- VALUE cXMLDocument;
58
-
59
-
60
- void rxml_document_free(xmlDocPtr xdoc)
61
- {
62
- xdoc->_private = NULL;
63
- xmlFreeDoc(xdoc);
64
- }
65
-
66
- VALUE rxml_document_wrap(xmlDocPtr xdoc)
67
- {
68
- VALUE result;
69
-
70
- // This node is already wrapped
71
- if (xdoc->_private != NULL)
72
- {
73
- result = (VALUE) xdoc->_private;
74
- }
75
- else
76
- {
77
- result = Data_Wrap_Struct(cXMLDocument, NULL, rxml_document_free, xdoc);
78
- xdoc->_private = (void*) result;
79
- }
80
-
81
- return result;
82
- }
83
-
84
- static void LibXML_validity_warning(void * ctxt, const char * msg, va_list ap)
85
- {
86
- if (rb_block_given_p())
87
- {
88
- char buff[1024];
89
- snprintf(buff, 1024, msg, ap);
90
- rb_yield(rb_ary_new3(2, rb_str_new2(buff), Qfalse));
91
- }
92
- else
93
- {
94
- fprintf(stderr, "warning -- found validity error: ");
95
- fprintf(stderr, msg, ap);
96
- }
97
- }
98
-
99
- /*
100
- * call-seq:
101
- * XML::Document.alloc(xml_version = 1.0) -> document
102
- *
103
- * Alocates a new XML::Document, optionally specifying the
104
- * XML version.
105
- */
106
- static VALUE rxml_document_alloc(VALUE klass)
107
- {
108
- return Data_Wrap_Struct(klass, NULL, rxml_document_free, NULL);
109
- }
110
-
111
- /*
112
- * call-seq:
113
- * XML::Document.initialize(xml_version = 1.0) -> document
114
- *
115
- * Initializes a new XML::Document, optionally specifying the
116
- * XML version.
117
- */
118
- static VALUE rxml_document_initialize(int argc, VALUE *argv, VALUE self)
119
- {
120
- xmlDocPtr xdoc;
121
- VALUE xmlver;
122
-
123
- switch (argc)
124
- {
125
- case 0:
126
- xmlver = rb_str_new2("1.0");
127
- break;
128
- case 1:
129
- rb_scan_args(argc, argv, "01", &xmlver);
130
- break;
131
- default:
132
- rb_raise(rb_eArgError, "wrong number of arguments (need 0 or 1)");
133
- }
134
-
135
- Check_Type(xmlver, T_STRING);
136
- xdoc = xmlNewDoc((xmlChar*) StringValuePtr(xmlver));
137
- xdoc->_private = (void*) self;
138
- DATA_PTR(self) = xdoc;
139
-
140
- return self;
141
- }
142
-
143
- /*
144
- * call-seq:
145
- * document.compression -> num
146
- *
147
- * Obtain this document's compression mode identifier.
148
- */
149
- static VALUE rxml_document_compression_get(VALUE self)
150
- {
151
- #ifdef HAVE_ZLIB_H
152
- xmlDocPtr xdoc;
153
-
154
- int compmode;
155
- Data_Get_Struct(self, xmlDoc, xdoc);
156
-
157
- compmode = xmlGetDocCompressMode(xdoc);
158
- if (compmode == -1)
159
- return(Qnil);
160
- else
161
- return(INT2NUM(compmode));
162
- #else
163
- rb_warn("libxml not compiled with zlib support");
164
- return (Qfalse);
165
- #endif
166
- }
167
-
168
- /*
169
- * call-seq:
170
- * document.compression = num
171
- *
172
- * Set this document's compression mode.
173
- */
174
- static VALUE rxml_document_compression_set(VALUE self, VALUE num)
175
- {
176
- #ifdef HAVE_ZLIB_H
177
- xmlDocPtr xdoc;
178
-
179
- int compmode;
180
- Check_Type(num, T_FIXNUM);
181
- Data_Get_Struct(self, xmlDoc, xdoc);
182
-
183
- if (xdoc == NULL)
184
- {
185
- return(Qnil);
186
- }
187
- else
188
- {
189
- xmlSetDocCompressMode(xdoc, NUM2INT(num));
190
-
191
- compmode = xmlGetDocCompressMode(xdoc);
192
- if (compmode == -1)
193
- return(Qnil);
194
- else
195
- return(INT2NUM(compmode));
196
- }
197
- #else
198
- rb_warn("libxml compiled without zlib support");
199
- return (Qfalse);
200
- #endif
201
- }
202
-
203
- /*
204
- * call-seq:
205
- * document.compression? -> (true|false)
206
- *
207
- * Determine whether this document is compressed.
208
- */
209
- static VALUE rxml_document_compression_q(VALUE self)
210
- {
211
- #ifdef HAVE_ZLIB_H
212
- xmlDocPtr xdoc;
213
-
214
- Data_Get_Struct(self, xmlDoc, xdoc);
215
-
216
- if (xdoc->compression != -1)
217
- return(Qtrue);
218
- else
219
- return(Qfalse);
220
- #else
221
- rb_warn("libxml compiled without zlib support");
222
- return (Qfalse);
223
- #endif
224
- }
225
-
226
- /*
227
- * call-seq:
228
- * document.child -> node
229
- *
230
- * Get this document's child node.
231
- */
232
- static VALUE rxml_document_child_get(VALUE self)
233
- {
234
- xmlDocPtr xdoc;
235
- Data_Get_Struct(self, xmlDoc, xdoc);
236
-
237
- if (xdoc->children == NULL)
238
- return (Qnil);
239
-
240
- return rxml_node_wrap(xdoc->children);
241
- }
242
-
243
- /*
244
- * call-seq:
245
- * document.child? -> (true|false)
246
- *
247
- * Determine whether this document has a child node.
248
- */
249
- static VALUE rxml_document_child_q(VALUE self)
250
- {
251
- xmlDocPtr xdoc;
252
- Data_Get_Struct(self, xmlDoc, xdoc);
253
-
254
- if (xdoc->children == NULL)
255
- return (Qfalse);
256
- else
257
- return (Qtrue);
258
- }
259
-
260
-
261
- /*
262
- * call-seq:
263
- * node.debug -> true|false
264
- *
265
- * Print libxml debugging information to stdout.
266
- * Requires that libxml was compiled with debugging enabled.
267
- */
268
- static VALUE rxml_document_debug(VALUE self)
269
- {
270
- #ifdef LIBXML_DEBUG_ENABLED
271
- xmlDocPtr xdoc;
272
- Data_Get_Struct(self, xmlDoc, xdoc);
273
- xmlDebugDumpDocument(NULL, xdoc);
274
- return Qtrue;
275
- #else
276
- rb_warn("libxml was compiled without debugging support.")
277
- return Qfalse;
278
- #endif
279
- }
280
-
281
- /*
282
- * call-seq:
283
- * document.encoding -> XML::Encoding::UTF_8
284
- *
285
- * Obtain the encoding specified by this document.
286
- */
287
- static VALUE rxml_document_encoding_get(VALUE self)
288
- {
289
- xmlDocPtr xdoc;
290
- const char *xencoding;
291
- Data_Get_Struct(self, xmlDoc, xdoc);
292
-
293
- xencoding = (const char*)xdoc->encoding;
294
- return INT2NUM(xmlParseCharEncoding(xencoding));
295
- }
296
-
297
- /*
298
- * call-seq:
299
- * document.encoding = XML::Encoding::UTF_8
300
- *
301
- * Set the encoding for this document.
302
- */
303
- static VALUE rxml_document_encoding_set(VALUE self, VALUE encoding)
304
- {
305
- xmlDocPtr xdoc;
306
- const char* xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(encoding));
307
-
308
- Data_Get_Struct(self, xmlDoc, xdoc);
309
-
310
- if (xdoc->encoding != NULL)
311
- xmlFree((xmlChar *) xdoc->encoding);
312
-
313
- xdoc->encoding = xmlStrdup((xmlChar *)xencoding);
314
- return self;
315
- }
316
-
317
- /*
318
- * call-seq:
319
- * document.last -> node
320
- *
321
- * Obtain the last node.
322
- */
323
- static VALUE rxml_document_last_get(VALUE self)
324
- {
325
- xmlDocPtr xdoc;
326
-
327
- Data_Get_Struct(self, xmlDoc, xdoc);
328
-
329
- if (xdoc->last == NULL)
330
- return (Qnil);
331
-
332
- return rxml_node_wrap(xdoc->last);
333
- }
334
-
335
- /*
336
- * call-seq:
337
- * document.last? -> (true|false)
338
- *
339
- * Determine whether there is a last node.
340
- */
341
- static VALUE rxml_document_last_q(VALUE self)
342
- {
343
- xmlDocPtr xdoc;
344
-
345
- Data_Get_Struct(self, xmlDoc, xdoc);
346
-
347
- if (xdoc->last == NULL)
348
- return (Qfalse);
349
- else
350
- return (Qtrue);
351
- }
352
-
353
- /*
354
- * call-seq:
355
- * document.next -> node
356
- *
357
- * Obtain the next node.
358
- */
359
- static VALUE rxml_document_next_get(VALUE self)
360
- {
361
- xmlDocPtr xdoc;
362
-
363
- Data_Get_Struct(self, xmlDoc, xdoc);
364
-
365
- if (xdoc->next == NULL)
366
- return (Qnil);
367
-
368
- return rxml_node_wrap(xdoc->next);
369
- }
370
-
371
- /*
372
- * call-seq:
373
- * document.next? -> (true|false)
374
- *
375
- * Determine whether there is a next node.
376
- */
377
- static VALUE rxml_document_next_q(VALUE self)
378
- {
379
- xmlDocPtr xdoc;
380
-
381
- Data_Get_Struct(self, xmlDoc, xdoc);
382
-
383
- if (xdoc->next == NULL)
384
- return (Qfalse);
385
- else
386
- return (Qtrue);
387
- }
388
-
389
- /*
390
- * call-seq:
391
- * node.type -> num
392
- *
393
- * Obtain this node's type identifier.
394
- */
395
- static VALUE rxml_document_node_type(VALUE self)
396
- {
397
- xmlNodePtr xnode;
398
- Data_Get_Struct(self, xmlNode, xnode);
399
- return (INT2NUM(xnode->type));
400
- }
401
-
402
- /*
403
- * call-seq:
404
- * document.parent -> node
405
- *
406
- * Obtain the parent node.
407
- */
408
- static VALUE rxml_document_parent_get(VALUE self)
409
- {
410
- xmlDocPtr xdoc;
411
-
412
- Data_Get_Struct(self, xmlDoc, xdoc);
413
-
414
- if (xdoc->parent == NULL)
415
- return (Qnil);
416
-
417
- return rxml_node_wrap(xdoc->parent);
418
- }
419
-
420
- /*
421
- * call-seq:
422
- * document.parent? -> (true|false)
423
- *
424
- * Determine whether there is a parent node.
425
- */
426
- static VALUE rxml_document_parent_q(VALUE self)
427
- {
428
- xmlDocPtr xdoc;
429
-
430
- Data_Get_Struct(self, xmlDoc, xdoc);
431
-
432
- if (xdoc->parent == NULL)
433
- return (Qfalse);
434
- else
435
- return (Qtrue);
436
- }
437
-
438
- /*
439
- * call-seq:
440
- * document.prev -> node
441
- *
442
- * Obtain the previous node.
443
- */
444
- static VALUE rxml_document_prev_get(VALUE self)
445
- {
446
- xmlDocPtr xdoc;
447
-
448
- Data_Get_Struct(self, xmlDoc, xdoc);
449
-
450
- if (xdoc->prev == NULL)
451
- return (Qnil);
452
-
453
- return rxml_node_wrap(xdoc->prev);
454
- }
455
-
456
- /*
457
- * call-seq:
458
- * document.prev? -> (true|false)
459
- *
460
- * Determine whether there is a previous node.
461
- */
462
- static VALUE rxml_document_prev_q(VALUE self)
463
- {
464
- xmlDocPtr xdoc;
465
-
466
- Data_Get_Struct(self, xmlDoc, xdoc);
467
-
468
- if (xdoc->prev == NULL)
469
- return (Qfalse);
470
- else
471
- return (Qtrue);
472
- }
473
-
474
- /*
475
- * call-seq:
476
- * document.root -> node
477
- *
478
- * Obtain the root node.
479
- */
480
- static VALUE rxml_document_root_get(VALUE self)
481
- {
482
- xmlDocPtr xdoc;
483
-
484
- xmlNodePtr root;
485
-
486
- Data_Get_Struct(self, xmlDoc, xdoc);
487
- root = xmlDocGetRootElement(xdoc);
488
-
489
- if (root == NULL)
490
- return (Qnil);
491
-
492
- return rxml_node_wrap(root);
493
- }
494
-
495
- /*
496
- * call-seq:
497
- * document.root = node
498
- *
499
- * Set the root node.
500
- */
501
- static VALUE rxml_document_root_set(VALUE self, VALUE node)
502
- {
503
- xmlDocPtr xdoc;
504
- xmlNodePtr xroot, xnode;
505
-
506
- if (rb_obj_is_kind_of(node, cXMLNode) == Qfalse)
507
- rb_raise(rb_eTypeError, "must pass an XML::Node type object");
508
-
509
- Data_Get_Struct(self, xmlDoc, xdoc);
510
- Data_Get_Struct(node, xmlNode, xnode);
511
-
512
- xroot = xmlDocSetRootElement(xdoc, xnode);
513
- if (xroot == NULL)
514
- return (Qnil);
515
-
516
- return rxml_node_wrap(xroot);
517
- }
518
-
519
- /*
520
- * call-seq:
521
- * document.save(filename) -> int
522
- * document.save(filename, :indent => true, :encoding => 'UTF-8') -> int
523
- *
524
- * Saves a document to a file. You may provide an optional hash table
525
- * to control how the string is generated. Valid options are:
526
- *
527
- * :indent - Specifies if the string should be indented. The default value
528
- * is true. Note that indentation is only added if both :indent is
529
- * true and XML.indent_tree_output is true. If :indent is set to false,
530
- * then both indentation and line feeds are removed from the result.
531
- *
532
- * :encoding - Specifies the output encoding of the string. It
533
- * defaults to the original encoding of the document (see
534
- * #encoding. To override the orginal encoding, use one of the
535
- * XML::Encoding encoding constants. */
536
- static VALUE rxml_document_save(int argc, VALUE *argv, VALUE self)
537
- {
538
- VALUE options = Qnil;
539
- VALUE filename = Qnil;
540
- xmlDocPtr xdoc;
541
- int indent = 1;
542
- const char *xfilename;
543
- const char *xencoding;
544
- int length;
545
-
546
- rb_scan_args(argc, argv, "11", &filename, &options);
547
-
548
- Check_Type(filename, T_STRING);
549
- xfilename = StringValuePtr(filename);
550
-
551
- Data_Get_Struct(self, xmlDoc, xdoc);
552
- xencoding = xdoc->encoding;
553
-
554
- if (!NIL_P(options))
555
- {
556
- VALUE rencoding, rindent;
557
- Check_Type(options, T_HASH);
558
- rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
559
- rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
560
-
561
- if (rindent == Qfalse)
562
- indent = 0;
563
-
564
- if (rencoding != Qnil)
565
- {
566
- xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
567
- if (!xencoding)
568
- rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
569
- }
570
- }
571
-
572
- length = xmlSaveFormatFileEnc(xfilename, xdoc, xencoding, indent);
573
-
574
- if (length == -1)
575
- rxml_raise(&xmlLastError);
576
-
577
- return (INT2NUM(length));
578
- }
579
-
580
- /*
581
- * call-seq:
582
- * document.standalone? -> (true|false)
583
- *
584
- * Determine whether this is a standalone document.
585
- */
586
- static VALUE rxml_document_standalone_q(VALUE self)
587
- {
588
- xmlDocPtr xdoc;
589
-
590
- Data_Get_Struct(self, xmlDoc, xdoc);
591
- if (xdoc->standalone)
592
- return (Qtrue);
593
- else
594
- return (Qfalse);
595
- }
596
-
597
- /*
598
- * call-seq:
599
- * document.to_s -> "string"
600
- * document.to_s(:indent => true, :encoding => 'UTF-8') -> "string"
601
- *
602
- * Converts a document, and all of its children, to a string representation.
603
- * You may provide an optional hash table to control how the string is
604
- * generated. Valid options are:
605
- *
606
- * :indent - Specifies if the string should be indented. The default value
607
- * is true. Note that indentation is only added if both :indent is
608
- * true and XML.indent_tree_output is true. If :indent is set to false,
609
- * then both indentation and line feeds are removed from the result.
610
- *
611
- * :encoding - Specifies the output encoding of the string. It
612
- * defaults to XML::Encoding::UTF8. To change it, use one of the
613
- * XML::Encoding encoding constants. */
614
- static VALUE rxml_document_to_s(int argc, VALUE *argv, VALUE self)
615
- {
616
- VALUE result;
617
- VALUE options = Qnil;
618
- xmlDocPtr xdoc;
619
- int indent = 1;
620
- const char *xencoding = "UTF-8";
621
- xmlChar *buffer;
622
- int length;
623
-
624
- rb_scan_args(argc, argv, "01", &options);
625
-
626
- if (!NIL_P(options))
627
- {
628
- VALUE rencoding, rindent;
629
- Check_Type(options, T_HASH);
630
- rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
631
- rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
632
-
633
- if (rindent == Qfalse)
634
- indent = 0;
635
-
636
- if (rencoding != Qnil)
637
- {
638
- xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
639
- if (!xencoding)
640
- rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
641
- }
642
- }
643
-
644
- Data_Get_Struct(self, xmlDoc, xdoc);
645
- xmlDocDumpFormatMemoryEnc(xdoc, &buffer, &length, xencoding, indent);
646
-
647
- result = rb_str_new((const char*) buffer, length);
648
- xmlFree(buffer);
649
- return result;
650
- }
651
-
652
- /*
653
- * call-seq:
654
- * document.url -> "url"
655
- *
656
- * Obtain this document's source URL, if any.
657
- */
658
- static VALUE rxml_document_url_get(VALUE self)
659
- {
660
- xmlDocPtr xdoc;
661
-
662
- Data_Get_Struct(self, xmlDoc, xdoc);
663
- if (xdoc->URL == NULL)
664
- return (Qnil);
665
- else
666
- return (rb_str_new2((const char*) xdoc->URL));
667
- }
668
-
669
- /*
670
- * call-seq:
671
- * document.version -> "version"
672
- *
673
- * Obtain the XML version specified by this document.
674
- */
675
- static VALUE rxml_document_version_get(VALUE self)
676
- {
677
- xmlDocPtr xdoc;
678
-
679
- Data_Get_Struct(self, xmlDoc, xdoc);
680
- if (xdoc->version == NULL)
681
- return (Qnil);
682
- else
683
- return (rb_str_new2((const char*) xdoc->version));
684
- }
685
-
686
- /*
687
- * call-seq:
688
- * document.xhtml? -> (true|false)
689
- *
690
- * Determine whether this is an XHTML document.
691
- */
692
- static VALUE rxml_document_xhtml_q(VALUE self)
693
- {
694
- xmlDocPtr xdoc;
695
- xmlDtdPtr xdtd;
696
- Data_Get_Struct(self, xmlDoc, xdoc);
697
- xdtd = xmlGetIntSubset(xdoc);
698
- if (xdtd != NULL && xmlIsXHTML(xdtd->SystemID, xdtd->ExternalID) > 0)
699
- return (Qtrue);
700
- else
701
- return (Qfalse);
702
- }
703
-
704
- /*
705
- * call-seq:
706
- * document.xinclude -> num
707
- *
708
- * Process xinclude directives in this document.
709
- */
710
- static VALUE rxml_document_xinclude(VALUE self)
711
- {
712
- #ifdef LIBXML_XINCLUDE_ENABLED
713
- xmlDocPtr xdoc;
714
-
715
- int ret;
716
-
717
- Data_Get_Struct(self, xmlDoc, xdoc);
718
- ret = xmlXIncludeProcess(xdoc);
719
- if (ret >= 0)
720
- {
721
- return(INT2NUM(ret));
722
- }
723
- else
724
- {
725
- rxml_raise(&xmlLastError);
726
- return Qnil;
727
- }
728
- #else
729
- rb_warn(
730
- "libxml was compiled without XInclude support. Please recompile libxml and ruby-libxml");
731
- return (Qfalse);
732
- #endif
733
- }
734
-
735
- void LibXML_validity_error(void * ctxt, const char * msg, va_list ap)
736
- {
737
- if (rb_block_given_p())
738
- {
739
- char buff[1024];
740
- snprintf(buff, 1024, msg, ap);
741
- rb_yield(rb_ary_new3(2, rb_str_new2(buff), Qtrue));
742
- }
743
- else
744
- {
745
- fprintf(stderr, "error -- found validity error: ");
746
- fprintf(stderr, msg, ap);
747
- }
748
- }
749
-
750
- /*
751
- * call-seq:
752
- * document.order_elements!
753
- *
754
- * Call this routine to speed up XPath computation on static documents.
755
- * This stamps all the element nodes with the document order.
756
- */
757
- static VALUE rxml_document_order_elements(VALUE self)
758
- {
759
- xmlDocPtr xdoc;
760
-
761
- Data_Get_Struct(self, xmlDoc, xdoc);
762
- return LONG2FIX(xmlXPathOrderDocElems(xdoc));
763
- }
764
-
765
- /*
766
- * call-seq:
767
- * document.validate_schema(schema) -> (true|false)
768
- *
769
- * Validate this document against the specified XML::Schema.
770
- *
771
- * If a block is provided it is used as an error handler for validaten errors.
772
- * The block is called with two argument, the message and a flag indication
773
- * if the message is an error (true) or a warning (false).
774
- */
775
- static VALUE rxml_document_validate_schema(VALUE self, VALUE schema)
776
- {
777
- xmlSchemaValidCtxtPtr vptr;
778
- xmlDocPtr xdoc;
779
- xmlSchemaPtr xschema;
780
- int is_invalid;
781
-
782
- Data_Get_Struct(self, xmlDoc, xdoc);
783
- Data_Get_Struct(schema, xmlSchema, xschema);
784
-
785
- vptr = xmlSchemaNewValidCtxt(xschema);
786
-
787
- xmlSchemaSetValidErrors(vptr,
788
- (xmlSchemaValidityErrorFunc) LibXML_validity_error,
789
- (xmlSchemaValidityWarningFunc) LibXML_validity_warning, NULL);
790
-
791
- is_invalid = xmlSchemaValidateDoc(vptr, xdoc);
792
- xmlSchemaFreeValidCtxt(vptr);
793
- if (is_invalid)
794
- {
795
- rxml_raise(&xmlLastError);
796
- return Qfalse;
797
- }
798
- else
799
- {
800
- return Qtrue;
801
- }
802
- }
803
-
804
- /*
805
- * call-seq:
806
- * document.validate_schema(relaxng) -> (true|false)
807
- *
808
- * Validate this document against the specified XML::RelaxNG.
809
- *
810
- * If a block is provided it is used as an error handler for validaten errors.
811
- * The block is called with two argument, the message and a flag indication
812
- * if the message is an error (true) or a warning (false).
813
- */
814
- static VALUE rxml_document_validate_relaxng(VALUE self, VALUE relaxng)
815
- {
816
- xmlRelaxNGValidCtxtPtr vptr;
817
- xmlDocPtr xdoc;
818
- xmlRelaxNGPtr xrelaxng;
819
- int is_invalid;
820
-
821
- Data_Get_Struct(self, xmlDoc, xdoc);
822
- Data_Get_Struct(relaxng, xmlRelaxNG, xrelaxng);
823
-
824
- vptr = xmlRelaxNGNewValidCtxt(xrelaxng);
825
-
826
- xmlRelaxNGSetValidErrors(vptr,
827
- (xmlRelaxNGValidityErrorFunc) LibXML_validity_error,
828
- (xmlRelaxNGValidityWarningFunc) LibXML_validity_warning, NULL);
829
-
830
- is_invalid = xmlRelaxNGValidateDoc(vptr, xdoc);
831
- xmlRelaxNGFreeValidCtxt(vptr);
832
- if (is_invalid)
833
- {
834
- rxml_raise(&xmlLastError);
835
- return Qfalse;
836
- }
837
- else
838
- {
839
- return Qtrue;
840
- }
841
- }
842
-
843
- /*
844
- * call-seq:
845
- * document.validate(dtd) -> (true|false)
846
- *
847
- * Validate this document against the specified XML::DTD.
848
- */
849
- static VALUE rxml_document_validate_dtd(VALUE self, VALUE dtd)
850
- {
851
- VALUE error = Qnil;
852
- xmlValidCtxt ctxt;
853
- xmlDocPtr xdoc;
854
- xmlDtdPtr xdtd;
855
-
856
- Data_Get_Struct(self, xmlDoc, xdoc);
857
- Data_Get_Struct(dtd, xmlDtd, xdtd);
858
-
859
- ctxt.userData = &error;
860
- ctxt.error = (xmlValidityErrorFunc) LibXML_validity_error;
861
- ctxt.warning = (xmlValidityWarningFunc) LibXML_validity_warning;
862
-
863
- ctxt.nodeNr = 0;
864
- ctxt.nodeTab = NULL;
865
- ctxt.vstateNr = 0;
866
- ctxt.vstateTab = NULL;
867
-
868
- if (xmlValidateDtd(&ctxt, xdoc, xdtd))
869
- {
870
- return (Qtrue);
871
- }
872
- else
873
- {
874
- rxml_raise(&xmlLastError);
875
- return Qfalse;
876
- }
877
- }
878
-
879
- void rxml_init_document(void)
880
- {
881
- cXMLDocument = rb_define_class_under(mXML, "Document", rb_cObject);
882
- rb_define_alloc_func(cXMLDocument, rxml_document_alloc);
883
-
884
- rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1);
885
- rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0);
886
- rb_define_method(cXMLDocument, "child?", rxml_document_child_q, 0);
887
- rb_define_method(cXMLDocument, "compression", rxml_document_compression_get, 0);
888
- rb_define_method(cXMLDocument, "compression=", rxml_document_compression_set, 1);
889
- rb_define_method(cXMLDocument, "compression?", rxml_document_compression_q, 0);
890
- rb_define_method(cXMLDocument, "debug", rxml_document_debug, 0);
891
- rb_define_method(cXMLDocument, "encoding", rxml_document_encoding_get, 0);
892
- rb_define_method(cXMLDocument, "encoding=", rxml_document_encoding_set, 1);
893
- rb_define_method(cXMLDocument, "last", rxml_document_last_get, 0);
894
- rb_define_method(cXMLDocument, "last?", rxml_document_last_q, 0);
895
- rb_define_method(cXMLDocument, "next", rxml_document_next_get, 0);
896
- rb_define_method(cXMLDocument, "next?", rxml_document_next_q, 0);
897
- rb_define_method(cXMLDocument, "node_type", rxml_document_node_type, 0);
898
- rb_define_method(cXMLDocument, "order_elements!", rxml_document_order_elements, 0);
899
- rb_define_method(cXMLDocument, "parent", rxml_document_parent_get, 0);
900
- rb_define_method(cXMLDocument, "parent?", rxml_document_parent_q, 0);
901
- rb_define_method(cXMLDocument, "prev", rxml_document_prev_get, 0);
902
- rb_define_method(cXMLDocument, "prev?", rxml_document_prev_q, 0);
903
- rb_define_method(cXMLDocument, "root", rxml_document_root_get, 0);
904
- rb_define_method(cXMLDocument, "root=", rxml_document_root_set, 1);
905
- rb_define_method(cXMLDocument, "save", rxml_document_save, -1);
906
- rb_define_method(cXMLDocument, "standalone?", rxml_document_standalone_q, 0);
907
- rb_define_method(cXMLDocument, "to_s", rxml_document_to_s, -1);
908
- rb_define_method(cXMLDocument, "url", rxml_document_url_get, 0);
909
- rb_define_method(cXMLDocument, "version", rxml_document_version_get, 0);
910
- rb_define_method(cXMLDocument, "xhtml?", rxml_document_xhtml_q, 0);
911
- rb_define_method(cXMLDocument, "xinclude", rxml_document_xinclude, 0);
912
- rb_define_method(cXMLDocument, "validate", rxml_document_validate_dtd, 1);
913
- rb_define_method(cXMLDocument, "validate_schema", rxml_document_validate_schema, 1);
914
- rb_define_method(cXMLDocument, "validate_relaxng", rxml_document_validate_relaxng, 1);
915
- }
1
+ /* $Id: ruby_xml_document.c 854 2009-03-22 04:27:13Z 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 read a document from a file:
12
+ *
13
+ * doc = XML::Document.file('my_file')
14
+ *
15
+ * To use a parser to read a document:
16
+ *
17
+ * parser = XML::Parser.file('my_file')
18
+ * doc = parser.parse
19
+ *
20
+ * To create a document from scratch:
21
+ *
22
+ * doc = XML::Document.new()
23
+ * doc.root = XML::Node.new('root_node')
24
+ * doc.root << XML::Node.new('elem1')
25
+ * doc.save(filename, :indent => true, :encoding => 'UTF-8')
26
+ *
27
+ * To write a document to a file:
28
+ *
29
+ * doc = XML::Document.new()
30
+ * doc.root = XML::Node.new('root_node')
31
+ * root = doc.root
32
+ *
33
+ * root << elem1 = XML::Node.new('elem1')
34
+ * elem1['attr1'] = 'val1'
35
+ * elem1['attr2'] = 'val2'
36
+ *
37
+ * root << elem2 = XML::Node.new('elem2')
38
+ * elem2['attr1'] = 'val1'
39
+ * elem2['attr2'] = 'val2'
40
+ *
41
+ * root << elem3 = XML::Node.new('elem3')
42
+ * elem3 << elem4 = XML::Node.new('elem4')
43
+ * elem3 << elem5 = XML::Node.new('elem5')
44
+ *
45
+ * elem5 << elem6 = XML::Node.new('elem6')
46
+ * elem6 << 'Content for element 6'
47
+ *
48
+ * elem3['attr'] = 'baz'
49
+ *
50
+ * doc.save(filename, :indent => true, :encoding => 'UTF-8')
51
+ */
52
+
53
+ #include <stdarg.h>
54
+ #include "ruby_libxml.h"
55
+ #include "ruby_xml_document.h"
56
+
57
+ VALUE cXMLDocument;
58
+
59
+
60
+ void rxml_document_free(xmlDocPtr xdoc)
61
+ {
62
+ xdoc->_private = NULL;
63
+ xmlFreeDoc(xdoc);
64
+ }
65
+
66
+ VALUE rxml_document_wrap(xmlDocPtr xdoc)
67
+ {
68
+ VALUE result;
69
+
70
+ // This node is already wrapped
71
+ if (xdoc->_private != NULL)
72
+ {
73
+ result = (VALUE) xdoc->_private;
74
+ }
75
+ else
76
+ {
77
+ result = Data_Wrap_Struct(cXMLDocument, NULL, rxml_document_free, xdoc);
78
+ xdoc->_private = (void*) result;
79
+ }
80
+
81
+ return result;
82
+ }
83
+
84
+ static void LibXML_validity_warning(void * ctxt, const char * msg, va_list ap)
85
+ {
86
+ if (rb_block_given_p())
87
+ {
88
+ char buff[1024];
89
+ snprintf(buff, 1024, msg, ap);
90
+ rb_yield(rb_ary_new3(2, rb_str_new2(buff), Qfalse));
91
+ }
92
+ else
93
+ {
94
+ fprintf(stderr, "warning -- found validity error: ");
95
+ fprintf(stderr, msg, ap);
96
+ }
97
+ }
98
+
99
+ /*
100
+ * call-seq:
101
+ * XML::Document.alloc(xml_version = 1.0) -> document
102
+ *
103
+ * Alocates a new XML::Document, optionally specifying the
104
+ * XML version.
105
+ */
106
+ static VALUE rxml_document_alloc(VALUE klass)
107
+ {
108
+ return Data_Wrap_Struct(klass, NULL, rxml_document_free, NULL);
109
+ }
110
+
111
+ /*
112
+ * call-seq:
113
+ * XML::Document.initialize(xml_version = 1.0) -> document
114
+ *
115
+ * Initializes a new XML::Document, optionally specifying the
116
+ * XML version.
117
+ */
118
+ static VALUE rxml_document_initialize(int argc, VALUE *argv, VALUE self)
119
+ {
120
+ xmlDocPtr xdoc;
121
+ VALUE xmlver;
122
+
123
+ switch (argc)
124
+ {
125
+ case 0:
126
+ xmlver = rb_str_new2("1.0");
127
+ break;
128
+ case 1:
129
+ rb_scan_args(argc, argv, "01", &xmlver);
130
+ break;
131
+ default:
132
+ rb_raise(rb_eArgError, "wrong number of arguments (need 0 or 1)");
133
+ }
134
+
135
+ Check_Type(xmlver, T_STRING);
136
+ xdoc = xmlNewDoc((xmlChar*) StringValuePtr(xmlver));
137
+ xdoc->_private = (void*) self;
138
+ DATA_PTR(self) = xdoc;
139
+
140
+ return self;
141
+ }
142
+
143
+ /*
144
+ * call-seq:
145
+ * document.compression -> num
146
+ *
147
+ * Obtain this document's compression mode identifier.
148
+ */
149
+ static VALUE rxml_document_compression_get(VALUE self)
150
+ {
151
+ #ifdef HAVE_ZLIB_H
152
+ xmlDocPtr xdoc;
153
+
154
+ int compmode;
155
+ Data_Get_Struct(self, xmlDoc, xdoc);
156
+
157
+ compmode = xmlGetDocCompressMode(xdoc);
158
+ if (compmode == -1)
159
+ return(Qnil);
160
+ else
161
+ return(INT2NUM(compmode));
162
+ #else
163
+ rb_warn("libxml not compiled with zlib support");
164
+ return (Qfalse);
165
+ #endif
166
+ }
167
+
168
+ /*
169
+ * call-seq:
170
+ * document.compression = num
171
+ *
172
+ * Set this document's compression mode.
173
+ */
174
+ static VALUE rxml_document_compression_set(VALUE self, VALUE num)
175
+ {
176
+ #ifdef HAVE_ZLIB_H
177
+ xmlDocPtr xdoc;
178
+
179
+ int compmode;
180
+ Check_Type(num, T_FIXNUM);
181
+ Data_Get_Struct(self, xmlDoc, xdoc);
182
+
183
+ if (xdoc == NULL)
184
+ {
185
+ return(Qnil);
186
+ }
187
+ else
188
+ {
189
+ xmlSetDocCompressMode(xdoc, NUM2INT(num));
190
+
191
+ compmode = xmlGetDocCompressMode(xdoc);
192
+ if (compmode == -1)
193
+ return(Qnil);
194
+ else
195
+ return(INT2NUM(compmode));
196
+ }
197
+ #else
198
+ rb_warn("libxml compiled without zlib support");
199
+ return (Qfalse);
200
+ #endif
201
+ }
202
+
203
+ /*
204
+ * call-seq:
205
+ * document.compression? -> (true|false)
206
+ *
207
+ * Determine whether this document is compressed.
208
+ */
209
+ static VALUE rxml_document_compression_q(VALUE self)
210
+ {
211
+ #ifdef HAVE_ZLIB_H
212
+ xmlDocPtr xdoc;
213
+
214
+ Data_Get_Struct(self, xmlDoc, xdoc);
215
+
216
+ if (xdoc->compression != -1)
217
+ return(Qtrue);
218
+ else
219
+ return(Qfalse);
220
+ #else
221
+ rb_warn("libxml compiled without zlib support");
222
+ return (Qfalse);
223
+ #endif
224
+ }
225
+
226
+ /*
227
+ * call-seq:
228
+ * document.child -> node
229
+ *
230
+ * Get this document's child node.
231
+ */
232
+ static VALUE rxml_document_child_get(VALUE self)
233
+ {
234
+ xmlDocPtr xdoc;
235
+ Data_Get_Struct(self, xmlDoc, xdoc);
236
+
237
+ if (xdoc->children == NULL)
238
+ return (Qnil);
239
+
240
+ return rxml_node_wrap(xdoc->children);
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * document.child? -> (true|false)
246
+ *
247
+ * Determine whether this document has a child node.
248
+ */
249
+ static VALUE rxml_document_child_q(VALUE self)
250
+ {
251
+ xmlDocPtr xdoc;
252
+ Data_Get_Struct(self, xmlDoc, xdoc);
253
+
254
+ if (xdoc->children == NULL)
255
+ return (Qfalse);
256
+ else
257
+ return (Qtrue);
258
+ }
259
+
260
+
261
+ /*
262
+ * call-seq:
263
+ * node.debug -> true|false
264
+ *
265
+ * Print libxml debugging information to stdout.
266
+ * Requires that libxml was compiled with debugging enabled.
267
+ */
268
+ static VALUE rxml_document_debug(VALUE self)
269
+ {
270
+ #ifdef LIBXML_DEBUG_ENABLED
271
+ xmlDocPtr xdoc;
272
+ Data_Get_Struct(self, xmlDoc, xdoc);
273
+ xmlDebugDumpDocument(NULL, xdoc);
274
+ return Qtrue;
275
+ #else
276
+ rb_warn("libxml was compiled without debugging support.")
277
+ return Qfalse;
278
+ #endif
279
+ }
280
+
281
+ /*
282
+ * call-seq:
283
+ * document.encoding -> XML::Encoding::UTF_8
284
+ *
285
+ * Obtain the encoding specified by this document.
286
+ */
287
+ static VALUE rxml_document_encoding_get(VALUE self)
288
+ {
289
+ xmlDocPtr xdoc;
290
+ const char *xencoding;
291
+ Data_Get_Struct(self, xmlDoc, xdoc);
292
+
293
+ xencoding = (const char*)xdoc->encoding;
294
+ return INT2NUM(xmlParseCharEncoding(xencoding));
295
+ }
296
+
297
+ /*
298
+ * call-seq:
299
+ * document.encoding = XML::Encoding::UTF_8
300
+ *
301
+ * Set the encoding for this document.
302
+ */
303
+ static VALUE rxml_document_encoding_set(VALUE self, VALUE encoding)
304
+ {
305
+ xmlDocPtr xdoc;
306
+ const char* xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(encoding));
307
+
308
+ Data_Get_Struct(self, xmlDoc, xdoc);
309
+
310
+ if (xdoc->encoding != NULL)
311
+ xmlFree((xmlChar *) xdoc->encoding);
312
+
313
+ xdoc->encoding = xmlStrdup((xmlChar *)xencoding);
314
+ return self;
315
+ }
316
+
317
+ /*
318
+ * call-seq:
319
+ * document.import(node) -> XML::Node
320
+ *
321
+ * Creates a copy of the node that can be inserted into the
322
+ * current document.
323
+ */
324
+ static VALUE rxml_document_import(VALUE self, VALUE node)
325
+ {
326
+ xmlDocPtr xdoc;
327
+ xmlNodePtr xnode, xresult;
328
+
329
+ Data_Get_Struct(self, xmlDoc, xdoc);
330
+ Data_Get_Struct(node, xmlNode, xnode);
331
+
332
+ xresult = xmlDocCopyNode(xnode, xdoc, 1);
333
+
334
+ if (xresult == NULL)
335
+ rxml_raise(&xmlLastError);
336
+
337
+ return rxml_node_wrap(xresult);
338
+ }
339
+
340
+ /*
341
+ * call-seq:
342
+ * document.last -> node
343
+ *
344
+ * Obtain the last node.
345
+ */
346
+ static VALUE rxml_document_last_get(VALUE self)
347
+ {
348
+ xmlDocPtr xdoc;
349
+
350
+ Data_Get_Struct(self, xmlDoc, xdoc);
351
+
352
+ if (xdoc->last == NULL)
353
+ return (Qnil);
354
+
355
+ return rxml_node_wrap(xdoc->last);
356
+ }
357
+
358
+ /*
359
+ * call-seq:
360
+ * document.last? -> (true|false)
361
+ *
362
+ * Determine whether there is a last node.
363
+ */
364
+ static VALUE rxml_document_last_q(VALUE self)
365
+ {
366
+ xmlDocPtr xdoc;
367
+
368
+ Data_Get_Struct(self, xmlDoc, xdoc);
369
+
370
+ if (xdoc->last == NULL)
371
+ return (Qfalse);
372
+ else
373
+ return (Qtrue);
374
+ }
375
+
376
+ /*
377
+ * call-seq:
378
+ * document.next -> node
379
+ *
380
+ * Obtain the next node.
381
+ */
382
+ static VALUE rxml_document_next_get(VALUE self)
383
+ {
384
+ xmlDocPtr xdoc;
385
+
386
+ Data_Get_Struct(self, xmlDoc, xdoc);
387
+
388
+ if (xdoc->next == NULL)
389
+ return (Qnil);
390
+
391
+ return rxml_node_wrap(xdoc->next);
392
+ }
393
+
394
+ /*
395
+ * call-seq:
396
+ * document.next? -> (true|false)
397
+ *
398
+ * Determine whether there is a next node.
399
+ */
400
+ static VALUE rxml_document_next_q(VALUE self)
401
+ {
402
+ xmlDocPtr xdoc;
403
+
404
+ Data_Get_Struct(self, xmlDoc, xdoc);
405
+
406
+ if (xdoc->next == NULL)
407
+ return (Qfalse);
408
+ else
409
+ return (Qtrue);
410
+ }
411
+
412
+ /*
413
+ * call-seq:
414
+ * node.type -> num
415
+ *
416
+ * Obtain this node's type identifier.
417
+ */
418
+ static VALUE rxml_document_node_type(VALUE self)
419
+ {
420
+ xmlNodePtr xnode;
421
+ Data_Get_Struct(self, xmlNode, xnode);
422
+ return (INT2NUM(xnode->type));
423
+ }
424
+
425
+ /*
426
+ * call-seq:
427
+ * document.parent -> node
428
+ *
429
+ * Obtain the parent node.
430
+ */
431
+ static VALUE rxml_document_parent_get(VALUE self)
432
+ {
433
+ xmlDocPtr xdoc;
434
+
435
+ Data_Get_Struct(self, xmlDoc, xdoc);
436
+
437
+ if (xdoc->parent == NULL)
438
+ return (Qnil);
439
+
440
+ return rxml_node_wrap(xdoc->parent);
441
+ }
442
+
443
+ /*
444
+ * call-seq:
445
+ * document.parent? -> (true|false)
446
+ *
447
+ * Determine whether there is a parent node.
448
+ */
449
+ static VALUE rxml_document_parent_q(VALUE self)
450
+ {
451
+ xmlDocPtr xdoc;
452
+
453
+ Data_Get_Struct(self, xmlDoc, xdoc);
454
+
455
+ if (xdoc->parent == NULL)
456
+ return (Qfalse);
457
+ else
458
+ return (Qtrue);
459
+ }
460
+
461
+ /*
462
+ * call-seq:
463
+ * document.prev -> node
464
+ *
465
+ * Obtain the previous node.
466
+ */
467
+ static VALUE rxml_document_prev_get(VALUE self)
468
+ {
469
+ xmlDocPtr xdoc;
470
+
471
+ Data_Get_Struct(self, xmlDoc, xdoc);
472
+
473
+ if (xdoc->prev == NULL)
474
+ return (Qnil);
475
+
476
+ return rxml_node_wrap(xdoc->prev);
477
+ }
478
+
479
+ /*
480
+ * call-seq:
481
+ * document.prev? -> (true|false)
482
+ *
483
+ * Determine whether there is a previous node.
484
+ */
485
+ static VALUE rxml_document_prev_q(VALUE self)
486
+ {
487
+ xmlDocPtr xdoc;
488
+
489
+ Data_Get_Struct(self, xmlDoc, xdoc);
490
+
491
+ if (xdoc->prev == NULL)
492
+ return (Qfalse);
493
+ else
494
+ return (Qtrue);
495
+ }
496
+
497
+ /*
498
+ * call-seq:
499
+ * document.root -> node
500
+ *
501
+ * Obtain the root node.
502
+ */
503
+ static VALUE rxml_document_root_get(VALUE self)
504
+ {
505
+ xmlDocPtr xdoc;
506
+
507
+ xmlNodePtr root;
508
+
509
+ Data_Get_Struct(self, xmlDoc, xdoc);
510
+ root = xmlDocGetRootElement(xdoc);
511
+
512
+ if (root == NULL)
513
+ return (Qnil);
514
+
515
+ return rxml_node_wrap(root);
516
+ }
517
+
518
+ /*
519
+ * call-seq:
520
+ * document.root = node
521
+ *
522
+ * Set the root node.
523
+ */
524
+ static VALUE rxml_document_root_set(VALUE self, VALUE node)
525
+ {
526
+ xmlDocPtr xdoc;
527
+ xmlNodePtr xroot, xnode;
528
+
529
+ if (rb_obj_is_kind_of(node, cXMLNode) == Qfalse)
530
+ rb_raise(rb_eTypeError, "must pass an XML::Node type object");
531
+
532
+ Data_Get_Struct(self, xmlDoc, xdoc);
533
+ Data_Get_Struct(node, xmlNode, xnode);
534
+
535
+ xroot = xmlDocSetRootElement(xdoc, xnode);
536
+ return node;
537
+ }
538
+
539
+ /*
540
+ * call-seq:
541
+ * document.save(filename) -> int
542
+ * document.save(filename, :indent => true, :encoding => 'UTF-8') -> int
543
+ *
544
+ * Saves a document to a file. You may provide an optional hash table
545
+ * to control how the string is generated. Valid options are:
546
+ *
547
+ * :indent - Specifies if the string should be indented. The default value
548
+ * is true. Note that indentation is only added if both :indent is
549
+ * true and XML.indent_tree_output is true. If :indent is set to false,
550
+ * then both indentation and line feeds are removed from the result.
551
+ *
552
+ * :encoding - Specifies the output encoding of the string. It
553
+ * defaults to the original encoding of the document (see
554
+ * #encoding. To override the orginal encoding, use one of the
555
+ * XML::Encoding encoding constants. */
556
+ static VALUE rxml_document_save(int argc, VALUE *argv, VALUE self)
557
+ {
558
+ VALUE options = Qnil;
559
+ VALUE filename = Qnil;
560
+ xmlDocPtr xdoc;
561
+ int indent = 1;
562
+ const char *xfilename;
563
+ const char *xencoding;
564
+ int length;
565
+
566
+ rb_scan_args(argc, argv, "11", &filename, &options);
567
+
568
+ Check_Type(filename, T_STRING);
569
+ xfilename = StringValuePtr(filename);
570
+
571
+ Data_Get_Struct(self, xmlDoc, xdoc);
572
+ xencoding = xdoc->encoding;
573
+
574
+ if (!NIL_P(options))
575
+ {
576
+ VALUE rencoding, rindent;
577
+ Check_Type(options, T_HASH);
578
+ rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
579
+ rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
580
+
581
+ if (rindent == Qfalse)
582
+ indent = 0;
583
+
584
+ if (rencoding != Qnil)
585
+ {
586
+ xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
587
+ if (!xencoding)
588
+ rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
589
+ }
590
+ }
591
+
592
+ length = xmlSaveFormatFileEnc(xfilename, xdoc, xencoding, indent);
593
+
594
+ if (length == -1)
595
+ rxml_raise(&xmlLastError);
596
+
597
+ return (INT2NUM(length));
598
+ }
599
+
600
+ /*
601
+ * call-seq:
602
+ * document.standalone? -> (true|false)
603
+ *
604
+ * Determine whether this is a standalone document.
605
+ */
606
+ static VALUE rxml_document_standalone_q(VALUE self)
607
+ {
608
+ xmlDocPtr xdoc;
609
+
610
+ Data_Get_Struct(self, xmlDoc, xdoc);
611
+ if (xdoc->standalone)
612
+ return (Qtrue);
613
+ else
614
+ return (Qfalse);
615
+ }
616
+
617
+ /*
618
+ * call-seq:
619
+ * document.to_s -> "string"
620
+ * document.to_s(:indent => true, :encoding => 'UTF-8') -> "string"
621
+ *
622
+ * Converts a document, and all of its children, to a string representation.
623
+ * You may provide an optional hash table to control how the string is
624
+ * generated. Valid options are:
625
+ *
626
+ * :indent - Specifies if the string should be indented. The default value
627
+ * is true. Note that indentation is only added if both :indent is
628
+ * true and XML.indent_tree_output is true. If :indent is set to false,
629
+ * then both indentation and line feeds are removed from the result.
630
+ *
631
+ * :encoding - Specifies the output encoding of the string. It
632
+ * defaults to XML::Encoding::UTF8. To change it, use one of the
633
+ * XML::Encoding encoding constants. */
634
+ static VALUE rxml_document_to_s(int argc, VALUE *argv, VALUE self)
635
+ {
636
+ VALUE result;
637
+ VALUE options = Qnil;
638
+ xmlDocPtr xdoc;
639
+ int indent = 1;
640
+ const char *xencoding = "UTF-8";
641
+ xmlChar *buffer;
642
+ int length;
643
+
644
+ rb_scan_args(argc, argv, "01", &options);
645
+
646
+ if (!NIL_P(options))
647
+ {
648
+ VALUE rencoding, rindent;
649
+ Check_Type(options, T_HASH);
650
+ rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
651
+ rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
652
+
653
+ if (rindent == Qfalse)
654
+ indent = 0;
655
+
656
+ if (rencoding != Qnil)
657
+ {
658
+ xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
659
+ if (!xencoding)
660
+ rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
661
+ }
662
+ }
663
+
664
+ Data_Get_Struct(self, xmlDoc, xdoc);
665
+ xmlDocDumpFormatMemoryEnc(xdoc, &buffer, &length, xencoding, indent);
666
+
667
+ result = rb_str_new((const char*) buffer, length);
668
+ xmlFree(buffer);
669
+ return result;
670
+ }
671
+
672
+ /*
673
+ * call-seq:
674
+ * document.url -> "url"
675
+ *
676
+ * Obtain this document's source URL, if any.
677
+ */
678
+ static VALUE rxml_document_url_get(VALUE self)
679
+ {
680
+ xmlDocPtr xdoc;
681
+
682
+ Data_Get_Struct(self, xmlDoc, xdoc);
683
+ if (xdoc->URL == NULL)
684
+ return (Qnil);
685
+ else
686
+ return (rb_str_new2((const char*) xdoc->URL));
687
+ }
688
+
689
+ /*
690
+ * call-seq:
691
+ * document.version -> "version"
692
+ *
693
+ * Obtain the XML version specified by this document.
694
+ */
695
+ static VALUE rxml_document_version_get(VALUE self)
696
+ {
697
+ xmlDocPtr xdoc;
698
+
699
+ Data_Get_Struct(self, xmlDoc, xdoc);
700
+ if (xdoc->version == NULL)
701
+ return (Qnil);
702
+ else
703
+ return (rb_str_new2((const char*) xdoc->version));
704
+ }
705
+
706
+ /*
707
+ * call-seq:
708
+ * document.xhtml? -> (true|false)
709
+ *
710
+ * Determine whether this is an XHTML document.
711
+ */
712
+ static VALUE rxml_document_xhtml_q(VALUE self)
713
+ {
714
+ xmlDocPtr xdoc;
715
+ xmlDtdPtr xdtd;
716
+ Data_Get_Struct(self, xmlDoc, xdoc);
717
+ xdtd = xmlGetIntSubset(xdoc);
718
+ if (xdtd != NULL && xmlIsXHTML(xdtd->SystemID, xdtd->ExternalID) > 0)
719
+ return (Qtrue);
720
+ else
721
+ return (Qfalse);
722
+ }
723
+
724
+ /*
725
+ * call-seq:
726
+ * document.xinclude -> num
727
+ *
728
+ * Process xinclude directives in this document.
729
+ */
730
+ static VALUE rxml_document_xinclude(VALUE self)
731
+ {
732
+ #ifdef LIBXML_XINCLUDE_ENABLED
733
+ xmlDocPtr xdoc;
734
+
735
+ int ret;
736
+
737
+ Data_Get_Struct(self, xmlDoc, xdoc);
738
+ ret = xmlXIncludeProcess(xdoc);
739
+ if (ret >= 0)
740
+ {
741
+ return(INT2NUM(ret));
742
+ }
743
+ else
744
+ {
745
+ rxml_raise(&xmlLastError);
746
+ return Qnil;
747
+ }
748
+ #else
749
+ rb_warn(
750
+ "libxml was compiled without XInclude support. Please recompile libxml and ruby-libxml");
751
+ return (Qfalse);
752
+ #endif
753
+ }
754
+
755
+ void LibXML_validity_error(void * ctxt, const char * msg, va_list ap)
756
+ {
757
+ if (rb_block_given_p())
758
+ {
759
+ char buff[1024];
760
+ snprintf(buff, 1024, msg, ap);
761
+ rb_yield(rb_ary_new3(2, rb_str_new2(buff), Qtrue));
762
+ }
763
+ else
764
+ {
765
+ fprintf(stderr, "error -- found validity error: ");
766
+ fprintf(stderr, msg, ap);
767
+ }
768
+ }
769
+
770
+ /*
771
+ * call-seq:
772
+ * document.order_elements!
773
+ *
774
+ * Call this routine to speed up XPath computation on static documents.
775
+ * This stamps all the element nodes with the document order.
776
+ */
777
+ static VALUE rxml_document_order_elements(VALUE self)
778
+ {
779
+ xmlDocPtr xdoc;
780
+
781
+ Data_Get_Struct(self, xmlDoc, xdoc);
782
+ return LONG2FIX(xmlXPathOrderDocElems(xdoc));
783
+ }
784
+
785
+ /*
786
+ * call-seq:
787
+ * document.validate_schema(schema) -> (true|false)
788
+ *
789
+ * Validate this document against the specified XML::Schema.
790
+ *
791
+ * If a block is provided it is used as an error handler for validaten errors.
792
+ * The block is called with two argument, the message and a flag indication
793
+ * if the message is an error (true) or a warning (false).
794
+ */
795
+ static VALUE rxml_document_validate_schema(VALUE self, VALUE schema)
796
+ {
797
+ xmlSchemaValidCtxtPtr vptr;
798
+ xmlDocPtr xdoc;
799
+ xmlSchemaPtr xschema;
800
+ int is_invalid;
801
+
802
+ Data_Get_Struct(self, xmlDoc, xdoc);
803
+ Data_Get_Struct(schema, xmlSchema, xschema);
804
+
805
+ vptr = xmlSchemaNewValidCtxt(xschema);
806
+
807
+ xmlSchemaSetValidErrors(vptr,
808
+ (xmlSchemaValidityErrorFunc) LibXML_validity_error,
809
+ (xmlSchemaValidityWarningFunc) LibXML_validity_warning, NULL);
810
+
811
+ is_invalid = xmlSchemaValidateDoc(vptr, xdoc);
812
+ xmlSchemaFreeValidCtxt(vptr);
813
+ if (is_invalid)
814
+ {
815
+ rxml_raise(&xmlLastError);
816
+ return Qfalse;
817
+ }
818
+ else
819
+ {
820
+ return Qtrue;
821
+ }
822
+ }
823
+
824
+ /*
825
+ * call-seq:
826
+ * document.validate_schema(relaxng) -> (true|false)
827
+ *
828
+ * Validate this document against the specified XML::RelaxNG.
829
+ *
830
+ * If a block is provided it is used as an error handler for validaten errors.
831
+ * The block is called with two argument, the message and a flag indication
832
+ * if the message is an error (true) or a warning (false).
833
+ */
834
+ static VALUE rxml_document_validate_relaxng(VALUE self, VALUE relaxng)
835
+ {
836
+ xmlRelaxNGValidCtxtPtr vptr;
837
+ xmlDocPtr xdoc;
838
+ xmlRelaxNGPtr xrelaxng;
839
+ int is_invalid;
840
+
841
+ Data_Get_Struct(self, xmlDoc, xdoc);
842
+ Data_Get_Struct(relaxng, xmlRelaxNG, xrelaxng);
843
+
844
+ vptr = xmlRelaxNGNewValidCtxt(xrelaxng);
845
+
846
+ xmlRelaxNGSetValidErrors(vptr,
847
+ (xmlRelaxNGValidityErrorFunc) LibXML_validity_error,
848
+ (xmlRelaxNGValidityWarningFunc) LibXML_validity_warning, NULL);
849
+
850
+ is_invalid = xmlRelaxNGValidateDoc(vptr, xdoc);
851
+ xmlRelaxNGFreeValidCtxt(vptr);
852
+ if (is_invalid)
853
+ {
854
+ rxml_raise(&xmlLastError);
855
+ return Qfalse;
856
+ }
857
+ else
858
+ {
859
+ return Qtrue;
860
+ }
861
+ }
862
+
863
+ /*
864
+ * call-seq:
865
+ * document.validate(dtd) -> (true|false)
866
+ *
867
+ * Validate this document against the specified XML::DTD.
868
+ */
869
+ static VALUE rxml_document_validate_dtd(VALUE self, VALUE dtd)
870
+ {
871
+ VALUE error = Qnil;
872
+ xmlValidCtxt ctxt;
873
+ xmlDocPtr xdoc;
874
+ xmlDtdPtr xdtd;
875
+
876
+ Data_Get_Struct(self, xmlDoc, xdoc);
877
+ Data_Get_Struct(dtd, xmlDtd, xdtd);
878
+
879
+ ctxt.userData = &error;
880
+ ctxt.error = (xmlValidityErrorFunc) LibXML_validity_error;
881
+ ctxt.warning = (xmlValidityWarningFunc) LibXML_validity_warning;
882
+
883
+ ctxt.nodeNr = 0;
884
+ ctxt.nodeTab = NULL;
885
+ ctxt.vstateNr = 0;
886
+ ctxt.vstateTab = NULL;
887
+
888
+ if (xmlValidateDtd(&ctxt, xdoc, xdtd))
889
+ {
890
+ return (Qtrue);
891
+ }
892
+ else
893
+ {
894
+ rxml_raise(&xmlLastError);
895
+ return Qfalse;
896
+ }
897
+ }
898
+
899
+ void rxml_init_document(void)
900
+ {
901
+ cXMLDocument = rb_define_class_under(mXML, "Document", rb_cObject);
902
+ rb_define_alloc_func(cXMLDocument, rxml_document_alloc);
903
+
904
+ rb_define_method(cXMLDocument, "initialize", rxml_document_initialize, -1);
905
+ rb_define_method(cXMLDocument, "child", rxml_document_child_get, 0);
906
+ rb_define_method(cXMLDocument, "child?", rxml_document_child_q, 0);
907
+ rb_define_method(cXMLDocument, "compression", rxml_document_compression_get, 0);
908
+ rb_define_method(cXMLDocument, "compression=", rxml_document_compression_set, 1);
909
+ rb_define_method(cXMLDocument, "compression?", rxml_document_compression_q, 0);
910
+ rb_define_method(cXMLDocument, "debug", rxml_document_debug, 0);
911
+ rb_define_method(cXMLDocument, "encoding", rxml_document_encoding_get, 0);
912
+ rb_define_method(cXMLDocument, "encoding=", rxml_document_encoding_set, 1);
913
+ rb_define_method(cXMLDocument, "import", rxml_document_import, 1);
914
+ rb_define_method(cXMLDocument, "last", rxml_document_last_get, 0);
915
+ rb_define_method(cXMLDocument, "last?", rxml_document_last_q, 0);
916
+ rb_define_method(cXMLDocument, "next", rxml_document_next_get, 0);
917
+ rb_define_method(cXMLDocument, "next?", rxml_document_next_q, 0);
918
+ rb_define_method(cXMLDocument, "node_type", rxml_document_node_type, 0);
919
+ rb_define_method(cXMLDocument, "order_elements!", rxml_document_order_elements, 0);
920
+ rb_define_method(cXMLDocument, "parent", rxml_document_parent_get, 0);
921
+ rb_define_method(cXMLDocument, "parent?", rxml_document_parent_q, 0);
922
+ rb_define_method(cXMLDocument, "prev", rxml_document_prev_get, 0);
923
+ rb_define_method(cXMLDocument, "prev?", rxml_document_prev_q, 0);
924
+ rb_define_method(cXMLDocument, "root", rxml_document_root_get, 0);
925
+ rb_define_method(cXMLDocument, "root=", rxml_document_root_set, 1);
926
+ rb_define_method(cXMLDocument, "save", rxml_document_save, -1);
927
+ rb_define_method(cXMLDocument, "standalone?", rxml_document_standalone_q, 0);
928
+ rb_define_method(cXMLDocument, "to_s", rxml_document_to_s, -1);
929
+ rb_define_method(cXMLDocument, "url", rxml_document_url_get, 0);
930
+ rb_define_method(cXMLDocument, "version", rxml_document_version_get, 0);
931
+ rb_define_method(cXMLDocument, "xhtml?", rxml_document_xhtml_q, 0);
932
+ rb_define_method(cXMLDocument, "xinclude", rxml_document_xinclude, 0);
933
+ rb_define_method(cXMLDocument, "validate", rxml_document_validate_dtd, 1);
934
+ rb_define_method(cXMLDocument, "validate_schema", rxml_document_validate_schema, 1);
935
+ rb_define_method(cXMLDocument, "validate_relaxng", rxml_document_validate_relaxng, 1);
936
+ }