libxml-ruby 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,281 +1,294 @@
1
- /* $Id: ruby_xml_xpath_context.c 566 2008-11-18 06:53:36Z cfis $ */
2
-
3
- /* Please see the LICENSE file for copyright and distribution information */
4
-
5
- #include "ruby_libxml.h"
6
- #include "ruby_xml_xpath_context.h"
7
- #include <st.h>
8
-
9
-
10
- /*
11
- * Document-class: LibXML::XML::XPath::Context
12
- *
13
- * The XML::XPath::Context class is used to evaluate XPath
14
- * expressions. Generally, you should not directly use this class,
15
- * but instead use the XML::Document#find and XML::Node#find methods.
16
- *
17
- * doc = XML::Document.string('<header>content</header>')
18
- * context = XPath::Context.new(doc)
19
- * context.node = doc.root
20
- * context.register_namespaces_from_node(doc.root)
21
- * nodes = context.find('/header')
22
- */
23
-
24
- VALUE cXMLXPathContext;
25
-
26
- void
27
- ruby_xml_xpath_context_free(xmlXPathContextPtr ctxt) {
28
- xmlXPathFreeContext(ctxt);
29
- }
30
-
31
-
32
- VALUE
33
- ruby_xml_xpath_context_alloc(VALUE klass) {
34
- return Data_Wrap_Struct(cXMLXPathContext,
35
- NULL,
36
- ruby_xml_xpath_context_free,
37
- NULL);
38
- }
39
-
40
- /* call-seq:
41
- * XPath::Context.new(node) -> XPath::Context
42
- *
43
- * Creates a new XPath context for the specified document. The
44
- * context can then be used to evaluate an XPath expression.
45
- *
46
- * doc = XML::Document.string('<header><first>hi</first></header>')
47
- * context = XPath::Context.new(doc)
48
- * nodes = XPath::Object.new('//first', context)
49
- * nodes.length == 1
50
- */
51
- VALUE
52
- ruby_xml_xpath_context_initialize(VALUE self, VALUE node) {
53
- xmlDocPtr xdoc;
54
- VALUE document;
55
- #ifndef LIBXML_XPATH_ENABLED
56
- rb_raise(rb_eTypeError, "libxml was not compiled with XPath support.");
57
- #endif
58
-
59
- if (rb_obj_is_kind_of(node, cXMLNode) == Qtrue)
60
- {
61
- document = rb_funcall(node, rb_intern("doc"), 0);
62
- if NIL_P(document)
63
- rb_raise(rb_eTypeError, "Supplied node must belong to a document.");
64
- }
65
- else if (rb_obj_is_kind_of(node, cXMLDocument) == Qtrue)
66
- {
67
- document = node;
68
- }
69
- else
70
- {
71
- rb_raise(rb_eTypeError, "Supplied argument must be a document or node.");
72
- }
73
-
74
- Data_Get_Struct(document, xmlDoc, xdoc);
75
- DATA_PTR(self) = xmlXPathNewContext(xdoc);
76
-
77
- /* Save the doc as an attribute, this will expose it to Ruby's GC. */
78
- rb_iv_set(self, "@doc", document);
79
-
80
- return self;
81
- }
82
-
83
-
84
- /*
85
- * call-seq:
86
- * context.register_namespace(prefix, uri) -> (true|false)
87
- *
88
- * Register the specified namespace URI with the specified prefix
89
- * in this context.
90
-
91
- * context.register_namespace('xi', 'http://www.w3.org/2001/XInclude')
92
- */
93
- VALUE
94
- ruby_xml_xpath_context_register_namespace(VALUE self, VALUE prefix, VALUE uri) {
95
- xmlXPathContextPtr ctxt;
96
-
97
- Data_Get_Struct(self, xmlXPathContext, ctxt);
98
- if (xmlXPathRegisterNs(ctxt,
99
- (xmlChar*)StringValuePtr(prefix),
100
- (xmlChar*)StringValuePtr(uri))
101
- == 0) {
102
- return(Qtrue);
103
- } else {
104
- /* Should raise an exception, IMHO (whose?, why shouldnt it? -danj)*/
105
- rb_warning("register namespace failed");
106
- return(Qfalse);
107
- }
108
- }
109
-
110
- /* call-seq:
111
- * context.register_namespaces_from_node(node) -> self
112
- *
113
- * Helper method to read in namespaces defined on a node.
114
- *
115
- * doc = XML::Document.string('<header><first>hi</first></header>')
116
- * context = XPath::Context.new(doc)
117
- * context.register_namespaces_from_node(doc.root)
118
- */
119
- VALUE
120
- ruby_xml_xpath_context_register_namespaces_from_node(VALUE self, VALUE node) {
121
- xmlXPathContextPtr xctxt;
122
- xmlNodePtr xnode;
123
- xmlNsPtr *xnsArr;
124
-
125
- Data_Get_Struct(self, xmlXPathContext, xctxt);
126
-
127
- if (rb_obj_is_kind_of(node, cXMLDocument) == Qtrue)
128
- {
129
- xmlDocPtr xdoc;
130
- Data_Get_Struct(node, xmlDoc, xdoc);
131
- xnode = xmlDocGetRootElement(xdoc);
132
- }
133
- else if (rb_obj_is_kind_of(node, cXMLNode) == Qtrue)
134
- {
135
- Data_Get_Struct(node, xmlNode, xnode);
136
- }
137
- else
138
- {
139
- rb_raise(rb_eTypeError, "The first argument must be a document or node.");
140
- }
141
-
142
- xnsArr = xmlGetNsList(xnode->doc, xnode);
143
-
144
- if (xnsArr)
145
- {
146
- xmlNsPtr xns = *xnsArr;
147
-
148
- while (xns) {
149
- /* If there is no prefix, then this is the default namespace.
150
- Skip it for now. */
151
- if (xns->prefix)
152
- {
153
- VALUE prefix = rb_str_new2(xns->prefix);
154
- VALUE uri = rb_str_new2(xns->href);
155
- ruby_xml_xpath_context_register_namespace(self, prefix, uri);
156
- }
157
- xns = xns->next;
158
- }
159
- xmlFree(xnsArr);
160
- }
161
-
162
- return self;
163
- }
164
-
165
- static int
166
- iterate_ns_hash(st_data_t prefix, st_data_t uri, st_data_t self)
167
- {
168
- ruby_xml_xpath_context_register_namespace(self, prefix, uri);
169
- return ST_CONTINUE;
170
- }
171
-
172
-
173
- /*
174
- * call-seq:
175
- * context.register_namespaces(["prefix:uri"]) -> self
176
- *
177
- * Register the specified namespaces in this context.
178
- *
179
- * context.register_namespaces('xi:http://www.w3.org/2001/XInclude')
180
- * context.register_namespaces(['xlink:http://www.w3.org/1999/xlink',
181
- * 'xi:http://www.w3.org/2001/XInclude')
182
- * context.register_namespaces('xlink' => 'http://www.w3.org/1999/xlink',
183
- * 'xi' => 'http://www.w3.org/2001/XInclude')
184
- */
185
- VALUE
186
- ruby_xml_xpath_context_register_namespaces(VALUE self, VALUE nslist) {
187
- char *cp;
188
- long i;
189
- VALUE rprefix, ruri;
190
-
191
- /* Need to loop through the 2nd argument and iterate through the
192
- * list of namespaces that we want to allow */
193
- switch (TYPE(nslist)) {
194
- case T_STRING:
195
- cp = strchr(StringValuePtr(nslist), (int)':');
196
- if (cp == NULL) {
197
- rprefix = nslist;
198
- ruri = Qnil;
199
- } else {
200
- rprefix = rb_str_new(StringValuePtr(nslist), (int)((long)cp - (long)StringValuePtr(nslist)));
201
- ruri = rb_str_new2(&cp[1]);
202
- }
203
- /* Should test the results of this */
204
- ruby_xml_xpath_context_register_namespace(self, rprefix, ruri);
205
- break;
206
- case T_ARRAY:
207
- for (i = 0; i < RARRAY(nslist)->len; i++) {
208
- ruby_xml_xpath_context_register_namespaces(self, RARRAY(nslist)->ptr[i]);
209
- }
210
- break;
211
- case T_HASH:
212
- st_foreach(RHASH(nslist)->tbl, iterate_ns_hash, self);
213
- break;
214
- default:
215
- rb_raise(rb_eArgError, "Invalid argument type, only accept string, array of strings, or an array of arrays");
216
- }
217
- return self;
218
- }
219
-
220
- /*
221
- * call-seq:
222
- * context.node = node
223
- *
224
- * Set the current node used by the XPath engine
225
-
226
- * doc = XML::Document.string('<header><first>hi</first></header>')
227
- * context.node = doc.root.first
228
- */
229
- VALUE
230
- ruby_xml_xpath_context_node_set(VALUE self, VALUE node) {
231
- xmlXPathContextPtr xctxt;
232
- xmlNodePtr xnode;
233
-
234
- Data_Get_Struct(self, xmlXPathContext, xctxt);
235
- Data_Get_Struct(node, xmlNode, xnode);
236
- xctxt->node = xnode;
237
- return node;
238
- }
239
-
240
- /*
241
- * call-seq:
242
- * context.find("xpath") -> XML::XPath::Object
243
- *
244
- * Find nodes matching the specified XPath expression
245
- */
246
- VALUE
247
- ruby_xml_xpath_context_find(VALUE self, VALUE xpath_expr) {
248
- xmlXPathContextPtr xctxt;
249
- xmlXPathObjectPtr xobject;
250
- VALUE result;
251
-
252
- Data_Get_Struct(self, xmlXPathContext, xctxt);
253
- xobject = xmlXPathEval((xmlChar*)StringValuePtr(xpath_expr), xctxt);
254
-
255
- if (xobject == NULL)
256
- {
257
- /* xmlLastError is differnet than xctxt->lastError. Use
258
- xmlLastError since it has the message set while xctxt->lastError
259
- does not. */
260
- xmlErrorPtr xerror = xmlGetLastError();
261
- ruby_xml_raise(xerror);
262
- }
263
-
264
- result = ruby_xml_xpath_object_wrap(xobject);
265
- rb_iv_set(result, "@context", self);
266
- return result;
267
- }
268
-
269
-
270
- void
271
- ruby_init_xml_xpath_context(void) {
272
- cXMLXPathContext = rb_define_class_under(mXPath, "Context", rb_cObject);
273
- rb_define_alloc_func(cXMLXPathContext, ruby_xml_xpath_context_alloc);
274
- rb_define_attr(cXMLXPathContext, "doc", 1, 0);
275
- rb_define_method(cXMLXPathContext, "initialize", ruby_xml_xpath_context_initialize, 1);
276
- rb_define_method(cXMLXPathContext, "register_namespaces", ruby_xml_xpath_context_register_namespaces, 1);
277
- rb_define_method(cXMLXPathContext, "register_namespaces_from_node", ruby_xml_xpath_context_register_namespaces_from_node, 1);
278
- rb_define_method(cXMLXPathContext, "register_namespace", ruby_xml_xpath_context_register_namespace, 2);
279
- rb_define_method(cXMLXPathContext, "node=", ruby_xml_xpath_context_node_set, 1);
280
- rb_define_method(cXMLXPathContext, "find", ruby_xml_xpath_context_find, 1);
281
- }
1
+ /* $Id: ruby_xml_xpath_context.c 600 2008-11-19 07:39:29Z cfis $ */
2
+
3
+ /* Please see the LICENSE file for copyright and distribution information */
4
+
5
+ #include "ruby_libxml.h"
6
+ #include "ruby_xml_xpath_context.h"
7
+ #include "ruby_xml_xpath_expression.h"
8
+ #include <st.h>
9
+
10
+
11
+ /*
12
+ * Document-class: LibXML::XML::XPath::Context
13
+ *
14
+ * The XML::XPath::Context class is used to evaluate XPath
15
+ * expressions. Generally, you should not directly use this class,
16
+ * but instead use the XML::Document#find and XML::Node#find methods.
17
+ *
18
+ * doc = XML::Document.string('<header>content</header>')
19
+ * context = XPath::Context.new(doc)
20
+ * context.node = doc.root
21
+ * context.register_namespaces_from_node(doc.root)
22
+ * nodes = context.find('/header')
23
+ */
24
+
25
+ VALUE cXMLXPathContext;
26
+
27
+ void
28
+ ruby_xml_xpath_context_free(xmlXPathContextPtr ctxt) {
29
+ xmlXPathFreeContext(ctxt);
30
+ }
31
+
32
+
33
+ VALUE
34
+ ruby_xml_xpath_context_alloc(VALUE klass) {
35
+ return Data_Wrap_Struct(cXMLXPathContext,
36
+ NULL,
37
+ ruby_xml_xpath_context_free,
38
+ NULL);
39
+ }
40
+
41
+ /* call-seq:
42
+ * XPath::Context.new(node) -> XPath::Context
43
+ *
44
+ * Creates a new XPath context for the specified document. The
45
+ * context can then be used to evaluate an XPath expression.
46
+ *
47
+ * doc = XML::Document.string('<header><first>hi</first></header>')
48
+ * context = XPath::Context.new(doc)
49
+ * nodes = XPath::Object.new('//first', context)
50
+ * nodes.length == 1
51
+ */
52
+ VALUE
53
+ ruby_xml_xpath_context_initialize(VALUE self, VALUE node) {
54
+ xmlDocPtr xdoc;
55
+ VALUE document;
56
+ #ifndef LIBXML_XPATH_ENABLED
57
+ rb_raise(rb_eTypeError, "libxml was not compiled with XPath support.");
58
+ #endif
59
+
60
+ if (rb_obj_is_kind_of(node, cXMLNode) == Qtrue)
61
+ {
62
+ document = rb_funcall(node, rb_intern("doc"), 0);
63
+ if NIL_P(document)
64
+ rb_raise(rb_eTypeError, "Supplied node must belong to a document.");
65
+ }
66
+ else if (rb_obj_is_kind_of(node, cXMLDocument) == Qtrue)
67
+ {
68
+ document = node;
69
+ }
70
+ else
71
+ {
72
+ rb_raise(rb_eTypeError, "Supplied argument must be a document or node.");
73
+ }
74
+
75
+ Data_Get_Struct(document, xmlDoc, xdoc);
76
+ DATA_PTR(self) = xmlXPathNewContext(xdoc);
77
+
78
+ /* Save the doc as an attribute, this will expose it to Ruby's GC. */
79
+ rb_iv_set(self, "@doc", document);
80
+
81
+ return self;
82
+ }
83
+
84
+
85
+ /*
86
+ * call-seq:
87
+ * context.register_namespace(prefix, uri) -> (true|false)
88
+ *
89
+ * Register the specified namespace URI with the specified prefix
90
+ * in this context.
91
+
92
+ * context.register_namespace('xi', 'http://www.w3.org/2001/XInclude')
93
+ */
94
+ VALUE
95
+ ruby_xml_xpath_context_register_namespace(VALUE self, VALUE prefix, VALUE uri) {
96
+ xmlXPathContextPtr ctxt;
97
+
98
+ Data_Get_Struct(self, xmlXPathContext, ctxt);
99
+ if (xmlXPathRegisterNs(ctxt,
100
+ (xmlChar*)StringValuePtr(prefix),
101
+ (xmlChar*)StringValuePtr(uri))
102
+ == 0) {
103
+ return(Qtrue);
104
+ } else {
105
+ /* Should raise an exception, IMHO (whose?, why shouldnt it? -danj)*/
106
+ rb_warning("register namespace failed");
107
+ return(Qfalse);
108
+ }
109
+ }
110
+
111
+ /* call-seq:
112
+ * context.register_namespaces_from_node(node) -> self
113
+ *
114
+ * Helper method to read in namespaces defined on a node.
115
+ *
116
+ * doc = XML::Document.string('<header><first>hi</first></header>')
117
+ * context = XPath::Context.new(doc)
118
+ * context.register_namespaces_from_node(doc.root)
119
+ */
120
+ VALUE
121
+ ruby_xml_xpath_context_register_namespaces_from_node(VALUE self, VALUE node) {
122
+ xmlXPathContextPtr xctxt;
123
+ xmlNodePtr xnode;
124
+ xmlNsPtr *xnsArr;
125
+
126
+ Data_Get_Struct(self, xmlXPathContext, xctxt);
127
+
128
+ if (rb_obj_is_kind_of(node, cXMLDocument) == Qtrue)
129
+ {
130
+ xmlDocPtr xdoc;
131
+ Data_Get_Struct(node, xmlDoc, xdoc);
132
+ xnode = xmlDocGetRootElement(xdoc);
133
+ }
134
+ else if (rb_obj_is_kind_of(node, cXMLNode) == Qtrue)
135
+ {
136
+ Data_Get_Struct(node, xmlNode, xnode);
137
+ }
138
+ else
139
+ {
140
+ rb_raise(rb_eTypeError, "The first argument must be a document or node.");
141
+ }
142
+
143
+ xnsArr = xmlGetNsList(xnode->doc, xnode);
144
+
145
+ if (xnsArr)
146
+ {
147
+ xmlNsPtr xns = *xnsArr;
148
+
149
+ while (xns) {
150
+ /* If there is no prefix, then this is the default namespace.
151
+ Skip it for now. */
152
+ if (xns->prefix)
153
+ {
154
+ VALUE prefix = rb_str_new2(xns->prefix);
155
+ VALUE uri = rb_str_new2(xns->href);
156
+ ruby_xml_xpath_context_register_namespace(self, prefix, uri);
157
+ }
158
+ xns = xns->next;
159
+ }
160
+ xmlFree(xnsArr);
161
+ }
162
+
163
+ return self;
164
+ }
165
+
166
+ static int
167
+ iterate_ns_hash(st_data_t prefix, st_data_t uri, st_data_t self)
168
+ {
169
+ ruby_xml_xpath_context_register_namespace(self, prefix, uri);
170
+ return ST_CONTINUE;
171
+ }
172
+
173
+
174
+ /*
175
+ * call-seq:
176
+ * context.register_namespaces(["prefix:uri"]) -> self
177
+ *
178
+ * Register the specified namespaces in this context.
179
+ *
180
+ * context.register_namespaces('xi:http://www.w3.org/2001/XInclude')
181
+ * context.register_namespaces(['xlink:http://www.w3.org/1999/xlink',
182
+ * 'xi:http://www.w3.org/2001/XInclude')
183
+ * context.register_namespaces('xlink' => 'http://www.w3.org/1999/xlink',
184
+ * 'xi' => 'http://www.w3.org/2001/XInclude')
185
+ */
186
+ VALUE
187
+ ruby_xml_xpath_context_register_namespaces(VALUE self, VALUE nslist) {
188
+ char *cp;
189
+ long i;
190
+ VALUE rprefix, ruri;
191
+
192
+ /* Need to loop through the 2nd argument and iterate through the
193
+ * list of namespaces that we want to allow */
194
+ switch (TYPE(nslist)) {
195
+ case T_STRING:
196
+ cp = strchr(StringValuePtr(nslist), (int)':');
197
+ if (cp == NULL) {
198
+ rprefix = nslist;
199
+ ruri = Qnil;
200
+ } else {
201
+ rprefix = rb_str_new(StringValuePtr(nslist), (int)((long)cp - (long)StringValuePtr(nslist)));
202
+ ruri = rb_str_new2(&cp[1]);
203
+ }
204
+ /* Should test the results of this */
205
+ ruby_xml_xpath_context_register_namespace(self, rprefix, ruri);
206
+ break;
207
+ case T_ARRAY:
208
+ for (i = 0; i < RARRAY(nslist)->len; i++) {
209
+ ruby_xml_xpath_context_register_namespaces(self, RARRAY(nslist)->ptr[i]);
210
+ }
211
+ break;
212
+ case T_HASH:
213
+ st_foreach(RHASH(nslist)->tbl, iterate_ns_hash, self);
214
+ break;
215
+ default:
216
+ rb_raise(rb_eArgError, "Invalid argument type, only accept string, array of strings, or an array of arrays");
217
+ }
218
+ return self;
219
+ }
220
+
221
+ /*
222
+ * call-seq:
223
+ * context.node = node
224
+ *
225
+ * Set the current node used by the XPath engine
226
+
227
+ * doc = XML::Document.string('<header><first>hi</first></header>')
228
+ * context.node = doc.root.first
229
+ */
230
+ VALUE
231
+ ruby_xml_xpath_context_node_set(VALUE self, VALUE node) {
232
+ xmlXPathContextPtr xctxt;
233
+ xmlNodePtr xnode;
234
+
235
+ Data_Get_Struct(self, xmlXPathContext, xctxt);
236
+ Data_Get_Struct(node, xmlNode, xnode);
237
+ xctxt->node = xnode;
238
+ return node;
239
+ }
240
+
241
+ /*
242
+ * call-seq:
243
+ * context.find("xpath") -> XML::XPath::Object
244
+ *
245
+ * Find nodes matching the specified XPath expression
246
+ */
247
+ VALUE
248
+ ruby_xml_xpath_context_find(VALUE self, VALUE xpath_expr) {
249
+ xmlXPathContextPtr xctxt;
250
+ xmlXPathObjectPtr xobject;
251
+ xmlXPathCompExprPtr xcompexpr;
252
+ VALUE result;
253
+
254
+ Data_Get_Struct(self, xmlXPathContext, xctxt);
255
+
256
+ if (TYPE(xpath_expr) == T_STRING) {
257
+ VALUE expression = rb_check_string_type(xpath_expr);
258
+ xobject = xmlXPathEval((xmlChar*)StringValueCStr(expression), xctxt);
259
+ }
260
+ else if (rb_obj_is_kind_of(xpath_expr, cXMLXPathExpression)) {
261
+ Data_Get_Struct(xpath_expr, xmlXPathCompExpr, xcompexpr);
262
+ xobject = xmlXPathCompiledEval(xcompexpr, xctxt);
263
+ }
264
+ else {
265
+ rb_raise(rb_eTypeError, "Argument should be an intance of a String or XPath::Expression");
266
+ }
267
+
268
+ if (xobject == NULL)
269
+ {
270
+ /* xmlLastError is different than xctxt->lastError. Use
271
+ xmlLastError since it has the message set while xctxt->lastError
272
+ does not. */
273
+ xmlErrorPtr xerror = xmlGetLastError();
274
+ ruby_xml_raise(xerror);
275
+ }
276
+
277
+ result = ruby_xml_xpath_object_wrap(xobject);
278
+ rb_iv_set(result, "@context", self);
279
+ return result;
280
+ }
281
+
282
+
283
+ void
284
+ ruby_init_xml_xpath_context(void) {
285
+ cXMLXPathContext = rb_define_class_under(mXPath, "Context", rb_cObject);
286
+ rb_define_alloc_func(cXMLXPathContext, ruby_xml_xpath_context_alloc);
287
+ rb_define_attr(cXMLXPathContext, "doc", 1, 0);
288
+ rb_define_method(cXMLXPathContext, "initialize", ruby_xml_xpath_context_initialize, 1);
289
+ rb_define_method(cXMLXPathContext, "register_namespaces", ruby_xml_xpath_context_register_namespaces, 1);
290
+ rb_define_method(cXMLXPathContext, "register_namespaces_from_node", ruby_xml_xpath_context_register_namespaces_from_node, 1);
291
+ rb_define_method(cXMLXPathContext, "register_namespace", ruby_xml_xpath_context_register_namespace, 2);
292
+ rb_define_method(cXMLXPathContext, "node=", ruby_xml_xpath_context_node_set, 1);
293
+ rb_define_method(cXMLXPathContext, "find", ruby_xml_xpath_context_find, 1);
294
+ }