libxml-ruby 2.0.0-x86-mingw32

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