libxml-ruby 0.5.1.0 → 0.5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/ext/xml/libxml.c +2 -1
  2. data/ext/xml/libxml.h +5 -3
  3. data/ext/xml/libxml.rb +1 -1
  4. data/ext/xml/ruby_xml_attr.c +13 -33
  5. data/ext/xml/ruby_xml_document.c +11 -22
  6. data/ext/xml/ruby_xml_document.h +2 -1
  7. data/ext/xml/ruby_xml_html_parser.c +3 -6
  8. data/ext/xml/ruby_xml_html_parser.h +1 -1
  9. data/ext/xml/ruby_xml_node.c +87 -70
  10. data/ext/xml/ruby_xml_node.h +2 -1
  11. data/ext/xml/ruby_xml_node_set.c +32 -111
  12. data/ext/xml/ruby_xml_node_set.h +5 -11
  13. data/ext/xml/ruby_xml_ns.c +1 -1
  14. data/ext/xml/ruby_xml_ns.h +1 -1
  15. data/ext/xml/ruby_xml_parser.c +11 -11
  16. data/ext/xml/ruby_xml_parser.h +1 -1
  17. data/ext/xml/ruby_xml_parser_context.c +11 -9
  18. data/ext/xml/ruby_xml_parser_context.h +1 -1
  19. data/ext/xml/ruby_xml_sax_parser.c +1 -1
  20. data/ext/xml/ruby_xml_sax_parser.h +1 -1
  21. data/ext/xml/ruby_xml_state.c +114 -0
  22. data/ext/xml/ruby_xml_state.h +11 -0
  23. data/ext/xml/ruby_xml_tree.c +1 -1
  24. data/ext/xml/ruby_xml_tree.h +1 -1
  25. data/ext/xml/ruby_xml_xinclude.c +1 -1
  26. data/ext/xml/ruby_xml_xinclude.h +1 -1
  27. data/ext/xml/ruby_xml_xpath.c +117 -231
  28. data/ext/xml/ruby_xml_xpath.h +4 -5
  29. data/ext/xml/ruby_xml_xpath_context.c +43 -50
  30. data/ext/xml/ruby_xml_xpath_context.h +3 -7
  31. data/ext/xml/ruby_xml_xpath_object.c +246 -0
  32. data/ext/xml/ruby_xml_xpath_object.h +29 -0
  33. data/ext/xml/ruby_xml_xpointer.c +8 -14
  34. data/ext/xml/ruby_xml_xpointer.h +1 -1
  35. data/ext/xml/ruby_xml_xpointer_context.c +1 -1
  36. data/ext/xml/ruby_xml_xpointer_context.h +1 -1
  37. data/ext/xml/sax_parser_callbacks.inc +1 -1
  38. data/tests/tc_xml_document.rb +5 -4
  39. data/tests/tc_xml_html_parser.rb +7 -4
  40. data/tests/tc_xml_node.rb +6 -5
  41. data/tests/tc_xml_node_set.rb +2 -2
  42. data/tests/tc_xml_node_set2.rb +3 -3
  43. data/tests/tc_xml_xpath.rb +3 -3
  44. data/tests/tc_xml_xpointer.rb +2 -2
  45. metadata +16 -10
@@ -0,0 +1,11 @@
1
+ /* $Id$ */
2
+
3
+ #ifndef __RUBY_XML_STATE__
4
+ #define __RUBY_XML_STATE__
5
+
6
+ extern VALUE cXMLState;
7
+
8
+ void ruby_xml_state_marker(void);
9
+ VALUE ruby_xml_state_object_find(VALUE id);
10
+
11
+ #endif
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_tree.c 39 2006-02-21 20:40:16Z roscopeco $ */
1
+ /* $Id: ruby_xml_tree.c 134 2007-08-29 17:30:19Z danj $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_tree.h 39 2006-02-21 20:40:16Z roscopeco $ */
1
+ /* $Id: ruby_xml_tree.h 134 2007-08-29 17:30:19Z danj $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_xinclude.c 39 2006-02-21 20:40:16Z roscopeco $ */
1
+ /* $Id: ruby_xml_xinclude.c 134 2007-08-29 17:30:19Z danj $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_xinclude.h 39 2006-02-21 20:40:16Z roscopeco $ */
1
+ /* $Id: ruby_xml_xinclude.h 134 2007-08-29 17:30:19Z danj $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_xpath.c 138 2007-08-29 18:00:35Z danj $ */
1
+ /* $Id: ruby_xml_xpath.c 192 2007-10-05 15:13:17Z danj $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -40,37 +40,61 @@ ruby_xml_xpath_debug(VALUE self) {
40
40
  #endif
41
41
  }
42
42
 
43
- // TODO Maybe we should support [] or some other kind of access if poss.
44
-
45
- /*
46
- * call-seq:
47
- * xpath.each { |node| ... } => self
48
- *
49
- * Call the supplied block for each matching node.
50
- */
51
- VALUE
52
- ruby_xml_xpath_each(VALUE self) {
53
- ruby_xml_xpath *rxxp;
54
- VALUE rxnset;
55
-
56
- Data_Get_Struct(self, ruby_xml_xpath, rxxp);
57
-
58
- if (rxxp->xpop == NULL || rxxp->xpop->type != XPATH_NODESET)
59
- return(Qnil);
60
-
61
- rxnset = ruby_xml_node_set_new(cXMLNodeSet, rxxp->xd, self,
62
- rxxp->xpop->nodesetval);
63
- ruby_xml_node_set_each(rxnset);
64
- return(rxnset);
65
- }
66
-
67
43
  ///////////////////////////////////////////////////
68
44
  // TODO xpath_find is throwing TypeError:
69
45
  //
70
46
  // TypeError: can't convert nil into String
71
47
  //
72
48
  // When given a namespace when non exist.
49
+ void
50
+ ruby_xml_xpath_register_namespaces(VALUE nslist, VALUE xxpc, int level) {
51
+ char *cp;
52
+ long i;
53
+ VALUE rprefix, ruri;
54
+ ruby_xml_ns *rxns;
73
55
 
56
+ /* Need to loop through the 2nd argument and iterate through the
57
+ * list of namespaces that we want to allow */
58
+ switch (TYPE(nslist)) {
59
+ case T_STRING:
60
+ cp = strchr(StringValuePtr(nslist), (int)':');
61
+ if (cp == NULL) {
62
+ rprefix = nslist;
63
+ ruri = Qnil;
64
+ } else {
65
+ rprefix = rb_str_new(StringValuePtr(nslist), (int)((long)cp - (long)StringValuePtr(nslist)));
66
+ ruri = rb_str_new2(&cp[1]);
67
+ }
68
+ /* Should test the results of this */
69
+ ruby_xml_xpath_context_register_namespace(xxpc, rprefix, ruri);
70
+ break;
71
+ case T_ARRAY:
72
+ if ( level == 0 ) {
73
+ for (i = 0; i < RARRAY(nslist)->len; i++) {
74
+ ruby_xml_xpath_register_namespaces(RARRAY(nslist)->ptr[i],xxpc,1);
75
+ }
76
+ }
77
+ else {
78
+ // tuples of prefix/uri
79
+ if (RARRAY(RARRAY(nslist)->ptr[i])->len == 2) {
80
+ rprefix = RARRAY(RARRAY(nslist)->ptr[i])->ptr[0];
81
+ ruri = RARRAY(RARRAY(nslist)->ptr[i])->ptr[1];
82
+ ruby_xml_xpath_context_register_namespace(xxpc, rprefix, ruri);
83
+ } else {
84
+ rb_raise(rb_eArgError, "nested array must be an array of strings, prefix and href/uri");
85
+ }
86
+ }
87
+ break;
88
+ default:
89
+ if (rb_obj_is_kind_of(nslist, cXMLNS) == Qtrue) {
90
+ Data_Get_Struct(nslist, ruby_xml_ns, rxns);
91
+ rprefix = rb_str_new2((const char*)rxns->ns->prefix);
92
+ ruri = rb_str_new2((const char*)rxns->ns->href);
93
+ ruby_xml_xpath_context_register_namespace(xxpc, rprefix, ruri);
94
+ } else
95
+ rb_raise(rb_eArgError, "Invalid argument type, only accept string, array of strings, or an array of arrays");
96
+ }
97
+ }
74
98
  /*
75
99
  * call-seq:
76
100
  * XML::XPath.find(path, namespaces = [any]) => xpath
@@ -90,145 +114,88 @@ ruby_xml_xpath_each(VALUE self) {
90
114
  * will be included.
91
115
  */
92
116
  VALUE
93
- ruby_xml_xpath_find(int argc, VALUE *argv, VALUE class) {
117
+ ruby_xml_xpath_find(VALUE class, VALUE anode, VALUE xpath_expr, VALUE nslist) {
94
118
  #ifdef LIBXML_XPATH_ENABLED
95
119
  xmlXPathCompExprPtr comp;
120
+ xmlXPathObjectPtr xxpop;
96
121
  ruby_xml_node *node;
97
122
  ruby_xml_xpath *rxxp;
98
- ruby_xml_xpath_context *rxxpc;
99
- ruby_xml_ns *rxns;
100
- VALUE rnode, rprefix, ruri, xxpc, xpath, xpath_expr;
101
- char *cp;
102
- long i;
103
-
104
- switch(argc) {
105
- case 3:
106
- /* array of namespaces we allow.
107
- *
108
- * Accept either:
109
- * A string in the form of: "prefix:uri", or
110
- * An array of:
111
- * *) strings in the form like above
112
- * *) arrays in the form of ['prefix','uri']
113
- */
114
-
115
- /* Intentionally fall through, we deal with the last arg below
116
- * after the XPathContext object has been setup */
117
- case 2:
118
- rnode = argv[0];
119
- xpath_expr = argv[1];
120
- break;
121
- default:
122
- rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)");
123
- }
124
-
125
- Data_Get_Struct(rnode, ruby_xml_node, node);
126
-
127
- xxpc = ruby_xml_xpath_context_new4(rnode);
123
+ xmlXPathContextPtr ctxt;
124
+ ruby_xml_document_t *rdocp;
125
+ VALUE rnode, xxpc;
126
+ VALUE rxpop;
127
+
128
+ if (rb_obj_is_kind_of(anode, cXMLDocument) == Qtrue) {
129
+ xxpc = ruby_xml_xpath_context_new(anode);
130
+ Data_Get_Struct(anode, ruby_xml_document_t, rdocp);
131
+ #ifdef DEBUG
132
+ fprintf(stderr,"rdocp=0x%x root=0x%x\n",rdocp,xmlDocGetRootElement(rdocp->doc));
133
+ #endif
134
+ rnode=ruby_xml_node2_wrap(cXMLNode,xmlDocGetRootElement(rdocp->doc));
135
+ #ifdef DEBUG
136
+ fprintf(stderr,"rnode 0x%x 0x%x\n",rnode,xmlDocGetRootElement(rdocp->doc)->_private);
137
+ #endif
138
+ Data_Get_Struct(rnode, ruby_xml_node, node);
139
+ } else if ( rb_obj_is_kind_of(anode, cXMLNode) == Qtrue) {
140
+ xxpc = ruby_xml_xpath_context_new(anode);
141
+ Data_Get_Struct(anode, ruby_xml_node, node);
142
+ } else
143
+ rb_raise(rb_eTypeError, "arg 1 must be XML::Document or XML::Node within a document %s", rb_obj_as_string(anode));
144
+
128
145
  if (NIL_P(xxpc))
129
146
  return(Qnil);
130
- Data_Get_Struct(xxpc, ruby_xml_xpath_context, rxxpc);
131
147
 
132
- xpath = ruby_xml_xpath_new(cXMLXPath, rnode, xxpc, NULL);
133
- Data_Get_Struct(xpath, ruby_xml_xpath, rxxp);
148
+ Data_Get_Struct(xxpc,xmlXPathContext,ctxt);
149
+ // XXX Is this legal? Set a subtree to apply xpath?
150
+ ctxt->node = node->node;
134
151
 
135
- rxxpc->ctxt->node = node->node;
152
+ // XXX is setting ->namespaces used?
136
153
  if (node->node->type == XML_DOCUMENT_NODE) {
137
- rxxpc->ctxt->namespaces = xmlGetNsList(node->node->doc,
138
- xmlDocGetRootElement(node->node->doc));
154
+ ctxt->namespaces = xmlGetNsList(node->node->doc,
155
+ xmlDocGetRootElement(node->node->doc));
139
156
  } else {
140
- rxxpc->ctxt->namespaces = xmlGetNsList(node->node->doc, node->node);
157
+ ctxt->namespaces = xmlGetNsList(node->node->doc, node->node);
141
158
  }
142
159
 
143
- rxxpc->ctxt->nsNr = 0;
144
- if (rxxpc->ctxt->namespaces != NULL) {
145
- while (rxxpc->ctxt->namespaces[rxxpc->ctxt->nsNr] != NULL)
146
- rxxpc->ctxt->nsNr++;
160
+ ctxt->nsNr = 0;
161
+ if (ctxt->namespaces != NULL) {
162
+ while (ctxt->namespaces[ctxt->nsNr] != NULL)
163
+ ctxt->nsNr++;
147
164
  }
148
165
 
149
- /* Need to loop through the 2nd argument and iterate through the
150
- * list of namespaces that we want to allow */
151
- if (argc == 3) {
152
- switch (TYPE(argv[2])) {
153
- case T_STRING:
154
- cp = strchr(StringValuePtr(argv[2]), (int)':');
155
- if (cp == NULL) {
156
- rprefix = argv[2];
157
- ruri = Qnil;
158
- } else {
159
- rprefix = rb_str_new(StringValuePtr(argv[2]), (int)((long)cp - (long)StringValuePtr(argv[2])));
160
- ruri = rb_str_new2(&cp[1]);
161
- }
162
- /* Should test the results of this */
163
- ruby_xml_xpath_context_register_namespace(xxpc, rprefix, ruri);
164
- break;
165
- case T_ARRAY:
166
- for (i = 0; i < RARRAY(argv[2])->len; i++) {
167
- switch (TYPE(RARRAY(argv[2])->ptr[i])) {
168
- case T_STRING:
169
- cp = strchr(StringValuePtr(RARRAY(argv[2])->ptr[i]), (int)':');
170
- if (cp == NULL) {
171
- rprefix = RARRAY(argv[2])->ptr[i];
172
- ruri = Qnil;
173
- } else {
174
- rprefix = rb_str_new(StringValuePtr(RARRAY(argv[2])->ptr[i]), (int)((long)cp - (long)StringValuePtr(RARRAY(argv[2])->ptr[i])));
175
- ruri = rb_str_new2(&cp[1]);
176
- }
177
- /* Should test the results of this */
178
- ruby_xml_xpath_context_register_namespace(xxpc, rprefix, ruri);
179
- break;
180
- case T_ARRAY:
181
- if (RARRAY(RARRAY(argv[2])->ptr[i])->len == 2) {
182
- rprefix = RARRAY(RARRAY(argv[2])->ptr[i])->ptr[0];
183
- ruri = RARRAY(RARRAY(argv[2])->ptr[i])->ptr[1];
184
- ruby_xml_xpath_context_register_namespace(xxpc, rprefix, ruri);
185
- } else {
186
- rb_raise(rb_eArgError, "nested array must be an array of strings, prefix and href/uri");
187
- }
188
- break;
189
- default:
190
- if (rb_obj_is_kind_of(RARRAY(argv[2])->ptr[i], cXMLNS) == Qtrue) {
191
- Data_Get_Struct(argv[2], ruby_xml_ns, rxns);
192
- rprefix = rb_str_new2((const char*)rxns->ns->prefix);
193
- ruri = rb_str_new2((const char*)rxns->ns->href);
194
- ruby_xml_xpath_context_register_namespace(xxpc, rprefix, ruri);
195
- } else
196
- rb_raise(rb_eArgError, "Invalid argument type, only accept string, array of strings, or an array of arrays");
197
- }
198
- }
199
- break;
200
- default:
201
- if (rb_obj_is_kind_of(argv[2], cXMLNS) == Qtrue) {
202
- Data_Get_Struct(argv[2], ruby_xml_ns, rxns);
203
- rprefix = rb_str_new2((const char*)rxns->ns->prefix);
204
- ruri = rb_str_new2((const char*)rxns->ns->href);
205
- ruby_xml_xpath_context_register_namespace(xxpc, rprefix, ruri);
206
- } else
207
- rb_raise(rb_eArgError, "Invalid argument type, only accept string, array of strings, or an array of arrays");
208
- }
209
- }
166
+ if ( ! NIL_P(nslist) )
167
+ ruby_xml_xpath_register_namespaces(nslist,xxpc,0);
168
+
210
169
  comp = xmlXPathCompile((xmlChar*)StringValuePtr(xpath_expr));
211
170
 
212
171
  if (comp == NULL) {
213
- xmlXPathFreeCompExpr(comp);
214
- rb_raise(eXMLXPathInvalidPath, "Invalid XPath expression");
172
+ rb_raise(eXMLXPathInvalidPath,
173
+ "Invalid XPath expression (expr does not compile)");
215
174
  }
216
- rxxp->xpop = xmlXPathCompiledEval(comp, rxxpc->ctxt);
217
- xmlXPathFreeCompExpr(comp);
175
+ xxpop=xmlXPathCompiledEval(comp, ctxt);
176
+ #define ALT
177
+ #ifdef ALT
178
+ rxpop = ruby_xml_xpath_object_wrap(xxpop);
179
+ #else
180
+ rxpop = Data_Wrap_Struct(cXMLXPathObject,
181
+ ruby_xml_xpath_object_mark,
182
+ ruby_xml_xpath_object_free,
183
+ xxpop);
184
+ #endif
185
+
186
+ #ifdef NODE_DEBUG
187
+ fprintf(stderr,"xpo 0x%x class=%s\n",
188
+ rxpop,
189
+ rb_class2name(rb_obj_class(rxpop)));
190
+ #endif
218
191
 
219
- if (rxxpc->ctxt->namespaces != NULL)
220
- xmlFree(rxxpc->ctxt->namespaces);
192
+ xmlXPathFreeCompExpr(comp);
221
193
 
222
- if (rxxp->xpop == NULL)
194
+ if (rxpop == Qnil)
223
195
  rb_raise(eXMLXPathInvalidPath,
224
196
  "Invalid XPath expression for this document");
225
197
 
226
- if (rxxp->xpop->type != XPATH_NODESET)
227
- return(Qnil);
228
-
229
- return(ruby_xml_node_set_new2(ruby_xml_document_wrap(cXMLDocument,node->node->doc),
230
- xpath,
231
- rxxp->xpop->nodesetval));
198
+ return rxpop;
232
199
  #else
233
200
  rb_warn("libxml was compiled without XPath support");
234
201
  return(Qfalse);
@@ -237,95 +204,16 @@ ruby_xml_xpath_find(int argc, VALUE *argv, VALUE class) {
237
204
 
238
205
 
239
206
  VALUE
240
- ruby_xml_xpath_find2(int argc, VALUE *argv) {
241
- return(ruby_xml_xpath_find(argc, argv, cXMLXPath));
242
- }
243
-
244
-
245
- void
246
- ruby_xml_xpath_free(ruby_xml_xpath *rxxp) {
247
- if (rxxp->xpop != NULL) {
248
- xmlXPathFreeObject(rxxp->xpop);
249
- rxxp->xpop = NULL;
250
- }
251
-
252
- free(rxxp);
253
- }
254
-
255
-
256
- void
257
- ruby_xml_xpath_mark(ruby_xml_xpath *rxxp) {
258
- if (rxxp == NULL) return;
259
- if (!NIL_P(rxxp->ctxt)) rb_gc_mark(rxxp->ctxt);
260
- if (!NIL_P(rxxp->xd)) rb_gc_mark(rxxp->xd);
261
- }
262
-
263
-
264
- VALUE
265
- ruby_xml_xpath_new(VALUE class, VALUE xd, VALUE ctxt,
266
- xmlXPathObjectPtr xpop) {
267
- ruby_xml_xpath *rxxp;
268
-
269
- rxxp = ALLOC(ruby_xml_xpath);
270
- rxxp->ctxt = ctxt;
271
- rxxp->xd = xd;
272
- rxxp->xpop = xpop;
273
- return(Data_Wrap_Struct(class, ruby_xml_xpath_mark,
274
- ruby_xml_xpath_free, rxxp));
275
- }
276
-
277
-
278
- /*
279
- * call-seq:
280
- * xpath.set => nodeset
281
- *
282
- * Obtain an XML::Node::Set with nodes matching this xpath.
283
- */
284
- VALUE
285
- ruby_xml_xpath_set(VALUE self) {
286
- ruby_xml_xpath *rxxp;
287
- Data_Get_Struct(self, ruby_xml_xpath, rxxp);
288
-
289
- if (rxxp->xpop == NULL || rxxp->xpop->type != XPATH_NODESET)
290
- return(Qnil);
291
-
292
- return(ruby_xml_node_set_new(cXMLNodeSet, rxxp->xd, self,
293
- rxxp->xpop->nodesetval));
294
- }
295
-
296
-
297
- /*
298
- * call-seq:
299
- * xpath.set_type => num
300
- *
301
- * Obtains the type identifier of this xpath
302
- * set.
303
- */
304
- VALUE
305
- ruby_xml_xpath_set_type(VALUE self) {
306
- ruby_xml_xpath *rxxp;
307
- Data_Get_Struct(self, ruby_xml_xpath, rxxp);
207
+ ruby_xml_xpath_findva(int argc, VALUE *argv, VALUE class) {
208
+ if ( argc < 2 || argc > 3 )
209
+ rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)");
308
210
 
309
- return(INT2FIX(rxxp->xpop->type));
211
+ return ruby_xml_xpath_find(class,argv[0],argv[1],(argc==3)?argv[2]:Qnil);
310
212
  }
311
213
 
312
- // TODO maybe 'string' should alias as 'to_s'?
313
-
314
- /*
315
- * call-seq:
316
- * xpath.string => "xpath"
317
- *
318
- * Obtain a string representation of this xpath.
319
- */
320
214
  VALUE
321
- ruby_xml_xpath_string(VALUE self) {
322
- ruby_xml_xpath *rxxp;
323
- Data_Get_Struct(self, ruby_xml_xpath, rxxp);
324
-
325
- if (rxxp->xpop->stringval == NULL)
326
- return(Qnil);
327
- else
328
- return(rb_str_new2((const char*)rxxp->xpop->stringval));
215
+ ruby_xml_xpath_find2(VALUE anode, VALUE xpath_expr, VALUE nslist) {
216
+ return ruby_xml_xpath_find(cXMLXPath, anode, xpath_expr, nslist);
329
217
  }
330
218
 
331
219
  // Rdoc needs to know
@@ -351,13 +239,11 @@ ruby_init_xml_xpath(void) {
351
239
  rb_define_const(cXMLXPath, "USERS", INT2NUM(XPATH_USERS));
352
240
  rb_define_const(cXMLXPath, "XSLT_TREE", INT2NUM(XPATH_XSLT_TREE));
353
241
 
354
- rb_define_singleton_method(cXMLXPath, "find", ruby_xml_xpath_find, 2);
242
+ rb_define_singleton_method(cXMLXPath, "find", ruby_xml_xpath_findva, -1);
355
243
 
356
244
  rb_define_method(cXMLXPath, "debug", ruby_xml_xpath_debug, 0);
357
- rb_define_method(cXMLXPath, "each", ruby_xml_xpath_each, 0);
358
- rb_define_method(cXMLXPath, "set", ruby_xml_xpath_set, 0);
359
- rb_define_method(cXMLXPath, "set_type", ruby_xml_xpath_set_type, 0);
360
- rb_define_method(cXMLXPath, "string", ruby_xml_xpath_string, 0);
245
+
246
+ ruby_init_xml_xpath_object();
361
247
  }
362
248
 
363
249
  #endif /* ifdef LIBXML_XPATH_ENABLED */