libxml-ruby 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/CHANGES +53 -0
  2. data/Rakefile +1 -0
  3. data/ext/libxml/build.log +4 -0
  4. data/ext/libxml/cbg.c +86 -86
  5. data/ext/libxml/libxml.c +878 -876
  6. data/ext/libxml/ruby_libxml.h +8 -4
  7. data/ext/libxml/ruby_xml_attr.c +36 -168
  8. data/ext/libxml/ruby_xml_attr.h +2 -4
  9. data/ext/libxml/ruby_xml_attr_decl.c +177 -0
  10. data/ext/libxml/ruby_xml_attr_decl.h +13 -0
  11. data/ext/libxml/ruby_xml_attributes.c +29 -20
  12. data/ext/libxml/ruby_xml_document.c +895 -898
  13. data/ext/libxml/ruby_xml_dtd.c +18 -1
  14. data/ext/libxml/ruby_xml_dtd.h +1 -0
  15. data/ext/libxml/ruby_xml_encoding.c +116 -0
  16. data/ext/libxml/ruby_xml_encoding.h +12 -0
  17. data/ext/libxml/ruby_xml_error.c +8 -2
  18. data/ext/libxml/ruby_xml_html_parser.c +53 -74
  19. data/ext/libxml/ruby_xml_html_parser.h +2 -3
  20. data/ext/libxml/ruby_xml_html_parser_context.c +145 -0
  21. data/ext/libxml/ruby_xml_html_parser_context.h +12 -0
  22. data/ext/libxml/ruby_xml_html_parser_options.c +48 -0
  23. data/ext/libxml/ruby_xml_html_parser_options.h +12 -0
  24. data/ext/libxml/ruby_xml_input_cbg.c +1 -1
  25. data/ext/libxml/ruby_xml_io.c +30 -0
  26. data/ext/libxml/ruby_xml_io.h +9 -0
  27. data/ext/libxml/ruby_xml_namespace.c +34 -16
  28. data/ext/libxml/ruby_xml_namespace.h +2 -2
  29. data/ext/libxml/ruby_xml_namespaces.c +6 -6
  30. data/ext/libxml/ruby_xml_node.c +1367 -1324
  31. data/ext/libxml/ruby_xml_node.h +2 -2
  32. data/ext/libxml/ruby_xml_parser.c +26 -78
  33. data/ext/libxml/ruby_xml_parser.h +1 -1
  34. data/ext/libxml/ruby_xml_parser_context.c +284 -13
  35. data/ext/libxml/ruby_xml_parser_context.h +1 -2
  36. data/ext/libxml/ruby_xml_parser_options.c +75 -0
  37. data/ext/libxml/ruby_xml_parser_options.h +14 -0
  38. data/ext/libxml/ruby_xml_reader.c +277 -183
  39. data/ext/libxml/ruby_xml_sax_parser.c +60 -57
  40. data/ext/libxml/ruby_xml_xpath_context.c +43 -8
  41. data/ext/libxml/ruby_xml_xpath_expression.c +6 -0
  42. data/ext/libxml/ruby_xml_xpath_object.c +107 -95
  43. data/ext/libxml/ruby_xml_xpath_object.h +9 -1
  44. data/ext/libxml/ruby_xml_xpointer.c +107 -107
  45. data/ext/libxml/version.h +2 -2
  46. data/ext/vc/libxml_ruby.vcproj +43 -3
  47. data/lib/libxml.rb +2 -3
  48. data/lib/libxml/attr.rb +71 -2
  49. data/lib/libxml/attr_decl.rb +81 -0
  50. data/lib/libxml/document.rb +78 -14
  51. data/lib/libxml/html_parser.rb +75 -42
  52. data/lib/libxml/node.rb +11 -0
  53. data/lib/libxml/parser.rb +106 -62
  54. data/lib/libxml/reader.rb +12 -0
  55. data/lib/libxml/sax_parser.rb +42 -52
  56. data/lib/libxml/xpath_object.rb +15 -0
  57. data/test/model/atom.xml +12 -12
  58. data/test/model/bands.xml +4 -4
  59. data/test/model/books.xml +146 -147
  60. data/test/model/merge_bug_data.xml +1 -1
  61. data/test/model/rubynet.xml +1 -0
  62. data/test/model/shiporder.rng +1 -1
  63. data/test/model/shiporder.xml +22 -22
  64. data/test/model/shiporder.xsd +30 -30
  65. data/test/model/xinclude.xml +1 -1
  66. data/test/{tc_node_attr.rb → tc_attr.rb} +1 -1
  67. data/test/tc_attr_decl.rb +131 -0
  68. data/test/tc_deprecated_require.rb +1 -3
  69. data/test/tc_document.rb +13 -3
  70. data/test/tc_document_write.rb +5 -5
  71. data/test/tc_dtd.rb +13 -5
  72. data/test/tc_html_parser.rb +14 -26
  73. data/test/tc_node_cdata.rb +1 -3
  74. data/test/tc_node_comment.rb +2 -4
  75. data/test/tc_node_edit.rb +2 -3
  76. data/test/tc_node_text.rb +35 -1
  77. data/test/tc_node_write.rb +3 -3
  78. data/test/tc_node_xlink.rb +2 -4
  79. data/test/tc_parser.rb +163 -70
  80. data/test/tc_parser_context.rb +103 -42
  81. data/test/tc_reader.rb +173 -45
  82. data/test/tc_relaxng.rb +2 -2
  83. data/test/tc_sax_parser.rb +48 -52
  84. data/test/tc_schema.rb +2 -2
  85. data/test/tc_xpath.rb +37 -6
  86. data/test/tc_xpath_context.rb +7 -1
  87. data/test/tc_xpath_expression.rb +1 -3
  88. data/test/tc_xpointer.rb +1 -3
  89. data/test/test_suite.rb +2 -3
  90. metadata +20 -13
  91. data/ext/libxml/ruby_xml_input.c +0 -329
  92. data/ext/libxml/ruby_xml_input.h +0 -20
  93. data/lib/libxml/parser_context.rb +0 -17
  94. data/lib/libxml/parser_options.rb +0 -25
  95. data/test/model/simple.xml +0 -7
  96. data/test/tc_input.rb +0 -13
  97. data/test/tc_well_formed.rb +0 -11
@@ -0,0 +1,12 @@
1
+ /* $Id: ruby_xml_parser_context.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_HTML_PARSER_CONTEXT__
6
+ #define __RXML_HTML_PARSER_CONTEXT__
7
+
8
+ extern VALUE cXMLHtmlParserContext;
9
+
10
+ void ruby_init_html_parser_context(void);
11
+
12
+ #endif
@@ -0,0 +1,48 @@
1
+ /* $Id: ruby_xml_html_parser.c 710 2009-01-20 05:30:51Z cfis $ */
2
+
3
+ /* Please see the LICENSE file for copyright and distribution information */
4
+
5
+ #include "ruby_libxml.h"
6
+
7
+
8
+ /* Document-class: LibXML::XML::HTMLParserOptions
9
+ *
10
+ * Options that control the operation of the HTMLParser. The easiest
11
+ * way to set a parser's options is to use the methods
12
+ * XML::HTMLParser.file, XML::HTMLParser.io or XML::HTMLParser.string.
13
+ * For additional control, see XML::HTMLParser::Context#options=.
14
+ */
15
+
16
+ VALUE mXMLHtmlParserOptions;
17
+
18
+
19
+ // Rdoc needs to know
20
+ #ifdef RDOC_NEVER_DEFINED
21
+ mLibXML = rb_define_module("LibXML");
22
+ mXML = rb_define_module_under(mLibXML, "XML");
23
+ cXMLHtmlParser = rb_define_class_under(mXML, "HTMLParser", rb_cObject);
24
+ #endif
25
+
26
+ void ruby_init_html_parser_options(void)
27
+ {
28
+ mXMLHtmlParserOptions = rb_define_module_under(cXMLHtmlParser, "Options");
29
+
30
+ #if LIBXML_VERSION >= 20621
31
+ /* Relaxed parsing */
32
+ rb_define_const(mXMLHtmlParserOptions, "RECOVER", INT2NUM(HTML_PARSE_RECOVER));
33
+ #endif
34
+ /* suppress error reports */
35
+ rb_define_const(mXMLHtmlParserOptions, "NOERROR", INT2NUM(HTML_PARSE_NOERROR));
36
+ /* suppress warning reports */
37
+ rb_define_const(mXMLHtmlParserOptions, "NOWARNING", INT2NUM(HTML_PARSE_NOWARNING));
38
+ /* pedantic error reporting */
39
+ rb_define_const(mXMLHtmlParserOptions, "PEDANTIC", INT2NUM(HTML_PARSE_PEDANTIC));
40
+ /* remove blank nodes */
41
+ rb_define_const(mXMLHtmlParserOptions, "NOBLANKS", INT2NUM(HTML_PARSE_NOBLANKS));
42
+ #if LIBXML_VERSION >= 20621
43
+ /* Forbid network access */
44
+ rb_define_const(mXMLHtmlParserOptions, "NONET", INT2NUM(HTML_PARSE_NONET));
45
+ /* compact small text nodes */
46
+ rb_define_const(mXMLHtmlParserOptions, "COMPACT", INT2NUM(HTML_PARSE_COMPACT));
47
+ #endif
48
+ }
@@ -0,0 +1,12 @@
1
+ /* $Id: ruby_xml_html_parser.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_HTML_PARSER_OPTIONS__
6
+ #define __RXML_HTML_PARSER_OPTIONS__
7
+
8
+ extern VALUE mXMLHtmlParserOptions;
9
+
10
+ void ruby_init_html_parser_options(void);
11
+
12
+ #endif
@@ -3,7 +3,7 @@
3
3
  #include "ruby_libxml.h"
4
4
  #include "ruby_xml_input_cbg.h"
5
5
 
6
- /* Document-class: LibXML::XML::InputCallbacks
6
+ /* Document-class: LibXML::XML::EncodingCallbacks
7
7
  *
8
8
  * Support for adding custom scheme handlers. */
9
9
 
@@ -0,0 +1,30 @@
1
+ /* $Id: libxml.c 734 2009-01-22 04:41:07Z cfis $ */
2
+
3
+ /* Please see the LICENSE file for copyright and distribution information */
4
+
5
+ #include "ruby_libxml.h"
6
+
7
+ static ID READ_METHOD;
8
+
9
+ /* This method is called by libxml when it wants to read
10
+ more data from a stream. We go with the duck typing
11
+ solution to support StringIO objects. */
12
+ int rxml_read_callback(void *context, char *buffer, int len)
13
+ {
14
+ VALUE io = (VALUE) context;
15
+ VALUE string = rb_funcall(io, READ_METHOD, 1, INT2NUM(len));
16
+ int size;
17
+
18
+ if (string == Qnil)
19
+ return 0;
20
+
21
+ size = RSTRING_LEN(string);
22
+ memcpy(buffer, StringValuePtr(string), size);
23
+
24
+ return size;
25
+ }
26
+
27
+ void rxml_init_io(void)
28
+ {
29
+ READ_METHOD = rb_intern("read");
30
+ }
@@ -0,0 +1,9 @@
1
+ /* Please see the LICENSE file for copyright and distribution information */
2
+
3
+ #ifndef __RXML_IO__
4
+ #define __RXML_IO__
5
+
6
+ int rxml_read_callback(void *context, char *buffer, int len);
7
+ void rxml_init_io(void);
8
+
9
+ #endif
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_namespace.c 685 2008-12-13 01:13:56Z cfis $ */
1
+ /* $Id: ruby_xml_namespace.c 740 2009-01-23 04:03:11Z cfis $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -33,6 +33,24 @@ static VALUE rxml_namespace_alloc(VALUE klass)
33
33
  return Data_Wrap_Struct(klass, NULL, rxml_namespace_free, NULL);
34
34
  }
35
35
 
36
+ VALUE rxml_namespace_wrap(xmlNsPtr xns, RUBY_DATA_FUNC freeFunc)
37
+ {
38
+ if (xns->_private)
39
+ {
40
+ return (VALUE)xns->_private;
41
+ }
42
+ else
43
+ {
44
+ VALUE ns;
45
+ if (freeFunc == NULL)
46
+ freeFunc = (RUBY_DATA_FUNC)rxml_namespace_free;
47
+
48
+ ns = Data_Wrap_Struct(cXMLNamespace, NULL, freeFunc, xns);
49
+ xns->_private = (void*)ns;
50
+ return ns;
51
+ }
52
+ }
53
+
36
54
  /*
37
55
  * call-seq:
38
56
  * initialize(node, "prefix", "href") -> XML::Namespace
@@ -63,20 +81,6 @@ static VALUE rxml_namespace_initialize(VALUE self, VALUE node, VALUE prefix,
63
81
  return self;
64
82
  }
65
83
 
66
- VALUE rxml_namespace_wrap(xmlNsPtr xns)
67
- {
68
- if (xns->_private)
69
- {
70
- return (VALUE)xns->_private;
71
- }
72
- else
73
- {
74
- VALUE ns = Data_Wrap_Struct(cXMLNamespace, NULL, rxml_namespace_free, xns);
75
- xns->_private = (void*)ns;
76
- return ns;
77
- }
78
- }
79
-
80
84
  /*
81
85
  * call-seq:
82
86
  * ns.href -> "href"
@@ -97,6 +101,19 @@ static VALUE rxml_namespace_href_get(VALUE self)
97
101
  return rb_str_new2((const char*) xns->href);
98
102
  }
99
103
 
104
+ /*
105
+ * call-seq:
106
+ * ns.node_type -> num
107
+ *
108
+ * Obtain this namespace's type identifier.
109
+ */
110
+ static VALUE rxml_namespace_node_type(VALUE self)
111
+ {
112
+ xmlNsPtr xns;
113
+ Data_Get_Struct(self, xmlNs, xns);
114
+ return INT2NUM(xns->type);
115
+ }
116
+
100
117
  /*
101
118
  * call-seq:
102
119
  * ns.prefix -> "prefix"
@@ -138,7 +155,7 @@ static VALUE rxml_namespace_next(VALUE self)
138
155
  if (xns == NULL || xns->next == NULL)
139
156
  return (Qnil);
140
157
  else
141
- return (rxml_namespace_wrap(xns->next));
158
+ return (rxml_namespace_wrap(xns->next, NULL));
142
159
  }
143
160
 
144
161
  // Rdoc needs to know
@@ -154,5 +171,6 @@ void ruby_init_xml_namespace(void)
154
171
  rb_define_method(cXMLNamespace, "initialize", rxml_namespace_initialize, 3);
155
172
  rb_define_method(cXMLNamespace, "href", rxml_namespace_href_get, 0);
156
173
  rb_define_method(cXMLNamespace, "next", rxml_namespace_next, 0);
174
+ rb_define_method(cXMLNamespace, "node_type", rxml_namespace_node_type, 0);
157
175
  rb_define_method(cXMLNamespace, "prefix", rxml_namespace_prefix_get, 0);
158
176
  }
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_namespace.h 666 2008-12-07 00:16:50Z cfis $ */
1
+ /* $Id: ruby_xml_namespace.h 739 2009-01-23 03:42:09Z cfis $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -8,5 +8,5 @@
8
8
  extern VALUE cXMLNamespace;
9
9
 
10
10
  void ruby_init_xml_namespace(void);
11
- VALUE rxml_namespace_wrap(xmlNsPtr ns);
11
+ VALUE rxml_namespace_wrap(xmlNsPtr xns, RUBY_DATA_FUNC freeFunc);
12
12
  #endif
@@ -92,7 +92,7 @@ static VALUE rxml_namespaces_definitions(VALUE self)
92
92
 
93
93
  while (xns)
94
94
  {
95
- VALUE anamespace = rxml_namespace_wrap(xns);
95
+ VALUE anamespace = rxml_namespace_wrap(xns, NULL);
96
96
  rb_ary_push(arr, anamespace);
97
97
  xns = xns->next;
98
98
  }
@@ -128,7 +128,7 @@ static VALUE rxml_namespaces_each(VALUE self)
128
128
 
129
129
  for (xns = nsList; *xns != NULL; xns++)
130
130
  {
131
- VALUE ns = rxml_namespace_wrap(*xns);
131
+ VALUE ns = rxml_namespace_wrap(*xns, NULL);
132
132
  rb_yield(ns);
133
133
  }
134
134
  xmlFree(nsList);
@@ -163,7 +163,7 @@ static VALUE rxml_namespaces_find_by_href(VALUE self, VALUE href)
163
163
 
164
164
  xns = xmlSearchNsByHref(xnode->doc, xnode, (xmlChar*) StringValuePtr(href));
165
165
  if (xns)
166
- return rxml_namespace_wrap(xns);
166
+ return rxml_namespace_wrap(xns, NULL);
167
167
  else
168
168
  return Qnil;
169
169
  }
@@ -202,7 +202,7 @@ static VALUE rxml_namespaces_find_by_prefix(VALUE self, VALUE prefix)
202
202
 
203
203
  xns = xmlSearchNs(xnode->doc, xnode, xprefix);
204
204
  if (xns)
205
- return rxml_namespace_wrap(xns);
205
+ return rxml_namespace_wrap(xns, NULL);
206
206
  else
207
207
  return Qnil;
208
208
  }
@@ -226,7 +226,7 @@ static VALUE rxml_namespaces_namespace_get(VALUE self)
226
226
  Data_Get_Struct(self, xmlNode, xnode);
227
227
 
228
228
  if (xnode->ns)
229
- return rxml_namespace_wrap(xnode->ns);
229
+ return rxml_namespace_wrap(xnode->ns, NULL);
230
230
  else
231
231
  return Qnil;
232
232
  }
@@ -274,7 +274,7 @@ static VALUE rxml_namespaces_node_get(VALUE self)
274
274
  {
275
275
  xmlNodePtr xnode;
276
276
  Data_Get_Struct(self, xmlNode, xnode);
277
- return rxml_node_wrap(cXMLNode, xnode);
277
+ return rxml_node_wrap(xnode);
278
278
  }
279
279
 
280
280
 
@@ -1,1324 +1,1367 @@
1
- #include "ruby_libxml.h"
2
- #include "ruby_xml_node.h"
3
-
4
- VALUE cXMLNode;
5
-
6
- /* Document-class: LibXML::XML::Node
7
- *
8
- * Nodes are the primary objects that make up an XML document.
9
- * The node class represents most node types that are found in
10
- * an XML document (but not Attributes, see LibXML::XML::Attribute).
11
- * It exposes libxml's full API for creating, querying
12
- * moving and deleting node objects. Many of these methods are
13
- * documented in the DOM Level 3 specification found at:
14
- * http://www.w3.org/TR/DOM-Level-3-Core/. */
15
-
16
- static VALUE rxml_node_content_set(VALUE self, VALUE content);
17
-
18
- VALUE check_string_or_symbol(VALUE val)
19
- {
20
- if (TYPE(val) != T_STRING && TYPE(val) != T_SYMBOL)
21
- {
22
- rb_raise(rb_eTypeError,
23
- "wrong argument type %s (expected String or Symbol)", rb_obj_classname(
24
- val));
25
- }
26
- return rb_obj_as_string(val);
27
- }
28
-
29
- /*
30
- * memory2 implementation: xmlNode->_private holds a reference
31
- * to the wrapping ruby object VALUE when there is one.
32
- * traversal for marking is upward, and top levels are marked
33
- * through and lower level mark entry.
34
- *
35
- * All ruby retrieval for an xml
36
- * node will result in the same ruby instance. When all handles to them
37
- * go out of scope, then ruby_xfree gets called and _private is set to NULL.
38
- * If the xmlNode has no parent or document, then call xmlFree.
39
- */
40
- void rxml_node2_free(xmlNodePtr xnode)
41
- {
42
- /* Set _private to NULL so that we won't reuse the
43
- same, freed, Ruby wrapper object later.*/
44
- xnode->_private = NULL;
45
-
46
- if (xnode->doc == NULL && xnode->parent == NULL)
47
- xmlFreeNode(xnode);
48
- }
49
-
50
- void rxml_node_mark_common(xmlNodePtr xnode)
51
- {
52
- if (xnode->parent == NULL)
53
- return;
54
-
55
- if (xnode->doc != NULL)
56
- {
57
- if (xnode->doc->_private == NULL)
58
- rb_bug("XmlNode Doc is not bound! (%s:%d)", __FILE__,__LINE__);
59
- rb_gc_mark((VALUE) xnode->doc->_private);
60
- }
61
- else
62
- {
63
- while (xnode->parent != NULL)
64
- xnode = xnode->parent;
65
-
66
- if (xnode->_private == NULL)
67
- rb_warning("XmlNode Root Parent is not bound! (%s:%d)", __FILE__,__LINE__);
68
- else
69
- rb_gc_mark((VALUE) xnode->_private);
70
- }
71
- }
72
-
73
- void rxml_node_mark(xmlNodePtr xnode)
74
- {
75
- if (xnode == NULL)
76
- return;
77
-
78
- if (xnode->_private == NULL)
79
- {
80
- rb_warning("XmlNode is not bound! (%s:%d)", __FILE__, __LINE__);
81
- return;
82
- }
83
-
84
- rxml_node_mark_common(xnode);
85
- }
86
-
87
- VALUE rxml_node_wrap(VALUE klass, xmlNodePtr xnode)
88
- {
89
- VALUE obj;
90
-
91
- // This node is already wrapped
92
- if (xnode->_private != NULL)
93
- {
94
- return (VALUE) xnode->_private;
95
- }
96
-
97
- obj = Data_Wrap_Struct(klass, rxml_node_mark, rxml_node2_free, xnode);
98
-
99
- xnode->_private = (void*) obj;
100
- return obj;
101
- }
102
-
103
- static VALUE rxml_node_alloc(VALUE klass)
104
- {
105
- return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node2_free, NULL);
106
- }
107
-
108
- /*
109
- * call-seq:
110
- * XML::Node.new_cdata(content = nil) -> XML::Node
111
- *
112
- * Create a new #CDATA node, optionally setting
113
- * the node's content.
114
- */
115
- static VALUE rxml_node_new_cdata(int argc, VALUE *argv, VALUE klass)
116
- {
117
- VALUE content = Qnil;
118
- xmlNodePtr xnode;
119
-
120
- rb_scan_args(argc, argv, "01", &content);
121
-
122
- if (NIL_P(content))
123
- {
124
- xnode = xmlNewCDataBlock(NULL, NULL, 0);
125
- }
126
- else
127
- {
128
- content = rb_obj_as_string(content);
129
- xnode = xmlNewCDataBlock(NULL, (xmlChar*) StringValuePtr(content),
130
- RSTRING_LEN(content));
131
- }
132
-
133
- if (xnode == NULL)
134
- rxml_raise(&xmlLastError);
135
-
136
- return rxml_node_wrap(klass, xnode);
137
- }
138
-
139
- /*
140
- * call-seq:
141
- * XML::Node.new_comment(content = nil) -> XML::Node
142
- *
143
- * Create a new comment node, optionally setting
144
- * the node's content.
145
- *
146
- */
147
- static VALUE rxml_node_new_comment(int argc, VALUE *argv, VALUE klass)
148
- {
149
- VALUE content = Qnil;
150
- xmlNodePtr xnode;
151
-
152
- rb_scan_args(argc, argv, "01", &content);
153
-
154
- if (NIL_P(content))
155
- {
156
- xnode = xmlNewComment(NULL);
157
- }
158
- else
159
- {
160
- content = rb_obj_as_string(content);
161
- xnode = xmlNewComment((xmlChar*) StringValueCStr(content));
162
- }
163
-
164
- if (xnode == NULL)
165
- rxml_raise(&xmlLastError);
166
-
167
- return rxml_node_wrap(klass, xnode);
168
- }
169
-
170
- /*
171
- * call-seq:
172
- * XML::Node.new_text(content) -> XML::Node
173
- *
174
- * Create a new text node.
175
- *
176
- */
177
- static VALUE rxml_node_new_text(VALUE klass, VALUE content)
178
- {
179
- xmlNodePtr xnode;
180
- Check_Type(content, T_STRING);
181
- content = rb_obj_as_string(content);
182
-
183
- xnode = xmlNewText((xmlChar*) StringValueCStr(content));
184
-
185
- if (xnode == NULL)
186
- rxml_raise(&xmlLastError);
187
-
188
- return rxml_node_wrap(klass, xnode);
189
- }
190
-
191
- /*
192
- * call-seq:
193
- * XML::Node.initialize(name, content = nil, namespace = nil) -> XML::Node
194
- *
195
- * Creates a new element with the specified name, content and
196
- * namespace. The content and namespace may be nil.
197
- */
198
- static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self)
199
- {
200
- VALUE name;
201
- VALUE content;
202
- VALUE ns;
203
- xmlNodePtr xnode = NULL;
204
- xmlNsPtr xns = NULL;
205
-
206
- rb_scan_args(argc, argv, "12", &name, &content, &ns);
207
-
208
- name = check_string_or_symbol(name);
209
-
210
- if (!NIL_P(ns))
211
- Data_Get_Struct(ns, xmlNs, xns);
212
-
213
- xnode = xmlNewNode(xns, (xmlChar*) StringValuePtr(name));
214
- xnode->_private = (void*) self;
215
- DATA_PTR( self) = xnode;
216
-
217
- if (!NIL_P(content))
218
- rxml_node_content_set(self, content);
219
-
220
- return self;
221
- }
222
-
223
- /*
224
- * call-seq:
225
- * node.base -> "uri"
226
- *
227
- * Obtain this node's base URI.
228
- */
229
- static VALUE rxml_node_base_get(VALUE self)
230
- {
231
- xmlNodePtr xnode;
232
- xmlChar* base_uri;
233
- VALUE result = Qnil;
234
-
235
- Data_Get_Struct(self, xmlNode, xnode);
236
-
237
- if (xnode->doc == NULL)
238
- return (result);
239
-
240
- base_uri = xmlNodeGetBase(xnode->doc, xnode);
241
- if (base_uri)
242
- {
243
- result = rb_str_new2((const char*) base_uri);
244
- xmlFree(base_uri);
245
- }
246
-
247
- return (result);
248
- }
249
-
250
- // TODO node_base_set should support setting back to nil
251
-
252
- /*
253
- * call-seq:
254
- * node.base = "uri"
255
- *
256
- * Set this node's base URI.
257
- */
258
- static VALUE rxml_node_base_set(VALUE self, VALUE uri)
259
- {
260
- xmlNodePtr xnode;
261
-
262
- Check_Type(uri, T_STRING);
263
- Data_Get_Struct(self, xmlNode, xnode);
264
- if (xnode->doc == NULL)
265
- return (Qnil);
266
-
267
- xmlNodeSetBase(xnode, (xmlChar*) StringValuePtr(uri));
268
- return (Qtrue);
269
- }
270
-
271
- /*
272
- * call-seq:
273
- * node.content -> "string"
274
- *
275
- * Obtain this node's content as a string.
276
- */
277
- static VALUE rxml_node_content_get(VALUE self)
278
- {
279
- xmlNodePtr xnode;
280
- xmlChar *content;
281
- VALUE result = Qnil;
282
-
283
- Data_Get_Struct(self, xmlNode, xnode);
284
- content = xmlNodeGetContent(xnode);
285
- if (content)
286
- {
287
- result = rb_str_new2((const char *) content);
288
- xmlFree(content);
289
- }
290
-
291
- return result;
292
- }
293
-
294
- /*
295
- * call-seq:
296
- * node.content = "string"
297
- *
298
- * Set this node's content to the specified string.
299
- */
300
- static VALUE rxml_node_content_set(VALUE self, VALUE content)
301
- {
302
- xmlNodePtr xnode;
303
-
304
- Check_Type(content, T_STRING);
305
- Data_Get_Struct(self, xmlNode, xnode);
306
- // XXX docs indicate need for escaping entites, need to be done? danj
307
- xmlNodeSetContent(xnode, (xmlChar*) StringValuePtr(content));
308
- return (Qtrue);
309
- }
310
-
311
- /*
312
- * call-seq:
313
- * node.content_stripped -> "string"
314
- *
315
- * Obtain this node's stripped content.
316
- *
317
- * *Deprecated*: Stripped content can be obtained via the
318
- * +content+ method.
319
- */
320
- static VALUE rxml_node_content_stripped_get(VALUE self)
321
- {
322
- xmlNodePtr xnode;
323
- xmlChar* content;
324
- VALUE result = Qnil;
325
-
326
- Data_Get_Struct(self, xmlNode, xnode);
327
-
328
- if (!xnode->content)
329
- return result;
330
-
331
- content = xmlNodeGetContent(xnode);
332
- if (content)
333
- {
334
- result = rb_str_new2((const char*) content);
335
- xmlFree(content);
336
- }
337
- return (result);
338
- }
339
-
340
- /*
341
- * call-seq:
342
- * node.debug -> true|false
343
- *
344
- * Print libxml debugging information to stdout.
345
- * Requires that libxml was compiled with debugging enabled.
346
- */
347
- static VALUE rxml_node_debug(VALUE self)
348
- {
349
- #ifdef LIBXML_DEBUG_ENABLED
350
- xmlNodePtr xnode;
351
- Data_Get_Struct(self, xmlNode, xnode);
352
- xmlDebugDumpNode(NULL, xnode, 2);
353
- return Qtrue;
354
- #else
355
- rb_warn("libxml was compiled without debugging support.")
356
- return Qfalse;
357
- #endif
358
- }
359
-
360
- /*
361
- * call-seq:
362
- * node.first -> XML::Node
363
- *
364
- * Returns this node's first child node if any.
365
- */
366
- static VALUE rxml_node_first_get(VALUE self)
367
- {
368
- xmlNodePtr xnode;
369
-
370
- Data_Get_Struct(self, xmlNode, xnode);
371
-
372
- if (xnode->children)
373
- return (rxml_node_wrap(cXMLNode, xnode->children));
374
- else
375
- return (Qnil);
376
- }
377
-
378
- /*
379
- * underlying for child_set and child_add, difference being
380
- * former raises on implicit copy, latter does not.
381
- */
382
- static VALUE rxml_node_child_set_aux(VALUE self, VALUE rnode)
383
- {
384
- xmlNodePtr pnode, chld, ret;
385
-
386
- if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
387
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
388
-
389
- Data_Get_Struct(self, xmlNode, pnode);
390
- Data_Get_Struct(rnode, xmlNode, chld);
391
-
392
- if (chld->parent != NULL || chld->doc != NULL)
393
- rb_raise(
394
- rb_eRuntimeError,
395
- "Cannot move a node from one document to another with child= or <<. First copy the node before moving it.");
396
-
397
- ret = xmlAddChild(pnode, chld);
398
- if (ret == NULL)
399
- {
400
- rxml_raise(&xmlLastError);
401
- }
402
- else if (ret == chld)
403
- {
404
- /* child was added whole to parent and we need to return it as a new object */
405
- return rxml_node_wrap(cXMLNode, chld);
406
- }
407
- /* else */
408
- /* If it was a text node, then ret should be parent->last, so we will just return ret. */
409
- return rxml_node_wrap(cXMLNode, ret);
410
- }
411
-
412
- /*
413
- * call-seq:
414
- * node.child = node
415
- *
416
- * Set a child node for this node. Also called for <<
417
- */
418
- static VALUE rxml_node_child_set(VALUE self, VALUE rnode)
419
- {
420
- return rxml_node_child_set_aux(self, rnode);
421
- }
422
-
423
- /*
424
- * call-seq:
425
- * node << ("string" | node) -> XML::Node
426
- *
427
- * Add the specified string or XML::Node to this node's
428
- * content. The returned node is the node that was
429
- * added and not self, thereby allowing << calls to
430
- * be chained.
431
- */
432
- static VALUE rxml_node_content_add(VALUE self, VALUE obj)
433
- {
434
- xmlNodePtr xnode;
435
- VALUE str;
436
-
437
- Data_Get_Struct(self, xmlNode, xnode);
438
- /* XXX This should only be legal for a CDATA type node, I think,
439
- * resulting in a merge of content, as if a string were passed
440
- * danj 070827
441
- */
442
- if (rb_obj_is_kind_of(obj, cXMLNode))
443
- {
444
- rxml_node_child_set(self, obj);
445
- }
446
- else
447
- {
448
- str = rb_obj_as_string(obj);
449
- if (NIL_P(str) || TYPE(str) != T_STRING)
450
- rb_raise(rb_eTypeError, "invalid argument: must be string or XML::Node");
451
-
452
- xmlNodeAddContent(xnode, (xmlChar*) StringValuePtr(str));
453
- }
454
- return (self);
455
- }
456
-
457
- /*
458
- * call-seq:
459
- * node.child_add(node)
460
- *
461
- * Set a child node for this node.
462
- */
463
- static VALUE rxml_node_child_add(VALUE self, VALUE rnode)
464
- {
465
- return rxml_node_child_set_aux(self, rnode);
466
- }
467
-
468
- /*
469
- * call-seq:
470
- * node.doc -> document
471
- *
472
- * Obtain the XML::Document this node belongs to.
473
- */
474
- static VALUE rxml_node_doc(VALUE self)
475
- {
476
- xmlNodePtr xnode;
477
- xmlDocPtr doc = NULL;
478
-
479
- Data_Get_Struct(self, xmlNode, xnode);
480
-
481
- switch (xnode->type)
482
- {
483
- case XML_DOCUMENT_NODE:
484
- #ifdef LIBXML_DOCB_ENABLED
485
- case XML_DOCB_DOCUMENT_NODE:
486
- #endif
487
- case XML_HTML_DOCUMENT_NODE:
488
- doc = NULL;
489
- break;
490
- case XML_ATTRIBUTE_NODE:
491
- {
492
- xmlAttrPtr attr = (xmlAttrPtr) xnode;
493
- doc = attr->doc;
494
- break;
495
- }
496
- case XML_NAMESPACE_DECL:
497
- doc = NULL;
498
- break;
499
- default:
500
- doc = xnode->doc;
501
- break;
502
- }
503
-
504
- if (doc == NULL)
505
- return (Qnil);
506
-
507
- if (doc->_private == NULL)
508
- rb_raise(rb_eRuntimeError, "existing document object has no ruby-instance");
509
-
510
- return (VALUE) doc->_private;
511
- }
512
-
513
- /*
514
- * call-seq:
515
- * node.to_s -> "string"
516
- * node.to_s(:indent => true, :encoding => 'UTF-8', :level => 0) -> "string"
517
- *
518
- * Converts a node, and all of its children, to a string representation.
519
- * You may provide an optional hash table to control how the string is
520
- * generated. Valid options are:
521
- *
522
- * :indent - Specifies if the string should be indented. The default value
523
- * is true. Note that indentation is only added if both :indent is
524
- * true and XML.indent_tree_output is true. If :indent is set to false,
525
- * then both indentation and line feeds are removed from the result.
526
- *
527
- * :level - Specifies the indentation level. The amount of indentation
528
- * is equal to the (level * number_spaces) + number_spaces, where libxml
529
- * defaults the number of spaces to 2. Thus a level of 0 results in
530
- * 2 spaces, level 1 results in 4 spaces, level 2 results in 6 spaces, etc.
531
- *
532
- * :encoding - Specifies the output encoding of the string. It
533
- * defaults to XML::Input::UTF8. To change it, use one of the
534
- * XML::Input encoding constants. */
535
-
536
- static VALUE rxml_node_to_s(int argc, VALUE *argv, VALUE self)
537
- {
538
- VALUE options = Qnil;
539
- xmlNodePtr xnode;
540
- xmlCharEncodingHandlerPtr encodingHandler;
541
- xmlOutputBufferPtr output;
542
-
543
- int level = 0;
544
- int indent = 1;
545
- const char *encoding = "UTF-8";
546
-
547
- rb_scan_args(argc, argv, "01", &options);
548
-
549
- if (!NIL_P(options))
550
- {
551
- VALUE rencoding, rindent, rlevel;
552
- Check_Type(options, T_HASH);
553
- rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
554
- rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
555
- rlevel = rb_hash_aref(options, ID2SYM(rb_intern("level")));
556
-
557
- if (rindent == Qfalse)
558
- indent = 0;
559
-
560
- if (rlevel != Qnil)
561
- level = NUM2INT(rlevel);
562
-
563
- if (rencoding != Qnil)
564
- encoding = RSTRING_PTR(rxml_input_encoding_to_s(cXMLInput, rencoding));
565
- }
566
-
567
- encodingHandler = xmlFindCharEncodingHandler(encoding);
568
- output = xmlAllocOutputBuffer(encodingHandler);
569
-
570
- Data_Get_Struct(self, xmlNode, xnode);
571
- xmlNodeDumpOutput(output, xnode->doc, xnode, level, indent, encoding);
572
- xmlOutputBufferFlush(output);
573
-
574
- if (output->conv)
575
- return rb_str_new2((const char*) output->conv->content);
576
- else
577
- return rb_str_new2((const char*) output->buffer->content);
578
- }
579
-
580
-
581
- /*
582
- * call-seq:
583
- * node.each -> XML::Node
584
- *
585
- * Iterates over this node's children, including text
586
- * nodes, element nodes, etc. If you wish to iterate
587
- * only over child elements, use XML::Node#each_element.
588
- *
589
- * doc = XML::Document.new('model/books.xml')
590
- * doc.root.each {|node| puts node}
591
- */
592
- static VALUE rxml_node_each(VALUE self)
593
- {
594
- xmlNodePtr xnode;
595
- xmlNodePtr xchild;
596
- Data_Get_Struct(self, xmlNode, xnode);
597
-
598
- xchild = xnode->children;
599
-
600
- while (xchild)
601
- {
602
- rb_yield(rxml_node_wrap(cXMLNode, xchild));
603
- xchild = xchild->next;
604
- }
605
- return Qnil;
606
- }
607
-
608
- /*
609
- * call-seq:
610
- * node.empty? -> (true|false)
611
- *
612
- * Determine whether this node is empty.
613
- */
614
- static VALUE rxml_node_empty_q(VALUE self)
615
- {
616
- xmlNodePtr xnode;
617
- Data_Get_Struct(self, xmlNode, xnode);
618
- if (xnode == NULL)
619
- return (Qnil);
620
-
621
- return ((xmlIsBlankNode(xnode) == 1) ? Qtrue : Qfalse);
622
- }
623
-
624
-
625
- /*
626
- * call-seq:
627
- * node.eql?(other_node) => (true|false)
628
- *
629
- * Test equality between the two nodes. Two nodes are equal
630
- * if they are the same node or have the same XML representation.*/
631
- static VALUE rxml_node_eql_q(VALUE self, VALUE other)
632
- {
633
- if(self == other)
634
- {
635
- return Qtrue;
636
- }
637
- else if (NIL_P(other))
638
- {
639
- return Qfalse;
640
- }
641
- else
642
- {
643
- VALUE self_xml;
644
- VALUE other_xml;
645
-
646
- if (rb_obj_is_kind_of(other, cXMLNode) == Qfalse)
647
- rb_raise(rb_eTypeError, "Nodes can only be compared against other nodes");
648
-
649
- self_xml = rxml_node_to_s(0, NULL, self);
650
- other_xml = rxml_node_to_s(0, NULL, other);
651
- return(rb_funcall(self_xml, rb_intern("=="), 1, other_xml));
652
- }
653
- }
654
-
655
- /*
656
- * call-seq:
657
- * node.lang -> "string"
658
- *
659
- * Obtain the language set for this node, if any.
660
- * This is set in XML via the xml:lang attribute.
661
- */
662
- static VALUE rxml_node_lang_get(VALUE self)
663
- {
664
- xmlNodePtr xnode;
665
- xmlChar *lang;
666
- VALUE result = Qnil;
667
-
668
- Data_Get_Struct(self, xmlNode, xnode);
669
- lang = xmlNodeGetLang(xnode);
670
-
671
- if (lang)
672
- {
673
- result = rb_str_new2((const char*) lang);
674
- xmlFree(lang);
675
- }
676
-
677
- return (result);
678
- }
679
-
680
- // TODO node_lang_set should support setting back to nil
681
-
682
- /*
683
- * call-seq:
684
- * node.lang = "string"
685
- *
686
- * Set the language for this node. This affects the value
687
- * of the xml:lang attribute.
688
- */
689
- static VALUE rxml_node_lang_set(VALUE self, VALUE lang)
690
- {
691
- xmlNodePtr xnode;
692
-
693
- Check_Type(lang, T_STRING);
694
- Data_Get_Struct(self, xmlNode, xnode);
695
- xmlNodeSetLang(xnode, (xmlChar*) StringValuePtr(lang));
696
-
697
- return (Qtrue);
698
- }
699
-
700
- /*
701
- * call-seq:
702
- * node.last -> XML::Node
703
- *
704
- * Obtain the last child node of this node, if any.
705
- */
706
- static VALUE rxml_node_last_get(VALUE self)
707
- {
708
- xmlNodePtr xnode;
709
-
710
- Data_Get_Struct(self, xmlNode, xnode);
711
-
712
- if (xnode->last)
713
- return (rxml_node_wrap(cXMLNode, xnode->last));
714
- else
715
- return (Qnil);
716
- }
717
-
718
- /*
719
- * call-seq:
720
- * node.line_num -> num
721
- *
722
- * Obtain the line number (in the XML document) that this
723
- * node was read from. If +default_line_numbers+ is set
724
- * false (the default), this method returns zero.
725
- */
726
- static VALUE rxml_node_line_num(VALUE self)
727
- {
728
- xmlNodePtr xnode;
729
- long line_num;
730
- Data_Get_Struct(self, xmlNode, xnode);
731
-
732
- if (!xmlLineNumbersDefaultValue)
733
- rb_warn(
734
- "Line numbers were not retained: use XML::Parser::default_line_numbers=true");
735
-
736
- line_num = xmlGetLineNo(xnode);
737
- if (line_num == -1)
738
- return (Qnil);
739
- else
740
- return (INT2NUM((long) line_num));
741
- }
742
-
743
- /*
744
- * call-seq:
745
- * node.xlink? -> (true|false)
746
- *
747
- * Determine whether this node is an xlink node.
748
- */
749
- static VALUE rxml_node_xlink_q(VALUE self)
750
- {
751
- xmlNodePtr xnode;
752
- xlinkType xlt;
753
-
754
- Data_Get_Struct(self, xmlNode, xnode);
755
- xlt = xlinkIsLink(xnode->doc, xnode);
756
-
757
- if (xlt == XLINK_TYPE_NONE)
758
- return (Qfalse);
759
- else
760
- return (Qtrue);
761
- }
762
-
763
- /*
764
- * call-seq:
765
- * node.xlink_type -> num
766
- *
767
- * Obtain the type identifier for this xlink, if applicable.
768
- * If this is not an xlink node (see +xlink?+), will return
769
- * nil.
770
- */
771
- static VALUE rxml_node_xlink_type(VALUE self)
772
- {
773
- xmlNodePtr xnode;
774
- xlinkType xlt;
775
-
776
- Data_Get_Struct(self, xmlNode, xnode);
777
- xlt = xlinkIsLink(xnode->doc, xnode);
778
-
779
- if (xlt == XLINK_TYPE_NONE)
780
- return (Qnil);
781
- else
782
- return (INT2NUM(xlt));
783
- }
784
-
785
- /*
786
- * call-seq:
787
- * node.xlink_type_name -> "string"
788
- *
789
- * Obtain the type name for this xlink, if applicable.
790
- * If this is not an xlink node (see +xlink?+), will return
791
- * nil.
792
- */
793
- static VALUE rxml_node_xlink_type_name(VALUE self)
794
- {
795
- xmlNodePtr xnode;
796
- xlinkType xlt;
797
-
798
- Data_Get_Struct(self, xmlNode, xnode);
799
- xlt = xlinkIsLink(xnode->doc, xnode);
800
-
801
- switch (xlt)
802
- {
803
- case XLINK_TYPE_NONE:
804
- return (Qnil);
805
- case XLINK_TYPE_SIMPLE:
806
- return (rb_str_new2("simple"));
807
- case XLINK_TYPE_EXTENDED:
808
- return (rb_str_new2("extended"));
809
- case XLINK_TYPE_EXTENDED_SET:
810
- return (rb_str_new2("extended_set"));
811
- default:
812
- rb_fatal("Unknowng xlink type, %d", xlt);
813
- }
814
- }
815
-
816
- /*
817
- * call-seq:
818
- * node.name -> "string"
819
- *
820
- * Obtain this node's name.
821
- */
822
- static VALUE rxml_node_name_get(VALUE self)
823
- {
824
- xmlNodePtr xnode;
825
- const xmlChar *name;
826
-
827
- Data_Get_Struct(self, xmlNode, xnode);
828
-
829
- switch (xnode->type)
830
- {
831
- case XML_DOCUMENT_NODE:
832
- #ifdef LIBXML_DOCB_ENABLED
833
- case XML_DOCB_DOCUMENT_NODE:
834
- #endif
835
- case XML_HTML_DOCUMENT_NODE:
836
- {
837
- xmlDocPtr doc = (xmlDocPtr) xnode;
838
- name = doc->URL;
839
- break;
840
- }
841
- case XML_ATTRIBUTE_NODE:
842
- {
843
- xmlAttrPtr attr = (xmlAttrPtr) xnode;
844
- name = attr->name;
845
- break;
846
- }
847
- case XML_NAMESPACE_DECL:
848
- {
849
- xmlNsPtr ns = (xmlNsPtr) xnode;
850
- name = ns->prefix;
851
- break;
852
- }
853
- default:
854
- name = xnode->name;
855
- break;
856
- }
857
-
858
- if (xnode->name == NULL)
859
- return (Qnil);
860
- else
861
- return (rb_str_new2((const char*) name));
862
- }
863
-
864
- /*
865
- * call-seq:
866
- * node.name = "string"
867
- *
868
- * Set this node's name.
869
- */
870
- static VALUE rxml_node_name_set(VALUE self, VALUE name)
871
- {
872
- xmlNodePtr xnode;
873
-
874
- Check_Type(name, T_STRING);
875
- Data_Get_Struct(self, xmlNode, xnode);
876
- xmlNodeSetName(xnode, (xmlChar*) StringValuePtr(name));
877
- return (Qtrue);
878
- }
879
-
880
- /*
881
- * call-seq:
882
- * node.next -> XML::Node
883
- *
884
- * Obtain the next sibling node, if any.
885
- */
886
- static VALUE rxml_node_next_get(VALUE self)
887
- {
888
- xmlNodePtr xnode;
889
-
890
- Data_Get_Struct(self, xmlNode, xnode);
891
-
892
- if (xnode->next)
893
- return (rxml_node_wrap(cXMLNode, xnode->next));
894
- else
895
- return (Qnil);
896
- }
897
-
898
- /*
899
- * call-seq:
900
- * node.next = node
901
- *
902
- * Insert the specified node as this node's next sibling.
903
- */
904
- static VALUE rxml_node_next_set(VALUE self, VALUE rnode)
905
- {
906
- xmlNodePtr cnode, pnode, ret;
907
-
908
- if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
909
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
910
-
911
- Data_Get_Struct(self, xmlNode, pnode);
912
- Data_Get_Struct(rnode, xmlNode, cnode);
913
-
914
- ret = xmlAddNextSibling(pnode, cnode);
915
- if (ret == NULL)
916
- rxml_raise(&xmlLastError);
917
-
918
- return (rxml_node_wrap(cXMLNode, ret));
919
- }
920
-
921
- /*
922
- * call-seq:
923
- * node.parent -> XML::Node
924
- *
925
- * Obtain this node's parent node, if any.
926
- */
927
- static VALUE rxml_node_parent_get(VALUE self)
928
- {
929
- xmlNodePtr xnode;
930
-
931
- Data_Get_Struct(self, xmlNode, xnode);
932
-
933
- if (xnode->parent)
934
- return (rxml_node_wrap(cXMLNode, xnode->parent));
935
- else
936
- return (Qnil);
937
- }
938
-
939
- /*
940
- * call-seq:
941
- * node.path -> path
942
- *
943
- * Obtain this node's path.
944
- */
945
- static VALUE rxml_node_path(VALUE self)
946
- {
947
- xmlNodePtr xnode;
948
- xmlChar *path;
949
-
950
- Data_Get_Struct(self, xmlNode, xnode);
951
- path = xmlGetNodePath(xnode);
952
-
953
- if (path == NULL)
954
- return (Qnil);
955
- else
956
- return (rb_str_new2((const char*) path));
957
- }
958
-
959
- /*
960
- * call-seq:
961
- * node.pointer -> XML::NodeSet
962
- *
963
- * Evaluates an XPointer expression relative to this node.
964
- */
965
- static VALUE rxml_node_pointer(VALUE self, VALUE xptr_str)
966
- {
967
- return (rxml_xpointer_point2(self, xptr_str));
968
- }
969
-
970
- /*
971
- * call-seq:
972
- * node.prev -> XML::Node
973
- *
974
- * Obtain the previous sibling, if any.
975
- */
976
- static VALUE rxml_node_prev_get(VALUE self)
977
- {
978
- xmlNodePtr xnode;
979
- xmlNodePtr node;
980
- Data_Get_Struct(self, xmlNode, xnode);
981
-
982
- switch (xnode->type)
983
- {
984
- case XML_DOCUMENT_NODE:
985
- #ifdef LIBXML_DOCB_ENABLED
986
- case XML_DOCB_DOCUMENT_NODE:
987
- #endif
988
- case XML_HTML_DOCUMENT_NODE:
989
- case XML_NAMESPACE_DECL:
990
- node = NULL;
991
- break;
992
- case XML_ATTRIBUTE_NODE:
993
- {
994
- xmlAttrPtr attr = (xmlAttrPtr) xnode;
995
- node = (xmlNodePtr) attr->prev;
996
- }
997
- break;
998
- default:
999
- node = xnode->prev;
1000
- break;
1001
- }
1002
-
1003
- if (node == NULL)
1004
- return (Qnil);
1005
- else
1006
- return (rxml_node_wrap(cXMLNode, node));
1007
- }
1008
-
1009
- /*
1010
- * call-seq:
1011
- * node.prev = node
1012
- *
1013
- * Insert the specified node as this node's previous sibling.
1014
- */
1015
- static VALUE rxml_node_prev_set(VALUE self, VALUE rnode)
1016
- {
1017
- xmlNodePtr cnode, pnode, ret;
1018
-
1019
- if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
1020
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1021
-
1022
- Data_Get_Struct(self, xmlNode, pnode);
1023
- Data_Get_Struct(rnode, xmlNode, cnode);
1024
-
1025
- ret = xmlAddPrevSibling(pnode, cnode);
1026
- if (ret == NULL)
1027
- rxml_raise(&xmlLastError);
1028
-
1029
- return (rxml_node_wrap(cXMLNode, ret));
1030
- }
1031
-
1032
- /*
1033
- * call-seq:
1034
- * node.attributes -> attributes
1035
- *
1036
- * Returns the XML::Attributes for this node.
1037
- */
1038
- static VALUE rxml_node_attributes_get(VALUE self)
1039
- {
1040
- xmlNodePtr xnode;
1041
-
1042
- Data_Get_Struct(self, xmlNode, xnode);
1043
- return rxml_attributes_new(xnode);
1044
- }
1045
-
1046
- /*
1047
- * call-seq:
1048
- * node.property("name") -> "string"
1049
- * node["name"] -> "string"
1050
- *
1051
- * Obtain the named pyroperty.
1052
- */
1053
- static VALUE rxml_node_attribute_get(VALUE self, VALUE name)
1054
- {
1055
- VALUE attributes = rxml_node_attributes_get(self);
1056
- return rxml_attributes_attribute_get(attributes, name);
1057
- }
1058
-
1059
- /*
1060
- * call-seq:
1061
- * node["name"] = "string"
1062
- *
1063
- * Set the named property.
1064
- */
1065
- static VALUE rxml_node_property_set(VALUE self, VALUE name, VALUE value)
1066
- {
1067
- VALUE attributes = rxml_node_attributes_get(self);
1068
- return rxml_attributes_attribute_set(attributes, name, value);
1069
- }
1070
-
1071
- /*
1072
- * call-seq:
1073
- * node.remove! -> node
1074
- *
1075
- * Removes this node and its children from its
1076
- * document tree by setting its document,
1077
- * parent and siblings to nil. You can add
1078
- * the returned node back into a document.
1079
- * Otherwise, the node will be freed once
1080
- * any references to it go out of scope. */
1081
-
1082
- static VALUE rxml_node_remove_ex(VALUE self)
1083
- {
1084
- xmlNodePtr xnode;
1085
- Data_Get_Struct(self, xmlNode, xnode);
1086
- /* Unlink the node from its parent. */
1087
- xmlUnlinkNode(xnode);
1088
- /* Now set the nodes parent to nil so it can
1089
- be freed if the reference to it goes out of scope*/
1090
- xmlSetTreeDoc(xnode, NULL);
1091
-
1092
- /* Now return the removed node so the user can
1093
- do something wiht it.*/
1094
- return self;
1095
- }
1096
-
1097
- /*
1098
- * call-seq:
1099
- * node.sibling(node) -> XML::Node
1100
- *
1101
- * Add the specified node as a sibling of this node.
1102
- */
1103
- static VALUE rxml_node_sibling_set(VALUE self, VALUE rnode)
1104
- {
1105
- xmlNodePtr cnode, pnode, ret;
1106
- VALUE obj;
1107
-
1108
- if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
1109
- rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1110
-
1111
- Data_Get_Struct(self, xmlNode, pnode);
1112
- Data_Get_Struct(rnode, xmlNode, cnode);
1113
-
1114
- ret = xmlAddSibling(pnode, cnode);
1115
- if (ret == NULL)
1116
- rxml_raise(&xmlLastError);
1117
-
1118
- if (ret->_private == NULL)
1119
- obj = rxml_node_wrap(cXMLNode, ret);
1120
- else
1121
- obj = (VALUE) ret->_private;
1122
-
1123
- return obj;
1124
- }
1125
-
1126
- /*
1127
- * call-seq:
1128
- * node.space_preserve -> (true|false)
1129
- *
1130
- * Determine whether this node preserves whitespace.
1131
- */
1132
- static VALUE rxml_node_space_preserve_get(VALUE self)
1133
- {
1134
- xmlNodePtr xnode;
1135
-
1136
- Data_Get_Struct(self, xmlNode, xnode);
1137
- return (INT2NUM(xmlNodeGetSpacePreserve(xnode)));
1138
- }
1139
-
1140
- /*
1141
- * call-seq:
1142
- * node.space_preserve = true|false
1143
- *
1144
- * Control whether this node preserves whitespace.
1145
- */
1146
- static VALUE rxml_node_space_preserve_set(VALUE self, VALUE bool)
1147
- {
1148
- xmlNodePtr xnode;
1149
- Data_Get_Struct(self, xmlNode, xnode);
1150
-
1151
- if (TYPE(bool) == T_FALSE)
1152
- xmlNodeSetSpacePreserve(xnode, 1);
1153
- else
1154
- xmlNodeSetSpacePreserve(xnode, 0);
1155
-
1156
- return (Qnil);
1157
- }
1158
-
1159
- /*
1160
- * call-seq:
1161
- * node.type -> num
1162
- *
1163
- * Obtain this node's type identifier.
1164
- */
1165
- static VALUE rxml_node_type(VALUE self)
1166
- {
1167
- xmlNodePtr xnode;
1168
- Data_Get_Struct(self, xmlNode, xnode);
1169
- return (INT2NUM(xnode->type));
1170
- }
1171
-
1172
- /*
1173
- * call-seq:
1174
- * node.copy -> XML::Node
1175
- *
1176
- * Creates a copy of this node. To create a
1177
- * shallow copy set the deep parameter to false.
1178
- * To create a deep copy set the deep parameter
1179
- * to true.
1180
- *
1181
- */
1182
- static VALUE rxml_node_copy(VALUE self, VALUE deep)
1183
- {
1184
- xmlNodePtr xnode;
1185
- xmlNodePtr xcopy;
1186
- int recursive = (deep == Qnil || deep == Qfalse) ? 0 : 1;
1187
- Data_Get_Struct(self, xmlNode, xnode);
1188
-
1189
- xcopy = xmlCopyNode(xnode, recursive);
1190
-
1191
- if (xcopy)
1192
- return rxml_node_wrap(cXMLNode, xcopy);
1193
- else
1194
- return Qnil;
1195
- }
1196
-
1197
- void rxml_node_registerNode(xmlNodePtr node)
1198
- {
1199
- node->_private = NULL;
1200
- }
1201
-
1202
- void rxml_node_deregisterNode(xmlNodePtr xnode)
1203
- {
1204
- VALUE node;
1205
-
1206
- if (xnode->_private == NULL)
1207
- return;
1208
- node = (VALUE) xnode->_private;
1209
- DATA_PTR( node) = NULL;
1210
- }
1211
-
1212
- // Rdoc needs to know
1213
- #ifdef RDOC_NEVER_DEFINED
1214
- mLibXML = rb_define_module("LibXML");
1215
- mXML = rb_define_module_under(mLibXML, "XML");
1216
- #endif
1217
-
1218
- void ruby_init_xml_node(void)
1219
- {
1220
- xmlRegisterNodeDefault(rxml_node_registerNode);
1221
- xmlDeregisterNodeDefault(rxml_node_deregisterNode);
1222
-
1223
- cXMLNode = rb_define_class_under(mXML, "Node", rb_cObject);
1224
-
1225
- rb_define_const(cXMLNode, "SPACE_DEFAULT", INT2NUM(0));
1226
- rb_define_const(cXMLNode, "SPACE_PRESERVE", INT2NUM(1));
1227
- rb_define_const(cXMLNode, "SPACE_NOT_INHERIT", INT2NUM(-1));
1228
- rb_define_const(cXMLNode, "XLINK_ACTUATE_AUTO", INT2NUM(1));
1229
- rb_define_const(cXMLNode, "XLINK_ACTUATE_NONE", INT2NUM(0));
1230
- rb_define_const(cXMLNode, "XLINK_ACTUATE_ONREQUEST", INT2NUM(2));
1231
- rb_define_const(cXMLNode, "XLINK_SHOW_EMBED", INT2NUM(2));
1232
- rb_define_const(cXMLNode, "XLINK_SHOW_NEW", INT2NUM(1));
1233
- rb_define_const(cXMLNode, "XLINK_SHOW_NONE", INT2NUM(0));
1234
- rb_define_const(cXMLNode, "XLINK_SHOW_REPLACE", INT2NUM(3));
1235
- rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED", INT2NUM(2));
1236
- rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED_SET", INT2NUM(3));
1237
- rb_define_const(cXMLNode, "XLINK_TYPE_NONE", INT2NUM(0));
1238
- rb_define_const(cXMLNode, "XLINK_TYPE_SIMPLE", INT2NUM(1));
1239
-
1240
- rb_define_const(cXMLNode, "ELEMENT_NODE", INT2FIX(XML_ELEMENT_NODE));
1241
- rb_define_const(cXMLNode, "ATTRIBUTE_NODE", INT2FIX(XML_ATTRIBUTE_NODE));
1242
- rb_define_const(cXMLNode, "TEXT_NODE", INT2FIX(XML_TEXT_NODE));
1243
- rb_define_const(cXMLNode, "CDATA_SECTION_NODE", INT2FIX(XML_CDATA_SECTION_NODE));
1244
- rb_define_const(cXMLNode, "ENTITY_REF_NODE", INT2FIX(XML_ENTITY_REF_NODE));
1245
- rb_define_const(cXMLNode, "ENTITY_NODE", INT2FIX(XML_ENTITY_NODE));
1246
- rb_define_const(cXMLNode, "PI_NODE", INT2FIX(XML_PI_NODE));
1247
- rb_define_const(cXMLNode, "COMMENT_NODE", INT2FIX(XML_COMMENT_NODE));
1248
- rb_define_const(cXMLNode, "DOCUMENT_NODE", INT2FIX(XML_DOCUMENT_NODE));
1249
- rb_define_const(cXMLNode, "DOCUMENT_TYPE_NODE", INT2FIX(XML_DOCUMENT_TYPE_NODE));
1250
- rb_define_const(cXMLNode, "DOCUMENT_FRAG_NODE", INT2FIX(XML_DOCUMENT_FRAG_NODE));
1251
- rb_define_const(cXMLNode, "NOTATION_NODE", INT2FIX(XML_NOTATION_NODE));
1252
- rb_define_const(cXMLNode, "HTML_DOCUMENT_NODE", INT2FIX(XML_HTML_DOCUMENT_NODE));
1253
- rb_define_const(cXMLNode, "DTD_NODE", INT2FIX(XML_DTD_NODE));
1254
- rb_define_const(cXMLNode, "ELEMENT_DECL", INT2FIX(XML_ELEMENT_DECL));
1255
- rb_define_const(cXMLNode, "ATTRIBUTE_DECL", INT2FIX(XML_ATTRIBUTE_DECL));
1256
- rb_define_const(cXMLNode, "ENTITY_DECL", INT2FIX(XML_ENTITY_DECL));
1257
- rb_define_const(cXMLNode, "NAMESPACE_DECL", INT2FIX(XML_NAMESPACE_DECL));
1258
- rb_define_const(cXMLNode, "XINCLUDE_START", INT2FIX(XML_XINCLUDE_START));
1259
- rb_define_const(cXMLNode, "XINCLUDE_END", INT2FIX(XML_XINCLUDE_END));
1260
-
1261
- #ifdef LIBXML_DOCB_ENABLED
1262
- rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", INT2FIX(XML_DOCB_DOCUMENT_NODE));
1263
- #else
1264
- rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", Qnil);
1265
- #endif
1266
-
1267
- rb_define_singleton_method(cXMLNode, "new_cdata", rxml_node_new_cdata, -1);
1268
- rb_define_singleton_method(cXMLNode, "new_comment", rxml_node_new_comment, -1);
1269
- rb_define_singleton_method(cXMLNode, "new_text", rxml_node_new_text, 1);
1270
-
1271
- /* Initialization */
1272
- rb_define_alloc_func(cXMLNode, rxml_node_alloc);
1273
- rb_define_method(cXMLNode, "initialize", rxml_node_initialize, -1);
1274
-
1275
- /* Traversal */
1276
- rb_include_module(cXMLNode, rb_mEnumerable);
1277
- rb_define_method(cXMLNode, "[]", rxml_node_attribute_get, 1);
1278
- rb_define_method(cXMLNode, "each", rxml_node_each, 0);
1279
- rb_define_method(cXMLNode, "first", rxml_node_first_get, 0);
1280
- rb_define_method(cXMLNode, "last", rxml_node_last_get, 0);
1281
- rb_define_method(cXMLNode, "next", rxml_node_next_get, 0);
1282
- rb_define_method(cXMLNode, "parent", rxml_node_parent_get, 0);
1283
- rb_define_method(cXMLNode, "prev", rxml_node_prev_get, 0);
1284
-
1285
- /* Modification */
1286
- rb_define_method(cXMLNode, "<<", rxml_node_content_add, 1);
1287
- rb_define_method(cXMLNode, "[]=", rxml_node_property_set, 2);
1288
- rb_define_method(cXMLNode, "child_add", rxml_node_child_add, 1);
1289
- rb_define_method(cXMLNode, "child=", rxml_node_child_set, 1);
1290
- rb_define_method(cXMLNode, "sibling=", rxml_node_sibling_set, 1);
1291
- rb_define_method(cXMLNode, "next=", rxml_node_next_set, 1);
1292
- rb_define_method(cXMLNode, "prev=", rxml_node_prev_set, 1);
1293
-
1294
- /* Rest of the node api */
1295
- rb_define_method(cXMLNode, "attributes", rxml_node_attributes_get, 0);
1296
- rb_define_method(cXMLNode, "base", rxml_node_base_get, 0);
1297
- rb_define_method(cXMLNode, "base=", rxml_node_base_set, 1);
1298
- rb_define_method(cXMLNode, "blank?", rxml_node_empty_q, 0);
1299
- rb_define_method(cXMLNode, "copy", rxml_node_copy, 1);
1300
- rb_define_method(cXMLNode, "content", rxml_node_content_get, 0);
1301
- rb_define_method(cXMLNode, "content=", rxml_node_content_set, 1);
1302
- rb_define_method(cXMLNode, "content_stripped", rxml_node_content_stripped_get, 0);
1303
- rb_define_method(cXMLNode, "debug", rxml_node_debug, 0);
1304
- rb_define_method(cXMLNode, "doc", rxml_node_doc, 0);
1305
- rb_define_method(cXMLNode, "empty?", rxml_node_empty_q, 0);
1306
- rb_define_method(cXMLNode, "eql?", rxml_node_eql_q, 1);
1307
- rb_define_method(cXMLNode, "lang", rxml_node_lang_get, 0);
1308
- rb_define_method(cXMLNode, "lang=", rxml_node_lang_set, 1);
1309
- rb_define_method(cXMLNode, "line_num", rxml_node_line_num, 0);
1310
- rb_define_method(cXMLNode, "name", rxml_node_name_get, 0);
1311
- rb_define_method(cXMLNode, "name=", rxml_node_name_set, 1);
1312
- rb_define_method(cXMLNode, "node_type", rxml_node_type, 0);
1313
- rb_define_method(cXMLNode, "path", rxml_node_path, 0);
1314
- rb_define_method(cXMLNode, "pointer", rxml_node_pointer, 1);
1315
- rb_define_method(cXMLNode, "remove!", rxml_node_remove_ex, 0);
1316
- rb_define_method(cXMLNode, "space_preserve", rxml_node_space_preserve_get, 0);
1317
- rb_define_method(cXMLNode, "space_preserve=", rxml_node_space_preserve_set, 1);
1318
- rb_define_method(cXMLNode, "to_s", rxml_node_to_s, -1);
1319
- rb_define_method(cXMLNode, "xlink?", rxml_node_xlink_q, 0);
1320
- rb_define_method(cXMLNode, "xlink_type", rxml_node_xlink_type, 0);
1321
- rb_define_method(cXMLNode, "xlink_type_name", rxml_node_xlink_type_name, 0);
1322
-
1323
- rb_define_alias(cXMLNode, "==", "eql?");
1324
- }
1
+ #include "ruby_libxml.h"
2
+ #include "ruby_xml_node.h"
3
+
4
+ VALUE cXMLNode;
5
+
6
+ static VALUE kXMLStringText;
7
+ static VALUE kXMLStringTextNoenc;
8
+
9
+ /* Document-class: LibXML::XML::Node
10
+ *
11
+ * Nodes are the primary objects that make up an XML document.
12
+ * The node class represents most node types that are found in
13
+ * an XML document (but not Attributes, see LibXML::XML::Attribute).
14
+ * It exposes libxml's full API for creating, querying
15
+ * moving and deleting node objects. Many of these methods are
16
+ * documented in the DOM Level 3 specification found at:
17
+ * http://www.w3.org/TR/DOM-Level-3-Core/. */
18
+
19
+ static VALUE rxml_node_content_set(VALUE self, VALUE content);
20
+
21
+ VALUE check_string_or_symbol(VALUE val)
22
+ {
23
+ if (TYPE(val) != T_STRING && TYPE(val) != T_SYMBOL)
24
+ {
25
+ rb_raise(rb_eTypeError,
26
+ "wrong argument type %s (expected String or Symbol)", rb_obj_classname(
27
+ val));
28
+ }
29
+ return rb_obj_as_string(val);
30
+ }
31
+
32
+ /*
33
+ * memory2 implementation: xmlNode->_private holds a reference
34
+ * to the wrapping ruby object VALUE when there is one.
35
+ * traversal for marking is upward, and top levels are marked
36
+ * through and lower level mark entry.
37
+ *
38
+ * All ruby retrieval for an xml
39
+ * node will result in the same ruby instance. When all handles to them
40
+ * go out of scope, then ruby_xfree gets called and _private is set to NULL.
41
+ * If the xmlNode has no parent or document, then call xmlFree.
42
+ */
43
+ void rxml_node_free(xmlNodePtr xnode)
44
+ {
45
+ /* Set _private to NULL so that we won't reuse the
46
+ same, freed, Ruby wrapper object later.*/
47
+ xnode->_private = NULL;
48
+
49
+ if (xnode->doc == NULL && xnode->parent == NULL)
50
+ xmlFreeNode(xnode);
51
+ }
52
+
53
+ void rxml_node_mark_common(xmlNodePtr xnode)
54
+ {
55
+ if (xnode->parent == NULL)
56
+ return;
57
+
58
+ if (xnode->doc != NULL)
59
+ {
60
+ if (xnode->doc->_private == NULL)
61
+ rb_bug("XmlNode Doc is not bound! (%s:%d)", __FILE__,__LINE__);
62
+ rb_gc_mark((VALUE) xnode->doc->_private);
63
+ }
64
+ else
65
+ {
66
+ while (xnode->parent != NULL)
67
+ xnode = xnode->parent;
68
+
69
+ if (xnode->_private == NULL)
70
+ rb_warning("XmlNode Root Parent is not bound! (%s:%d)", __FILE__,__LINE__);
71
+ else
72
+ rb_gc_mark((VALUE) xnode->_private);
73
+ }
74
+ }
75
+
76
+ void rxml_node_mark(xmlNodePtr xnode)
77
+ {
78
+ if (xnode == NULL)
79
+ return;
80
+
81
+ if (xnode->_private == NULL)
82
+ {
83
+ rb_warning("XmlNode is not bound! (%s:%d)", __FILE__, __LINE__);
84
+ return;
85
+ }
86
+
87
+ rxml_node_mark_common(xnode);
88
+ }
89
+
90
+ VALUE rxml_node_wrap(xmlNodePtr xnode)
91
+ {
92
+ /* Is the node already wrapped? */
93
+ if (xnode->_private != NULL)
94
+ {
95
+ return (VALUE) xnode->_private;
96
+ }
97
+ else
98
+ {
99
+ VALUE node = Data_Wrap_Struct(cXMLNode, rxml_node_mark, rxml_node_free, xnode);
100
+ xnode->_private = (void*) node;
101
+ return node;
102
+ }
103
+ }
104
+
105
+ static VALUE rxml_node_alloc(VALUE klass)
106
+ {
107
+ return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node_free, NULL);
108
+ }
109
+
110
+ /*
111
+ * call-seq:
112
+ * XML::Node.new_cdata(content = nil) -> XML::Node
113
+ *
114
+ * Create a new #CDATA node, optionally setting
115
+ * the node's content.
116
+ */
117
+ static VALUE rxml_node_new_cdata(int argc, VALUE *argv, VALUE klass)
118
+ {
119
+ VALUE content = Qnil;
120
+ xmlNodePtr xnode;
121
+
122
+ rb_scan_args(argc, argv, "01", &content);
123
+
124
+ if (NIL_P(content))
125
+ {
126
+ xnode = xmlNewCDataBlock(NULL, NULL, 0);
127
+ }
128
+ else
129
+ {
130
+ content = rb_obj_as_string(content);
131
+ xnode = xmlNewCDataBlock(NULL, (xmlChar*) StringValuePtr(content),
132
+ RSTRING_LEN(content));
133
+ }
134
+
135
+ if (xnode == NULL)
136
+ rxml_raise(&xmlLastError);
137
+
138
+ return rxml_node_wrap(xnode);
139
+ }
140
+
141
+ /*
142
+ * call-seq:
143
+ * XML::Node.new_comment(content = nil) -> XML::Node
144
+ *
145
+ * Create a new comment node, optionally setting
146
+ * the node's content.
147
+ *
148
+ */
149
+ static VALUE rxml_node_new_comment(int argc, VALUE *argv, VALUE klass)
150
+ {
151
+ VALUE content = Qnil;
152
+ xmlNodePtr xnode;
153
+
154
+ rb_scan_args(argc, argv, "01", &content);
155
+
156
+ if (NIL_P(content))
157
+ {
158
+ xnode = xmlNewComment(NULL);
159
+ }
160
+ else
161
+ {
162
+ content = rb_obj_as_string(content);
163
+ xnode = xmlNewComment((xmlChar*) StringValueCStr(content));
164
+ }
165
+
166
+ if (xnode == NULL)
167
+ rxml_raise(&xmlLastError);
168
+
169
+ return rxml_node_wrap(xnode);
170
+ }
171
+
172
+ /*
173
+ * call-seq:
174
+ * XML::Node.new_text(content) -> XML::Node
175
+ *
176
+ * Create a new text node.
177
+ *
178
+ */
179
+ static VALUE rxml_node_new_text(VALUE klass, VALUE content)
180
+ {
181
+ xmlNodePtr xnode;
182
+ Check_Type(content, T_STRING);
183
+ content = rb_obj_as_string(content);
184
+
185
+ xnode = xmlNewText((xmlChar*) StringValueCStr(content));
186
+
187
+ if (xnode == NULL)
188
+ rxml_raise(&xmlLastError);
189
+
190
+ return rxml_node_wrap(xnode);
191
+ }
192
+
193
+ /*
194
+ * call-seq:
195
+ * XML::Node.initialize(name, content = nil, namespace = nil) -> XML::Node
196
+ *
197
+ * Creates a new element with the specified name, content and
198
+ * namespace. The content and namespace may be nil.
199
+ */
200
+ static VALUE rxml_node_initialize(int argc, VALUE *argv, VALUE self)
201
+ {
202
+ VALUE name;
203
+ VALUE content;
204
+ VALUE ns;
205
+ xmlNodePtr xnode = NULL;
206
+ xmlNsPtr xns = NULL;
207
+
208
+ rb_scan_args(argc, argv, "12", &name, &content, &ns);
209
+
210
+ name = check_string_or_symbol(name);
211
+
212
+ if (!NIL_P(ns))
213
+ Data_Get_Struct(ns, xmlNs, xns);
214
+
215
+ xnode = xmlNewNode(xns, (xmlChar*) StringValuePtr(name));
216
+ xnode->_private = (void*) self;
217
+ DATA_PTR( self) = xnode;
218
+
219
+ if (!NIL_P(content))
220
+ rxml_node_content_set(self, content);
221
+
222
+ return self;
223
+ }
224
+
225
+ /*
226
+ * call-seq:
227
+ * node.base_uri -> "uri"
228
+ *
229
+ * Obtain this node's base URI.
230
+ */
231
+ static VALUE rxml_node_base_uri_get(VALUE self)
232
+ {
233
+ xmlNodePtr xnode;
234
+ xmlChar* base_uri;
235
+ VALUE result = Qnil;
236
+
237
+ Data_Get_Struct(self, xmlNode, xnode);
238
+
239
+ if (xnode->doc == NULL)
240
+ return (result);
241
+
242
+ base_uri = xmlNodeGetBase(xnode->doc, xnode);
243
+ if (base_uri)
244
+ {
245
+ result = rb_str_new2((const char*) base_uri);
246
+ xmlFree(base_uri);
247
+ }
248
+
249
+ return (result);
250
+ }
251
+
252
+ // TODO node_base_set should support setting back to nil
253
+
254
+ /*
255
+ * call-seq:
256
+ * node.base_uri = "uri"
257
+ *
258
+ * Set this node's base URI.
259
+ */
260
+ static VALUE rxml_node_base_uri_set(VALUE self, VALUE uri)
261
+ {
262
+ xmlNodePtr xnode;
263
+
264
+ Check_Type(uri, T_STRING);
265
+ Data_Get_Struct(self, xmlNode, xnode);
266
+ if (xnode->doc == NULL)
267
+ return (Qnil);
268
+
269
+ xmlNodeSetBase(xnode, (xmlChar*) StringValuePtr(uri));
270
+ return (Qtrue);
271
+ }
272
+
273
+ /*
274
+ * call-seq:
275
+ * node.content -> "string"
276
+ *
277
+ * Obtain this node's content as a string.
278
+ */
279
+ static VALUE rxml_node_content_get(VALUE self)
280
+ {
281
+ xmlNodePtr xnode;
282
+ xmlChar *content;
283
+ VALUE result = Qnil;
284
+
285
+ Data_Get_Struct(self, xmlNode, xnode);
286
+ content = xmlNodeGetContent(xnode);
287
+ if (content)
288
+ {
289
+ result = rb_str_new2((const char *) content);
290
+ xmlFree(content);
291
+ }
292
+
293
+ return result;
294
+ }
295
+
296
+ /*
297
+ * call-seq:
298
+ * node.content = "string"
299
+ *
300
+ * Set this node's content to the specified string.
301
+ */
302
+ static VALUE rxml_node_content_set(VALUE self, VALUE content)
303
+ {
304
+ xmlNodePtr xnode;
305
+
306
+ Check_Type(content, T_STRING);
307
+ Data_Get_Struct(self, xmlNode, xnode);
308
+ // XXX docs indicate need for escaping entites, need to be done? danj
309
+ xmlNodeSetContent(xnode, (xmlChar*) StringValuePtr(content));
310
+ return (Qtrue);
311
+ }
312
+
313
+ /*
314
+ * call-seq:
315
+ * node.content_stripped -> "string"
316
+ *
317
+ * Obtain this node's stripped content.
318
+ *
319
+ * *Deprecated*: Stripped content can be obtained via the
320
+ * +content+ method.
321
+ */
322
+ static VALUE rxml_node_content_stripped_get(VALUE self)
323
+ {
324
+ xmlNodePtr xnode;
325
+ xmlChar* content;
326
+ VALUE result = Qnil;
327
+
328
+ Data_Get_Struct(self, xmlNode, xnode);
329
+
330
+ if (!xnode->content)
331
+ return result;
332
+
333
+ content = xmlNodeGetContent(xnode);
334
+ if (content)
335
+ {
336
+ result = rb_str_new2((const char*) content);
337
+ xmlFree(content);
338
+ }
339
+ return (result);
340
+ }
341
+
342
+ /*
343
+ * call-seq:
344
+ * node.debug -> true|false
345
+ *
346
+ * Print libxml debugging information to stdout.
347
+ * Requires that libxml was compiled with debugging enabled.
348
+ */
349
+ static VALUE rxml_node_debug(VALUE self)
350
+ {
351
+ #ifdef LIBXML_DEBUG_ENABLED
352
+ xmlNodePtr xnode;
353
+ Data_Get_Struct(self, xmlNode, xnode);
354
+ xmlDebugDumpNode(NULL, xnode, 2);
355
+ return Qtrue;
356
+ #else
357
+ rb_warn("libxml was compiled without debugging support.")
358
+ return Qfalse;
359
+ #endif
360
+ }
361
+
362
+ /*
363
+ * call-seq:
364
+ * node.first -> XML::Node
365
+ *
366
+ * Returns this node's first child node if any.
367
+ */
368
+ static VALUE rxml_node_first_get(VALUE self)
369
+ {
370
+ xmlNodePtr xnode;
371
+
372
+ Data_Get_Struct(self, xmlNode, xnode);
373
+
374
+ if (xnode->children)
375
+ return (rxml_node_wrap(xnode->children));
376
+ else
377
+ return (Qnil);
378
+ }
379
+
380
+ /*
381
+ * underlying for child_set and child_add, difference being
382
+ * former raises on implicit copy, latter does not.
383
+ */
384
+ static VALUE rxml_node_child_set_aux(VALUE self, VALUE rnode)
385
+ {
386
+ xmlNodePtr pnode, chld, ret;
387
+
388
+ if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
389
+ rb_raise(rb_eTypeError, "Must pass an XML::Node object");
390
+
391
+ Data_Get_Struct(self, xmlNode, pnode);
392
+ Data_Get_Struct(rnode, xmlNode, chld);
393
+
394
+ if (chld->parent != NULL || chld->doc != NULL)
395
+ rb_raise(
396
+ rb_eRuntimeError,
397
+ "Cannot move a node from one document to another with child= or <<. First copy the node before moving it.");
398
+
399
+ ret = xmlAddChild(pnode, chld);
400
+ if (ret == NULL)
401
+ {
402
+ rxml_raise(&xmlLastError);
403
+ }
404
+ else if (ret == chld)
405
+ {
406
+ /* child was added whole to parent and we need to return it as a new object */
407
+ return rxml_node_wrap(chld);
408
+ }
409
+ /* else */
410
+ /* If it was a text node, then ret should be parent->last, so we will just return ret. */
411
+ return rxml_node_wrap(ret);
412
+ }
413
+
414
+ /*
415
+ * call-seq:
416
+ * node.child = node
417
+ *
418
+ * Set a child node for this node. Also called for <<
419
+ */
420
+ static VALUE rxml_node_child_set(VALUE self, VALUE rnode)
421
+ {
422
+ return rxml_node_child_set_aux(self, rnode);
423
+ }
424
+
425
+ /*
426
+ * call-seq:
427
+ * node << ("string" | node) -> XML::Node
428
+ *
429
+ * Add the specified string or XML::Node to this node's
430
+ * content. The returned node is the node that was
431
+ * added and not self, thereby allowing << calls to
432
+ * be chained.
433
+ */
434
+ static VALUE rxml_node_content_add(VALUE self, VALUE obj)
435
+ {
436
+ xmlNodePtr xnode;
437
+ VALUE str;
438
+
439
+ Data_Get_Struct(self, xmlNode, xnode);
440
+ /* XXX This should only be legal for a CDATA type node, I think,
441
+ * resulting in a merge of content, as if a string were passed
442
+ * danj 070827
443
+ */
444
+ if (rb_obj_is_kind_of(obj, cXMLNode))
445
+ {
446
+ rxml_node_child_set(self, obj);
447
+ }
448
+ else
449
+ {
450
+ str = rb_obj_as_string(obj);
451
+ if (NIL_P(str) || TYPE(str) != T_STRING)
452
+ rb_raise(rb_eTypeError, "invalid argument: must be string or XML::Node");
453
+
454
+ xmlNodeAddContent(xnode, (xmlChar*) StringValuePtr(str));
455
+ }
456
+ return (self);
457
+ }
458
+
459
+ /*
460
+ * call-seq:
461
+ * node.child_add(node)
462
+ *
463
+ * Set a child node for this node.
464
+ */
465
+ static VALUE rxml_node_child_add(VALUE self, VALUE rnode)
466
+ {
467
+ return rxml_node_child_set_aux(self, rnode);
468
+ }
469
+
470
+ /*
471
+ * call-seq:
472
+ * node.doc -> document
473
+ *
474
+ * Obtain the XML::Document this node belongs to.
475
+ */
476
+ static VALUE rxml_node_doc(VALUE self)
477
+ {
478
+ xmlNodePtr xnode;
479
+ xmlDocPtr doc = NULL;
480
+
481
+ Data_Get_Struct(self, xmlNode, xnode);
482
+
483
+ switch (xnode->type)
484
+ {
485
+ case XML_DOCUMENT_NODE:
486
+ #ifdef LIBXML_DOCB_ENABLED
487
+ case XML_DOCB_DOCUMENT_NODE:
488
+ #endif
489
+ case XML_HTML_DOCUMENT_NODE:
490
+ doc = NULL;
491
+ break;
492
+ case XML_ATTRIBUTE_NODE:
493
+ {
494
+ xmlAttrPtr attr = (xmlAttrPtr) xnode;
495
+ doc = attr->doc;
496
+ break;
497
+ }
498
+ case XML_NAMESPACE_DECL:
499
+ doc = NULL;
500
+ break;
501
+ default:
502
+ doc = xnode->doc;
503
+ break;
504
+ }
505
+
506
+ if (doc == NULL)
507
+ return (Qnil);
508
+
509
+ if (doc->_private == NULL)
510
+ rb_raise(rb_eRuntimeError, "existing document object has no ruby-instance");
511
+
512
+ return (VALUE) doc->_private;
513
+ }
514
+
515
+ /*
516
+ * call-seq:
517
+ * node.to_s -> "string"
518
+ * node.to_s(:indent => true, :encoding => 'UTF-8', :level => 0) -> "string"
519
+ *
520
+ * Converts a node, and all of its children, to a string representation.
521
+ * You may provide an optional hash table to control how the string is
522
+ * generated. Valid options are:
523
+ *
524
+ * :indent - Specifies if the string should be indented. The default value
525
+ * is true. Note that indentation is only added if both :indent is
526
+ * true and XML.indent_tree_output is true. If :indent is set to false,
527
+ * then both indentation and line feeds are removed from the result.
528
+ *
529
+ * :level - Specifies the indentation level. The amount of indentation
530
+ * is equal to the (level * number_spaces) + number_spaces, where libxml
531
+ * defaults the number of spaces to 2. Thus a level of 0 results in
532
+ * 2 spaces, level 1 results in 4 spaces, level 2 results in 6 spaces, etc.
533
+ *
534
+ * :encoding - Specifies the output encoding of the string. It
535
+ * defaults to XML::Encoding::UTF8. To change it, use one of the
536
+ * XML::Encoding encoding constants. */
537
+
538
+ static VALUE rxml_node_to_s(int argc, VALUE *argv, VALUE self)
539
+ {
540
+ VALUE result = Qnil;
541
+ VALUE options = Qnil;
542
+ xmlNodePtr xnode;
543
+ xmlCharEncodingHandlerPtr encodingHandler;
544
+ xmlOutputBufferPtr output;
545
+
546
+ int level = 0;
547
+ int indent = 1;
548
+ const char *xencoding = NULL;
549
+
550
+ rb_scan_args(argc, argv, "01", &options);
551
+
552
+ if (!NIL_P(options))
553
+ {
554
+ VALUE rencoding, rindent, rlevel;
555
+ Check_Type(options, T_HASH);
556
+ rencoding = rb_hash_aref(options, ID2SYM(rb_intern("encoding")));
557
+ rindent = rb_hash_aref(options, ID2SYM(rb_intern("indent")));
558
+ rlevel = rb_hash_aref(options, ID2SYM(rb_intern("level")));
559
+
560
+ if (rindent == Qfalse)
561
+ indent = 0;
562
+
563
+ if (rlevel != Qnil)
564
+ level = NUM2INT(rlevel);
565
+
566
+ if (rencoding != Qnil)
567
+ {
568
+ xencoding = xmlGetCharEncodingName((xmlCharEncoding)NUM2INT(rencoding));
569
+ if (!xencoding)
570
+ rb_raise(rb_eArgError, "Unknown encoding value: %d", NUM2INT(rencoding));
571
+ }
572
+ }
573
+
574
+ encodingHandler = xmlFindCharEncodingHandler(xencoding);
575
+ output = xmlAllocOutputBuffer(encodingHandler);
576
+
577
+ Data_Get_Struct(self, xmlNode, xnode);
578
+ xmlNodeDumpOutput(output, xnode->doc, xnode, level, indent, xencoding);
579
+ xmlOutputBufferFlush(output);
580
+
581
+ if (output->conv)
582
+ result = rb_str_new2((const char*) output->conv->content);
583
+ else
584
+ result = rb_str_new2((const char*) output->buffer->content);
585
+
586
+ xmlOutputBufferClose(output);
587
+
588
+ return result;
589
+ }
590
+
591
+
592
+ /*
593
+ * call-seq:
594
+ * node.each -> XML::Node
595
+ *
596
+ * Iterates over this node's children, including text
597
+ * nodes, element nodes, etc. If you wish to iterate
598
+ * only over child elements, use XML::Node#each_element.
599
+ *
600
+ * doc = XML::Document.new('model/books.xml')
601
+ * doc.root.each {|node| puts node}
602
+ */
603
+ static VALUE rxml_node_each(VALUE self)
604
+ {
605
+ xmlNodePtr xnode;
606
+ xmlNodePtr xchild;
607
+ Data_Get_Struct(self, xmlNode, xnode);
608
+
609
+ xchild = xnode->children;
610
+
611
+ while (xchild)
612
+ {
613
+ rb_yield(rxml_node_wrap(xchild));
614
+ xchild = xchild->next;
615
+ }
616
+ return Qnil;
617
+ }
618
+
619
+ /*
620
+ * call-seq:
621
+ * node.empty? -> (true|false)
622
+ *
623
+ * Determine whether this node is empty.
624
+ */
625
+ static VALUE rxml_node_empty_q(VALUE self)
626
+ {
627
+ xmlNodePtr xnode;
628
+ Data_Get_Struct(self, xmlNode, xnode);
629
+ if (xnode == NULL)
630
+ return (Qnil);
631
+
632
+ return ((xmlIsBlankNode(xnode) == 1) ? Qtrue : Qfalse);
633
+ }
634
+
635
+
636
+ /*
637
+ * call-seq:
638
+ * node.eql?(other_node) => (true|false)
639
+ *
640
+ * Test equality between the two nodes. Two nodes are equal
641
+ * if they are the same node or have the same XML representation.*/
642
+ static VALUE rxml_node_eql_q(VALUE self, VALUE other)
643
+ {
644
+ if(self == other)
645
+ {
646
+ return Qtrue;
647
+ }
648
+ else if (NIL_P(other))
649
+ {
650
+ return Qfalse;
651
+ }
652
+ else
653
+ {
654
+ VALUE self_xml;
655
+ VALUE other_xml;
656
+
657
+ if (rb_obj_is_kind_of(other, cXMLNode) == Qfalse)
658
+ rb_raise(rb_eTypeError, "Nodes can only be compared against other nodes");
659
+
660
+ self_xml = rxml_node_to_s(0, NULL, self);
661
+ other_xml = rxml_node_to_s(0, NULL, other);
662
+ return(rb_funcall(self_xml, rb_intern("=="), 1, other_xml));
663
+ }
664
+ }
665
+
666
+ /*
667
+ * call-seq:
668
+ * node.lang -> "string"
669
+ *
670
+ * Obtain the language set for this node, if any.
671
+ * This is set in XML via the xml:lang attribute.
672
+ */
673
+ static VALUE rxml_node_lang_get(VALUE self)
674
+ {
675
+ xmlNodePtr xnode;
676
+ xmlChar *lang;
677
+ VALUE result = Qnil;
678
+
679
+ Data_Get_Struct(self, xmlNode, xnode);
680
+ lang = xmlNodeGetLang(xnode);
681
+
682
+ if (lang)
683
+ {
684
+ result = rb_str_new2((const char*) lang);
685
+ xmlFree(lang);
686
+ }
687
+
688
+ return (result);
689
+ }
690
+
691
+ // TODO node_lang_set should support setting back to nil
692
+
693
+ /*
694
+ * call-seq:
695
+ * node.lang = "string"
696
+ *
697
+ * Set the language for this node. This affects the value
698
+ * of the xml:lang attribute.
699
+ */
700
+ static VALUE rxml_node_lang_set(VALUE self, VALUE lang)
701
+ {
702
+ xmlNodePtr xnode;
703
+
704
+ Check_Type(lang, T_STRING);
705
+ Data_Get_Struct(self, xmlNode, xnode);
706
+ xmlNodeSetLang(xnode, (xmlChar*) StringValuePtr(lang));
707
+
708
+ return (Qtrue);
709
+ }
710
+
711
+ /*
712
+ * call-seq:
713
+ * node.last -> XML::Node
714
+ *
715
+ * Obtain the last child node of this node, if any.
716
+ */
717
+ static VALUE rxml_node_last_get(VALUE self)
718
+ {
719
+ xmlNodePtr xnode;
720
+
721
+ Data_Get_Struct(self, xmlNode, xnode);
722
+
723
+ if (xnode->last)
724
+ return (rxml_node_wrap(xnode->last));
725
+ else
726
+ return (Qnil);
727
+ }
728
+
729
+ /*
730
+ * call-seq:
731
+ * node.line_num -> num
732
+ *
733
+ * Obtain the line number (in the XML document) that this
734
+ * node was read from. If +default_line_numbers+ is set
735
+ * false (the default), this method returns zero.
736
+ */
737
+ static VALUE rxml_node_line_num(VALUE self)
738
+ {
739
+ xmlNodePtr xnode;
740
+ long line_num;
741
+ Data_Get_Struct(self, xmlNode, xnode);
742
+
743
+ if (!xmlLineNumbersDefaultValue)
744
+ rb_warn(
745
+ "Line numbers were not retained: use XML::Parser::default_line_numbers=true");
746
+
747
+ line_num = xmlGetLineNo(xnode);
748
+ if (line_num == -1)
749
+ return (Qnil);
750
+ else
751
+ return (INT2NUM((long) line_num));
752
+ }
753
+
754
+ /*
755
+ * call-seq:
756
+ * node.xlink? -> (true|false)
757
+ *
758
+ * Determine whether this node is an xlink node.
759
+ */
760
+ static VALUE rxml_node_xlink_q(VALUE self)
761
+ {
762
+ xmlNodePtr xnode;
763
+ xlinkType xlt;
764
+
765
+ Data_Get_Struct(self, xmlNode, xnode);
766
+ xlt = xlinkIsLink(xnode->doc, xnode);
767
+
768
+ if (xlt == XLINK_TYPE_NONE)
769
+ return (Qfalse);
770
+ else
771
+ return (Qtrue);
772
+ }
773
+
774
+ /*
775
+ * call-seq:
776
+ * node.xlink_type -> num
777
+ *
778
+ * Obtain the type identifier for this xlink, if applicable.
779
+ * If this is not an xlink node (see +xlink?+), will return
780
+ * nil.
781
+ */
782
+ static VALUE rxml_node_xlink_type(VALUE self)
783
+ {
784
+ xmlNodePtr xnode;
785
+ xlinkType xlt;
786
+
787
+ Data_Get_Struct(self, xmlNode, xnode);
788
+ xlt = xlinkIsLink(xnode->doc, xnode);
789
+
790
+ if (xlt == XLINK_TYPE_NONE)
791
+ return (Qnil);
792
+ else
793
+ return (INT2NUM(xlt));
794
+ }
795
+
796
+ /*
797
+ * call-seq:
798
+ * node.xlink_type_name -> "string"
799
+ *
800
+ * Obtain the type name for this xlink, if applicable.
801
+ * If this is not an xlink node (see +xlink?+), will return
802
+ * nil.
803
+ */
804
+ static VALUE rxml_node_xlink_type_name(VALUE self)
805
+ {
806
+ xmlNodePtr xnode;
807
+ xlinkType xlt;
808
+
809
+ Data_Get_Struct(self, xmlNode, xnode);
810
+ xlt = xlinkIsLink(xnode->doc, xnode);
811
+
812
+ switch (xlt)
813
+ {
814
+ case XLINK_TYPE_NONE:
815
+ return (Qnil);
816
+ case XLINK_TYPE_SIMPLE:
817
+ return (rb_str_new2("simple"));
818
+ case XLINK_TYPE_EXTENDED:
819
+ return (rb_str_new2("extended"));
820
+ case XLINK_TYPE_EXTENDED_SET:
821
+ return (rb_str_new2("extended_set"));
822
+ default:
823
+ rb_fatal("Unknowng xlink type, %d", xlt);
824
+ }
825
+ }
826
+
827
+ /*
828
+ * call-seq:
829
+ * node.name -> "string"
830
+ *
831
+ * Obtain this node's name.
832
+ */
833
+ static VALUE rxml_node_name_get(VALUE self)
834
+ {
835
+ xmlNodePtr xnode;
836
+ const xmlChar *name;
837
+
838
+ Data_Get_Struct(self, xmlNode, xnode);
839
+
840
+ switch (xnode->type)
841
+ {
842
+ case XML_DOCUMENT_NODE:
843
+ #ifdef LIBXML_DOCB_ENABLED
844
+ case XML_DOCB_DOCUMENT_NODE:
845
+ #endif
846
+ case XML_HTML_DOCUMENT_NODE:
847
+ {
848
+ xmlDocPtr doc = (xmlDocPtr) xnode;
849
+ name = doc->URL;
850
+ break;
851
+ }
852
+ case XML_ATTRIBUTE_NODE:
853
+ {
854
+ xmlAttrPtr attr = (xmlAttrPtr) xnode;
855
+ name = attr->name;
856
+ break;
857
+ }
858
+ case XML_NAMESPACE_DECL:
859
+ {
860
+ xmlNsPtr ns = (xmlNsPtr) xnode;
861
+ name = ns->prefix;
862
+ break;
863
+ }
864
+ default:
865
+ name = xnode->name;
866
+ break;
867
+ }
868
+
869
+ if (xnode->name == NULL)
870
+ return (Qnil);
871
+ else if (name == xmlStringText)
872
+ return (kXMLStringText);
873
+ else if (name == xmlStringTextNoenc)
874
+ return (kXMLStringTextNoenc);
875
+ else
876
+ return (rb_str_new2((const char*) name));
877
+ }
878
+
879
+ /*
880
+ * call-seq:
881
+ * node.name = "string"
882
+ *
883
+ * Set this node's name.
884
+ */
885
+ static VALUE rxml_node_name_set(VALUE self, VALUE name)
886
+ {
887
+ xmlNodePtr xnode;
888
+ const xmlChar *xname;
889
+
890
+ Check_Type(name, T_STRING);
891
+ Data_Get_Struct(self, xmlNode, xnode);
892
+ xname = (const xmlChar*)StringValuePtr(name);
893
+
894
+ if (xnode->type != XML_TEXT_NODE)
895
+ xmlNodeSetName(xnode, xname);
896
+ else if (xname == xmlStringText) /* compare addresses instead of string contents. */
897
+ xnode->name = xmlStringText;
898
+ else if (xname == xmlStringTextNoenc) /* compare addresses instead of string contents. */
899
+ xnode->name = xmlStringTextNoenc;
900
+
901
+ /* Note: calling xmlNodeSetName() for a text node is ignored by libXML. */
902
+ return (Qtrue);
903
+ }
904
+
905
+ /*
906
+ * call-seq:
907
+ * node.next -> XML::Node
908
+ *
909
+ * Obtain the next sibling node, if any.
910
+ */
911
+ static VALUE rxml_node_next_get(VALUE self)
912
+ {
913
+ xmlNodePtr xnode;
914
+
915
+ Data_Get_Struct(self, xmlNode, xnode);
916
+
917
+ if (xnode->next)
918
+ return (rxml_node_wrap(xnode->next));
919
+ else
920
+ return (Qnil);
921
+ }
922
+
923
+ /*
924
+ * call-seq:
925
+ * node.next = node
926
+ *
927
+ * Insert the specified node as this node's next sibling.
928
+ */
929
+ static VALUE rxml_node_next_set(VALUE self, VALUE rnode)
930
+ {
931
+ xmlNodePtr cnode, pnode, ret;
932
+
933
+ if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
934
+ rb_raise(rb_eTypeError, "Must pass an XML::Node object");
935
+
936
+ Data_Get_Struct(self, xmlNode, pnode);
937
+ Data_Get_Struct(rnode, xmlNode, cnode);
938
+
939
+ ret = xmlAddNextSibling(pnode, cnode);
940
+ if (ret == NULL)
941
+ rxml_raise(&xmlLastError);
942
+
943
+ return (rxml_node_wrap(ret));
944
+ }
945
+
946
+ /*
947
+ * call-seq:
948
+ * node.parent -> XML::Node
949
+ *
950
+ * Obtain this node's parent node, if any.
951
+ */
952
+ static VALUE rxml_node_parent_get(VALUE self)
953
+ {
954
+ xmlNodePtr xnode;
955
+
956
+ Data_Get_Struct(self, xmlNode, xnode);
957
+
958
+ if (xnode->parent)
959
+ return (rxml_node_wrap(xnode->parent));
960
+ else
961
+ return (Qnil);
962
+ }
963
+
964
+ /*
965
+ * call-seq:
966
+ * node.path -> path
967
+ *
968
+ * Obtain this node's path.
969
+ */
970
+ static VALUE rxml_node_path(VALUE self)
971
+ {
972
+ xmlNodePtr xnode;
973
+ xmlChar *path;
974
+
975
+ Data_Get_Struct(self, xmlNode, xnode);
976
+ path = xmlGetNodePath(xnode);
977
+
978
+ if (path == NULL)
979
+ return (Qnil);
980
+ else
981
+ return (rb_str_new2((const char*) path));
982
+ }
983
+
984
+ /*
985
+ * call-seq:
986
+ * node.pointer -> XML::NodeSet
987
+ *
988
+ * Evaluates an XPointer expression relative to this node.
989
+ */
990
+ static VALUE rxml_node_pointer(VALUE self, VALUE xptr_str)
991
+ {
992
+ return (rxml_xpointer_point2(self, xptr_str));
993
+ }
994
+
995
+ /*
996
+ * call-seq:
997
+ * node.prev -> XML::Node
998
+ *
999
+ * Obtain the previous sibling, if any.
1000
+ */
1001
+ static VALUE rxml_node_prev_get(VALUE self)
1002
+ {
1003
+ xmlNodePtr xnode;
1004
+ xmlNodePtr node;
1005
+ Data_Get_Struct(self, xmlNode, xnode);
1006
+
1007
+ switch (xnode->type)
1008
+ {
1009
+ case XML_DOCUMENT_NODE:
1010
+ #ifdef LIBXML_DOCB_ENABLED
1011
+ case XML_DOCB_DOCUMENT_NODE:
1012
+ #endif
1013
+ case XML_HTML_DOCUMENT_NODE:
1014
+ case XML_NAMESPACE_DECL:
1015
+ node = NULL;
1016
+ break;
1017
+ case XML_ATTRIBUTE_NODE:
1018
+ {
1019
+ xmlAttrPtr attr = (xmlAttrPtr) xnode;
1020
+ node = (xmlNodePtr) attr->prev;
1021
+ }
1022
+ break;
1023
+ default:
1024
+ node = xnode->prev;
1025
+ break;
1026
+ }
1027
+
1028
+ if (node == NULL)
1029
+ return (Qnil);
1030
+ else
1031
+ return (rxml_node_wrap(node));
1032
+ }
1033
+
1034
+ /*
1035
+ * call-seq:
1036
+ * node.prev = node
1037
+ *
1038
+ * Insert the specified node as this node's previous sibling.
1039
+ */
1040
+ static VALUE rxml_node_prev_set(VALUE self, VALUE rnode)
1041
+ {
1042
+ xmlNodePtr cnode, pnode, ret;
1043
+
1044
+ if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
1045
+ rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1046
+
1047
+ Data_Get_Struct(self, xmlNode, pnode);
1048
+ Data_Get_Struct(rnode, xmlNode, cnode);
1049
+
1050
+ ret = xmlAddPrevSibling(pnode, cnode);
1051
+ if (ret == NULL)
1052
+ rxml_raise(&xmlLastError);
1053
+
1054
+ return (rxml_node_wrap(ret));
1055
+ }
1056
+
1057
+ /*
1058
+ * call-seq:
1059
+ * node.attributes -> attributes
1060
+ *
1061
+ * Returns the XML::Attributes for this node.
1062
+ */
1063
+ static VALUE rxml_node_attributes_get(VALUE self)
1064
+ {
1065
+ xmlNodePtr xnode;
1066
+
1067
+ Data_Get_Struct(self, xmlNode, xnode);
1068
+ return rxml_attributes_new(xnode);
1069
+ }
1070
+
1071
+ /*
1072
+ * call-seq:
1073
+ * node.property("name") -> "string"
1074
+ * node["name"] -> "string"
1075
+ *
1076
+ * Obtain the named pyroperty.
1077
+ */
1078
+ static VALUE rxml_node_attribute_get(VALUE self, VALUE name)
1079
+ {
1080
+ VALUE attributes = rxml_node_attributes_get(self);
1081
+ return rxml_attributes_attribute_get(attributes, name);
1082
+ }
1083
+
1084
+ /*
1085
+ * call-seq:
1086
+ * node["name"] = "string"
1087
+ *
1088
+ * Set the named property.
1089
+ */
1090
+ static VALUE rxml_node_property_set(VALUE self, VALUE name, VALUE value)
1091
+ {
1092
+ VALUE attributes = rxml_node_attributes_get(self);
1093
+ return rxml_attributes_attribute_set(attributes, name, value);
1094
+ }
1095
+
1096
+ /*
1097
+ * call-seq:
1098
+ * node.remove! -> node
1099
+ *
1100
+ * Removes this node and its children from its
1101
+ * document tree by setting its document,
1102
+ * parent and siblings to nil. You can add
1103
+ * the returned node back into a document.
1104
+ * Otherwise, the node will be freed once
1105
+ * any references to it go out of scope. */
1106
+
1107
+ static VALUE rxml_node_remove_ex(VALUE self)
1108
+ {
1109
+ xmlNodePtr xnode;
1110
+ Data_Get_Struct(self, xmlNode, xnode);
1111
+ /* Unlink the node from its parent. */
1112
+ xmlUnlinkNode(xnode);
1113
+ /* Now set the nodes parent to nil so it can
1114
+ be freed if the reference to it goes out of scope*/
1115
+ xmlSetTreeDoc(xnode, NULL);
1116
+
1117
+ /* Now return the removed node so the user can
1118
+ do something wiht it.*/
1119
+ return self;
1120
+ }
1121
+
1122
+ /*
1123
+ * call-seq:
1124
+ * node.sibling(node) -> XML::Node
1125
+ *
1126
+ * Add the specified node as a sibling of this node.
1127
+ */
1128
+ static VALUE rxml_node_sibling_set(VALUE self, VALUE rnode)
1129
+ {
1130
+ xmlNodePtr cnode, pnode, ret;
1131
+ VALUE obj;
1132
+
1133
+ if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
1134
+ rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1135
+
1136
+ Data_Get_Struct(self, xmlNode, pnode);
1137
+ Data_Get_Struct(rnode, xmlNode, cnode);
1138
+
1139
+ ret = xmlAddSibling(pnode, cnode);
1140
+ if (ret == NULL)
1141
+ rxml_raise(&xmlLastError);
1142
+
1143
+ if (ret->_private == NULL)
1144
+ obj = rxml_node_wrap(ret);
1145
+ else
1146
+ obj = (VALUE) ret->_private;
1147
+
1148
+ return obj;
1149
+ }
1150
+
1151
+ /*
1152
+ * call-seq:
1153
+ * node.space_preserve -> (true|false)
1154
+ *
1155
+ * Determine whether this node preserves whitespace.
1156
+ */
1157
+ static VALUE rxml_node_space_preserve_get(VALUE self)
1158
+ {
1159
+ xmlNodePtr xnode;
1160
+
1161
+ Data_Get_Struct(self, xmlNode, xnode);
1162
+ return (INT2NUM(xmlNodeGetSpacePreserve(xnode)));
1163
+ }
1164
+
1165
+ /*
1166
+ * call-seq:
1167
+ * node.space_preserve = true|false
1168
+ *
1169
+ * Control whether this node preserves whitespace.
1170
+ */
1171
+ static VALUE rxml_node_space_preserve_set(VALUE self, VALUE bool)
1172
+ {
1173
+ xmlNodePtr xnode;
1174
+ Data_Get_Struct(self, xmlNode, xnode);
1175
+
1176
+ if (TYPE(bool) == T_FALSE)
1177
+ xmlNodeSetSpacePreserve(xnode, 1);
1178
+ else
1179
+ xmlNodeSetSpacePreserve(xnode, 0);
1180
+
1181
+ return (Qnil);
1182
+ }
1183
+
1184
+ /*
1185
+ * call-seq:
1186
+ * node.type -> num
1187
+ *
1188
+ * Obtain this node's type identifier.
1189
+ */
1190
+ static VALUE rxml_node_type(VALUE self)
1191
+ {
1192
+ xmlNodePtr xnode;
1193
+ Data_Get_Struct(self, xmlNode, xnode);
1194
+ return (INT2NUM(xnode->type));
1195
+ }
1196
+
1197
+ /*
1198
+ * call-seq:
1199
+ * node.copy -> XML::Node
1200
+ *
1201
+ * Creates a copy of this node. To create a
1202
+ * shallow copy set the deep parameter to false.
1203
+ * To create a deep copy set the deep parameter
1204
+ * to true.
1205
+ *
1206
+ */
1207
+ static VALUE rxml_node_copy(VALUE self, VALUE deep)
1208
+ {
1209
+ xmlNodePtr xnode;
1210
+ xmlNodePtr xcopy;
1211
+ int recursive = (deep == Qnil || deep == Qfalse) ? 0 : 1;
1212
+ Data_Get_Struct(self, xmlNode, xnode);
1213
+
1214
+ xcopy = xmlCopyNode(xnode, recursive);
1215
+
1216
+ if (xcopy)
1217
+ return rxml_node_wrap(xcopy);
1218
+ else
1219
+ return Qnil;
1220
+ }
1221
+
1222
+ void rxml_node_registerNode(xmlNodePtr node)
1223
+ {
1224
+ node->_private = NULL;
1225
+ }
1226
+
1227
+ void rxml_node_deregisterNode(xmlNodePtr xnode)
1228
+ {
1229
+ VALUE node;
1230
+
1231
+ if (xnode->_private == NULL)
1232
+ return;
1233
+ node = (VALUE) xnode->_private;
1234
+ DATA_PTR( node) = NULL;
1235
+ }
1236
+
1237
+ // Rdoc needs to know
1238
+ #ifdef RDOC_NEVER_DEFINED
1239
+ mLibXML = rb_define_module("LibXML");
1240
+ mXML = rb_define_module_under(mLibXML, "XML");
1241
+ #endif
1242
+
1243
+ static VALUE rxml_constant_stringref(const xmlChar *ptr)
1244
+ {
1245
+ VALUE str = rb_str_new("", 0);
1246
+ FL_SET(str, ELTS_SHARED | FL_USER3);
1247
+ xfree(RSTRING_PTR(str));
1248
+ RSTRING_PTR(str) = (void*)ptr;
1249
+ RSTRING_LEN(str) = strlen(ptr);
1250
+ RSTRING(str)->aux.capa = 0;
1251
+ OBJ_FREEZE(str);
1252
+ return str;
1253
+ }
1254
+
1255
+ void ruby_init_xml_node(void)
1256
+ {
1257
+ xmlRegisterNodeDefault(rxml_node_registerNode);
1258
+ xmlDeregisterNodeDefault(rxml_node_deregisterNode);
1259
+
1260
+ kXMLStringText = rxml_constant_stringref(xmlStringText);
1261
+ kXMLStringTextNoenc = rxml_constant_stringref(xmlStringTextNoenc);
1262
+
1263
+ cXMLNode = rb_define_class_under(mXML, "Node", rb_cObject);
1264
+
1265
+ rb_define_const(cXMLNode, "SPACE_DEFAULT", INT2NUM(0));
1266
+ rb_define_const(cXMLNode, "SPACE_PRESERVE", INT2NUM(1));
1267
+ rb_define_const(cXMLNode, "SPACE_NOT_INHERIT", INT2NUM(-1));
1268
+ rb_define_const(cXMLNode, "XLINK_ACTUATE_AUTO", INT2NUM(1));
1269
+ rb_define_const(cXMLNode, "XLINK_ACTUATE_NONE", INT2NUM(0));
1270
+ rb_define_const(cXMLNode, "XLINK_ACTUATE_ONREQUEST", INT2NUM(2));
1271
+ rb_define_const(cXMLNode, "XLINK_SHOW_EMBED", INT2NUM(2));
1272
+ rb_define_const(cXMLNode, "XLINK_SHOW_NEW", INT2NUM(1));
1273
+ rb_define_const(cXMLNode, "XLINK_SHOW_NONE", INT2NUM(0));
1274
+ rb_define_const(cXMLNode, "XLINK_SHOW_REPLACE", INT2NUM(3));
1275
+ rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED", INT2NUM(2));
1276
+ rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED_SET", INT2NUM(3));
1277
+ rb_define_const(cXMLNode, "XLINK_TYPE_NONE", INT2NUM(0));
1278
+ rb_define_const(cXMLNode, "XLINK_TYPE_SIMPLE", INT2NUM(1));
1279
+
1280
+ rb_define_const(cXMLNode, "ELEMENT_NODE", INT2FIX(XML_ELEMENT_NODE));
1281
+ rb_define_const(cXMLNode, "ATTRIBUTE_NODE", INT2FIX(XML_ATTRIBUTE_NODE));
1282
+ rb_define_const(cXMLNode, "TEXT_NODE", INT2FIX(XML_TEXT_NODE));
1283
+ rb_define_const(cXMLNode, "CDATA_SECTION_NODE", INT2FIX(XML_CDATA_SECTION_NODE));
1284
+ rb_define_const(cXMLNode, "ENTITY_REF_NODE", INT2FIX(XML_ENTITY_REF_NODE));
1285
+ rb_define_const(cXMLNode, "ENTITY_NODE", INT2FIX(XML_ENTITY_NODE));
1286
+ rb_define_const(cXMLNode, "PI_NODE", INT2FIX(XML_PI_NODE));
1287
+ rb_define_const(cXMLNode, "COMMENT_NODE", INT2FIX(XML_COMMENT_NODE));
1288
+ rb_define_const(cXMLNode, "DOCUMENT_NODE", INT2FIX(XML_DOCUMENT_NODE));
1289
+ rb_define_const(cXMLNode, "DOCUMENT_TYPE_NODE", INT2FIX(XML_DOCUMENT_TYPE_NODE));
1290
+ rb_define_const(cXMLNode, "DOCUMENT_FRAG_NODE", INT2FIX(XML_DOCUMENT_FRAG_NODE));
1291
+ rb_define_const(cXMLNode, "NOTATION_NODE", INT2FIX(XML_NOTATION_NODE));
1292
+ rb_define_const(cXMLNode, "HTML_DOCUMENT_NODE", INT2FIX(XML_HTML_DOCUMENT_NODE));
1293
+ rb_define_const(cXMLNode, "DTD_NODE", INT2FIX(XML_DTD_NODE));
1294
+ rb_define_const(cXMLNode, "ELEMENT_DECL", INT2FIX(XML_ELEMENT_DECL));
1295
+ rb_define_const(cXMLNode, "ATTRIBUTE_DECL", INT2FIX(XML_ATTRIBUTE_DECL));
1296
+ rb_define_const(cXMLNode, "ENTITY_DECL", INT2FIX(XML_ENTITY_DECL));
1297
+ rb_define_const(cXMLNode, "NAMESPACE_DECL", INT2FIX(XML_NAMESPACE_DECL));
1298
+ rb_define_const(cXMLNode, "XINCLUDE_START", INT2FIX(XML_XINCLUDE_START));
1299
+ rb_define_const(cXMLNode, "XINCLUDE_END", INT2FIX(XML_XINCLUDE_END));
1300
+
1301
+ #ifdef LIBXML_DOCB_ENABLED
1302
+ rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", INT2FIX(XML_DOCB_DOCUMENT_NODE));
1303
+ #else
1304
+ rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", Qnil);
1305
+ #endif
1306
+
1307
+ rb_define_const(cXMLNode, "XML_STRING_TEXT", kXMLStringText);
1308
+ rb_define_const(cXMLNode, "XML_STRING_TEXT_NOENC", kXMLStringTextNoenc);
1309
+
1310
+ rb_define_singleton_method(cXMLNode, "new_cdata", rxml_node_new_cdata, -1);
1311
+ rb_define_singleton_method(cXMLNode, "new_comment", rxml_node_new_comment, -1);
1312
+ rb_define_singleton_method(cXMLNode, "new_text", rxml_node_new_text, 1);
1313
+
1314
+ /* Initialization */
1315
+ rb_define_alloc_func(cXMLNode, rxml_node_alloc);
1316
+ rb_define_method(cXMLNode, "initialize", rxml_node_initialize, -1);
1317
+
1318
+ /* Traversal */
1319
+ rb_include_module(cXMLNode, rb_mEnumerable);
1320
+ rb_define_method(cXMLNode, "[]", rxml_node_attribute_get, 1);
1321
+ rb_define_method(cXMLNode, "each", rxml_node_each, 0);
1322
+ rb_define_method(cXMLNode, "first", rxml_node_first_get, 0);
1323
+ rb_define_method(cXMLNode, "last", rxml_node_last_get, 0);
1324
+ rb_define_method(cXMLNode, "next", rxml_node_next_get, 0);
1325
+ rb_define_method(cXMLNode, "parent", rxml_node_parent_get, 0);
1326
+ rb_define_method(cXMLNode, "prev", rxml_node_prev_get, 0);
1327
+
1328
+ /* Modification */
1329
+ rb_define_method(cXMLNode, "<<", rxml_node_content_add, 1);
1330
+ rb_define_method(cXMLNode, "[]=", rxml_node_property_set, 2);
1331
+ rb_define_method(cXMLNode, "child_add", rxml_node_child_add, 1);
1332
+ rb_define_method(cXMLNode, "child=", rxml_node_child_set, 1);
1333
+ rb_define_method(cXMLNode, "sibling=", rxml_node_sibling_set, 1);
1334
+ rb_define_method(cXMLNode, "next=", rxml_node_next_set, 1);
1335
+ rb_define_method(cXMLNode, "prev=", rxml_node_prev_set, 1);
1336
+
1337
+ /* Rest of the node api */
1338
+ rb_define_method(cXMLNode, "attributes", rxml_node_attributes_get, 0);
1339
+ rb_define_method(cXMLNode, "base_uri", rxml_node_base_uri_get, 0);
1340
+ rb_define_method(cXMLNode, "base_uri=", rxml_node_base_uri_set, 1);
1341
+ rb_define_method(cXMLNode, "blank?", rxml_node_empty_q, 0);
1342
+ rb_define_method(cXMLNode, "copy", rxml_node_copy, 1);
1343
+ rb_define_method(cXMLNode, "content", rxml_node_content_get, 0);
1344
+ rb_define_method(cXMLNode, "content=", rxml_node_content_set, 1);
1345
+ rb_define_method(cXMLNode, "content_stripped", rxml_node_content_stripped_get, 0);
1346
+ rb_define_method(cXMLNode, "debug", rxml_node_debug, 0);
1347
+ rb_define_method(cXMLNode, "doc", rxml_node_doc, 0);
1348
+ rb_define_method(cXMLNode, "empty?", rxml_node_empty_q, 0);
1349
+ rb_define_method(cXMLNode, "eql?", rxml_node_eql_q, 1);
1350
+ rb_define_method(cXMLNode, "lang", rxml_node_lang_get, 0);
1351
+ rb_define_method(cXMLNode, "lang=", rxml_node_lang_set, 1);
1352
+ rb_define_method(cXMLNode, "line_num", rxml_node_line_num, 0);
1353
+ rb_define_method(cXMLNode, "name", rxml_node_name_get, 0);
1354
+ rb_define_method(cXMLNode, "name=", rxml_node_name_set, 1);
1355
+ rb_define_method(cXMLNode, "node_type", rxml_node_type, 0);
1356
+ rb_define_method(cXMLNode, "path", rxml_node_path, 0);
1357
+ rb_define_method(cXMLNode, "pointer", rxml_node_pointer, 1);
1358
+ rb_define_method(cXMLNode, "remove!", rxml_node_remove_ex, 0);
1359
+ rb_define_method(cXMLNode, "space_preserve", rxml_node_space_preserve_get, 0);
1360
+ rb_define_method(cXMLNode, "space_preserve=", rxml_node_space_preserve_set, 1);
1361
+ rb_define_method(cXMLNode, "to_s", rxml_node_to_s, -1);
1362
+ rb_define_method(cXMLNode, "xlink?", rxml_node_xlink_q, 0);
1363
+ rb_define_method(cXMLNode, "xlink_type", rxml_node_xlink_type, 0);
1364
+ rb_define_method(cXMLNode, "xlink_type_name", rxml_node_xlink_type_name, 0);
1365
+
1366
+ rb_define_alias(cXMLNode, "==", "eql?");
1367
+ }