libxml-ruby 2.8.0 → 2.9.0

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