libxml-ruby 2.8.0 → 3.2.3

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