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