libxml-ruby 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/CHANGES +41 -1
  2. data/LICENSE +3 -4
  3. data/README +37 -24
  4. data/Rakefile +2 -2
  5. data/ext/libxml/extconf.rb +31 -12
  6. data/ext/libxml/libxml.c +56 -858
  7. data/ext/libxml/ruby_libxml.h +93 -96
  8. data/ext/libxml/ruby_xml.c +855 -0
  9. data/ext/libxml/ruby_xml.h +9 -0
  10. data/ext/libxml/ruby_xml_attr.c +3 -9
  11. data/ext/libxml/ruby_xml_attr.h +2 -2
  12. data/ext/libxml/ruby_xml_attr_decl.c +2 -8
  13. data/ext/libxml/ruby_xml_attr_decl.h +1 -1
  14. data/ext/libxml/ruby_xml_attributes.c +6 -8
  15. data/ext/libxml/ruby_xml_attributes.h +1 -1
  16. data/ext/libxml/ruby_xml_document.c +915 -895
  17. data/ext/libxml/ruby_xml_document.h +2 -2
  18. data/ext/libxml/ruby_xml_dtd.c +257 -136
  19. data/ext/libxml/ruby_xml_dtd.h +1 -1
  20. data/ext/libxml/ruby_xml_encoding.c +55 -37
  21. data/ext/libxml/ruby_xml_encoding.h +1 -1
  22. data/ext/libxml/ruby_xml_error.c +526 -1058
  23. data/ext/libxml/ruby_xml_error.h +1 -1
  24. data/ext/libxml/ruby_xml_html_parser.c +2 -8
  25. data/ext/libxml/ruby_xml_html_parser.h +2 -2
  26. data/ext/libxml/ruby_xml_html_parser_context.c +175 -145
  27. data/ext/libxml/ruby_xml_html_parser_context.h +1 -1
  28. data/ext/libxml/ruby_xml_html_parser_options.c +12 -20
  29. data/ext/libxml/ruby_xml_html_parser_options.h +1 -1
  30. data/ext/libxml/ruby_xml_input_cbg.c +2 -8
  31. data/ext/libxml/ruby_xml_input_cbg.h +1 -1
  32. data/ext/libxml/ruby_xml_namespace.c +2 -8
  33. data/ext/libxml/ruby_xml_namespace.h +2 -2
  34. data/ext/libxml/ruby_xml_namespaces.c +1 -9
  35. data/ext/libxml/ruby_xml_namespaces.h +1 -1
  36. data/ext/libxml/ruby_xml_node.c +182 -121
  37. data/ext/libxml/ruby_xml_node.h +2 -2
  38. data/ext/libxml/ruby_xml_parser.c +2 -8
  39. data/ext/libxml/ruby_xml_parser.h +2 -2
  40. data/ext/libxml/ruby_xml_parser_context.c +952 -901
  41. data/ext/libxml/ruby_xml_parser_context.h +2 -2
  42. data/ext/libxml/ruby_xml_parser_options.c +2 -9
  43. data/ext/libxml/ruby_xml_parser_options.h +1 -1
  44. data/ext/libxml/ruby_xml_reader.c +1002 -993
  45. data/ext/libxml/ruby_xml_reader.h +1 -1
  46. data/ext/libxml/ruby_xml_relaxng.c +1 -7
  47. data/ext/libxml/ruby_xml_relaxng.h +1 -1
  48. data/ext/libxml/ruby_xml_sax2_handler.c +2 -2
  49. data/ext/libxml/ruby_xml_sax2_handler.h +1 -1
  50. data/ext/libxml/ruby_xml_sax_parser.c +2 -8
  51. data/ext/libxml/ruby_xml_sax_parser.h +2 -2
  52. data/ext/libxml/ruby_xml_schema.c +1 -7
  53. data/ext/libxml/ruby_xml_schema.h +1 -1
  54. data/ext/libxml/{version.h → ruby_xml_version.h} +2 -2
  55. data/ext/libxml/ruby_xml_xinclude.c +2 -8
  56. data/ext/libxml/ruby_xml_xinclude.h +2 -2
  57. data/ext/libxml/ruby_xml_xpath.c +17 -18
  58. data/ext/libxml/ruby_xml_xpath.h +2 -2
  59. data/ext/libxml/ruby_xml_xpath_context.c +387 -389
  60. data/ext/libxml/ruby_xml_xpath_context.h +2 -2
  61. data/ext/libxml/ruby_xml_xpath_expression.c +18 -8
  62. data/ext/libxml/ruby_xml_xpath_expression.h +1 -1
  63. data/ext/libxml/ruby_xml_xpath_object.c +19 -8
  64. data/ext/libxml/ruby_xml_xpath_object.h +1 -1
  65. data/ext/libxml/ruby_xml_xpointer.c +2 -8
  66. data/ext/libxml/ruby_xml_xpointer.h +2 -2
  67. data/ext/vc/libxml_ruby.sln +7 -1
  68. data/lib/libxml.rb +1 -12
  69. data/lib/libxml/attr.rb +0 -3
  70. data/lib/libxml/attr_decl.rb +0 -3
  71. data/lib/libxml/attributes.rb +0 -3
  72. data/lib/libxml/document.rb +31 -5
  73. data/lib/libxml/error.rb +8 -4
  74. data/lib/libxml/properties.rb +0 -5
  75. data/lib/libxml/sax_callbacks.rb +30 -19
  76. data/lib/libxml/tree.rb +0 -1
  77. data/lib/libxml/xpath_object.rb +0 -13
  78. data/test/model/definition.dtd +8 -0
  79. data/test/tc_attributes.rb +4 -1
  80. data/test/tc_document.rb +16 -0
  81. data/test/tc_dtd.rb +30 -2
  82. data/test/tc_html_parser.rb +55 -10
  83. data/test/tc_node.rb +67 -1
  84. data/test/tc_node_edit.rb +26 -6
  85. data/test/tc_node_text.rb +41 -23
  86. data/test/tc_parser.rb +50 -0
  87. data/test/tc_reader.rb +15 -0
  88. data/test/tc_relaxng.rb +1 -1
  89. data/test/tc_sax_parser.rb +37 -5
  90. data/test/tc_schema.rb +1 -1
  91. data/test/tc_xpath.rb +1 -0
  92. data/test/tc_xpath_expression.rb +4 -2
  93. metadata +6 -6
  94. data/ext/libxml/ruby_xml_state.c +0 -51
  95. data/ext/libxml/ruby_xml_state.h +0 -11
  96. data/ext/vc/libxml_ruby.vcproj +0 -460
@@ -1,7 +1,7 @@
1
1
  #ifndef _INPUT_CBG_
2
2
  #define _INPUT_CBG_
3
3
 
4
- void ruby_init_input_callbacks(void);
4
+ void rxml_init_input_callbacks(void);
5
5
 
6
6
  typedef struct ic_doc_context {
7
7
  char *buffer;
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_namespace.c 740 2009-01-23 04:03:11Z cfis $ */
1
+ /* $Id: ruby_xml_namespace.c 758 2009-01-25 20:36:03Z cfis $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -158,13 +158,7 @@ static VALUE rxml_namespace_next(VALUE self)
158
158
  return (rxml_namespace_wrap(xns->next, NULL));
159
159
  }
160
160
 
161
- // Rdoc needs to know
162
- #ifdef RDOC_NEVER_DEFINED
163
- mLibXML = rb_define_module("LibXML");
164
- mXML = rb_define_module_under(mLibXML, "XML");
165
- #endif
166
-
167
- void ruby_init_xml_namespace(void)
161
+ void rxml_init_namespace(void)
168
162
  {
169
163
  cXMLNamespace = rb_define_class_under(mXML, "Namespace", rb_cObject);
170
164
  rb_define_alloc_func(cXMLNamespace, rxml_namespace_alloc);
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_namespace.h 739 2009-01-23 03:42:09Z cfis $ */
1
+ /* $Id: ruby_xml_namespace.h 758 2009-01-25 20:36:03Z cfis $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -7,6 +7,6 @@
7
7
 
8
8
  extern VALUE cXMLNamespace;
9
9
 
10
- void ruby_init_xml_namespace(void);
10
+ void rxml_init_namespace(void);
11
11
  VALUE rxml_namespace_wrap(xmlNsPtr xns, RUBY_DATA_FUNC freeFunc);
12
12
  #endif
@@ -277,15 +277,7 @@ static VALUE rxml_namespaces_node_get(VALUE self)
277
277
  return rxml_node_wrap(xnode);
278
278
  }
279
279
 
280
-
281
-
282
- // Rdoc needs to know
283
- #ifdef RDOC_NEVER_DEFINED
284
- mLibXML = rb_define_module("LibXML");
285
- mXML = rb_define_module_under(mLibXML, "XML");
286
- #endif
287
-
288
- void ruby_init_xml_namespaces(void)
280
+ void rxml_init_namespaces(void)
289
281
  {
290
282
  cXMLNamespaces = rb_define_class_under(mXML, "Namespaces", rb_cObject);
291
283
  rb_include_module(cXMLNamespaces, rb_mEnumerable);
@@ -7,5 +7,5 @@
7
7
 
8
8
  extern VALUE cXMLNamespaces;
9
9
 
10
- void ruby_init_xml_namespaces(void);
10
+ void rxml_init_namespaces(void);
11
11
  #endif
@@ -3,9 +3,6 @@
3
3
 
4
4
  VALUE cXMLNode;
5
5
 
6
- static VALUE kXMLStringText;
7
- static VALUE kXMLStringTextNoenc;
8
-
9
6
  /* Document-class: LibXML::XML::Node
10
7
  *
11
8
  * Nodes are the primary objects that make up an XML document.
@@ -29,23 +26,48 @@ VALUE check_string_or_symbol(VALUE val)
29
26
  return rb_obj_as_string(val);
30
27
  }
31
28
 
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.
29
+ /* Memory management:
30
+ *
31
+ * The bindings create a one-to-one mapping between libxml nodes
32
+ * and Ruby nodes. If a libxml node is wraped, its _private member
33
+ * is set with a reference to the Ruby object.
37
34
  *
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.
35
+ * When a libxml document or top level node is freed, it will free
36
+ * all its children. Thus Ruby is responsible for:
37
+ *
38
+ * * Using the mark function to keep alive any documents Ruby is
39
+ * referencing via the document or child nodes.
40
+ * * Using the mark function to keep alive any top level, free
41
+ * standing nodes Ruby is referencing via the node or its children.
42
+ *
43
+ * Ruby will always set a free function when wrapping a node. However,
44
+ * the bindings also register a callback that is invoked by libxml
45
+ * each time a node is freed. When the callback is called, the node's
46
+ * dfree member is set to NULL since Ruby no longer should free the node.
42
47
  */
48
+
49
+ void rxml_node_deregisterNode(xmlNodePtr xnode)
50
+ {
51
+ /* Has the node been wrapped and exposed to Ruby? */
52
+ if (xnode->_private)
53
+ {
54
+ /* Node was wrapped. Set the _private member to free and
55
+ then dislabe the dfree function so that Ruby will not
56
+ try to free the node a second time. */
57
+ VALUE node = (VALUE) xnode->_private;
58
+ RDATA(node)->dfree = NULL;
59
+ xnode->_private = NULL;
60
+ }
61
+ }
62
+
43
63
  void rxml_node_free(xmlNodePtr xnode)
44
64
  {
45
- /* Set _private to NULL so that we won't reuse the
46
- same, freed, Ruby wrapper object later.*/
65
+ /* The Ruby object that wraps the node no longer exists. */
47
66
  xnode->_private = NULL;
48
67
 
68
+ /* Only free nodes that are stand-alone, top level nodes.
69
+ If a node belongs to a document, or a parent node, then
70
+ the document or parent node will free thsi node. */
49
71
  if (xnode->doc == NULL && xnode->parent == NULL)
50
72
  xmlFreeNode(xnode);
51
73
  }
@@ -96,6 +118,9 @@ VALUE rxml_node_wrap(xmlNodePtr xnode)
96
118
  }
97
119
  else
98
120
  {
121
+ /* Assume Ruby is responsible for freeing this node. If libxml frees it
122
+ instead, the rxml_node_deregisterNode callback is executed, and
123
+ we set the free function to NULL. */
99
124
  VALUE node = Data_Wrap_Struct(cXMLNode, rxml_node_mark, rxml_node_free, xnode);
100
125
  xnode->_private = (void*) node;
101
126
  return node;
@@ -104,6 +129,7 @@ VALUE rxml_node_wrap(xmlNodePtr xnode)
104
129
 
105
130
  static VALUE rxml_node_alloc(VALUE klass)
106
131
  {
132
+ /* Ruby is responsible for freeing this node not libxml. */
107
133
  return Data_Wrap_Struct(klass, rxml_node_mark, rxml_node_free, NULL);
108
134
  }
109
135
 
@@ -381,34 +407,26 @@ static VALUE rxml_node_first_get(VALUE self)
381
407
  * underlying for child_set and child_add, difference being
382
408
  * former raises on implicit copy, latter does not.
383
409
  */
384
- static VALUE rxml_node_child_set_aux(VALUE self, VALUE rnode)
410
+ static VALUE rxml_node_child_set_aux(VALUE self, VALUE child)
385
411
  {
386
- xmlNodePtr pnode, chld, ret;
412
+ xmlNodePtr xnode, xchild, xresult;
387
413
 
388
- if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
414
+ if (rb_obj_is_kind_of(child, cXMLNode) == Qfalse)
389
415
  rb_raise(rb_eTypeError, "Must pass an XML::Node object");
390
416
 
391
- Data_Get_Struct(self, xmlNode, pnode);
392
- Data_Get_Struct(rnode, xmlNode, chld);
417
+ Data_Get_Struct(self, xmlNode, xnode);
418
+ Data_Get_Struct(child, xmlNode, xchild);
393
419
 
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.");
420
+ if (xchild->parent != NULL || xchild->doc != NULL)
421
+ rb_raise(rb_eRuntimeError,
422
+ "Cannot move a node from one document to another with child= or <<. First copy the node before moving it.");
398
423
 
399
- ret = xmlAddChild(pnode, chld);
400
- if (ret == NULL)
401
- {
424
+ xresult = xmlAddChild(xnode, xchild);
425
+
426
+ if (!xresult)
402
427
  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);
428
+
429
+ return rxml_node_wrap(xresult);
412
430
  }
413
431
 
414
432
  /*
@@ -603,15 +621,19 @@ static VALUE rxml_node_to_s(int argc, VALUE *argv, VALUE self)
603
621
  static VALUE rxml_node_each(VALUE self)
604
622
  {
605
623
  xmlNodePtr xnode;
606
- xmlNodePtr xchild;
624
+ xmlNodePtr xcurrent;
607
625
  Data_Get_Struct(self, xmlNode, xnode);
608
626
 
609
- xchild = xnode->children;
627
+ xcurrent = xnode->children;
610
628
 
611
- while (xchild)
629
+ while (xcurrent)
612
630
  {
613
- rb_yield(rxml_node_wrap(xchild));
614
- xchild = xchild->next;
631
+ /* The user could remove this node, so first stache
632
+ away the next node. */
633
+ xmlNodePtr xnext = xcurrent->next;
634
+
635
+ rb_yield(rxml_node_wrap(xcurrent));
636
+ xcurrent = xnext;
615
637
  }
616
638
  return Qnil;
617
639
  }
@@ -868,10 +890,6 @@ static VALUE rxml_node_name_get(VALUE self)
868
890
 
869
891
  if (xnode->name == NULL)
870
892
  return (Qnil);
871
- else if (name == xmlStringText)
872
- return (kXMLStringText);
873
- else if (name == xmlStringTextNoenc)
874
- return (kXMLStringTextNoenc);
875
893
  else
876
894
  return (rb_str_new2((const char*) name));
877
895
  }
@@ -891,14 +909,9 @@ static VALUE rxml_node_name_set(VALUE self, VALUE name)
891
909
  Data_Get_Struct(self, xmlNode, xnode);
892
910
  xname = (const xmlChar*)StringValuePtr(name);
893
911
 
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
912
  /* Note: calling xmlNodeSetName() for a text node is ignored by libXML. */
913
+ xmlNodeSetName(xnode, xname);
914
+
902
915
  return (Qtrue);
903
916
  }
904
917
 
@@ -926,21 +939,21 @@ static VALUE rxml_node_next_get(VALUE self)
926
939
  *
927
940
  * Insert the specified node as this node's next sibling.
928
941
  */
929
- static VALUE rxml_node_next_set(VALUE self, VALUE rnode)
942
+ static VALUE rxml_node_next_set(VALUE self, VALUE next)
930
943
  {
931
- xmlNodePtr cnode, pnode, ret;
944
+ xmlNodePtr xnode, xnext, xresult;
932
945
 
933
- if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
946
+ if (rb_obj_is_kind_of(next, cXMLNode) == Qfalse)
934
947
  rb_raise(rb_eTypeError, "Must pass an XML::Node object");
935
948
 
936
- Data_Get_Struct(self, xmlNode, pnode);
937
- Data_Get_Struct(rnode, xmlNode, cnode);
949
+ Data_Get_Struct(self, xmlNode, xnode);
950
+ Data_Get_Struct(next, xmlNode, xnext);
938
951
 
939
- ret = xmlAddNextSibling(pnode, cnode);
940
- if (ret == NULL)
952
+ xresult = xmlAddNextSibling(xnode, xnext);
953
+ if (xresult == NULL)
941
954
  rxml_raise(&xmlLastError);
942
955
 
943
- return (rxml_node_wrap(ret));
956
+ return rxml_node_wrap(xresult);
944
957
  }
945
958
 
946
959
  /*
@@ -1037,21 +1050,21 @@ static VALUE rxml_node_prev_get(VALUE self)
1037
1050
  *
1038
1051
  * Insert the specified node as this node's previous sibling.
1039
1052
  */
1040
- static VALUE rxml_node_prev_set(VALUE self, VALUE rnode)
1053
+ static VALUE rxml_node_prev_set(VALUE self, VALUE prev)
1041
1054
  {
1042
- xmlNodePtr cnode, pnode, ret;
1055
+ xmlNodePtr xnode, xprev, xresult;
1043
1056
 
1044
- if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
1057
+ if (rb_obj_is_kind_of(prev, cXMLNode) == Qfalse)
1045
1058
  rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1046
1059
 
1047
- Data_Get_Struct(self, xmlNode, pnode);
1048
- Data_Get_Struct(rnode, xmlNode, cnode);
1060
+ Data_Get_Struct(self, xmlNode, xnode);
1061
+ Data_Get_Struct(prev, xmlNode, xprev);
1049
1062
 
1050
- ret = xmlAddPrevSibling(pnode, cnode);
1051
- if (ret == NULL)
1063
+ xresult = xmlAddPrevSibling(xnode, xprev);
1064
+ if (xresult == NULL)
1052
1065
  rxml_raise(&xmlLastError);
1053
1066
 
1054
- return (rxml_node_wrap(ret));
1067
+ return rxml_node_wrap(xresult);
1055
1068
  }
1056
1069
 
1057
1070
  /*
@@ -1108,8 +1121,10 @@ static VALUE rxml_node_remove_ex(VALUE self)
1108
1121
  {
1109
1122
  xmlNodePtr xnode;
1110
1123
  Data_Get_Struct(self, xmlNode, xnode);
1124
+
1111
1125
  /* Unlink the node from its parent. */
1112
1126
  xmlUnlinkNode(xnode);
1127
+
1113
1128
  /* Now set the nodes parent to nil so it can
1114
1129
  be freed if the reference to it goes out of scope*/
1115
1130
  xmlSetTreeDoc(xnode, NULL);
@@ -1125,27 +1140,111 @@ static VALUE rxml_node_remove_ex(VALUE self)
1125
1140
  *
1126
1141
  * Add the specified node as a sibling of this node.
1127
1142
  */
1128
- static VALUE rxml_node_sibling_set(VALUE self, VALUE rnode)
1143
+ static VALUE rxml_node_sibling_set(VALUE self, VALUE sibling)
1129
1144
  {
1130
- xmlNodePtr cnode, pnode, ret;
1131
- VALUE obj;
1145
+ xmlNodePtr xnode, xsibling, xresult;
1132
1146
 
1133
- if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
1147
+ if (rb_obj_is_kind_of(sibling, cXMLNode) == Qfalse)
1134
1148
  rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1135
1149
 
1136
- Data_Get_Struct(self, xmlNode, pnode);
1137
- Data_Get_Struct(rnode, xmlNode, cnode);
1150
+ Data_Get_Struct(self, xmlNode, xnode);
1151
+ Data_Get_Struct(sibling, xmlNode, xsibling);
1138
1152
 
1139
- ret = xmlAddSibling(pnode, cnode);
1140
- if (ret == NULL)
1153
+ xresult = xmlAddSibling(xnode, xsibling);
1154
+ if (xresult == NULL)
1141
1155
  rxml_raise(&xmlLastError);
1142
1156
 
1143
- if (ret->_private == NULL)
1144
- obj = rxml_node_wrap(ret);
1145
- else
1146
- obj = (VALUE) ret->_private;
1157
+ return rxml_node_wrap(xresult);
1158
+ }
1147
1159
 
1148
- return obj;
1160
+ /*
1161
+ * call-seq:
1162
+ * text_node.output_escaping? -> (true|false)
1163
+ * element_node.output_escaping? -> (true|false|nil)
1164
+ * attribute_node.output_escaping? -> (true|false|nil)
1165
+ * other_node.output_escaping? -> (nil)
1166
+ *
1167
+ * Determine whether this node escapes it's output or not.
1168
+ *
1169
+ * Text nodes return only +true+ or +false+. Element and attribute nodes
1170
+ * examine their immediate text node children to determine the value.
1171
+ * Any other type of node always returns +nil+.
1172
+ *
1173
+ * If an element or attribute node has at least one immediate child text node
1174
+ * and all the immediate text node children have the same +output_escaping?+
1175
+ * value, that value is returned. Otherwise, +nil+ is returned.
1176
+ */
1177
+ static VALUE rxml_node_output_escaping_q(VALUE self)
1178
+ {
1179
+ xmlNodePtr xnode;
1180
+ Data_Get_Struct(self, xmlNode, xnode);
1181
+
1182
+ switch (xnode->type) {
1183
+ case XML_TEXT_NODE:
1184
+ return xnode->name==xmlStringTextNoenc ? Qfalse : Qtrue;
1185
+ case XML_ELEMENT_NODE:
1186
+ case XML_ATTRIBUTE_NODE:
1187
+ {
1188
+ xmlNodePtr tmp = xnode->children;
1189
+ const xmlChar *match = NULL;
1190
+
1191
+ /* Find the first text node and use it as the reference. */
1192
+ while (tmp && tmp->type != XML_TEXT_NODE)
1193
+ tmp = tmp->next;
1194
+ if (! tmp)
1195
+ return Qnil;
1196
+ match = tmp->name;
1197
+
1198
+ /* Walk the remaining text nodes until we run out or one doesn't match. */
1199
+ while (tmp && (tmp->type != XML_TEXT_NODE || match == tmp->name))
1200
+ tmp = tmp->next;
1201
+
1202
+ /* We're left with either the mismatched node or the aggregate result. */
1203
+ return tmp ? Qnil : (match==xmlStringTextNoenc ? Qfalse : Qtrue);
1204
+ }
1205
+ break;
1206
+ default:
1207
+ return Qnil;
1208
+ }
1209
+ }
1210
+
1211
+ /*
1212
+ * call-seq:
1213
+ * text_node.output_escaping = true|false
1214
+ * element_node.output_escaping = true|false
1215
+ * attribute_node.output_escaping = true|false
1216
+ *
1217
+ * Controls whether this text node or the immediate text node children of an
1218
+ * element or attribute node escapes their output. Any other type of node
1219
+ * will simply ignore this operation.
1220
+ *
1221
+ * Text nodes which are added to an element or attribute node will be affected
1222
+ * by any previous setting of this property.
1223
+ */
1224
+ static VALUE rxml_node_output_escaping_set(VALUE self, VALUE bool)
1225
+ {
1226
+ xmlNodePtr xnode;
1227
+ Data_Get_Struct(self, xmlNode, xnode);
1228
+
1229
+ switch (xnode->type) {
1230
+ case XML_TEXT_NODE:
1231
+ xnode->name = (bool!=Qfalse && bool!=Qnil) ? xmlStringText : xmlStringTextNoenc;
1232
+ break;
1233
+ case XML_ELEMENT_NODE:
1234
+ case XML_ATTRIBUTE_NODE:
1235
+ {
1236
+ const xmlChar *name = (bool!=Qfalse && bool!=Qnil) ? xmlStringText : xmlStringTextNoenc;
1237
+ xmlNodePtr tmp;
1238
+ for (tmp = xnode->children; tmp; tmp = tmp->next)
1239
+ if (tmp->type == XML_TEXT_NODE)
1240
+ tmp->name = name;
1241
+ }
1242
+ break;
1243
+ default:
1244
+ return Qnil;
1245
+ }
1246
+
1247
+ return (bool!=Qfalse && bool!=Qnil) ? Qtrue : Qfalse;
1149
1248
  }
1150
1249
 
1151
1250
  /*
@@ -1219,47 +1318,10 @@ static VALUE rxml_node_copy(VALUE self, VALUE deep)
1219
1318
  return Qnil;
1220
1319
  }
1221
1320
 
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)
1321
+ void rxml_init_node(void)
1256
1322
  {
1257
- xmlRegisterNodeDefault(rxml_node_registerNode);
1258
1323
  xmlDeregisterNodeDefault(rxml_node_deregisterNode);
1259
1324
 
1260
- kXMLStringText = rxml_constant_stringref(xmlStringText);
1261
- kXMLStringTextNoenc = rxml_constant_stringref(xmlStringTextNoenc);
1262
-
1263
1325
  cXMLNode = rb_define_class_under(mXML, "Node", rb_cObject);
1264
1326
 
1265
1327
  rb_define_const(cXMLNode, "SPACE_DEFAULT", INT2NUM(0));
@@ -1304,9 +1366,6 @@ void ruby_init_xml_node(void)
1304
1366
  rb_define_const(cXMLNode, "DOCB_DOCUMENT_NODE", Qnil);
1305
1367
  #endif
1306
1368
 
1307
- rb_define_const(cXMLNode, "XML_STRING_TEXT", kXMLStringText);
1308
- rb_define_const(cXMLNode, "XML_STRING_TEXT_NOENC", kXMLStringTextNoenc);
1309
-
1310
1369
  rb_define_singleton_method(cXMLNode, "new_cdata", rxml_node_new_cdata, -1);
1311
1370
  rb_define_singleton_method(cXMLNode, "new_comment", rxml_node_new_comment, -1);
1312
1371
  rb_define_singleton_method(cXMLNode, "new_text", rxml_node_new_text, 1);
@@ -1353,6 +1412,8 @@ void ruby_init_xml_node(void)
1353
1412
  rb_define_method(cXMLNode, "name", rxml_node_name_get, 0);
1354
1413
  rb_define_method(cXMLNode, "name=", rxml_node_name_set, 1);
1355
1414
  rb_define_method(cXMLNode, "node_type", rxml_node_type, 0);
1415
+ rb_define_method(cXMLNode, "output_escaping?", rxml_node_output_escaping_q, 0);
1416
+ rb_define_method(cXMLNode, "output_escaping=", rxml_node_output_escaping_set, 1);
1356
1417
  rb_define_method(cXMLNode, "path", rxml_node_path, 0);
1357
1418
  rb_define_method(cXMLNode, "pointer", rxml_node_pointer, 1);
1358
1419
  rb_define_method(cXMLNode, "remove!", rxml_node_remove_ex, 0);