nokogiri 1.13.0-aarch64-linux

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (198) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +5 -0
  3. data/LICENSE-DEPENDENCIES.md +1903 -0
  4. data/LICENSE.md +9 -0
  5. data/README.md +280 -0
  6. data/bin/nokogiri +131 -0
  7. data/dependencies.yml +73 -0
  8. data/ext/nokogiri/depend +38 -0
  9. data/ext/nokogiri/extconf.rb +1000 -0
  10. data/ext/nokogiri/gumbo.c +584 -0
  11. data/ext/nokogiri/html4_document.c +166 -0
  12. data/ext/nokogiri/html4_element_description.c +294 -0
  13. data/ext/nokogiri/html4_entity_lookup.c +37 -0
  14. data/ext/nokogiri/html4_sax_parser_context.c +120 -0
  15. data/ext/nokogiri/html4_sax_push_parser.c +95 -0
  16. data/ext/nokogiri/include/libexslt/exslt.h +102 -0
  17. data/ext/nokogiri/include/libexslt/exsltconfig.h +70 -0
  18. data/ext/nokogiri/include/libexslt/exsltexports.h +140 -0
  19. data/ext/nokogiri/include/libxml2/libxml/DOCBparser.h +96 -0
  20. data/ext/nokogiri/include/libxml2/libxml/HTMLparser.h +306 -0
  21. data/ext/nokogiri/include/libxml2/libxml/HTMLtree.h +147 -0
  22. data/ext/nokogiri/include/libxml2/libxml/SAX.h +173 -0
  23. data/ext/nokogiri/include/libxml2/libxml/SAX2.h +178 -0
  24. data/ext/nokogiri/include/libxml2/libxml/c14n.h +128 -0
  25. data/ext/nokogiri/include/libxml2/libxml/catalog.h +182 -0
  26. data/ext/nokogiri/include/libxml2/libxml/chvalid.h +230 -0
  27. data/ext/nokogiri/include/libxml2/libxml/debugXML.h +217 -0
  28. data/ext/nokogiri/include/libxml2/libxml/dict.h +79 -0
  29. data/ext/nokogiri/include/libxml2/libxml/encoding.h +245 -0
  30. data/ext/nokogiri/include/libxml2/libxml/entities.h +151 -0
  31. data/ext/nokogiri/include/libxml2/libxml/globals.h +508 -0
  32. data/ext/nokogiri/include/libxml2/libxml/hash.h +236 -0
  33. data/ext/nokogiri/include/libxml2/libxml/list.h +137 -0
  34. data/ext/nokogiri/include/libxml2/libxml/nanoftp.h +163 -0
  35. data/ext/nokogiri/include/libxml2/libxml/nanohttp.h +81 -0
  36. data/ext/nokogiri/include/libxml2/libxml/parser.h +1243 -0
  37. data/ext/nokogiri/include/libxml2/libxml/parserInternals.h +644 -0
  38. data/ext/nokogiri/include/libxml2/libxml/pattern.h +100 -0
  39. data/ext/nokogiri/include/libxml2/libxml/relaxng.h +217 -0
  40. data/ext/nokogiri/include/libxml2/libxml/schemasInternals.h +958 -0
  41. data/ext/nokogiri/include/libxml2/libxml/schematron.h +142 -0
  42. data/ext/nokogiri/include/libxml2/libxml/threads.h +89 -0
  43. data/ext/nokogiri/include/libxml2/libxml/tree.h +1311 -0
  44. data/ext/nokogiri/include/libxml2/libxml/uri.h +94 -0
  45. data/ext/nokogiri/include/libxml2/libxml/valid.h +458 -0
  46. data/ext/nokogiri/include/libxml2/libxml/xinclude.h +129 -0
  47. data/ext/nokogiri/include/libxml2/libxml/xlink.h +189 -0
  48. data/ext/nokogiri/include/libxml2/libxml/xmlIO.h +368 -0
  49. data/ext/nokogiri/include/libxml2/libxml/xmlautomata.h +146 -0
  50. data/ext/nokogiri/include/libxml2/libxml/xmlerror.h +946 -0
  51. data/ext/nokogiri/include/libxml2/libxml/xmlexports.h +77 -0
  52. data/ext/nokogiri/include/libxml2/libxml/xmlmemory.h +224 -0
  53. data/ext/nokogiri/include/libxml2/libxml/xmlmodule.h +57 -0
  54. data/ext/nokogiri/include/libxml2/libxml/xmlreader.h +428 -0
  55. data/ext/nokogiri/include/libxml2/libxml/xmlregexp.h +222 -0
  56. data/ext/nokogiri/include/libxml2/libxml/xmlsave.h +88 -0
  57. data/ext/nokogiri/include/libxml2/libxml/xmlschemas.h +246 -0
  58. data/ext/nokogiri/include/libxml2/libxml/xmlschemastypes.h +151 -0
  59. data/ext/nokogiri/include/libxml2/libxml/xmlstring.h +140 -0
  60. data/ext/nokogiri/include/libxml2/libxml/xmlunicode.h +202 -0
  61. data/ext/nokogiri/include/libxml2/libxml/xmlversion.h +485 -0
  62. data/ext/nokogiri/include/libxml2/libxml/xmlwriter.h +488 -0
  63. data/ext/nokogiri/include/libxml2/libxml/xpath.h +564 -0
  64. data/ext/nokogiri/include/libxml2/libxml/xpathInternals.h +632 -0
  65. data/ext/nokogiri/include/libxml2/libxml/xpointer.h +114 -0
  66. data/ext/nokogiri/include/libxslt/attributes.h +38 -0
  67. data/ext/nokogiri/include/libxslt/documents.h +93 -0
  68. data/ext/nokogiri/include/libxslt/extensions.h +262 -0
  69. data/ext/nokogiri/include/libxslt/extra.h +72 -0
  70. data/ext/nokogiri/include/libxslt/functions.h +78 -0
  71. data/ext/nokogiri/include/libxslt/imports.h +75 -0
  72. data/ext/nokogiri/include/libxslt/keys.h +53 -0
  73. data/ext/nokogiri/include/libxslt/namespaces.h +68 -0
  74. data/ext/nokogiri/include/libxslt/numbersInternals.h +73 -0
  75. data/ext/nokogiri/include/libxslt/pattern.h +84 -0
  76. data/ext/nokogiri/include/libxslt/preproc.h +43 -0
  77. data/ext/nokogiri/include/libxslt/security.h +104 -0
  78. data/ext/nokogiri/include/libxslt/templates.h +77 -0
  79. data/ext/nokogiri/include/libxslt/transform.h +207 -0
  80. data/ext/nokogiri/include/libxslt/variables.h +118 -0
  81. data/ext/nokogiri/include/libxslt/xslt.h +110 -0
  82. data/ext/nokogiri/include/libxslt/xsltInternals.h +1978 -0
  83. data/ext/nokogiri/include/libxslt/xsltconfig.h +180 -0
  84. data/ext/nokogiri/include/libxslt/xsltexports.h +142 -0
  85. data/ext/nokogiri/include/libxslt/xsltlocale.h +76 -0
  86. data/ext/nokogiri/include/libxslt/xsltutils.h +313 -0
  87. data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
  88. data/ext/nokogiri/nokogiri.c +278 -0
  89. data/ext/nokogiri/nokogiri.h +223 -0
  90. data/ext/nokogiri/test_global_handlers.c +40 -0
  91. data/ext/nokogiri/xml_attr.c +103 -0
  92. data/ext/nokogiri/xml_attribute_decl.c +70 -0
  93. data/ext/nokogiri/xml_cdata.c +57 -0
  94. data/ext/nokogiri/xml_comment.c +62 -0
  95. data/ext/nokogiri/xml_document.c +680 -0
  96. data/ext/nokogiri/xml_document_fragment.c +44 -0
  97. data/ext/nokogiri/xml_dtd.c +208 -0
  98. data/ext/nokogiri/xml_element_content.c +128 -0
  99. data/ext/nokogiri/xml_element_decl.c +69 -0
  100. data/ext/nokogiri/xml_encoding_handler.c +104 -0
  101. data/ext/nokogiri/xml_entity_decl.c +112 -0
  102. data/ext/nokogiri/xml_entity_reference.c +50 -0
  103. data/ext/nokogiri/xml_namespace.c +120 -0
  104. data/ext/nokogiri/xml_node.c +2144 -0
  105. data/ext/nokogiri/xml_node_set.c +498 -0
  106. data/ext/nokogiri/xml_processing_instruction.c +54 -0
  107. data/ext/nokogiri/xml_reader.c +719 -0
  108. data/ext/nokogiri/xml_relax_ng.c +185 -0
  109. data/ext/nokogiri/xml_sax_parser.c +310 -0
  110. data/ext/nokogiri/xml_sax_parser_context.c +281 -0
  111. data/ext/nokogiri/xml_sax_push_parser.c +168 -0
  112. data/ext/nokogiri/xml_schema.c +284 -0
  113. data/ext/nokogiri/xml_syntax_error.c +85 -0
  114. data/ext/nokogiri/xml_text.c +48 -0
  115. data/ext/nokogiri/xml_xpath_context.c +406 -0
  116. data/ext/nokogiri/xslt_stylesheet.c +264 -0
  117. data/gumbo-parser/CHANGES.md +63 -0
  118. data/gumbo-parser/Makefile +101 -0
  119. data/gumbo-parser/THANKS +27 -0
  120. data/lib/nokogiri/2.6/nokogiri.so +0 -0
  121. data/lib/nokogiri/2.7/nokogiri.so +0 -0
  122. data/lib/nokogiri/3.0/nokogiri.so +0 -0
  123. data/lib/nokogiri/3.1/nokogiri.so +0 -0
  124. data/lib/nokogiri/class_resolver.rb +67 -0
  125. data/lib/nokogiri/css/node.rb +54 -0
  126. data/lib/nokogiri/css/parser.rb +759 -0
  127. data/lib/nokogiri/css/parser.y +280 -0
  128. data/lib/nokogiri/css/parser_extras.rb +94 -0
  129. data/lib/nokogiri/css/syntax_error.rb +9 -0
  130. data/lib/nokogiri/css/tokenizer.rb +155 -0
  131. data/lib/nokogiri/css/tokenizer.rex +56 -0
  132. data/lib/nokogiri/css/xpath_visitor.rb +359 -0
  133. data/lib/nokogiri/css.rb +60 -0
  134. data/lib/nokogiri/decorators/slop.rb +44 -0
  135. data/lib/nokogiri/extension.rb +31 -0
  136. data/lib/nokogiri/gumbo.rb +15 -0
  137. data/lib/nokogiri/html.rb +48 -0
  138. data/lib/nokogiri/html4/builder.rb +37 -0
  139. data/lib/nokogiri/html4/document.rb +331 -0
  140. data/lib/nokogiri/html4/document_fragment.rb +54 -0
  141. data/lib/nokogiri/html4/element_description.rb +25 -0
  142. data/lib/nokogiri/html4/element_description_defaults.rb +578 -0
  143. data/lib/nokogiri/html4/entity_lookup.rb +15 -0
  144. data/lib/nokogiri/html4/sax/parser.rb +61 -0
  145. data/lib/nokogiri/html4/sax/parser_context.rb +20 -0
  146. data/lib/nokogiri/html4/sax/push_parser.rb +37 -0
  147. data/lib/nokogiri/html4.rb +46 -0
  148. data/lib/nokogiri/html5/document.rb +88 -0
  149. data/lib/nokogiri/html5/document_fragment.rb +83 -0
  150. data/lib/nokogiri/html5/node.rb +96 -0
  151. data/lib/nokogiri/html5.rb +477 -0
  152. data/lib/nokogiri/jruby/dependencies.rb +21 -0
  153. data/lib/nokogiri/syntax_error.rb +6 -0
  154. data/lib/nokogiri/version/constant.rb +6 -0
  155. data/lib/nokogiri/version/info.rb +221 -0
  156. data/lib/nokogiri/version.rb +4 -0
  157. data/lib/nokogiri/xml/attr.rb +17 -0
  158. data/lib/nokogiri/xml/attribute_decl.rb +20 -0
  159. data/lib/nokogiri/xml/builder.rb +485 -0
  160. data/lib/nokogiri/xml/cdata.rb +13 -0
  161. data/lib/nokogiri/xml/character_data.rb +9 -0
  162. data/lib/nokogiri/xml/document.rb +418 -0
  163. data/lib/nokogiri/xml/document_fragment.rb +162 -0
  164. data/lib/nokogiri/xml/dtd.rb +34 -0
  165. data/lib/nokogiri/xml/element_content.rb +38 -0
  166. data/lib/nokogiri/xml/element_decl.rb +15 -0
  167. data/lib/nokogiri/xml/entity_decl.rb +21 -0
  168. data/lib/nokogiri/xml/entity_reference.rb +20 -0
  169. data/lib/nokogiri/xml/namespace.rb +16 -0
  170. data/lib/nokogiri/xml/node/save_options.rb +65 -0
  171. data/lib/nokogiri/xml/node.rb +1402 -0
  172. data/lib/nokogiri/xml/node_set.rb +364 -0
  173. data/lib/nokogiri/xml/notation.rb +19 -0
  174. data/lib/nokogiri/xml/parse_options.rb +133 -0
  175. data/lib/nokogiri/xml/pp/character_data.rb +21 -0
  176. data/lib/nokogiri/xml/pp/node.rb +55 -0
  177. data/lib/nokogiri/xml/pp.rb +4 -0
  178. data/lib/nokogiri/xml/processing_instruction.rb +10 -0
  179. data/lib/nokogiri/xml/reader.rb +107 -0
  180. data/lib/nokogiri/xml/relax_ng.rb +38 -0
  181. data/lib/nokogiri/xml/sax/document.rb +167 -0
  182. data/lib/nokogiri/xml/sax/parser.rb +125 -0
  183. data/lib/nokogiri/xml/sax/parser_context.rb +21 -0
  184. data/lib/nokogiri/xml/sax/push_parser.rb +61 -0
  185. data/lib/nokogiri/xml/sax.rb +6 -0
  186. data/lib/nokogiri/xml/schema.rb +73 -0
  187. data/lib/nokogiri/xml/searchable.rb +259 -0
  188. data/lib/nokogiri/xml/syntax_error.rb +71 -0
  189. data/lib/nokogiri/xml/text.rb +11 -0
  190. data/lib/nokogiri/xml/xpath/syntax_error.rb +13 -0
  191. data/lib/nokogiri/xml/xpath.rb +21 -0
  192. data/lib/nokogiri/xml/xpath_context.rb +16 -0
  193. data/lib/nokogiri/xml.rb +75 -0
  194. data/lib/nokogiri/xslt/stylesheet.rb +27 -0
  195. data/lib/nokogiri/xslt.rb +58 -0
  196. data/lib/nokogiri.rb +128 -0
  197. data/lib/xsd/xmlparser/nokogiri.rb +104 -0
  198. metadata +539 -0
@@ -0,0 +1,2144 @@
1
+ #include <nokogiri.h>
2
+
3
+ // :stopdoc:
4
+
5
+ VALUE cNokogiriXmlNode ;
6
+ static ID id_decorate, id_decorate_bang;
7
+
8
+ typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
9
+
10
+
11
+ #ifdef DEBUG
12
+ static void
13
+ _xml_node_dealloc(xmlNodePtr x)
14
+ {
15
+ NOKOGIRI_DEBUG_START(x)
16
+ NOKOGIRI_DEBUG_END(x)
17
+ }
18
+ #else
19
+ # define _xml_node_dealloc 0
20
+ #endif
21
+
22
+
23
+ static void
24
+ _xml_node_mark(xmlNodePtr node)
25
+ {
26
+ xmlDocPtr doc = node->doc;
27
+ if (doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
28
+ if (DOC_RUBY_OBJECT_TEST(doc)) {
29
+ rb_gc_mark(DOC_RUBY_OBJECT(doc));
30
+ }
31
+ } else if (node->doc->_private) {
32
+ rb_gc_mark((VALUE)doc->_private);
33
+ }
34
+ }
35
+
36
+
37
+ static void
38
+ relink_namespace(xmlNodePtr reparented)
39
+ {
40
+ xmlNodePtr child;
41
+ xmlAttrPtr attr;
42
+
43
+ if (reparented->type != XML_ATTRIBUTE_NODE &&
44
+ reparented->type != XML_ELEMENT_NODE) { return; }
45
+
46
+ if (reparented->ns == NULL || reparented->ns->prefix == NULL) {
47
+ xmlNsPtr ns = NULL;
48
+ xmlChar *name = NULL, *prefix = NULL;
49
+
50
+ name = xmlSplitQName2(reparented->name, &prefix);
51
+
52
+ if (reparented->type == XML_ATTRIBUTE_NODE) {
53
+ if (prefix == NULL || strcmp((char *)prefix, XMLNS_PREFIX) == 0) {
54
+ xmlFree(name);
55
+ xmlFree(prefix);
56
+ return;
57
+ }
58
+ }
59
+
60
+ ns = xmlSearchNs(reparented->doc, reparented, prefix);
61
+
62
+ if (ns != NULL) {
63
+ xmlNodeSetName(reparented, name);
64
+ xmlSetNs(reparented, ns);
65
+ }
66
+
67
+ xmlFree(name);
68
+ xmlFree(prefix);
69
+ }
70
+
71
+ /* Avoid segv when relinking against unlinked nodes. */
72
+ if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; }
73
+
74
+ /* Make sure that our reparented node has the correct namespaces */
75
+ if (!reparented->ns &&
76
+ (reparented->doc != (xmlDocPtr)reparented->parent) &&
77
+ (rb_iv_get(DOC_RUBY_OBJECT(reparented->doc), "@namespace_inheritance") == Qtrue)) {
78
+ xmlSetNs(reparented, reparented->parent->ns);
79
+ }
80
+
81
+ /* Search our parents for an existing definition */
82
+ if (reparented->nsDef) {
83
+ xmlNsPtr curr = reparented->nsDef;
84
+ xmlNsPtr prev = NULL;
85
+
86
+ while (curr) {
87
+ xmlNsPtr ns = xmlSearchNsByHref(
88
+ reparented->doc,
89
+ reparented->parent,
90
+ curr->href
91
+ );
92
+ /* If we find the namespace is already declared, remove it from this
93
+ * definition list. */
94
+ if (ns && ns != curr && xmlStrEqual(ns->prefix, curr->prefix)) {
95
+ if (prev) {
96
+ prev->next = curr->next;
97
+ } else {
98
+ reparented->nsDef = curr->next;
99
+ }
100
+ noko_xml_document_pin_namespace(curr, reparented->doc);
101
+ } else {
102
+ prev = curr;
103
+ }
104
+ curr = curr->next;
105
+ }
106
+ }
107
+
108
+ /*
109
+ * Search our parents for an existing definition of current namespace,
110
+ * because the definition it's pointing to may have just been removed nsDef.
111
+ *
112
+ * And although that would technically probably be OK, I'd feel better if we
113
+ * referred to a namespace that's still present in a node's nsDef somewhere
114
+ * in the doc.
115
+ */
116
+ if (reparented->ns) {
117
+ xmlNsPtr ns = xmlSearchNs(reparented->doc, reparented, reparented->ns->prefix);
118
+ if (ns
119
+ && ns != reparented->ns
120
+ && xmlStrEqual(ns->prefix, reparented->ns->prefix)
121
+ && xmlStrEqual(ns->href, reparented->ns->href)
122
+ ) {
123
+ xmlSetNs(reparented, ns);
124
+ }
125
+ }
126
+
127
+ /* Only walk all children if there actually is a namespace we need to */
128
+ /* reparent. */
129
+ if (NULL == reparented->ns) { return; }
130
+
131
+ /* When a node gets reparented, walk it's children to make sure that */
132
+ /* their namespaces are reparented as well. */
133
+ child = reparented->children;
134
+ while (NULL != child) {
135
+ relink_namespace(child);
136
+ child = child->next;
137
+ }
138
+
139
+ if (reparented->type == XML_ELEMENT_NODE) {
140
+ attr = reparented->properties;
141
+ while (NULL != attr) {
142
+ relink_namespace((xmlNodePtr)attr);
143
+ attr = attr->next;
144
+ }
145
+ }
146
+ }
147
+
148
+
149
+ /* internal function meant to wrap xmlReplaceNode
150
+ and fix some issues we have with libxml2 merging nodes */
151
+ static xmlNodePtr
152
+ xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
153
+ {
154
+ xmlNodePtr retval ;
155
+
156
+ retval = xmlReplaceNode(pivot, new_node) ;
157
+
158
+ if (retval == pivot) {
159
+ retval = new_node ; /* return semantics for reparent_node_with */
160
+ }
161
+
162
+ /* work around libxml2 issue: https://bugzilla.gnome.org/show_bug.cgi?id=615612 */
163
+ if (retval && retval->type == XML_TEXT_NODE) {
164
+ if (retval->prev && retval->prev->type == XML_TEXT_NODE) {
165
+ retval = xmlTextMerge(retval->prev, retval);
166
+ }
167
+ if (retval->next && retval->next->type == XML_TEXT_NODE) {
168
+ retval = xmlTextMerge(retval, retval->next);
169
+ }
170
+ }
171
+
172
+ return retval ;
173
+ }
174
+
175
+
176
+ static void
177
+ raise_if_ancestor_of_self(xmlNodePtr self)
178
+ {
179
+ for (xmlNodePtr ancestor = self->parent ; ancestor ; ancestor = ancestor->parent) {
180
+ if (self == ancestor) {
181
+ rb_raise(rb_eRuntimeError, "cycle detected: node '%s' is an ancestor of itself", self->name);
182
+ }
183
+ }
184
+ }
185
+
186
+
187
+ static VALUE
188
+ reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
189
+ {
190
+ VALUE reparented_obj ;
191
+ xmlNodePtr reparentee, original_reparentee, pivot, reparented, next_text, new_next_text, parent ;
192
+ int original_ns_prefix_is_default = 0 ;
193
+
194
+ if (!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) {
195
+ rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
196
+ }
197
+ if (rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument)) {
198
+ rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
199
+ }
200
+
201
+ Data_Get_Struct(reparentee_obj, xmlNode, reparentee);
202
+ Data_Get_Struct(pivot_obj, xmlNode, pivot);
203
+
204
+ /*
205
+ * Check if nodes given are appropriate to have a parent-child
206
+ * relationship, based on the DOM specification.
207
+ *
208
+ * cf. http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-1590626202
209
+ */
210
+ if (prf == xmlAddChild) {
211
+ parent = pivot;
212
+ } else {
213
+ parent = pivot->parent;
214
+ }
215
+
216
+ if (parent) {
217
+ switch (parent->type) {
218
+ case XML_DOCUMENT_NODE:
219
+ case XML_HTML_DOCUMENT_NODE:
220
+ switch (reparentee->type) {
221
+ case XML_ELEMENT_NODE:
222
+ case XML_PI_NODE:
223
+ case XML_COMMENT_NODE:
224
+ case XML_DOCUMENT_TYPE_NODE:
225
+ /*
226
+ * The DOM specification says no to adding text-like nodes
227
+ * directly to a document, but we allow it for compatibility.
228
+ */
229
+ case XML_TEXT_NODE:
230
+ case XML_CDATA_SECTION_NODE:
231
+ case XML_ENTITY_REF_NODE:
232
+ goto ok;
233
+ default:
234
+ break;
235
+ }
236
+ break;
237
+ case XML_DOCUMENT_FRAG_NODE:
238
+ case XML_ENTITY_REF_NODE:
239
+ case XML_ELEMENT_NODE:
240
+ switch (reparentee->type) {
241
+ case XML_ELEMENT_NODE:
242
+ case XML_PI_NODE:
243
+ case XML_COMMENT_NODE:
244
+ case XML_TEXT_NODE:
245
+ case XML_CDATA_SECTION_NODE:
246
+ case XML_ENTITY_REF_NODE:
247
+ goto ok;
248
+ default:
249
+ break;
250
+ }
251
+ break;
252
+ case XML_ATTRIBUTE_NODE:
253
+ switch (reparentee->type) {
254
+ case XML_TEXT_NODE:
255
+ case XML_ENTITY_REF_NODE:
256
+ goto ok;
257
+ default:
258
+ break;
259
+ }
260
+ break;
261
+ case XML_TEXT_NODE:
262
+ /*
263
+ * xmlAddChild() breaks the DOM specification in that it allows
264
+ * adding a text node to another, in which case text nodes are
265
+ * coalesced, but since our JRuby version does not support such
266
+ * operation, we should inhibit it.
267
+ */
268
+ break;
269
+ default:
270
+ break;
271
+ }
272
+
273
+ rb_raise(rb_eArgError, "cannot reparent %s there", rb_obj_classname(reparentee_obj));
274
+ }
275
+
276
+ ok:
277
+ original_reparentee = reparentee;
278
+
279
+ if (reparentee->doc != pivot->doc || reparentee->type == XML_TEXT_NODE) {
280
+ /*
281
+ * if the reparentee is a text node, there's a very good chance it will be
282
+ * merged with an adjacent text node after being reparented, and in that case
283
+ * libxml will free the underlying C struct.
284
+ *
285
+ * since we clearly have a ruby object which references the underlying
286
+ * memory, we can't let the C struct get freed. let's pickle the original
287
+ * reparentee by rooting it; and then we'll reparent a duplicate of the
288
+ * node that we don't care about preserving.
289
+ *
290
+ * alternatively, if the reparentee is from a different document than the
291
+ * pivot node, libxml2 is going to get confused about which document's
292
+ * "dictionary" the node's strings belong to (this is an otherwise
293
+ * uninteresting libxml2 implementation detail). as a result, we cannot
294
+ * reparent the actual reparentee, so we reparent a duplicate.
295
+ */
296
+ if (reparentee->type == XML_TEXT_NODE && reparentee->_private) {
297
+ /*
298
+ * additionally, since we know this C struct isn't going to be related to
299
+ * a Ruby object anymore, let's break the relationship on this end as
300
+ * well.
301
+ *
302
+ * this is not absolutely necessary unless libxml-ruby is also in effect,
303
+ * in which case its global callback `rxml_node_deregisterNode` will try
304
+ * to do things to our data.
305
+ *
306
+ * for more details on this particular (and particularly nasty) edge
307
+ * case, see:
308
+ *
309
+ * https://github.com/sparklemotion/nokogiri/issues/1426
310
+ */
311
+ reparentee->_private = NULL ;
312
+ }
313
+
314
+ if (reparentee->ns != NULL && reparentee->ns->prefix == NULL) {
315
+ original_ns_prefix_is_default = 1;
316
+ }
317
+
318
+ noko_xml_document_pin_node(reparentee);
319
+
320
+ if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) {
321
+ rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
322
+ }
323
+
324
+ if (original_ns_prefix_is_default && reparentee->ns != NULL && reparentee->ns->prefix != NULL) {
325
+ /*
326
+ * issue #391, where new node's prefix may become the string "default"
327
+ * see libxml2 tree.c xmlNewReconciliedNs which implements this behavior.
328
+ */
329
+ xmlFree(DISCARD_CONST_QUAL_XMLCHAR(reparentee->ns->prefix));
330
+ reparentee->ns->prefix = NULL;
331
+ }
332
+ }
333
+
334
+ xmlUnlinkNode(original_reparentee);
335
+
336
+ if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling
337
+ && reparentee->type == XML_TEXT_NODE && pivot->next && pivot->next->type == XML_TEXT_NODE) {
338
+ /*
339
+ * libxml merges text nodes in a right-to-left fashion, meaning that if
340
+ * there are two text nodes who would be adjacent, the right (or following,
341
+ * or next) node will be merged into the left (or preceding, or previous)
342
+ * node.
343
+ *
344
+ * and by "merged" I mean the string contents will be concatenated onto the
345
+ * left node's contents, and then the node will be freed.
346
+ *
347
+ * which means that if we have a ruby object wrapped around the right node,
348
+ * its memory would be freed out from under it.
349
+ *
350
+ * so, we detect this edge case and unlink-and-root the text node before it gets
351
+ * merged. then we dup the node and insert that duplicate back into the
352
+ * document where the real node was.
353
+ *
354
+ * yes, this is totally lame.
355
+ */
356
+ next_text = pivot->next ;
357
+ new_next_text = xmlDocCopyNode(next_text, pivot->doc, 1) ;
358
+
359
+ xmlUnlinkNode(next_text);
360
+ noko_xml_document_pin_node(next_text);
361
+
362
+ xmlAddNextSibling(pivot, new_next_text);
363
+ }
364
+
365
+ if (!(reparented = (*prf)(pivot, reparentee))) {
366
+ rb_raise(rb_eRuntimeError, "Could not reparent node");
367
+ }
368
+
369
+ /*
370
+ * make sure the ruby object is pointed at the just-reparented node, which
371
+ * might be a duplicate (see above) or might be the result of merging
372
+ * adjacent text nodes.
373
+ */
374
+ DATA_PTR(reparentee_obj) = reparented ;
375
+ reparented_obj = noko_xml_node_wrap(Qnil, reparented);
376
+
377
+ rb_funcall(reparented_obj, id_decorate_bang, 0);
378
+
379
+ /* if we've created a cycle, raise an exception */
380
+ raise_if_ancestor_of_self(reparented);
381
+
382
+ relink_namespace(reparented);
383
+
384
+ return reparented_obj ;
385
+ }
386
+
387
+ // :startdoc:
388
+
389
+ /*
390
+ * :call-seq:
391
+ * add_namespace_definition(prefix, href) → Nokogiri::XML::Namespace
392
+ * add_namespace(prefix, href) → Nokogiri::XML::Namespace
393
+ *
394
+ * :category: Manipulating Document Structure
395
+ *
396
+ * Adds a namespace definition to this node with +prefix+ using +href+ value, as if this node had
397
+ * included an attribute "xmlns:prefix=href".
398
+ *
399
+ * A default namespace definition for this node can be added by passing +nil+ for +prefix+.
400
+ *
401
+ * [Parameters]
402
+ * - +prefix+ (String, +nil+) An {XML Name}[https://www.w3.org/TR/xml-names/#ns-decl]
403
+ * - +href+ (String) The {URI reference}[https://www.w3.org/TR/xml-names/#sec-namespaces]
404
+ *
405
+ * [Returns] The new Nokogiri::XML::Namespace
406
+ *
407
+ * *Example:* adding a non-default namespace definition
408
+ *
409
+ * doc = Nokogiri::XML("<store><inventory></inventory></store>")
410
+ * inventory = doc.at_css("inventory")
411
+ * inventory.add_namespace_definition("automobile", "http://alices-autos.com/")
412
+ * inventory.add_namespace_definition("bicycle", "http://bobs-bikes.com/")
413
+ * inventory.add_child("<automobile:tire>Michelin model XGV, size 75R</automobile:tire>")
414
+ * doc.to_xml
415
+ * # => "<?xml version=\"1.0\"?>\n" +
416
+ * # "<store>\n" +
417
+ * # " <inventory xmlns:automobile=\"http://alices-autos.com/\" xmlns:bicycle=\"http://bobs-bikes.com/\">\n" +
418
+ * # " <automobile:tire>Michelin model XGV, size 75R</automobile:tire>\n" +
419
+ * # " </inventory>\n" +
420
+ * # "</store>\n"
421
+ *
422
+ * *Example:* adding a default namespace definition
423
+ *
424
+ * doc = Nokogiri::XML("<store><inventory><tire>Michelin model XGV, size 75R</tire></inventory></store>")
425
+ * doc.at_css("tire").add_namespace_definition(nil, "http://bobs-bikes.com/")
426
+ * doc.to_xml
427
+ * # => "<?xml version=\"1.0\"?>\n" +
428
+ * # "<store>\n" +
429
+ * # " <inventory>\n" +
430
+ * # " <tire xmlns=\"http://bobs-bikes.com/\">Michelin model XGV, size 75R</tire>\n" +
431
+ * # " </inventory>\n" +
432
+ * # "</store>\n"
433
+ *
434
+ */
435
+ static VALUE
436
+ rb_xml_node_add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
437
+ {
438
+ xmlNodePtr c_node, element;
439
+ xmlNsPtr c_namespace;
440
+ const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix));
441
+
442
+ Data_Get_Struct(rb_node, xmlNode, c_node);
443
+ element = c_node ;
444
+
445
+ c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix);
446
+
447
+ if (!c_namespace) {
448
+ if (c_node->type != XML_ELEMENT_NODE) {
449
+ element = c_node->parent;
450
+ }
451
+ c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
452
+ }
453
+
454
+ if (!c_namespace) {
455
+ return Qnil ;
456
+ }
457
+
458
+ if (NIL_P(rb_prefix) || c_node != element) {
459
+ xmlSetNs(c_node, c_namespace);
460
+ }
461
+
462
+ return noko_xml_namespace_wrap(c_namespace, c_node->doc);
463
+ }
464
+
465
+
466
+ /*
467
+ * :call-seq: attribute(name) → Nokogiri::XML::Attr
468
+ *
469
+ * :category: Working With Node Attributes
470
+ *
471
+ * [Returns] Attribute (Nokogiri::XML::Attr) belonging to this node with name +name+.
472
+ *
473
+ * ⚠ Note that attribute namespaces are ignored and only the simple (non-namespace-prefixed) name is
474
+ * used to find a matching attribute. In case of a simple name collision, only one of the matching
475
+ * attributes will be returned. In this case, you will need to use #attribute_with_ns.
476
+ *
477
+ * *Example:*
478
+ *
479
+ * doc = Nokogiri::XML("<root><child size='large' class='big wide tall'/></root>")
480
+ * child = doc.at_css("child")
481
+ * child.attribute("size") # => #<Nokogiri::XML::Attr:0x550 name="size" value="large">
482
+ * child.attribute("class") # => #<Nokogiri::XML::Attr:0x564 name="class" value="big wide tall">
483
+ *
484
+ * *Example* showing that namespaced attributes will not be returned:
485
+ *
486
+ * ⚠ Note that only one of the two matching attributes is returned.
487
+ *
488
+ * doc = Nokogiri::XML(<<~EOF)
489
+ * <root xmlns:width='http://example.com/widths'
490
+ * xmlns:height='http://example.com/heights'>
491
+ * <child width:size='broad' height:size='tall'/>
492
+ * </root>
493
+ * EOF
494
+ * doc.at_css("child").attribute("size")
495
+ * # => #(Attr:0x550 {
496
+ * # name = "size",
497
+ * # namespace = #(Namespace:0x564 {
498
+ * # prefix = "width",
499
+ * # href = "http://example.com/widths"
500
+ * # }),
501
+ * # value = "broad"
502
+ * # })
503
+ */
504
+ static VALUE
505
+ rb_xml_node_attribute(VALUE self, VALUE name)
506
+ {
507
+ xmlNodePtr node;
508
+ xmlAttrPtr prop;
509
+ Data_Get_Struct(self, xmlNode, node);
510
+ prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
511
+
512
+ if (! prop) { return Qnil; }
513
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
514
+ }
515
+
516
+
517
+ /*
518
+ * :call-seq: attribute_nodes() → Array<Nokogiri::XML::Attr>
519
+ *
520
+ * :category: Working With Node Attributes
521
+ *
522
+ * [Returns] Attributes (an Array of Nokogiri::XML::Attr) belonging to this node.
523
+ *
524
+ * Note that this is the preferred alternative to #attributes when the simple
525
+ * (non-namespace-prefixed) attribute names may collide.
526
+ *
527
+ * *Example:*
528
+ *
529
+ * Contrast this with the colliding-name example from #attributes.
530
+ *
531
+ * doc = Nokogiri::XML(<<~EOF)
532
+ * <root xmlns:width='http://example.com/widths'
533
+ * xmlns:height='http://example.com/heights'>
534
+ * <child width:size='broad' height:size='tall'/>
535
+ * </root>
536
+ * EOF
537
+ * doc.at_css("child").attribute_nodes
538
+ * # => [#(Attr:0x550 {
539
+ * # name = "size",
540
+ * # namespace = #(Namespace:0x564 {
541
+ * # prefix = "width",
542
+ * # href = "http://example.com/widths"
543
+ * # }),
544
+ * # value = "broad"
545
+ * # }),
546
+ * # #(Attr:0x578 {
547
+ * # name = "size",
548
+ * # namespace = #(Namespace:0x58c {
549
+ * # prefix = "height",
550
+ * # href = "http://example.com/heights"
551
+ * # }),
552
+ * # value = "tall"
553
+ * # })]
554
+ */
555
+ static VALUE
556
+ rb_xml_node_attribute_nodes(VALUE rb_node)
557
+ {
558
+ xmlNodePtr c_node;
559
+
560
+ Data_Get_Struct(rb_node, xmlNode, c_node);
561
+
562
+ return noko_xml_node_attrs(c_node);
563
+ }
564
+
565
+
566
+ /*
567
+ * :call-seq: attribute_with_ns(name, namespace) → Nokogiri::XML::Attr
568
+ *
569
+ * :category: Working With Node Attributes
570
+ *
571
+ * [Returns]
572
+ * Attribute (Nokogiri::XML::Attr) belonging to this node with matching +name+ and +namespace+.
573
+ *
574
+ * [Parameters]
575
+ * - +name+ (String): the simple (non-namespace-prefixed) name of the attribute
576
+ * - +namespace+ (String): the URI of the attribute's namespace
577
+ *
578
+ * See related: #attribute
579
+ *
580
+ * *Example:*
581
+ *
582
+ * doc = Nokogiri::XML(<<~EOF)
583
+ * <root xmlns:width='http://example.com/widths'
584
+ * xmlns:height='http://example.com/heights'>
585
+ * <child width:size='broad' height:size='tall'/>
586
+ * </root>
587
+ * EOF
588
+ * doc.at_css("child").attribute_with_ns("size", "http://example.com/widths")
589
+ * # => #(Attr:0x550 {
590
+ * # name = "size",
591
+ * # namespace = #(Namespace:0x564 {
592
+ * # prefix = "width",
593
+ * # href = "http://example.com/widths"
594
+ * # }),
595
+ * # value = "broad"
596
+ * # })
597
+ * doc.at_css("child").attribute_with_ns("size", "http://example.com/heights")
598
+ * # => #(Attr:0x578 {
599
+ * # name = "size",
600
+ * # namespace = #(Namespace:0x58c {
601
+ * # prefix = "height",
602
+ * # href = "http://example.com/heights"
603
+ * # }),
604
+ * # value = "tall"
605
+ * # })
606
+ */
607
+ static VALUE
608
+ rb_xml_node_attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
609
+ {
610
+ xmlNodePtr node;
611
+ xmlAttrPtr prop;
612
+ Data_Get_Struct(self, xmlNode, node);
613
+ prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
614
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
615
+
616
+ if (! prop) { return Qnil; }
617
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
618
+ }
619
+
620
+
621
+
622
+ /*
623
+ * call-seq: blank? → Boolean
624
+ *
625
+ * [Returns] +true+ if the node is an empty or whitespace-only text or cdata node, else +false+.
626
+ *
627
+ * *Example:*
628
+ *
629
+ * Nokogiri("<root><child/></root>").root.child.blank? # => false
630
+ * Nokogiri("<root>\t \n</root>").root.child.blank? # => true
631
+ * Nokogiri("<root><![CDATA[\t \n]]></root>").root.child.blank? # => true
632
+ * Nokogiri("<root>not-blank</root>").root.child
633
+ * .tap { |n| n.content = "" }.blank # => true
634
+ */
635
+ static VALUE
636
+ rb_xml_node_blank_eh(VALUE self)
637
+ {
638
+ xmlNodePtr node;
639
+ Data_Get_Struct(self, xmlNode, node);
640
+ return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
641
+ }
642
+
643
+
644
+ /*
645
+ * :call-seq: child() → Nokogiri::XML::Node
646
+ *
647
+ * :category: Traversing Document Structure
648
+ *
649
+ * [Returns] First of this node's children, or +nil+ if there are no children
650
+ *
651
+ * This is a convenience method and is equivalent to:
652
+ *
653
+ * node.children.first
654
+ *
655
+ * See related: #children
656
+ */
657
+ static VALUE
658
+ rb_xml_node_child(VALUE self)
659
+ {
660
+ xmlNodePtr node, child;
661
+ Data_Get_Struct(self, xmlNode, node);
662
+
663
+ child = node->children;
664
+ if (!child) { return Qnil; }
665
+
666
+ return noko_xml_node_wrap(Qnil, child);
667
+ }
668
+
669
+
670
+ /*
671
+ * :call-seq: children() → Nokogiri::XML::NodeSet
672
+ *
673
+ * :category: Traversing Document Structure
674
+ *
675
+ * [Returns] Nokogiri::XML::NodeSet containing this node's children.
676
+ */
677
+ static VALUE
678
+ rb_xml_node_children(VALUE self)
679
+ {
680
+ xmlNodePtr node;
681
+ xmlNodePtr child;
682
+ xmlNodeSetPtr set;
683
+ VALUE document;
684
+ VALUE node_set;
685
+
686
+ Data_Get_Struct(self, xmlNode, node);
687
+
688
+ child = node->children;
689
+ set = xmlXPathNodeSetCreate(child);
690
+
691
+ document = DOC_RUBY_OBJECT(node->doc);
692
+
693
+ if (!child) { return noko_xml_node_set_wrap(set, document); }
694
+
695
+ child = child->next;
696
+ while (NULL != child) {
697
+ xmlXPathNodeSetAddUnique(set, child);
698
+ child = child->next;
699
+ }
700
+
701
+ node_set = noko_xml_node_set_wrap(set, document);
702
+
703
+ return node_set;
704
+ }
705
+
706
+
707
+ /*
708
+ * :call-seq:
709
+ * content() → String
710
+ * inner_text() → String
711
+ * text() → String
712
+ * to_str() → String
713
+ *
714
+ * [Returns]
715
+ * Contents of all the text nodes in this node's subtree, concatenated together into a single
716
+ * String.
717
+ *
718
+ * ⚠ Note that entities will _always_ be expanded in the returned String.
719
+ *
720
+ * See related: #inner_html
721
+ *
722
+ * *Example* of how entities are handled:
723
+ *
724
+ * Note that <tt>&lt;</tt> becomes <tt><</tt> in the returned String.
725
+ *
726
+ * doc = Nokogiri::XML.fragment("<child>a &lt; b</child>")
727
+ * doc.at_css("child").content
728
+ * # => "a < b"
729
+ *
730
+ * *Example* of how a subtree is handled:
731
+ *
732
+ * Note that the <tt><span></tt> tags are omitted and only the text node contents are returned,
733
+ * concatenated into a single string.
734
+ *
735
+ * doc = Nokogiri::XML.fragment("<child><span>first</span> <span>second</span></child>")
736
+ * doc.at_css("child").content
737
+ * # => "first second"
738
+ */
739
+ static VALUE
740
+ rb_xml_node_content(VALUE self)
741
+ {
742
+ xmlNodePtr node;
743
+ xmlChar *content;
744
+
745
+ Data_Get_Struct(self, xmlNode, node);
746
+
747
+ content = xmlNodeGetContent(node);
748
+ if (content) {
749
+ VALUE rval = NOKOGIRI_STR_NEW2(content);
750
+ xmlFree(content);
751
+ return rval;
752
+ }
753
+ return Qnil;
754
+ }
755
+
756
+
757
+ /*
758
+ * :call-seq: document() → Nokogiri::XML::Document
759
+ *
760
+ * :category: Traversing Document Structure
761
+ *
762
+ * [Returns] Parent Nokogiri::XML::Document for this node
763
+ */
764
+ static VALUE
765
+ rb_xml_node_document(VALUE self)
766
+ {
767
+ xmlNodePtr node;
768
+ Data_Get_Struct(self, xmlNode, node);
769
+ return DOC_RUBY_OBJECT(node->doc);
770
+ }
771
+
772
+ /*
773
+ * :call-seq: pointer_id() → Integer
774
+ *
775
+ * [Returns]
776
+ * A unique id for this node based on the internal memory structures. This method is used by #==
777
+ * to determine node identity.
778
+ */
779
+ static VALUE
780
+ rb_xml_node_pointer_id(VALUE self)
781
+ {
782
+ xmlNodePtr node;
783
+ Data_Get_Struct(self, xmlNode, node);
784
+
785
+ return INT2NUM((long)(node));
786
+ }
787
+
788
+ /*
789
+ * :call-seq: encode_special_chars(string) → String
790
+ *
791
+ * Encode any special characters in +string+
792
+ */
793
+ static VALUE
794
+ encode_special_chars(VALUE self, VALUE string)
795
+ {
796
+ xmlNodePtr node;
797
+ xmlChar *encoded;
798
+ VALUE encoded_str;
799
+
800
+ Data_Get_Struct(self, xmlNode, node);
801
+ encoded = xmlEncodeSpecialChars(
802
+ node->doc,
803
+ (const xmlChar *)StringValueCStr(string)
804
+ );
805
+
806
+ encoded_str = NOKOGIRI_STR_NEW2(encoded);
807
+ xmlFree(encoded);
808
+
809
+ return encoded_str;
810
+ }
811
+
812
+ /*
813
+ * :call-seq:
814
+ * create_internal_subset(name, external_id, system_id)
815
+ *
816
+ * Create the internal subset of a document.
817
+ *
818
+ * doc.create_internal_subset("chapter", "-//OASIS//DTD DocBook XML//EN", "chapter.dtd")
819
+ * # => <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML//EN" "chapter.dtd">
820
+ *
821
+ * doc.create_internal_subset("chapter", nil, "chapter.dtd")
822
+ * # => <!DOCTYPE chapter SYSTEM "chapter.dtd">
823
+ */
824
+ static VALUE
825
+ create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
826
+ {
827
+ xmlNodePtr node;
828
+ xmlDocPtr doc;
829
+ xmlDtdPtr dtd;
830
+
831
+ Data_Get_Struct(self, xmlNode, node);
832
+
833
+ doc = node->doc;
834
+
835
+ if (xmlGetIntSubset(doc)) {
836
+ rb_raise(rb_eRuntimeError, "Document already has an internal subset");
837
+ }
838
+
839
+ dtd = xmlCreateIntSubset(
840
+ doc,
841
+ NIL_P(name) ? NULL : (const xmlChar *)StringValueCStr(name),
842
+ NIL_P(external_id) ? NULL : (const xmlChar *)StringValueCStr(external_id),
843
+ NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
844
+ );
845
+
846
+ if (!dtd) { return Qnil; }
847
+
848
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
849
+ }
850
+
851
+ /*
852
+ * :call-seq:
853
+ * create_external_subset(name, external_id, system_id)
854
+ *
855
+ * Create an external subset
856
+ */
857
+ static VALUE
858
+ create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
859
+ {
860
+ xmlNodePtr node;
861
+ xmlDocPtr doc;
862
+ xmlDtdPtr dtd;
863
+
864
+ Data_Get_Struct(self, xmlNode, node);
865
+
866
+ doc = node->doc;
867
+
868
+ if (doc->extSubset) {
869
+ rb_raise(rb_eRuntimeError, "Document already has an external subset");
870
+ }
871
+
872
+ dtd = xmlNewDtd(
873
+ doc,
874
+ NIL_P(name) ? NULL : (const xmlChar *)StringValueCStr(name),
875
+ NIL_P(external_id) ? NULL : (const xmlChar *)StringValueCStr(external_id),
876
+ NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
877
+ );
878
+
879
+ if (!dtd) { return Qnil; }
880
+
881
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
882
+ }
883
+
884
+ /*
885
+ * :call-seq:
886
+ * external_subset()
887
+ *
888
+ * Get the external subset
889
+ */
890
+ static VALUE
891
+ external_subset(VALUE self)
892
+ {
893
+ xmlNodePtr node;
894
+ xmlDocPtr doc;
895
+ xmlDtdPtr dtd;
896
+
897
+ Data_Get_Struct(self, xmlNode, node);
898
+
899
+ if (!node->doc) { return Qnil; }
900
+
901
+ doc = node->doc;
902
+ dtd = doc->extSubset;
903
+
904
+ if (!dtd) { return Qnil; }
905
+
906
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
907
+ }
908
+
909
+ /*
910
+ * :call-seq:
911
+ * internal_subset()
912
+ *
913
+ * Get the internal subset
914
+ */
915
+ static VALUE
916
+ internal_subset(VALUE self)
917
+ {
918
+ xmlNodePtr node;
919
+ xmlDocPtr doc;
920
+ xmlDtdPtr dtd;
921
+
922
+ Data_Get_Struct(self, xmlNode, node);
923
+
924
+ if (!node->doc) { return Qnil; }
925
+
926
+ doc = node->doc;
927
+ dtd = xmlGetIntSubset(doc);
928
+
929
+ if (!dtd) { return Qnil; }
930
+
931
+ return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
932
+ }
933
+
934
+ /*
935
+ * :call-seq:
936
+ * dup → Nokogiri::XML::Node
937
+ * dup(depth) → Nokogiri::XML::Node
938
+ * dup(depth, new_parent_doc) → Nokogiri::XML::Node
939
+ *
940
+ * Copy this node.
941
+ *
942
+ * [Parameters]
943
+ * - +depth+ 0 is a shallow copy, 1 (the default) is a deep copy.
944
+ * - +new_parent_doc+
945
+ * The new node's parent Document. Defaults to the this node's document.
946
+ *
947
+ * [Returns] The new Nokgiri::XML::Node
948
+ */
949
+ static VALUE
950
+ duplicate_node(int argc, VALUE *argv, VALUE self)
951
+ {
952
+ VALUE r_level, r_new_parent_doc;
953
+ int level;
954
+ int n_args;
955
+ xmlDocPtr new_parent_doc;
956
+ xmlNodePtr node, dup;
957
+
958
+ Data_Get_Struct(self, xmlNode, node);
959
+
960
+ n_args = rb_scan_args(argc, argv, "02", &r_level, &r_new_parent_doc);
961
+
962
+ if (n_args < 1) {
963
+ r_level = INT2NUM((long)1);
964
+ }
965
+ level = (int)NUM2INT(r_level);
966
+
967
+ if (n_args < 2) {
968
+ new_parent_doc = node->doc;
969
+ } else {
970
+ Data_Get_Struct(r_new_parent_doc, xmlDoc, new_parent_doc);
971
+ }
972
+
973
+ dup = xmlDocCopyNode(node, new_parent_doc, level);
974
+ if (dup == NULL) { return Qnil; }
975
+
976
+ noko_xml_document_pin_node(dup);
977
+
978
+ return noko_xml_node_wrap(rb_obj_class(self), dup);
979
+ }
980
+
981
+ /*
982
+ * :call-seq:
983
+ * unlink() → self
984
+ *
985
+ * Unlink this node from its current context.
986
+ */
987
+ static VALUE
988
+ unlink_node(VALUE self)
989
+ {
990
+ xmlNodePtr node;
991
+ Data_Get_Struct(self, xmlNode, node);
992
+ xmlUnlinkNode(node);
993
+ noko_xml_document_pin_node(node);
994
+ return self;
995
+ }
996
+
997
+
998
+ /*
999
+ * call-seq:
1000
+ * next_sibling
1001
+ *
1002
+ * Returns the next sibling node
1003
+ */
1004
+ static VALUE
1005
+ next_sibling(VALUE self)
1006
+ {
1007
+ xmlNodePtr node, sibling;
1008
+ Data_Get_Struct(self, xmlNode, node);
1009
+
1010
+ sibling = node->next;
1011
+ if (!sibling) { return Qnil; }
1012
+
1013
+ return noko_xml_node_wrap(Qnil, sibling) ;
1014
+ }
1015
+
1016
+ /*
1017
+ * call-seq:
1018
+ * previous_sibling
1019
+ *
1020
+ * Returns the previous sibling node
1021
+ */
1022
+ static VALUE
1023
+ previous_sibling(VALUE self)
1024
+ {
1025
+ xmlNodePtr node, sibling;
1026
+ Data_Get_Struct(self, xmlNode, node);
1027
+
1028
+ sibling = node->prev;
1029
+ if (!sibling) { return Qnil; }
1030
+
1031
+ return noko_xml_node_wrap(Qnil, sibling);
1032
+ }
1033
+
1034
+ /*
1035
+ * call-seq:
1036
+ * next_element
1037
+ *
1038
+ * Returns the next Nokogiri::XML::Element type sibling node.
1039
+ */
1040
+ static VALUE
1041
+ next_element(VALUE self)
1042
+ {
1043
+ xmlNodePtr node, sibling;
1044
+ Data_Get_Struct(self, xmlNode, node);
1045
+
1046
+ sibling = xmlNextElementSibling(node);
1047
+ if (!sibling) { return Qnil; }
1048
+
1049
+ return noko_xml_node_wrap(Qnil, sibling);
1050
+ }
1051
+
1052
+ /*
1053
+ * call-seq:
1054
+ * previous_element
1055
+ *
1056
+ * Returns the previous Nokogiri::XML::Element type sibling node.
1057
+ */
1058
+ static VALUE
1059
+ previous_element(VALUE self)
1060
+ {
1061
+ xmlNodePtr node, sibling;
1062
+ Data_Get_Struct(self, xmlNode, node);
1063
+
1064
+ /*
1065
+ * note that we don't use xmlPreviousElementSibling here because it's buggy pre-2.7.7.
1066
+ */
1067
+ sibling = node->prev;
1068
+ if (!sibling) { return Qnil; }
1069
+
1070
+ while (sibling && sibling->type != XML_ELEMENT_NODE) {
1071
+ sibling = sibling->prev;
1072
+ }
1073
+
1074
+ return sibling ? noko_xml_node_wrap(Qnil, sibling) : Qnil ;
1075
+ }
1076
+
1077
+ /* :nodoc: */
1078
+ static VALUE
1079
+ replace(VALUE self, VALUE new_node)
1080
+ {
1081
+ VALUE reparent = reparent_node_with(self, new_node, xmlReplaceNodeWrapper);
1082
+
1083
+ xmlNodePtr pivot;
1084
+ Data_Get_Struct(self, xmlNode, pivot);
1085
+ noko_xml_document_pin_node(pivot);
1086
+
1087
+ return reparent;
1088
+ }
1089
+
1090
+ /*
1091
+ * :call-seq:
1092
+ * element_children() → NodeSet
1093
+ * elements() → NodeSet
1094
+ *
1095
+ * [Returns]
1096
+ * The node's child elements as a NodeSet. Only children that are elements will be returned, which
1097
+ * notably excludes Text nodes.
1098
+ *
1099
+ * *Example:*
1100
+ *
1101
+ * Note that #children returns the Text node "hello" while #element_children does not.
1102
+ *
1103
+ * div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
1104
+ * div.element_children
1105
+ * # => [#<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
1106
+ * div.children
1107
+ * # => [#<Nokogiri::XML::Text:0x64 "hello">,
1108
+ * # #<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
1109
+ */
1110
+ static VALUE
1111
+ rb_xml_node_element_children(VALUE self)
1112
+ {
1113
+ xmlNodePtr node;
1114
+ xmlNodePtr child;
1115
+ xmlNodeSetPtr set;
1116
+ VALUE document;
1117
+ VALUE node_set;
1118
+
1119
+ Data_Get_Struct(self, xmlNode, node);
1120
+
1121
+ child = xmlFirstElementChild(node);
1122
+ set = xmlXPathNodeSetCreate(child);
1123
+
1124
+ document = DOC_RUBY_OBJECT(node->doc);
1125
+
1126
+ if (!child) { return noko_xml_node_set_wrap(set, document); }
1127
+
1128
+ child = xmlNextElementSibling(child);
1129
+ while (NULL != child) {
1130
+ xmlXPathNodeSetAddUnique(set, child);
1131
+ child = xmlNextElementSibling(child);
1132
+ }
1133
+
1134
+ node_set = noko_xml_node_set_wrap(set, document);
1135
+
1136
+ return node_set;
1137
+ }
1138
+
1139
+ /*
1140
+ * :call-seq:
1141
+ * first_element_child() → Node
1142
+ *
1143
+ * [Returns] The first child Node that is an element.
1144
+ *
1145
+ * *Example:*
1146
+ *
1147
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span></tt> element is
1148
+ * returned.
1149
+ *
1150
+ * div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
1151
+ * div.first_element_child
1152
+ * # => #(Element:0x3c { name = "span", children = [ #(Text "world")] })
1153
+ */
1154
+ static VALUE
1155
+ rb_xml_node_first_element_child(VALUE self)
1156
+ {
1157
+ xmlNodePtr node, child;
1158
+ Data_Get_Struct(self, xmlNode, node);
1159
+
1160
+ child = xmlFirstElementChild(node);
1161
+ if (!child) { return Qnil; }
1162
+
1163
+ return noko_xml_node_wrap(Qnil, child);
1164
+ }
1165
+
1166
+ /*
1167
+ * :call-seq:
1168
+ * last_element_child() → Node
1169
+ *
1170
+ * [Returns] The last child Node that is an element.
1171
+ *
1172
+ * *Example:*
1173
+ *
1174
+ * Note that the "hello" child, which is a Text node, is skipped and the <tt><span>yes</span></tt>
1175
+ * element is returned.
1176
+ *
1177
+ * div = Nokogiri::HTML5("<div><span>no</span><span>yes</span>skip</div>").at_css("div")
1178
+ * div.last_element_child
1179
+ * # => #(Element:0x3c { name = "span", children = [ #(Text "yes")] })
1180
+ */
1181
+ static VALUE
1182
+ rb_xml_node_last_element_child(VALUE self)
1183
+ {
1184
+ xmlNodePtr node, child;
1185
+ Data_Get_Struct(self, xmlNode, node);
1186
+
1187
+ child = xmlLastElementChild(node);
1188
+ if (!child) { return Qnil; }
1189
+
1190
+ return noko_xml_node_wrap(Qnil, child);
1191
+ }
1192
+
1193
+ /*
1194
+ * call-seq:
1195
+ * key?(attribute)
1196
+ *
1197
+ * Returns true if +attribute+ is set
1198
+ */
1199
+ static VALUE
1200
+ key_eh(VALUE self, VALUE attribute)
1201
+ {
1202
+ xmlNodePtr node;
1203
+ Data_Get_Struct(self, xmlNode, node);
1204
+ if (xmlHasProp(node, (xmlChar *)StringValueCStr(attribute))) {
1205
+ return Qtrue;
1206
+ }
1207
+ return Qfalse;
1208
+ }
1209
+
1210
+ /*
1211
+ * call-seq:
1212
+ * namespaced_key?(attribute, namespace)
1213
+ *
1214
+ * Returns true if +attribute+ is set with +namespace+
1215
+ */
1216
+ static VALUE
1217
+ namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
1218
+ {
1219
+ xmlNodePtr node;
1220
+ Data_Get_Struct(self, xmlNode, node);
1221
+ if (xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute),
1222
+ NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace))) {
1223
+ return Qtrue;
1224
+ }
1225
+ return Qfalse;
1226
+ }
1227
+
1228
+ /*
1229
+ * call-seq:
1230
+ * []=(property, value)
1231
+ *
1232
+ * Set the +property+ to +value+
1233
+ */
1234
+ static VALUE
1235
+ set(VALUE self, VALUE property, VALUE value)
1236
+ {
1237
+ xmlNodePtr node, cur;
1238
+ xmlAttrPtr prop;
1239
+ Data_Get_Struct(self, xmlNode, node);
1240
+
1241
+ /* If a matching attribute node already exists, then xmlSetProp will destroy
1242
+ * the existing node's children. However, if Nokogiri has a node object
1243
+ * pointing to one of those children, we are left with a broken reference.
1244
+ *
1245
+ * We can avoid this by unlinking these nodes first.
1246
+ */
1247
+ if (node->type != XML_ELEMENT_NODE) {
1248
+ return (Qnil);
1249
+ }
1250
+ prop = xmlHasProp(node, (xmlChar *)StringValueCStr(property));
1251
+ if (prop && prop->children) {
1252
+ for (cur = prop->children; cur; cur = cur->next) {
1253
+ if (cur->_private) {
1254
+ noko_xml_document_pin_node(cur);
1255
+ xmlUnlinkNode(cur);
1256
+ }
1257
+ }
1258
+ }
1259
+
1260
+ xmlSetProp(node, (xmlChar *)StringValueCStr(property),
1261
+ (xmlChar *)StringValueCStr(value));
1262
+
1263
+ return value;
1264
+ }
1265
+
1266
+ /*
1267
+ * call-seq:
1268
+ * get(attribute)
1269
+ *
1270
+ * Get the value for +attribute+
1271
+ */
1272
+ static VALUE
1273
+ get(VALUE self, VALUE rattribute)
1274
+ {
1275
+ xmlNodePtr node;
1276
+ xmlChar *value = 0;
1277
+ VALUE rvalue;
1278
+ xmlChar *colon;
1279
+ xmlChar *attribute, *attr_name, *prefix;
1280
+ xmlNsPtr ns;
1281
+
1282
+ if (NIL_P(rattribute)) { return Qnil; }
1283
+
1284
+ Data_Get_Struct(self, xmlNode, node);
1285
+ attribute = xmlCharStrdup(StringValueCStr(rattribute));
1286
+
1287
+ colon = DISCARD_CONST_QUAL_XMLCHAR(xmlStrchr(attribute, (const xmlChar)':'));
1288
+ if (colon) {
1289
+ /* split the attribute string into separate prefix and name by
1290
+ * null-terminating the prefix at the colon */
1291
+ prefix = attribute;
1292
+ attr_name = colon + 1;
1293
+ (*colon) = 0;
1294
+
1295
+ ns = xmlSearchNs(node->doc, node, prefix);
1296
+ if (ns) {
1297
+ value = xmlGetNsProp(node, attr_name, ns->href);
1298
+ } else {
1299
+ value = xmlGetProp(node, (xmlChar *)StringValueCStr(rattribute));
1300
+ }
1301
+ } else {
1302
+ value = xmlGetNoNsProp(node, attribute);
1303
+ }
1304
+
1305
+ xmlFree((void *)attribute);
1306
+ if (!value) { return Qnil; }
1307
+
1308
+ rvalue = NOKOGIRI_STR_NEW2(value);
1309
+ xmlFree((void *)value);
1310
+
1311
+ return rvalue ;
1312
+ }
1313
+
1314
+ /*
1315
+ * call-seq:
1316
+ * set_namespace(namespace)
1317
+ *
1318
+ * Set the namespace to +namespace+
1319
+ */
1320
+ static VALUE
1321
+ set_namespace(VALUE self, VALUE namespace)
1322
+ {
1323
+ xmlNodePtr node;
1324
+ xmlNsPtr ns = NULL;
1325
+
1326
+ Data_Get_Struct(self, xmlNode, node);
1327
+
1328
+ if (!NIL_P(namespace)) {
1329
+ Data_Get_Struct(namespace, xmlNs, ns);
1330
+ }
1331
+
1332
+ xmlSetNs(node, ns);
1333
+
1334
+ return self;
1335
+ }
1336
+
1337
+ /*
1338
+ * :call-seq:
1339
+ * namespace() → Namespace
1340
+ *
1341
+ * [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace.
1342
+ *
1343
+ * *Example:*
1344
+ *
1345
+ * doc = Nokogiri::XML(<<~EOF)
1346
+ * <root>
1347
+ * <first/>
1348
+ * <second xmlns="http://example.com/child"/>
1349
+ * <foo:third xmlns:foo="http://example.com/foo"/>
1350
+ * </root>
1351
+ * EOF
1352
+ * doc.at_xpath("//first").namespace
1353
+ * # => nil
1354
+ * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace
1355
+ * # => #(Namespace:0x3c { href = "http://example.com/child" })
1356
+ * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace
1357
+ * # => #(Namespace:0x50 { prefix = "foo", href = "http://example.com/foo" })
1358
+ */
1359
+ static VALUE
1360
+ rb_xml_node_namespace(VALUE rb_node)
1361
+ {
1362
+ xmlNodePtr c_node ;
1363
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1364
+
1365
+ if (c_node->ns) {
1366
+ return noko_xml_namespace_wrap(c_node->ns, c_node->doc);
1367
+ }
1368
+
1369
+ return Qnil ;
1370
+ }
1371
+
1372
+ /*
1373
+ * :call-seq:
1374
+ * namespace_definitions() → Array<Nokogiri::XML::Namespace>
1375
+ *
1376
+ * [Returns]
1377
+ * Namespaces that are defined directly on this node, as an Array of Namespace objects. The array
1378
+ * will be empty if no namespaces are defined on this node.
1379
+ *
1380
+ * *Example:*
1381
+ *
1382
+ * doc = Nokogiri::XML(<<~EOF)
1383
+ * <root xmlns="http://example.com/root">
1384
+ * <first/>
1385
+ * <second xmlns="http://example.com/child" xmlns:unused="http://example.com/unused"/>
1386
+ * <foo:third xmlns:foo="http://example.com/foo"/>
1387
+ * </root>
1388
+ * EOF
1389
+ * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_definitions
1390
+ * # => []
1391
+ * doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace_definitions
1392
+ * # => [#(Namespace:0x3c { href = "http://example.com/child" }),
1393
+ * # #(Namespace:0x50 {
1394
+ * # prefix = "unused",
1395
+ * # href = "http://example.com/unused"
1396
+ * # })]
1397
+ * doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace_definitions
1398
+ * # => [#(Namespace:0x64 { prefix = "foo", href = "http://example.com/foo" })]
1399
+ */
1400
+ static VALUE
1401
+ namespace_definitions(VALUE rb_node)
1402
+ {
1403
+ /* this code in the mode of xmlHasProp() */
1404
+ xmlNodePtr c_node ;
1405
+ xmlNsPtr c_namespace;
1406
+ VALUE definitions = rb_ary_new();
1407
+
1408
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1409
+
1410
+ c_namespace = c_node->nsDef;
1411
+ if (!c_namespace) {
1412
+ return definitions;
1413
+ }
1414
+
1415
+ while (c_namespace != NULL) {
1416
+ rb_ary_push(definitions, noko_xml_namespace_wrap(c_namespace, c_node->doc));
1417
+ c_namespace = c_namespace->next;
1418
+ }
1419
+
1420
+ return definitions;
1421
+ }
1422
+
1423
+ /*
1424
+ * :call-seq:
1425
+ * namespace_scopes() → Array<Nokogiri::XML::Namespace>
1426
+ *
1427
+ * [Returns] Array of all the Namespaces on this node and its ancestors.
1428
+ *
1429
+ * See also #namespaces
1430
+ *
1431
+ * *Example:*
1432
+ *
1433
+ * doc = Nokogiri::XML(<<~EOF)
1434
+ * <root xmlns="http://example.com/root" xmlns:bar="http://example.com/bar">
1435
+ * <first/>
1436
+ * <second xmlns="http://example.com/child"/>
1437
+ * <third xmlns:foo="http://example.com/foo"/>
1438
+ * </root>
1439
+ * EOF
1440
+ * doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_scopes
1441
+ * # => [#(Namespace:0x3c { href = "http://example.com/root" }),
1442
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1443
+ * doc.at_xpath("//child:second", "child" => "http://example.com/child").namespace_scopes
1444
+ * # => [#(Namespace:0x64 { href = "http://example.com/child" }),
1445
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1446
+ * doc.at_xpath("//root:third", "root" => "http://example.com/root").namespace_scopes
1447
+ * # => [#(Namespace:0x78 { prefix = "foo", href = "http://example.com/foo" }),
1448
+ * # #(Namespace:0x3c { href = "http://example.com/root" }),
1449
+ * # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
1450
+ */
1451
+ static VALUE
1452
+ rb_xml_node_namespace_scopes(VALUE rb_node)
1453
+ {
1454
+ xmlNodePtr c_node ;
1455
+ xmlNsPtr *namespaces;
1456
+ VALUE scopes = rb_ary_new();
1457
+ int j;
1458
+
1459
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1460
+
1461
+ namespaces = xmlGetNsList(c_node->doc, c_node);
1462
+ if (!namespaces) {
1463
+ return scopes;
1464
+ }
1465
+
1466
+ for (j = 0 ; namespaces[j] != NULL ; ++j) {
1467
+ rb_ary_push(scopes, noko_xml_namespace_wrap(namespaces[j], c_node->doc));
1468
+ }
1469
+
1470
+ xmlFree(namespaces);
1471
+ return scopes;
1472
+ }
1473
+
1474
+ /*
1475
+ * call-seq:
1476
+ * node_type
1477
+ *
1478
+ * Get the type for this Node
1479
+ */
1480
+ static VALUE
1481
+ node_type(VALUE self)
1482
+ {
1483
+ xmlNodePtr node;
1484
+ Data_Get_Struct(self, xmlNode, node);
1485
+ return INT2NUM((long)node->type);
1486
+ }
1487
+
1488
+ /*
1489
+ * call-seq:
1490
+ * content=
1491
+ *
1492
+ * Set the content for this Node
1493
+ */
1494
+ static VALUE
1495
+ set_native_content(VALUE self, VALUE content)
1496
+ {
1497
+ xmlNodePtr node, child, next ;
1498
+ Data_Get_Struct(self, xmlNode, node);
1499
+
1500
+ child = node->children;
1501
+ while (NULL != child) {
1502
+ next = child->next ;
1503
+ xmlUnlinkNode(child) ;
1504
+ noko_xml_document_pin_node(child);
1505
+ child = next ;
1506
+ }
1507
+
1508
+ xmlNodeSetContent(node, (xmlChar *)StringValueCStr(content));
1509
+ return content;
1510
+ }
1511
+
1512
+ /*
1513
+ * call-seq:
1514
+ * lang=
1515
+ *
1516
+ * Set the language of a node, i.e. the values of the xml:lang attribute.
1517
+ */
1518
+ static VALUE
1519
+ set_lang(VALUE self_rb, VALUE lang_rb)
1520
+ {
1521
+ xmlNodePtr self ;
1522
+ xmlChar *lang ;
1523
+
1524
+ Data_Get_Struct(self_rb, xmlNode, self);
1525
+ lang = (xmlChar *)StringValueCStr(lang_rb);
1526
+
1527
+ xmlNodeSetLang(self, lang);
1528
+
1529
+ return Qnil ;
1530
+ }
1531
+
1532
+ /*
1533
+ * call-seq:
1534
+ * lang
1535
+ *
1536
+ * Searches the language of a node, i.e. the values of the xml:lang attribute or
1537
+ * the one carried by the nearest ancestor.
1538
+ */
1539
+ static VALUE
1540
+ get_lang(VALUE self_rb)
1541
+ {
1542
+ xmlNodePtr self ;
1543
+ xmlChar *lang ;
1544
+ VALUE lang_rb ;
1545
+
1546
+ Data_Get_Struct(self_rb, xmlNode, self);
1547
+
1548
+ lang = xmlNodeGetLang(self);
1549
+ if (lang) {
1550
+ lang_rb = NOKOGIRI_STR_NEW2(lang);
1551
+ xmlFree(lang);
1552
+ return lang_rb ;
1553
+ }
1554
+
1555
+ return Qnil ;
1556
+ }
1557
+
1558
+ /* :nodoc: */
1559
+ static VALUE
1560
+ add_child(VALUE self, VALUE new_child)
1561
+ {
1562
+ return reparent_node_with(self, new_child, xmlAddChild);
1563
+ }
1564
+
1565
+ /*
1566
+ * call-seq:
1567
+ * parent
1568
+ *
1569
+ * Get the parent Node for this Node
1570
+ */
1571
+ static VALUE
1572
+ get_parent(VALUE self)
1573
+ {
1574
+ xmlNodePtr node, parent;
1575
+ Data_Get_Struct(self, xmlNode, node);
1576
+
1577
+ parent = node->parent;
1578
+ if (!parent) { return Qnil; }
1579
+
1580
+ return noko_xml_node_wrap(Qnil, parent) ;
1581
+ }
1582
+
1583
+ /*
1584
+ * call-seq:
1585
+ * name=(new_name)
1586
+ *
1587
+ * Set the name for this Node
1588
+ */
1589
+ static VALUE
1590
+ set_name(VALUE self, VALUE new_name)
1591
+ {
1592
+ xmlNodePtr node;
1593
+ Data_Get_Struct(self, xmlNode, node);
1594
+ xmlNodeSetName(node, (xmlChar *)StringValueCStr(new_name));
1595
+ return new_name;
1596
+ }
1597
+
1598
+ /*
1599
+ * call-seq:
1600
+ * name
1601
+ *
1602
+ * Returns the name for this Node
1603
+ */
1604
+ static VALUE
1605
+ get_name(VALUE self)
1606
+ {
1607
+ xmlNodePtr node;
1608
+ Data_Get_Struct(self, xmlNode, node);
1609
+ if (node->name) {
1610
+ return NOKOGIRI_STR_NEW2(node->name);
1611
+ }
1612
+ return Qnil;
1613
+ }
1614
+
1615
+ /*
1616
+ * call-seq:
1617
+ * path
1618
+ *
1619
+ * Returns the path associated with this Node
1620
+ */
1621
+ static VALUE
1622
+ rb_xml_node_path(VALUE rb_node)
1623
+ {
1624
+ xmlNodePtr c_node;
1625
+ xmlChar *c_path ;
1626
+ VALUE rval;
1627
+
1628
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1629
+
1630
+ c_path = xmlGetNodePath(c_node);
1631
+ if (c_path == NULL) {
1632
+ // see https://github.com/sparklemotion/nokogiri/issues/2250
1633
+ // this behavior is clearly undesirable, but is what libxml <= 2.9.10 returned, and so we
1634
+ // do this for now to preserve the behavior across libxml2 versions.
1635
+ rval = NOKOGIRI_STR_NEW2("?");
1636
+ } else {
1637
+ rval = NOKOGIRI_STR_NEW2(c_path);
1638
+ xmlFree(c_path);
1639
+ }
1640
+
1641
+ return rval ;
1642
+ }
1643
+
1644
+ /* :nodoc: */
1645
+ static VALUE
1646
+ add_next_sibling(VALUE self, VALUE new_sibling)
1647
+ {
1648
+ return reparent_node_with(self, new_sibling, xmlAddNextSibling) ;
1649
+ }
1650
+
1651
+ /* :nodoc: */
1652
+ static VALUE
1653
+ add_previous_sibling(VALUE self, VALUE new_sibling)
1654
+ {
1655
+ return reparent_node_with(self, new_sibling, xmlAddPrevSibling) ;
1656
+ }
1657
+
1658
+ /*
1659
+ * call-seq:
1660
+ * native_write_to(io, encoding, options)
1661
+ *
1662
+ * Write this Node to +io+ with +encoding+ and +options+
1663
+ */
1664
+ static VALUE
1665
+ native_write_to(
1666
+ VALUE self,
1667
+ VALUE io,
1668
+ VALUE encoding,
1669
+ VALUE indent_string,
1670
+ VALUE options
1671
+ )
1672
+ {
1673
+ xmlNodePtr node;
1674
+ const char *before_indent;
1675
+ xmlSaveCtxtPtr savectx;
1676
+
1677
+ Data_Get_Struct(self, xmlNode, node);
1678
+
1679
+ xmlIndentTreeOutput = 1;
1680
+
1681
+ before_indent = xmlTreeIndentString;
1682
+
1683
+ xmlTreeIndentString = StringValueCStr(indent_string);
1684
+
1685
+ savectx = xmlSaveToIO(
1686
+ (xmlOutputWriteCallback)noko_io_write,
1687
+ (xmlOutputCloseCallback)noko_io_close,
1688
+ (void *)io,
1689
+ RTEST(encoding) ? StringValueCStr(encoding) : NULL,
1690
+ (int)NUM2INT(options)
1691
+ );
1692
+
1693
+ xmlSaveTree(savectx, node);
1694
+ xmlSaveClose(savectx);
1695
+
1696
+ xmlTreeIndentString = before_indent;
1697
+ return io;
1698
+ }
1699
+
1700
+ /*
1701
+ * :call-seq:
1702
+ * line() → Integer
1703
+ *
1704
+ * [Returns] The line number of this Node.
1705
+ *
1706
+ * ---
1707
+ *
1708
+ * <b> ⚠ The CRuby and JRuby implementations differ in important ways! </b>
1709
+ *
1710
+ * Semantic differences:
1711
+ * - The CRuby method reflects the node's line number <i>in the parsed string</i>
1712
+ * - The JRuby method reflects the node's line number <i>in the final DOM structure</i> after
1713
+ * corrections have been applied
1714
+ *
1715
+ * Performance differences:
1716
+ * - The CRuby method is {O(1)}[https://en.wikipedia.org/wiki/Time_complexity#Constant_time]
1717
+ * (constant time)
1718
+ * - The JRuby method is {O(n)}[https://en.wikipedia.org/wiki/Time_complexity#Linear_time] (linear
1719
+ * time, where n is the number of nodes before/above the element in the DOM)
1720
+ *
1721
+ * If you'd like to help improve the JRuby implementation, please review these issues and reach out
1722
+ * to the maintainers:
1723
+ * - https://github.com/sparklemotion/nokogiri/issues/1223
1724
+ * - https://github.com/sparklemotion/nokogiri/pull/2177
1725
+ * - https://github.com/sparklemotion/nokogiri/issues/2380
1726
+ */
1727
+ static VALUE
1728
+ rb_xml_node_line(VALUE rb_node)
1729
+ {
1730
+ xmlNodePtr c_node;
1731
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1732
+
1733
+ return INT2NUM(xmlGetLineNo(c_node));
1734
+ }
1735
+
1736
+ /*
1737
+ * call-seq:
1738
+ * line=(num)
1739
+ *
1740
+ * Sets the line for this Node. num must be less than 65535.
1741
+ */
1742
+ static VALUE
1743
+ rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number)
1744
+ {
1745
+ xmlNodePtr c_node;
1746
+ int line_number = NUM2INT(rb_line_number);
1747
+
1748
+ Data_Get_Struct(rb_node, xmlNode, c_node);
1749
+
1750
+ // libxml2 optionally uses xmlNode.psvi to store longer line numbers, but only for text nodes.
1751
+ // search for "psvi" in SAX2.c and tree.c to learn more.
1752
+ if (line_number < 65535) {
1753
+ c_node->line = (short) line_number;
1754
+ } else {
1755
+ c_node->line = 65535;
1756
+ if (c_node->type == XML_TEXT_NODE) {
1757
+ c_node->psvi = (void *)(ptrdiff_t) line_number;
1758
+ }
1759
+ }
1760
+
1761
+ return rb_line_number;
1762
+ }
1763
+
1764
+ /* :nodoc: documented in lib/nokogiri/xml/node.rb */
1765
+ static VALUE
1766
+ rb_xml_node_new(int argc, VALUE *argv, VALUE klass)
1767
+ {
1768
+ xmlNodePtr c_document_node;
1769
+ xmlNodePtr c_node;
1770
+ VALUE rb_name;
1771
+ VALUE rb_document_node;
1772
+ VALUE rest;
1773
+ VALUE rb_node;
1774
+
1775
+ rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest);
1776
+
1777
+ if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlNode)) {
1778
+ rb_raise(rb_eArgError, "document must be a Nokogiri::XML::Node");
1779
+ }
1780
+ if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlDocument)) {
1781
+ // TODO: deprecate allowing Node
1782
+ rb_warn("Passing a Node as the second parameter to Node.new is deprecated. Please pass a Document instead, or prefer an alternative constructor like Node#add_child. This will become an error in a future release of Nokogiri.");
1783
+ }
1784
+ Data_Get_Struct(rb_document_node, xmlNode, c_document_node);
1785
+
1786
+ c_node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(rb_name));
1787
+ c_node->doc = c_document_node->doc;
1788
+ noko_xml_document_pin_node(c_node);
1789
+
1790
+ rb_node = noko_xml_node_wrap(
1791
+ klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
1792
+ c_node
1793
+ );
1794
+ rb_obj_call_init(rb_node, argc, argv);
1795
+
1796
+ if (rb_block_given_p()) { rb_yield(rb_node); }
1797
+
1798
+ return rb_node;
1799
+ }
1800
+
1801
+ /*
1802
+ * call-seq:
1803
+ * dump_html
1804
+ *
1805
+ * Returns the Node as html.
1806
+ */
1807
+ static VALUE
1808
+ dump_html(VALUE self)
1809
+ {
1810
+ xmlBufferPtr buf ;
1811
+ xmlNodePtr node ;
1812
+ VALUE html;
1813
+
1814
+ Data_Get_Struct(self, xmlNode, node);
1815
+
1816
+ buf = xmlBufferCreate() ;
1817
+ htmlNodeDump(buf, node->doc, node);
1818
+ html = NOKOGIRI_STR_NEW2(buf->content);
1819
+ xmlBufferFree(buf);
1820
+ return html ;
1821
+ }
1822
+
1823
+ /*
1824
+ * call-seq:
1825
+ * compare(other)
1826
+ *
1827
+ * Compare this Node to +other+ with respect to their Document
1828
+ */
1829
+ static VALUE
1830
+ compare(VALUE self, VALUE _other)
1831
+ {
1832
+ xmlNodePtr node, other;
1833
+ Data_Get_Struct(self, xmlNode, node);
1834
+ Data_Get_Struct(_other, xmlNode, other);
1835
+
1836
+ return INT2NUM((long)xmlXPathCmpNodes(other, node));
1837
+ }
1838
+
1839
+
1840
+ /*
1841
+ * call-seq:
1842
+ * process_xincludes(options)
1843
+ *
1844
+ * Loads and substitutes all xinclude elements below the node. The
1845
+ * parser context will be initialized with +options+.
1846
+ */
1847
+ static VALUE
1848
+ process_xincludes(VALUE self, VALUE options)
1849
+ {
1850
+ int rcode ;
1851
+ xmlNodePtr node;
1852
+ VALUE error_list = rb_ary_new();
1853
+
1854
+ Data_Get_Struct(self, xmlNode, node);
1855
+
1856
+ xmlSetStructuredErrorFunc((void *)error_list, Nokogiri_error_array_pusher);
1857
+ rcode = xmlXIncludeProcessTreeFlags(node, (int)NUM2INT(options));
1858
+ xmlSetStructuredErrorFunc(NULL, NULL);
1859
+
1860
+ if (rcode < 0) {
1861
+ xmlErrorPtr error;
1862
+
1863
+ error = xmlGetLastError();
1864
+ if (error) {
1865
+ rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
1866
+ } else {
1867
+ rb_raise(rb_eRuntimeError, "Could not perform xinclude substitution");
1868
+ }
1869
+ }
1870
+
1871
+ return self;
1872
+ }
1873
+
1874
+
1875
+ /* TODO: DOCUMENT ME */
1876
+ static VALUE
1877
+ in_context(VALUE self, VALUE _str, VALUE _options)
1878
+ {
1879
+ xmlNodePtr node, list = 0, tmp, child_iter, node_children, doc_children;
1880
+ xmlNodeSetPtr set;
1881
+ xmlParserErrors error;
1882
+ VALUE doc, err;
1883
+ int doc_is_empty;
1884
+
1885
+ Data_Get_Struct(self, xmlNode, node);
1886
+
1887
+ doc = DOC_RUBY_OBJECT(node->doc);
1888
+ err = rb_iv_get(doc, "@errors");
1889
+ doc_is_empty = (node->doc->children == NULL) ? 1 : 0;
1890
+ node_children = node->children;
1891
+ doc_children = node->doc->children;
1892
+
1893
+ xmlSetStructuredErrorFunc((void *)err, Nokogiri_error_array_pusher);
1894
+
1895
+ /* Twiddle global variable because of a bug in libxml2.
1896
+ * http://git.gnome.org/browse/libxml2/commit/?id=e20fb5a72c83cbfc8e4a8aa3943c6be8febadab7
1897
+ */
1898
+ #ifndef HTML_PARSE_NOIMPLIED
1899
+ htmlHandleOmittedElem(0);
1900
+ #endif
1901
+
1902
+ /* This function adds a fake node to the child of +node+. If the parser
1903
+ * does not exit cleanly with XML_ERR_OK, the list is freed. This can
1904
+ * leave the child pointers in a bad state if they were originally empty.
1905
+ *
1906
+ * http://git.gnome.org/browse/libxml2/tree/parser.c#n13177
1907
+ * */
1908
+ error = xmlParseInNodeContext(node, StringValuePtr(_str),
1909
+ (int)RSTRING_LEN(_str),
1910
+ (int)NUM2INT(_options), &list);
1911
+
1912
+ /* xmlParseInNodeContext should not mutate the original document or node,
1913
+ * so reassigning these pointers should be OK. The reason we're reassigning
1914
+ * is because if there were errors, it's possible for the child pointers
1915
+ * to be manipulated. */
1916
+ if (error != XML_ERR_OK) {
1917
+ node->doc->children = doc_children;
1918
+ node->children = node_children;
1919
+ }
1920
+
1921
+ /* make sure parent/child pointers are coherent so an unlink will work
1922
+ * properly (#331)
1923
+ */
1924
+ child_iter = node->doc->children ;
1925
+ while (child_iter) {
1926
+ child_iter->parent = (xmlNodePtr)node->doc;
1927
+ child_iter = child_iter->next;
1928
+ }
1929
+
1930
+ #ifndef HTML_PARSE_NOIMPLIED
1931
+ htmlHandleOmittedElem(1);
1932
+ #endif
1933
+
1934
+ xmlSetStructuredErrorFunc(NULL, NULL);
1935
+
1936
+ /* Workaround for a libxml2 bug where a parsing error may leave a broken
1937
+ * node reference in node->doc->children.
1938
+ * This workaround is limited to when a parse error occurs, the document
1939
+ * went from having no children to having children, and the context node is
1940
+ * part of a document fragment.
1941
+ * https://bugzilla.gnome.org/show_bug.cgi?id=668155
1942
+ */
1943
+ if (error != XML_ERR_OK && doc_is_empty && node->doc->children != NULL) {
1944
+ child_iter = node;
1945
+ while (child_iter->parent) {
1946
+ child_iter = child_iter->parent;
1947
+ }
1948
+
1949
+ if (child_iter->type == XML_DOCUMENT_FRAG_NODE) {
1950
+ node->doc->children = NULL;
1951
+ }
1952
+ }
1953
+
1954
+ /* FIXME: This probably needs to handle more constants... */
1955
+ switch (error) {
1956
+ case XML_ERR_INTERNAL_ERROR:
1957
+ case XML_ERR_NO_MEMORY:
1958
+ rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
1959
+ break;
1960
+ default:
1961
+ break;
1962
+ }
1963
+
1964
+ set = xmlXPathNodeSetCreate(NULL);
1965
+
1966
+ while (list) {
1967
+ tmp = list->next;
1968
+ list->next = NULL;
1969
+ xmlXPathNodeSetAddUnique(set, list);
1970
+ noko_xml_document_pin_node(list);
1971
+ list = tmp;
1972
+ }
1973
+
1974
+ return noko_xml_node_set_wrap(set, doc);
1975
+ }
1976
+
1977
+
1978
+ VALUE
1979
+ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
1980
+ {
1981
+ VALUE rb_document, rb_node_cache, rb_node;
1982
+ nokogiriTuplePtr node_has_a_document;
1983
+ xmlDocPtr c_doc;
1984
+ void (*f_mark)(xmlNodePtr) = NULL ;
1985
+
1986
+ assert(c_node);
1987
+
1988
+ if (c_node->type == XML_DOCUMENT_NODE || c_node->type == XML_HTML_DOCUMENT_NODE) {
1989
+ return DOC_RUBY_OBJECT(c_node->doc);
1990
+ }
1991
+
1992
+ /* It's OK if the node doesn't have a fully-realized document (as in XML::Reader). */
1993
+ /* see https://github.com/sparklemotion/nokogiri/issues/95 */
1994
+ /* and https://github.com/sparklemotion/nokogiri/issues/439 */
1995
+ c_doc = c_node->doc;
1996
+ if (c_doc->type == XML_DOCUMENT_FRAG_NODE) { c_doc = c_doc->doc; }
1997
+ node_has_a_document = DOC_RUBY_OBJECT_TEST(c_doc);
1998
+
1999
+ if (c_node->_private && node_has_a_document) {
2000
+ return (VALUE)c_node->_private;
2001
+ }
2002
+
2003
+ if (!RTEST(rb_class)) {
2004
+ switch (c_node->type) {
2005
+ case XML_ELEMENT_NODE:
2006
+ rb_class = cNokogiriXmlElement;
2007
+ break;
2008
+ case XML_TEXT_NODE:
2009
+ rb_class = cNokogiriXmlText;
2010
+ break;
2011
+ case XML_ATTRIBUTE_NODE:
2012
+ rb_class = cNokogiriXmlAttr;
2013
+ break;
2014
+ case XML_ENTITY_REF_NODE:
2015
+ rb_class = cNokogiriXmlEntityReference;
2016
+ break;
2017
+ case XML_COMMENT_NODE:
2018
+ rb_class = cNokogiriXmlComment;
2019
+ break;
2020
+ case XML_DOCUMENT_FRAG_NODE:
2021
+ rb_class = cNokogiriXmlDocumentFragment;
2022
+ break;
2023
+ case XML_PI_NODE:
2024
+ rb_class = cNokogiriXmlProcessingInstruction;
2025
+ break;
2026
+ case XML_ENTITY_DECL:
2027
+ rb_class = cNokogiriXmlEntityDecl;
2028
+ break;
2029
+ case XML_CDATA_SECTION_NODE:
2030
+ rb_class = cNokogiriXmlCData;
2031
+ break;
2032
+ case XML_DTD_NODE:
2033
+ rb_class = cNokogiriXmlDtd;
2034
+ break;
2035
+ case XML_ATTRIBUTE_DECL:
2036
+ rb_class = cNokogiriXmlAttributeDecl;
2037
+ break;
2038
+ case XML_ELEMENT_DECL:
2039
+ rb_class = cNokogiriXmlElementDecl;
2040
+ break;
2041
+ default:
2042
+ rb_class = cNokogiriXmlNode;
2043
+ }
2044
+ }
2045
+
2046
+ f_mark = node_has_a_document ? _xml_node_mark : NULL ;
2047
+
2048
+ rb_node = Data_Wrap_Struct(rb_class, f_mark, _xml_node_dealloc, c_node) ;
2049
+ c_node->_private = (void *)rb_node;
2050
+
2051
+ if (node_has_a_document) {
2052
+ rb_document = DOC_RUBY_OBJECT(c_doc);
2053
+ rb_node_cache = DOC_NODE_CACHE(c_doc);
2054
+ rb_ary_push(rb_node_cache, rb_node);
2055
+ rb_funcall(rb_document, id_decorate, 1, rb_node);
2056
+ }
2057
+
2058
+ return rb_node ;
2059
+ }
2060
+
2061
+
2062
+ /*
2063
+ * return Array<Nokogiri::XML::Attr> containing the node's attributes
2064
+ */
2065
+ VALUE
2066
+ noko_xml_node_attrs(xmlNodePtr c_node)
2067
+ {
2068
+ VALUE rb_properties = rb_ary_new();
2069
+ xmlAttrPtr c_property;
2070
+
2071
+ c_property = c_node->properties ;
2072
+ while (c_property != NULL) {
2073
+ rb_ary_push(rb_properties, noko_xml_node_wrap(Qnil, (xmlNodePtr)c_property));
2074
+ c_property = c_property->next ;
2075
+ }
2076
+
2077
+ return rb_properties;
2078
+ }
2079
+
2080
+ void
2081
+ noko_init_xml_node()
2082
+ {
2083
+ cNokogiriXmlNode = rb_define_class_under(mNokogiriXml, "Node", rb_cObject);
2084
+
2085
+ rb_undef_alloc_func(cNokogiriXmlNode);
2086
+
2087
+ rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1);
2088
+
2089
+ rb_define_method(cNokogiriXmlNode, "add_namespace_definition", rb_xml_node_add_namespace_definition, 2);
2090
+ rb_define_method(cNokogiriXmlNode, "attribute", rb_xml_node_attribute, 1);
2091
+ rb_define_method(cNokogiriXmlNode, "attribute_nodes", rb_xml_node_attribute_nodes, 0);
2092
+ rb_define_method(cNokogiriXmlNode, "attribute_with_ns", rb_xml_node_attribute_with_ns, 2);
2093
+ rb_define_method(cNokogiriXmlNode, "blank?", rb_xml_node_blank_eh, 0);
2094
+ rb_define_method(cNokogiriXmlNode, "child", rb_xml_node_child, 0);
2095
+ rb_define_method(cNokogiriXmlNode, "children", rb_xml_node_children, 0);
2096
+ rb_define_method(cNokogiriXmlNode, "content", rb_xml_node_content, 0);
2097
+ rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
2098
+ rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
2099
+ rb_define_method(cNokogiriXmlNode, "document", rb_xml_node_document, 0);
2100
+ rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
2101
+ rb_define_method(cNokogiriXmlNode, "element_children", rb_xml_node_element_children, 0);
2102
+ rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
2103
+ rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
2104
+ rb_define_method(cNokogiriXmlNode, "first_element_child", rb_xml_node_first_element_child, 0);
2105
+ rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
2106
+ rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
2107
+ rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
2108
+ rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
2109
+ rb_define_method(cNokogiriXmlNode, "last_element_child", rb_xml_node_last_element_child, 0);
2110
+ rb_define_method(cNokogiriXmlNode, "line", rb_xml_node_line, 0);
2111
+ rb_define_method(cNokogiriXmlNode, "line=", rb_xml_node_line_set, 1);
2112
+ rb_define_method(cNokogiriXmlNode, "namespace", rb_xml_node_namespace, 0);
2113
+ rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
2114
+ rb_define_method(cNokogiriXmlNode, "namespace_scopes", rb_xml_node_namespace_scopes, 0);
2115
+ rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
2116
+ rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
2117
+ rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0);
2118
+ rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
2119
+ rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0);
2120
+ rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1);
2121
+ rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
2122
+ rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0);
2123
+ rb_define_method(cNokogiriXmlNode, "path", rb_xml_node_path, 0);
2124
+ rb_define_method(cNokogiriXmlNode, "pointer_id", rb_xml_node_pointer_id, 0);
2125
+ rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0);
2126
+ rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
2127
+ rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
2128
+
2129
+ rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
2130
+ rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1);
2131
+ rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
2132
+ rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
2133
+ rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0);
2134
+ rb_define_private_method(cNokogiriXmlNode, "get", get, 1);
2135
+ rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
2136
+ rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
2137
+ rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
2138
+ rb_define_private_method(cNokogiriXmlNode, "replace_node", replace, 1);
2139
+ rb_define_private_method(cNokogiriXmlNode, "set", set, 2);
2140
+ rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1);
2141
+
2142
+ id_decorate = rb_intern("decorate");
2143
+ id_decorate_bang = rb_intern("decorate!");
2144
+ }