libxml-ruby 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/CHANGES +22 -0
  2. data/README +3 -1
  3. data/ext/libxml/cbg.c +86 -76
  4. data/ext/libxml/extconf.rb +2 -1
  5. data/ext/libxml/libxml.c +899 -885
  6. data/ext/libxml/ruby_libxml.h +65 -70
  7. data/ext/libxml/ruby_xml_attr.c +485 -500
  8. data/ext/libxml/ruby_xml_attributes.c +107 -106
  9. data/ext/libxml/ruby_xml_document.c +355 -356
  10. data/ext/libxml/ruby_xml_dtd.c +119 -117
  11. data/ext/libxml/ruby_xml_error.c +1112 -581
  12. data/ext/libxml/ruby_xml_html_parser.c +35 -34
  13. data/ext/libxml/ruby_xml_input.c +182 -187
  14. data/ext/libxml/ruby_xml_input_cbg.c +197 -179
  15. data/ext/libxml/ruby_xml_node.c +1529 -1566
  16. data/ext/libxml/ruby_xml_node.h +2 -2
  17. data/ext/libxml/ruby_xml_ns.c +150 -156
  18. data/ext/libxml/ruby_xml_parser.c +37 -36
  19. data/ext/libxml/ruby_xml_parser_context.c +657 -659
  20. data/ext/libxml/ruby_xml_reader.c +203 -209
  21. data/ext/libxml/ruby_xml_relaxng.c +29 -25
  22. data/ext/libxml/ruby_xml_sax_parser.c +33 -32
  23. data/ext/libxml/ruby_xml_schema.c +165 -161
  24. data/ext/libxml/ruby_xml_state.c +19 -21
  25. data/ext/libxml/ruby_xml_xinclude.c +24 -25
  26. data/ext/libxml/ruby_xml_xpath.c +108 -108
  27. data/ext/libxml/ruby_xml_xpath_context.c +305 -293
  28. data/ext/libxml/ruby_xml_xpath_expression.c +24 -24
  29. data/ext/libxml/ruby_xml_xpath_object.c +89 -96
  30. data/ext/libxml/ruby_xml_xpointer.c +107 -109
  31. data/ext/libxml/ruby_xml_xpointer.h +13 -13
  32. data/ext/libxml/version.h +2 -2
  33. data/ext/mingw/Rakefile +1 -1
  34. data/ext/vc/libxml_ruby.vcproj +1 -1
  35. data/lib/libxml/error.rb +4 -4
  36. data/test/tc_node_edit.rb +14 -2
  37. data/test/tc_node_text.rb +9 -9
  38. metadata +2 -2
@@ -7,36 +7,34 @@ VALUE LIBXML_STATE = Qnil;
7
7
 
8
8
  static int dummy = 0;
9
9
 
10
- static void
11
- rxml_state_free(int dummy) {
10
+ static void rxml_state_free(int dummy)
11
+ {
12
12
  xmlCleanupParser();
13
13
  LIBXML_STATE = Qnil;
14
14
  }
15
15
 
16
- static VALUE
17
- rxml_state_alloc(VALUE klass) {
18
- #ifdef DEBUG
16
+ static VALUE rxml_state_alloc(VALUE klass)
17
+ {
18
+ #ifdef DEBUG
19
19
  fprintf(stderr, "Allocating state");
20
- #endif
21
-
20
+ #endif
21
+
22
22
  xmlInitParser();
23
-
24
- return Data_Wrap_Struct(cXMLState,
25
- NULL, rxml_state_free,
26
- &dummy);
23
+
24
+ return Data_Wrap_Struct(cXMLState, NULL, rxml_state_free, &dummy);
27
25
  }
28
26
 
29
- // Rdoc needs to know
27
+ // Rdoc needs to know
30
28
  #ifdef RDOC_NEVER_DEFINED
31
- mLibXML = rb_define_module("LibXML");
32
- mXML = rb_define_module_under(mLibXML, "XML");
29
+ mLibXML = rb_define_module("LibXML");
30
+ mXML = rb_define_module_under(mLibXML, "XML");
33
31
  #endif
34
32
 
35
- void
36
- ruby_init_state(void) {
33
+ void ruby_init_state(void)
34
+ {
37
35
  VALUE rb_mSingleton;
38
36
  cXMLState = rb_define_class_under(mXML, "State", rb_cObject);
39
-
37
+
40
38
  /* Mixin singleton so only one xml state object can be created. */
41
39
  rb_require("singleton");
42
40
  rb_mSingleton = rb_const_get(rb_cObject, rb_intern("Singleton"));
@@ -45,9 +43,9 @@ ruby_init_state(void) {
45
43
  rb_define_alloc_func(cXMLState, rxml_state_alloc);
46
44
 
47
45
  /* Create one instance of the state object that is used
48
- to initalize and cleanup libxml. Then register it with
49
- the garbage collector so its not freed until the process
50
- exists.*/
46
+ to initalize and cleanup libxml. Then register it with
47
+ the garbage collector so its not freed until the process
48
+ exists.*/
51
49
  LIBXML_STATE = rb_class_new_instance(0, NULL, cXMLState);
52
- rb_global_variable(&LIBXML_STATE);
50
+ rb_global_variable(&LIBXML_STATE);
53
51
  }
@@ -1,25 +1,24 @@
1
- /* $Id: rxml_xinclude.c 566 2008-11-18 06:53:36Z cfis $ */
2
-
3
- #include "ruby_libxml.h"
4
- #include "ruby_xml_xinclude.h"
5
-
6
- VALUE cXMLXInclude;
7
-
8
- /*
9
- * Document-class: LibXML::XML::XInclude
10
- *
11
- * The ruby bindings do not currently expose libxml's
12
- * XInclude fuctionality.
13
- */
14
-
15
-
16
- // Rdoc needs to know
17
- #ifdef RDOC_NEVER_DEFINED
18
- mLibXML = rb_define_module("LibXML");
19
- mXML = rb_define_module_under(mLibXML, "XML");
20
- #endif
21
-
22
- void
23
- ruby_init_xml_xinclude(void) {
24
- cXMLXInclude = rb_define_class_under(mXML, "XInclude", rb_cObject);
25
- }
1
+ /* $Id: ruby_xml_xinclude.c 650 2008-11-30 03:40:22Z cfis $ */
2
+
3
+ #include "ruby_libxml.h"
4
+ #include "ruby_xml_xinclude.h"
5
+
6
+ VALUE cXMLXInclude;
7
+
8
+ /*
9
+ * Document-class: LibXML::XML::XInclude
10
+ *
11
+ * The ruby bindings do not currently expose libxml's
12
+ * XInclude fuctionality.
13
+ */
14
+
15
+ // Rdoc needs to know
16
+ #ifdef RDOC_NEVER_DEFINED
17
+ mLibXML = rb_define_module("LibXML");
18
+ mXML = rb_define_module_under(mLibXML, "XML");
19
+ #endif
20
+
21
+ void ruby_init_xml_xinclude(void)
22
+ {
23
+ cXMLXInclude = rb_define_class_under(mXML, "XInclude", rb_cObject);
24
+ }
@@ -1,108 +1,108 @@
1
- /* $Id: rxml_xpath.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.h"
7
- #include "ruby_xml_xpath_context.h"
8
-
9
- /*
10
- * Document-class: LibXML::XML::XPath
11
- *
12
- * The XML::XPath module is used to query XML documents. It is
13
- * usually accessed via the XML::Document#find or
14
- * XML::Node#find methods. For example:
15
- *
16
- * document.find('/foo', namespaces) -> XML::XPath::Object
17
- *
18
- * The optional namespaces parameter can be a string, array or
19
- * hash table.
20
- *
21
- * document.find('/foo', 'xlink:http://www.w3.org/1999/xlink')
22
- * document.find('/foo', ['xlink:http://www.w3.org/1999/xlink',
23
- * 'xi:http://www.w3.org/2001/XInclude')
24
- * document.find('/foo', 'xlink' => 'http://www.w3.org/1999/xlink',
25
- * 'xi' => 'http://www.w3.org/2001/XInclude')
26
- *
27
- *
28
- * === Working With Default Namespaces
29
- *
30
- * Finding namespaced elements and attributes can be tricky.
31
- * Lets work through an example of a document with a default
32
- * namespace:
33
- *
34
- * <?xml version="1.0" encoding="utf-8"?>
35
- * <feed xmlns="http://www.w3.org/2005/Atom">
36
- * <title type="text">Phil Bogle's Contacts</title>
37
- * </feed>
38
- *
39
- * To find nodes you must define the atom namespace for
40
- * libxml. One way to do this is:
41
- *
42
- * node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom')
43
- *
44
- * Alternatively, you can register the default namespace like this:
45
- *
46
- * doc.root.register_default_namespace('atom')
47
- * node = doc.find('atom:title')
48
- *
49
- * === More Complex Namespace Examples
50
- *
51
- * Lets work through some more complex examples using the
52
- * following xml document:
53
- *
54
- * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
55
- * <soap:Body>
56
- * <getManufacturerNamesResponse xmlns="http://services.somewhere.com">
57
- * <IDAndNameList xmlns="http://services.somewhere.com">
58
- * <ns1:IdAndName xmlns:ns1="http://domain.somewhere.com"/>
59
- * </IDAndNameList>
60
- * </getManufacturerNamesResponse>
61
- * </soap:Envelope>
62
- *
63
- * # Since the soap namespace is defined on the root
64
- * # node we can directly use it.
65
- * doc.find('/soap:Envelope')
66
- *
67
- * # Since the ns1 namespace is not defined on the root node
68
- * # we have to first register it with the xpath engine.
69
- * doc.find('//ns1:IdAndName',
70
- * 'ns1:http://domain.somewhere.com')
71
- *
72
- * # Since the getManufacturerNamesResponse element uses a default
73
- * # namespace we first have to give it a prefix and register
74
- * # it with the xpath engine.
75
- * doc.find('//ns:getManufacturerNamesResponse',
76
- * 'ns:http://services.somewhere.com')
77
- *
78
- * # Here is an example showing a complex namespace aware
79
- * # xpath expression.
80
- * doc.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse/ns0:IDAndNameList/ns1:IdAndName',
81
- ['ns0:http://services.somewhere.com', 'ns1:http://domain.somewhere.com'])
82
- */
83
-
84
- VALUE mXPath;
85
-
86
- // Rdoc needs to know
87
- #ifdef RDOC_NEVER_DEFINED
88
- mLibXML = rb_define_module("LibXML");
89
- mXML = rb_define_module_under(mLibXML, "XML");
90
- #endif
91
-
92
- void
93
- ruby_init_xml_xpath(void) {
94
- mXPath = rb_define_module_under(mXML, "XPath");
95
-
96
- rb_define_const(mXPath, "UNDEFINED", INT2NUM(XPATH_UNDEFINED));
97
- rb_define_const(mXPath, "NODESET", INT2NUM(XPATH_NODESET));
98
- rb_define_const(mXPath, "BOOLEAN", INT2NUM(XPATH_BOOLEAN));
99
- rb_define_const(mXPath, "NUMBER", INT2NUM(XPATH_NUMBER));
100
- rb_define_const(mXPath, "STRING", INT2NUM(XPATH_STRING));
101
- rb_define_const(mXPath, "POINT", INT2NUM(XPATH_POINT));
102
- rb_define_const(mXPath, "RANGE", INT2NUM(XPATH_RANGE));
103
- rb_define_const(mXPath, "LOCATIONSET", INT2NUM(XPATH_LOCATIONSET));
104
- rb_define_const(mXPath, "USERS", INT2NUM(XPATH_USERS));
105
- rb_define_const(mXPath, "XSLT_TREE", INT2NUM(XPATH_XSLT_TREE));
106
-
107
- ruby_init_xml_xpath_object();
108
- }
1
+ /* $Id: ruby_xml_xpath.c 650 2008-11-30 03:40:22Z cfis $ */
2
+
3
+ /* Please see the LICENSE file for copyright and distribution information */
4
+
5
+ #include "ruby_libxml.h"
6
+ #include "ruby_xml_xpath.h"
7
+ #include "ruby_xml_xpath_context.h"
8
+
9
+ /*
10
+ * Document-class: LibXML::XML::XPath
11
+ *
12
+ * The XML::XPath module is used to query XML documents. It is
13
+ * usually accessed via the XML::Document#find or
14
+ * XML::Node#find methods. For example:
15
+ *
16
+ * document.find('/foo', namespaces) -> XML::XPath::Object
17
+ *
18
+ * The optional namespaces parameter can be a string, array or
19
+ * hash table.
20
+ *
21
+ * document.find('/foo', 'xlink:http://www.w3.org/1999/xlink')
22
+ * document.find('/foo', ['xlink:http://www.w3.org/1999/xlink',
23
+ * 'xi:http://www.w3.org/2001/XInclude')
24
+ * document.find('/foo', 'xlink' => 'http://www.w3.org/1999/xlink',
25
+ * 'xi' => 'http://www.w3.org/2001/XInclude')
26
+ *
27
+ *
28
+ * === Working With Default Namespaces
29
+ *
30
+ * Finding namespaced elements and attributes can be tricky.
31
+ * Lets work through an example of a document with a default
32
+ * namespace:
33
+ *
34
+ * <?xml version="1.0" encoding="utf-8"?>
35
+ * <feed xmlns="http://www.w3.org/2005/Atom">
36
+ * <title type="text">Phil Bogle's Contacts</title>
37
+ * </feed>
38
+ *
39
+ * To find nodes you must define the atom namespace for
40
+ * libxml. One way to do this is:
41
+ *
42
+ * node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom')
43
+ *
44
+ * Alternatively, you can register the default namespace like this:
45
+ *
46
+ * doc.root.register_default_namespace('atom')
47
+ * node = doc.find('atom:title')
48
+ *
49
+ * === More Complex Namespace Examples
50
+ *
51
+ * Lets work through some more complex examples using the
52
+ * following xml document:
53
+ *
54
+ * <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
55
+ * <soap:Body>
56
+ * <getManufacturerNamesResponse xmlns="http://services.somewhere.com">
57
+ * <IDAndNameList xmlns="http://services.somewhere.com">
58
+ * <ns1:IdAndName xmlns:ns1="http://domain.somewhere.com"/>
59
+ * </IDAndNameList>
60
+ * </getManufacturerNamesResponse>
61
+ * </soap:Envelope>
62
+ *
63
+ * # Since the soap namespace is defined on the root
64
+ * # node we can directly use it.
65
+ * doc.find('/soap:Envelope')
66
+ *
67
+ * # Since the ns1 namespace is not defined on the root node
68
+ * # we have to first register it with the xpath engine.
69
+ * doc.find('//ns1:IdAndName',
70
+ * 'ns1:http://domain.somewhere.com')
71
+ *
72
+ * # Since the getManufacturerNamesResponse element uses a default
73
+ * # namespace we first have to give it a prefix and register
74
+ * # it with the xpath engine.
75
+ * doc.find('//ns:getManufacturerNamesResponse',
76
+ * 'ns:http://services.somewhere.com')
77
+ *
78
+ * # Here is an example showing a complex namespace aware
79
+ * # xpath expression.
80
+ * doc.find('/soap:Envelope/soap:Body/ns0:getManufacturerNamesResponse/ns0:IDAndNameList/ns1:IdAndName',
81
+ ['ns0:http://services.somewhere.com', 'ns1:http://domain.somewhere.com'])
82
+ */
83
+
84
+ VALUE mXPath;
85
+
86
+ // Rdoc needs to know
87
+ #ifdef RDOC_NEVER_DEFINED
88
+ mLibXML = rb_define_module("LibXML");
89
+ mXML = rb_define_module_under(mLibXML, "XML");
90
+ #endif
91
+
92
+ void ruby_init_xml_xpath(void)
93
+ {
94
+ mXPath = rb_define_module_under(mXML, "XPath");
95
+
96
+ rb_define_const(mXPath, "UNDEFINED", INT2NUM(XPATH_UNDEFINED));
97
+ rb_define_const(mXPath, "NODESET", INT2NUM(XPATH_NODESET));
98
+ rb_define_const(mXPath, "BOOLEAN", INT2NUM(XPATH_BOOLEAN));
99
+ rb_define_const(mXPath, "NUMBER", INT2NUM(XPATH_NUMBER));
100
+ rb_define_const(mXPath, "STRING", INT2NUM(XPATH_STRING));
101
+ rb_define_const(mXPath, "POINT", INT2NUM(XPATH_POINT));
102
+ rb_define_const(mXPath, "RANGE", INT2NUM(XPATH_RANGE));
103
+ rb_define_const(mXPath, "LOCATIONSET", INT2NUM(XPATH_LOCATIONSET));
104
+ rb_define_const(mXPath, "USERS", INT2NUM(XPATH_USERS));
105
+ rb_define_const(mXPath, "XSLT_TREE", INT2NUM(XPATH_XSLT_TREE));
106
+
107
+ ruby_init_xml_xpath_object();
108
+ }
@@ -1,293 +1,305 @@
1
- /* $Id: ruby_xml_xpath_context.c 612 2008-11-21 08:01: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
- static void
28
- rxml_xpath_context_free(xmlXPathContextPtr ctxt) {
29
- xmlXPathFreeContext(ctxt);
30
- }
31
-
32
-
33
- static VALUE
34
- rxml_xpath_context_alloc(VALUE klass) {
35
- return Data_Wrap_Struct(cXMLXPathContext,
36
- NULL,
37
- rxml_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
- static VALUE
53
- rxml_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
- static VALUE
95
- rxml_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
- static VALUE
121
- rxml_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
- rxml_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
- rxml_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
- static VALUE
187
- rxml_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
- rxml_xpath_context_register_namespace(self, rprefix, ruri);
206
- break;
207
- case T_ARRAY:
208
- for (i = 0; i < RARRAY(nslist)->len; i++) {
209
- rxml_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
- static VALUE
231
- rxml_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
- static VALUE
248
- rxml_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
- rxml_raise(xerror);
275
- }
276
-
277
- result = rxml_xpath_object_wrap(xobject);
278
- rb_iv_set(result, "@context", self);
279
- return result;
280
- }
281
-
282
- void
283
- ruby_init_xml_xpath_context(void) {
284
- cXMLXPathContext = rb_define_class_under(mXPath, "Context", rb_cObject);
285
- rb_define_alloc_func(cXMLXPathContext, rxml_xpath_context_alloc);
286
- rb_define_attr(cXMLXPathContext, "doc", 1, 0);
287
- rb_define_method(cXMLXPathContext, "initialize", rxml_xpath_context_initialize, 1);
288
- rb_define_method(cXMLXPathContext, "register_namespaces", rxml_xpath_context_register_namespaces, 1);
289
- rb_define_method(cXMLXPathContext, "register_namespaces_from_node", rxml_xpath_context_register_namespaces_from_node, 1);
290
- rb_define_method(cXMLXPathContext, "register_namespace", rxml_xpath_context_register_namespace, 2);
291
- rb_define_method(cXMLXPathContext, "node=", rxml_xpath_context_node_set, 1);
292
- rb_define_method(cXMLXPathContext, "find", rxml_xpath_context_find, 1);
293
- }
1
+ /* $Id: ruby_xml_xpath_context.c 650 2008-11-30 03:40:22Z 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
+ * 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
+ static void rxml_xpath_context_free(xmlXPathContextPtr ctxt)
27
+ {
28
+ xmlXPathFreeContext(ctxt);
29
+ }
30
+
31
+ static VALUE rxml_xpath_context_alloc(VALUE klass)
32
+ {
33
+ return Data_Wrap_Struct(cXMLXPathContext, NULL, rxml_xpath_context_free, NULL);
34
+ }
35
+
36
+ /* call-seq:
37
+ * XPath::Context.new(node) -> XPath::Context
38
+ *
39
+ * Creates a new XPath context for the specified document. The
40
+ * context can then be used to evaluate an XPath expression.
41
+ *
42
+ * doc = XML::Document.string('<header><first>hi</first></header>')
43
+ * context = XPath::Context.new(doc)
44
+ * nodes = XPath::Object.new('//first', context)
45
+ * nodes.length == 1
46
+ */
47
+ static VALUE rxml_xpath_context_initialize(VALUE self, VALUE node)
48
+ {
49
+ xmlDocPtr xdoc;
50
+ VALUE document;
51
+ #ifndef LIBXML_XPATH_ENABLED
52
+ rb_raise(rb_eTypeError, "libxml was not compiled with XPath support.");
53
+ #endif
54
+
55
+ if (rb_obj_is_kind_of(node, cXMLNode) == Qtrue)
56
+ {
57
+ document = rb_funcall(node, rb_intern("doc"), 0);
58
+ if NIL_P(document)
59
+ rb_raise(rb_eTypeError, "Supplied node must belong to a document.");
60
+ }
61
+ else if (rb_obj_is_kind_of(node, cXMLDocument) == Qtrue)
62
+ {
63
+ document = node;
64
+ }
65
+ else
66
+ {
67
+ rb_raise(rb_eTypeError, "Supplied argument must be a document or node.");
68
+ }
69
+
70
+ Data_Get_Struct(document, xmlDoc, xdoc);
71
+ DATA_PTR(self) = xmlXPathNewContext(xdoc);
72
+
73
+ /* Save the doc as an attribute, this will expose it to Ruby's GC. */
74
+ rb_iv_set(self, "@doc", document);
75
+
76
+ return self;
77
+ }
78
+
79
+ /*
80
+ * call-seq:
81
+ * context.register_namespace(prefix, uri) -> (true|false)
82
+ *
83
+ * Register the specified namespace URI with the specified prefix
84
+ * in this context.
85
+
86
+ * context.register_namespace('xi', 'http://www.w3.org/2001/XInclude')
87
+ */
88
+ static VALUE rxml_xpath_context_register_namespace(VALUE self, VALUE prefix,
89
+ VALUE uri)
90
+ {
91
+ xmlXPathContextPtr ctxt;
92
+
93
+ Data_Get_Struct(self, xmlXPathContext, ctxt);
94
+ if (xmlXPathRegisterNs(ctxt, (xmlChar*) StringValuePtr(prefix),
95
+ (xmlChar*) StringValuePtr(uri)) == 0)
96
+ {
97
+ return (Qtrue);
98
+ }
99
+ else
100
+ {
101
+ /* Should raise an exception, IMHO (whose?, why shouldnt it? -danj)*/
102
+ rb_warning("register namespace failed");
103
+ return (Qfalse);
104
+ }
105
+ }
106
+
107
+ /* call-seq:
108
+ * context.register_namespaces_from_node(node) -> self
109
+ *
110
+ * Helper method to read in namespaces defined on a node.
111
+ *
112
+ * doc = XML::Document.string('<header><first>hi</first></header>')
113
+ * context = XPath::Context.new(doc)
114
+ * context.register_namespaces_from_node(doc.root)
115
+ */
116
+ static VALUE rxml_xpath_context_register_namespaces_from_node(VALUE self,
117
+ VALUE node)
118
+ {
119
+ xmlXPathContextPtr xctxt;
120
+ xmlNodePtr xnode;
121
+ xmlNsPtr *xnsArr;
122
+
123
+ Data_Get_Struct(self, xmlXPathContext, xctxt);
124
+
125
+ if (rb_obj_is_kind_of(node, cXMLDocument) == Qtrue)
126
+ {
127
+ xmlDocPtr xdoc;
128
+ Data_Get_Struct(node, xmlDoc, xdoc);
129
+ xnode = xmlDocGetRootElement(xdoc);
130
+ }
131
+ else if (rb_obj_is_kind_of(node, cXMLNode) == Qtrue)
132
+ {
133
+ Data_Get_Struct(node, xmlNode, xnode);
134
+ }
135
+ else
136
+ {
137
+ rb_raise(rb_eTypeError, "The first argument must be a document or node.");
138
+ }
139
+
140
+ xnsArr = xmlGetNsList(xnode->doc, xnode);
141
+
142
+ if (xnsArr)
143
+ {
144
+ xmlNsPtr xns = *xnsArr;
145
+
146
+ while (xns)
147
+ {
148
+ /* If there is no prefix, then this is the default namespace.
149
+ Skip it for now. */
150
+ if (xns->prefix)
151
+ {
152
+ VALUE prefix = rb_str_new2(xns->prefix);
153
+ VALUE uri = rb_str_new2(xns->href);
154
+ rxml_xpath_context_register_namespace(self, prefix, uri);
155
+ }
156
+ xns = xns->next;
157
+ }
158
+ xmlFree(xnsArr);
159
+ }
160
+
161
+ return self;
162
+ }
163
+
164
+ static int iterate_ns_hash(st_data_t prefix, st_data_t uri, st_data_t self)
165
+ {
166
+ rxml_xpath_context_register_namespace(self, prefix, uri);
167
+ return ST_CONTINUE;
168
+ }
169
+
170
+ /*
171
+ * call-seq:
172
+ * context.register_namespaces(["prefix:uri"]) -> self
173
+ *
174
+ * Register the specified namespaces in this context.
175
+ *
176
+ * context.register_namespaces('xi:http://www.w3.org/2001/XInclude')
177
+ * context.register_namespaces(['xlink:http://www.w3.org/1999/xlink',
178
+ * 'xi:http://www.w3.org/2001/XInclude')
179
+ * context.register_namespaces('xlink' => 'http://www.w3.org/1999/xlink',
180
+ * 'xi' => 'http://www.w3.org/2001/XInclude')
181
+ */
182
+ static VALUE rxml_xpath_context_register_namespaces(VALUE self, VALUE nslist)
183
+ {
184
+ char *cp;
185
+ long i;
186
+ VALUE rprefix, ruri;
187
+
188
+ /* Need to loop through the 2nd argument and iterate through the
189
+ * list of namespaces that we want to allow */
190
+ switch (TYPE(nslist))
191
+ {
192
+ case T_STRING:
193
+ cp = strchr(StringValuePtr(nslist), (int) ':');
194
+ if (cp == NULL)
195
+ {
196
+ rprefix = nslist;
197
+ ruri = Qnil;
198
+ }
199
+ else
200
+ {
201
+ rprefix = rb_str_new(StringValuePtr(nslist), (int) ((long) cp
202
+ - (long) StringValuePtr(nslist)));
203
+ ruri = rb_str_new2(&cp[1]);
204
+ }
205
+ /* Should test the results of this */
206
+ rxml_xpath_context_register_namespace(self, rprefix, ruri);
207
+ break;
208
+ case T_ARRAY:
209
+ for (i = 0; i < RARRAY_LEN(nslist); i++)
210
+ {
211
+ rxml_xpath_context_register_namespaces(self, RARRAY_PTR(nslist)[i]);
212
+ }
213
+ break;
214
+ case T_HASH:
215
+ st_foreach(RHASH(nslist)->tbl, iterate_ns_hash, self);
216
+ break;
217
+ default:
218
+ rb_raise(
219
+ rb_eArgError,
220
+ "Invalid argument type, only accept string, array of strings, or an array of arrays");
221
+ }
222
+ return self;
223
+ }
224
+
225
+ /*
226
+ * call-seq:
227
+ * context.node = node
228
+ *
229
+ * Set the current node used by the XPath engine
230
+
231
+ * doc = XML::Document.string('<header><first>hi</first></header>')
232
+ * context.node = doc.root.first
233
+ */
234
+ static VALUE rxml_xpath_context_node_set(VALUE self, VALUE node)
235
+ {
236
+ xmlXPathContextPtr xctxt;
237
+ xmlNodePtr xnode;
238
+
239
+ Data_Get_Struct(self, xmlXPathContext, xctxt);
240
+ Data_Get_Struct(node, xmlNode, xnode);
241
+ xctxt->node = xnode;
242
+ return node;
243
+ }
244
+
245
+ /*
246
+ * call-seq:
247
+ * context.find("xpath") -> XML::XPath::Object
248
+ *
249
+ * Find nodes matching the specified XPath expression
250
+ */
251
+ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr)
252
+ {
253
+ xmlXPathContextPtr xctxt;
254
+ xmlXPathObjectPtr xobject;
255
+ xmlXPathCompExprPtr xcompexpr;
256
+ VALUE result;
257
+
258
+ Data_Get_Struct(self, xmlXPathContext, xctxt);
259
+
260
+ if (TYPE(xpath_expr) == T_STRING)
261
+ {
262
+ VALUE expression = rb_check_string_type(xpath_expr);
263
+ xobject = xmlXPathEval((xmlChar*) StringValueCStr(expression), xctxt);
264
+ }
265
+ else if (rb_obj_is_kind_of(xpath_expr, cXMLXPathExpression))
266
+ {
267
+ Data_Get_Struct(xpath_expr, xmlXPathCompExpr, xcompexpr);
268
+ xobject = xmlXPathCompiledEval(xcompexpr, xctxt);
269
+ }
270
+ else
271
+ {
272
+ rb_raise(rb_eTypeError,
273
+ "Argument should be an intance of a String or XPath::Expression");
274
+ }
275
+
276
+ if (xobject == NULL)
277
+ {
278
+ /* xmlLastError is different than xctxt->lastError. Use
279
+ xmlLastError since it has the message set while xctxt->lastError
280
+ does not. */
281
+ xmlErrorPtr xerror = xmlGetLastError();
282
+ rxml_raise(xerror);
283
+ }
284
+
285
+ result = rxml_xpath_object_wrap(xobject);
286
+ rb_iv_set(result, "@context", self);
287
+ return result;
288
+ }
289
+
290
+ void ruby_init_xml_xpath_context(void)
291
+ {
292
+ cXMLXPathContext = rb_define_class_under(mXPath, "Context", rb_cObject);
293
+ rb_define_alloc_func(cXMLXPathContext, rxml_xpath_context_alloc);
294
+ rb_define_attr(cXMLXPathContext, "doc", 1, 0);
295
+ rb_define_method(cXMLXPathContext, "initialize",
296
+ rxml_xpath_context_initialize, 1);
297
+ rb_define_method(cXMLXPathContext, "register_namespaces",
298
+ rxml_xpath_context_register_namespaces, 1);
299
+ rb_define_method(cXMLXPathContext, "register_namespaces_from_node",
300
+ rxml_xpath_context_register_namespaces_from_node, 1);
301
+ rb_define_method(cXMLXPathContext, "register_namespace",
302
+ rxml_xpath_context_register_namespace, 2);
303
+ rb_define_method(cXMLXPathContext, "node=", rxml_xpath_context_node_set, 1);
304
+ rb_define_method(cXMLXPathContext, "find", rxml_xpath_context_find, 1);
305
+ }