libxml-ruby 2.8.0 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
+ }