nokogiri 1.8.5 → 1.15.3
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.
- checksums.yaml +4 -4
- data/Gemfile +40 -18
- data/LICENSE-DEPENDENCIES.md +1636 -1024
- data/LICENSE.md +5 -28
- data/README.md +203 -90
- data/bin/nokogiri +63 -50
- data/dependencies.yml +33 -61
- data/ext/nokogiri/depend +38 -358
- data/ext/nokogiri/extconf.rb +867 -417
- data/ext/nokogiri/gumbo.c +594 -0
- data/ext/nokogiri/html4_document.c +165 -0
- data/ext/nokogiri/html4_element_description.c +299 -0
- data/ext/nokogiri/html4_entity_lookup.c +37 -0
- data/ext/nokogiri/html4_sax_parser_context.c +108 -0
- data/ext/nokogiri/html4_sax_push_parser.c +95 -0
- data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
- data/ext/nokogiri/nokogiri.c +251 -105
- data/ext/nokogiri/nokogiri.h +215 -90
- data/ext/nokogiri/test_global_handlers.c +40 -0
- data/ext/nokogiri/xml_attr.c +42 -37
- data/ext/nokogiri/xml_attribute_decl.c +22 -22
- data/ext/nokogiri/xml_cdata.c +40 -31
- data/ext/nokogiri/xml_comment.c +20 -27
- data/ext/nokogiri/xml_document.c +401 -237
- data/ext/nokogiri/xml_document_fragment.c +13 -17
- data/ext/nokogiri/xml_dtd.c +64 -58
- data/ext/nokogiri/xml_element_content.c +63 -55
- data/ext/nokogiri/xml_element_decl.c +31 -31
- data/ext/nokogiri/xml_encoding_handler.c +54 -21
- data/ext/nokogiri/xml_entity_decl.c +37 -35
- data/ext/nokogiri/xml_entity_reference.c +17 -19
- data/ext/nokogiri/xml_namespace.c +136 -62
- data/ext/nokogiri/xml_node.c +1387 -678
- data/ext/nokogiri/xml_node_set.c +246 -216
- data/ext/nokogiri/xml_processing_instruction.c +18 -20
- data/ext/nokogiri/xml_reader.c +347 -212
- data/ext/nokogiri/xml_relax_ng.c +86 -77
- data/ext/nokogiri/xml_sax_parser.c +149 -124
- data/ext/nokogiri/xml_sax_parser_context.c +145 -103
- data/ext/nokogiri/xml_sax_push_parser.c +64 -36
- data/ext/nokogiri/xml_schema.c +138 -81
- data/ext/nokogiri/xml_syntax_error.c +42 -21
- data/ext/nokogiri/xml_text.c +36 -26
- data/ext/nokogiri/xml_xpath_context.c +366 -178
- data/ext/nokogiri/xslt_stylesheet.c +335 -189
- data/gumbo-parser/CHANGES.md +63 -0
- data/gumbo-parser/Makefile +111 -0
- data/gumbo-parser/THANKS +27 -0
- data/gumbo-parser/src/Makefile +34 -0
- data/gumbo-parser/src/README.md +41 -0
- data/gumbo-parser/src/ascii.c +75 -0
- data/gumbo-parser/src/ascii.h +115 -0
- data/gumbo-parser/src/attribute.c +42 -0
- data/gumbo-parser/src/attribute.h +17 -0
- data/gumbo-parser/src/char_ref.c +22225 -0
- data/gumbo-parser/src/char_ref.h +29 -0
- data/gumbo-parser/src/char_ref.rl +2154 -0
- data/gumbo-parser/src/error.c +630 -0
- data/gumbo-parser/src/error.h +148 -0
- data/gumbo-parser/src/foreign_attrs.c +103 -0
- data/gumbo-parser/src/foreign_attrs.gperf +27 -0
- data/gumbo-parser/src/insertion_mode.h +33 -0
- data/gumbo-parser/src/macros.h +91 -0
- data/gumbo-parser/src/nokogiri_gumbo.h +944 -0
- data/gumbo-parser/src/parser.c +4891 -0
- data/gumbo-parser/src/parser.h +41 -0
- data/gumbo-parser/src/replacement.h +33 -0
- data/gumbo-parser/src/string_buffer.c +103 -0
- data/gumbo-parser/src/string_buffer.h +68 -0
- data/gumbo-parser/src/string_piece.c +48 -0
- data/gumbo-parser/src/svg_attrs.c +174 -0
- data/gumbo-parser/src/svg_attrs.gperf +77 -0
- data/gumbo-parser/src/svg_tags.c +137 -0
- data/gumbo-parser/src/svg_tags.gperf +55 -0
- data/gumbo-parser/src/tag.c +223 -0
- data/gumbo-parser/src/tag_lookup.c +382 -0
- data/gumbo-parser/src/tag_lookup.gperf +170 -0
- data/gumbo-parser/src/tag_lookup.h +13 -0
- data/gumbo-parser/src/token_buffer.c +79 -0
- data/gumbo-parser/src/token_buffer.h +71 -0
- data/gumbo-parser/src/token_type.h +17 -0
- data/gumbo-parser/src/tokenizer.c +3463 -0
- data/gumbo-parser/src/tokenizer.h +112 -0
- data/gumbo-parser/src/tokenizer_states.h +339 -0
- data/gumbo-parser/src/utf8.c +245 -0
- data/gumbo-parser/src/utf8.h +164 -0
- data/gumbo-parser/src/util.c +66 -0
- data/gumbo-parser/src/util.h +34 -0
- data/gumbo-parser/src/vector.c +111 -0
- data/gumbo-parser/src/vector.h +45 -0
- data/lib/nokogiri/class_resolver.rb +67 -0
- data/lib/nokogiri/css/node.rb +10 -8
- data/lib/nokogiri/css/parser.rb +397 -377
- data/lib/nokogiri/css/parser.y +250 -245
- data/lib/nokogiri/css/parser_extras.rb +54 -49
- data/lib/nokogiri/css/syntax_error.rb +3 -1
- data/lib/nokogiri/css/tokenizer.rb +107 -104
- data/lib/nokogiri/css/tokenizer.rex +3 -2
- data/lib/nokogiri/css/xpath_visitor.rb +224 -95
- data/lib/nokogiri/css.rb +56 -17
- data/lib/nokogiri/decorators/slop.rb +9 -7
- data/lib/nokogiri/encoding_handler.rb +57 -0
- data/lib/nokogiri/extension.rb +32 -0
- data/lib/nokogiri/gumbo.rb +15 -0
- data/lib/nokogiri/html.rb +38 -27
- data/lib/nokogiri/{html → html4}/builder.rb +4 -2
- data/lib/nokogiri/html4/document.rb +214 -0
- data/lib/nokogiri/html4/document_fragment.rb +54 -0
- data/lib/nokogiri/{html → html4}/element_description.rb +3 -1
- data/lib/nokogiri/html4/element_description_defaults.rb +2040 -0
- data/lib/nokogiri/html4/encoding_reader.rb +121 -0
- data/lib/nokogiri/{html → html4}/entity_lookup.rb +4 -2
- data/lib/nokogiri/{html → html4}/sax/parser.rb +17 -16
- data/lib/nokogiri/html4/sax/parser_context.rb +20 -0
- data/lib/nokogiri/{html → html4}/sax/push_parser.rb +12 -11
- data/lib/nokogiri/html4.rb +47 -0
- data/lib/nokogiri/html5/document.rb +168 -0
- data/lib/nokogiri/html5/document_fragment.rb +90 -0
- data/lib/nokogiri/html5/node.rb +103 -0
- data/lib/nokogiri/html5.rb +392 -0
- data/lib/nokogiri/jruby/dependencies.rb +3 -0
- data/lib/nokogiri/jruby/nokogiri_jars.rb +43 -0
- data/lib/nokogiri/syntax_error.rb +2 -0
- data/lib/nokogiri/version/constant.rb +6 -0
- data/lib/nokogiri/version/info.rb +223 -0
- data/lib/nokogiri/version.rb +3 -108
- data/lib/nokogiri/xml/attr.rb +55 -3
- data/lib/nokogiri/xml/attribute_decl.rb +6 -2
- data/lib/nokogiri/xml/builder.rb +98 -54
- data/lib/nokogiri/xml/cdata.rb +3 -1
- data/lib/nokogiri/xml/character_data.rb +2 -0
- data/lib/nokogiri/xml/document.rb +312 -126
- data/lib/nokogiri/xml/document_fragment.rb +104 -48
- data/lib/nokogiri/xml/dtd.rb +4 -2
- data/lib/nokogiri/xml/element_content.rb +12 -2
- data/lib/nokogiri/xml/element_decl.rb +6 -2
- data/lib/nokogiri/xml/entity_decl.rb +7 -3
- data/lib/nokogiri/xml/entity_reference.rb +2 -0
- data/lib/nokogiri/xml/namespace.rb +45 -0
- data/lib/nokogiri/xml/node/save_options.rb +23 -8
- data/lib/nokogiri/xml/node.rb +1093 -411
- data/lib/nokogiri/xml/node_set.rb +173 -67
- data/lib/nokogiri/xml/notation.rb +13 -0
- data/lib/nokogiri/xml/parse_options.rb +145 -52
- data/lib/nokogiri/xml/pp/character_data.rb +9 -6
- data/lib/nokogiri/xml/pp/node.rb +42 -30
- data/lib/nokogiri/xml/pp.rb +4 -2
- data/lib/nokogiri/xml/processing_instruction.rb +4 -1
- data/lib/nokogiri/xml/reader.rb +21 -28
- data/lib/nokogiri/xml/relax_ng.rb +8 -2
- data/lib/nokogiri/xml/sax/document.rb +45 -49
- data/lib/nokogiri/xml/sax/parser.rb +39 -36
- data/lib/nokogiri/xml/sax/parser_context.rb +8 -3
- data/lib/nokogiri/xml/sax/push_parser.rb +6 -5
- data/lib/nokogiri/xml/sax.rb +6 -4
- data/lib/nokogiri/xml/schema.rb +19 -9
- data/lib/nokogiri/xml/searchable.rb +120 -72
- data/lib/nokogiri/xml/syntax_error.rb +6 -4
- data/lib/nokogiri/xml/text.rb +2 -0
- data/lib/nokogiri/xml/xpath/syntax_error.rb +4 -2
- data/lib/nokogiri/xml/xpath.rb +15 -4
- data/lib/nokogiri/xml/xpath_context.rb +3 -3
- data/lib/nokogiri/xml.rb +38 -37
- data/lib/nokogiri/xslt/stylesheet.rb +3 -1
- data/lib/nokogiri/xslt.rb +101 -22
- data/lib/nokogiri.rb +59 -75
- data/lib/xsd/xmlparser/nokogiri.rb +29 -25
- data/patches/libxml2/0001-Remove-script-macro-support.patch +40 -0
- data/patches/libxml2/0002-Update-entities-to-remove-handling-of-ssi.patch +44 -0
- data/patches/libxml2/0003-libxml2.la-is-in-top_builddir.patch +25 -0
- data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
- data/patches/libxml2/0010-update-config.guess-and-config.sub-for-libxml2.patch +224 -0
- data/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +30 -0
- data/patches/libxslt/0001-update-config.guess-and-config.sub-for-libxslt.patch +224 -0
- data/ports/archives/libxml2-2.11.4.tar.xz +0 -0
- data/ports/archives/libxslt-1.1.38.tar.xz +0 -0
- metadata +126 -399
- data/.autotest +0 -22
- data/.cross_rubies +0 -8
- data/.editorconfig +0 -17
- data/.gemtest +0 -0
- data/.travis.yml +0 -63
- data/CHANGELOG.md +0 -1368
- data/CONTRIBUTING.md +0 -42
- data/C_CODING_STYLE.rdoc +0 -33
- data/Gemfile-libxml-ruby +0 -3
- data/Manifest.txt +0 -370
- data/ROADMAP.md +0 -111
- data/Rakefile +0 -348
- data/SECURITY.md +0 -19
- data/STANDARD_RESPONSES.md +0 -47
- data/Y_U_NO_GEMSPEC.md +0 -155
- data/appveyor.yml +0 -29
- data/build_all +0 -44
- data/ext/nokogiri/html_document.c +0 -170
- data/ext/nokogiri/html_document.h +0 -10
- data/ext/nokogiri/html_element_description.c +0 -279
- data/ext/nokogiri/html_element_description.h +0 -10
- data/ext/nokogiri/html_entity_lookup.c +0 -32
- data/ext/nokogiri/html_entity_lookup.h +0 -8
- data/ext/nokogiri/html_sax_parser_context.c +0 -116
- data/ext/nokogiri/html_sax_parser_context.h +0 -11
- data/ext/nokogiri/html_sax_push_parser.c +0 -87
- data/ext/nokogiri/html_sax_push_parser.h +0 -9
- data/ext/nokogiri/xml_attr.h +0 -9
- data/ext/nokogiri/xml_attribute_decl.h +0 -9
- data/ext/nokogiri/xml_cdata.h +0 -9
- data/ext/nokogiri/xml_comment.h +0 -9
- data/ext/nokogiri/xml_document.h +0 -23
- data/ext/nokogiri/xml_document_fragment.h +0 -10
- data/ext/nokogiri/xml_dtd.h +0 -10
- data/ext/nokogiri/xml_element_content.h +0 -10
- data/ext/nokogiri/xml_element_decl.h +0 -9
- data/ext/nokogiri/xml_encoding_handler.h +0 -8
- data/ext/nokogiri/xml_entity_decl.h +0 -10
- data/ext/nokogiri/xml_entity_reference.h +0 -9
- data/ext/nokogiri/xml_io.c +0 -61
- data/ext/nokogiri/xml_io.h +0 -11
- data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
- data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
- data/ext/nokogiri/xml_namespace.h +0 -15
- data/ext/nokogiri/xml_node.h +0 -13
- data/ext/nokogiri/xml_node_set.h +0 -12
- data/ext/nokogiri/xml_processing_instruction.h +0 -9
- data/ext/nokogiri/xml_reader.h +0 -10
- data/ext/nokogiri/xml_relax_ng.h +0 -9
- data/ext/nokogiri/xml_sax_parser.h +0 -39
- data/ext/nokogiri/xml_sax_parser_context.h +0 -10
- data/ext/nokogiri/xml_sax_push_parser.h +0 -9
- data/ext/nokogiri/xml_schema.h +0 -9
- data/ext/nokogiri/xml_syntax_error.h +0 -13
- data/ext/nokogiri/xml_text.h +0 -9
- data/ext/nokogiri/xml_xpath_context.h +0 -10
- data/ext/nokogiri/xslt_stylesheet.h +0 -14
- data/lib/nokogiri/html/document.rb +0 -335
- data/lib/nokogiri/html/document_fragment.rb +0 -49
- data/lib/nokogiri/html/element_description_defaults.rb +0 -671
- data/lib/nokogiri/html/sax/parser_context.rb +0 -16
- data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
- data/patches/libxml2/0002-Fix-nullptr-deref-with-XPath-logic-ops.patch +0 -54
- data/patches/libxml2/0003-Fix-infinite-loop-in-LZMA-decompression.patch +0 -50
- data/patches/sort-patches-by-date +0 -25
- data/ports/archives/libxml2-2.9.8.tar.gz +0 -0
- data/ports/archives/libxslt-1.1.32.tar.gz +0 -0
- data/suppressions/README.txt +0 -1
- data/suppressions/nokogiri_ruby-2.supp +0 -10
- data/tasks/test.rb +0 -100
- data/test/css/test_nthiness.rb +0 -226
- data/test/css/test_parser.rb +0 -386
- data/test/css/test_tokenizer.rb +0 -215
- data/test/css/test_xpath_visitor.rb +0 -96
- data/test/decorators/test_slop.rb +0 -23
- data/test/files/2ch.html +0 -108
- data/test/files/GH_1042.html +0 -18
- data/test/files/address_book.rlx +0 -12
- data/test/files/address_book.xml +0 -10
- data/test/files/atom.xml +0 -344
- data/test/files/bar/bar.xsd +0 -4
- data/test/files/bogus.xml +0 -0
- data/test/files/dont_hurt_em_why.xml +0 -422
- data/test/files/encoding.html +0 -82
- data/test/files/encoding.xhtml +0 -84
- data/test/files/exslt.xml +0 -8
- data/test/files/exslt.xslt +0 -35
- data/test/files/foo/foo.xsd +0 -4
- data/test/files/metacharset.html +0 -10
- data/test/files/namespace_pressure_test.xml +0 -1684
- data/test/files/noencoding.html +0 -47
- data/test/files/po.xml +0 -32
- data/test/files/po.xsd +0 -66
- data/test/files/saml/saml20assertion_schema.xsd +0 -283
- data/test/files/saml/saml20protocol_schema.xsd +0 -302
- data/test/files/saml/xenc_schema.xsd +0 -146
- data/test/files/saml/xmldsig_schema.xsd +0 -318
- data/test/files/shift_jis.html +0 -10
- data/test/files/shift_jis.xml +0 -5
- data/test/files/shift_jis_no_charset.html +0 -9
- data/test/files/slow-xpath.xml +0 -25509
- data/test/files/snuggles.xml +0 -3
- data/test/files/staff.dtd +0 -10
- data/test/files/staff.xml +0 -59
- data/test/files/staff.xslt +0 -32
- data/test/files/test_document_url/bar.xml +0 -2
- data/test/files/test_document_url/document.dtd +0 -4
- data/test/files/test_document_url/document.xml +0 -6
- data/test/files/tlm.html +0 -851
- data/test/files/to_be_xincluded.xml +0 -2
- data/test/files/valid_bar.xml +0 -2
- data/test/files/xinclude.xml +0 -4
- data/test/helper.rb +0 -271
- data/test/html/sax/test_parser.rb +0 -168
- data/test/html/sax/test_parser_context.rb +0 -46
- data/test/html/sax/test_parser_text.rb +0 -163
- data/test/html/sax/test_push_parser.rb +0 -87
- data/test/html/test_attributes.rb +0 -85
- data/test/html/test_builder.rb +0 -164
- data/test/html/test_document.rb +0 -712
- data/test/html/test_document_encoding.rb +0 -143
- data/test/html/test_document_fragment.rb +0 -310
- data/test/html/test_element_description.rb +0 -105
- data/test/html/test_named_characters.rb +0 -14
- data/test/html/test_node.rb +0 -212
- data/test/html/test_node_encoding.rb +0 -91
- data/test/namespaces/test_additional_namespaces_in_builder_doc.rb +0 -14
- data/test/namespaces/test_namespaces_aliased_default.rb +0 -24
- data/test/namespaces/test_namespaces_in_builder_doc.rb +0 -75
- data/test/namespaces/test_namespaces_in_cloned_doc.rb +0 -31
- data/test/namespaces/test_namespaces_in_created_doc.rb +0 -75
- data/test/namespaces/test_namespaces_in_parsed_doc.rb +0 -80
- data/test/namespaces/test_namespaces_preservation.rb +0 -31
- data/test/test_convert_xpath.rb +0 -135
- data/test/test_css_cache.rb +0 -47
- data/test/test_encoding_handler.rb +0 -48
- data/test/test_memory_leak.rb +0 -156
- data/test/test_nokogiri.rb +0 -138
- data/test/test_soap4r_sax.rb +0 -52
- data/test/test_xslt_transforms.rb +0 -314
- data/test/xml/node/test_save_options.rb +0 -28
- data/test/xml/node/test_subclass.rb +0 -44
- data/test/xml/sax/test_parser.rb +0 -402
- data/test/xml/sax/test_parser_context.rb +0 -115
- data/test/xml/sax/test_parser_text.rb +0 -202
- data/test/xml/sax/test_push_parser.rb +0 -265
- data/test/xml/test_attr.rb +0 -74
- data/test/xml/test_attribute_decl.rb +0 -86
- data/test/xml/test_builder.rb +0 -341
- data/test/xml/test_c14n.rb +0 -180
- data/test/xml/test_cdata.rb +0 -54
- data/test/xml/test_comment.rb +0 -40
- data/test/xml/test_document.rb +0 -982
- data/test/xml/test_document_encoding.rb +0 -31
- data/test/xml/test_document_fragment.rb +0 -298
- data/test/xml/test_dtd.rb +0 -187
- data/test/xml/test_dtd_encoding.rb +0 -31
- data/test/xml/test_element_content.rb +0 -56
- data/test/xml/test_element_decl.rb +0 -73
- data/test/xml/test_entity_decl.rb +0 -122
- data/test/xml/test_entity_reference.rb +0 -262
- data/test/xml/test_namespace.rb +0 -96
- data/test/xml/test_node.rb +0 -1325
- data/test/xml/test_node_attributes.rb +0 -115
- data/test/xml/test_node_encoding.rb +0 -75
- data/test/xml/test_node_inheritance.rb +0 -32
- data/test/xml/test_node_reparenting.rb +0 -592
- data/test/xml/test_node_set.rb +0 -809
- data/test/xml/test_parse_options.rb +0 -64
- data/test/xml/test_processing_instruction.rb +0 -30
- data/test/xml/test_reader.rb +0 -620
- data/test/xml/test_reader_encoding.rb +0 -134
- data/test/xml/test_relax_ng.rb +0 -60
- data/test/xml/test_schema.rb +0 -142
- data/test/xml/test_syntax_error.rb +0 -36
- data/test/xml/test_text.rb +0 -60
- data/test/xml/test_unparented_node.rb +0 -483
- data/test/xml/test_xinclude.rb +0 -83
- data/test/xml/test_xpath.rb +0 -470
- data/test/xslt/test_custom_functions.rb +0 -133
- data/test/xslt/test_exception_handling.rb +0 -37
data/ext/nokogiri/xml_node.c
CHANGED
@@ -1,48 +1,73 @@
|
|
1
|
-
#include <
|
1
|
+
#include <nokogiri.h>
|
2
2
|
|
3
|
-
|
3
|
+
#include <stdbool.h>
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#else
|
12
|
-
# define debug_node_dealloc 0
|
13
|
-
#endif
|
5
|
+
// :stopdoc:
|
6
|
+
|
7
|
+
VALUE cNokogiriXmlNode ;
|
8
|
+
static ID id_decorate, id_decorate_bang;
|
9
|
+
|
10
|
+
typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
|
14
11
|
|
15
|
-
static void
|
12
|
+
static void
|
13
|
+
_xml_node_mark(void *ptr)
|
16
14
|
{
|
15
|
+
xmlNodePtr node = ptr;
|
16
|
+
|
17
|
+
if (!DOC_RUBY_OBJECT_TEST(node->doc)) {
|
18
|
+
return;
|
19
|
+
}
|
20
|
+
|
17
21
|
xmlDocPtr doc = node->doc;
|
18
|
-
if(doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
|
19
|
-
if(DOC_RUBY_OBJECT_TEST(doc)) {
|
22
|
+
if (doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
|
23
|
+
if (DOC_RUBY_OBJECT_TEST(doc)) {
|
20
24
|
rb_gc_mark(DOC_RUBY_OBJECT(doc));
|
21
25
|
}
|
22
|
-
} else if(node->doc->_private) {
|
26
|
+
} else if (node->doc->_private) {
|
23
27
|
rb_gc_mark((VALUE)doc->_private);
|
24
28
|
}
|
25
29
|
}
|
26
30
|
|
27
|
-
|
28
|
-
|
31
|
+
#ifdef HAVE_RB_GC_LOCATION
|
32
|
+
static void
|
33
|
+
_xml_node_update_references(void *ptr)
|
34
|
+
{
|
35
|
+
xmlNodePtr node = ptr;
|
29
36
|
|
30
|
-
|
31
|
-
|
37
|
+
if (node->_private) {
|
38
|
+
node->_private = (void *)rb_gc_location((VALUE)node->_private);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
#else
|
42
|
+
# define _xml_node_update_references 0
|
43
|
+
#endif
|
44
|
+
|
45
|
+
static const rb_data_type_t nokogiri_node_type = {
|
46
|
+
.wrap_struct_name = "Nokogiri::XML::Node",
|
47
|
+
.function = {
|
48
|
+
.dmark = _xml_node_mark,
|
49
|
+
.dcompact = _xml_node_update_references,
|
50
|
+
},
|
51
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
52
|
+
};
|
53
|
+
|
54
|
+
static void
|
55
|
+
relink_namespace(xmlNodePtr reparented)
|
32
56
|
{
|
33
57
|
xmlNodePtr child;
|
34
|
-
|
58
|
+
xmlAttrPtr attr;
|
35
59
|
|
36
60
|
if (reparented->type != XML_ATTRIBUTE_NODE &&
|
37
61
|
reparented->type != XML_ELEMENT_NODE) { return; }
|
38
62
|
|
39
63
|
if (reparented->ns == NULL || reparented->ns->prefix == NULL) {
|
40
|
-
|
64
|
+
xmlNsPtr ns = NULL;
|
65
|
+
xmlChar *name = NULL, *prefix = NULL;
|
41
66
|
|
42
67
|
name = xmlSplitQName2(reparented->name, &prefix);
|
43
68
|
|
44
69
|
if (reparented->type == XML_ATTRIBUTE_NODE) {
|
45
|
-
if (prefix == NULL || strcmp((char*)prefix, XMLNS_PREFIX) == 0) {
|
70
|
+
if (prefix == NULL || strcmp((char *)prefix, XMLNS_PREFIX) == 0) {
|
46
71
|
xmlFree(name);
|
47
72
|
xmlFree(prefix);
|
48
73
|
return;
|
@@ -51,10 +76,6 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
51
76
|
|
52
77
|
ns = xmlSearchNs(reparented->doc, reparented, prefix);
|
53
78
|
|
54
|
-
if (ns == NULL && reparented->parent) {
|
55
|
-
ns = xmlSearchNs(reparented->doc, reparented->parent, prefix);
|
56
|
-
}
|
57
|
-
|
58
79
|
if (ns != NULL) {
|
59
80
|
xmlNodeSetName(reparented, name);
|
60
81
|
xmlSetNs(reparented, ns);
|
@@ -68,7 +89,9 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
68
89
|
if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; }
|
69
90
|
|
70
91
|
/* Make sure that our reparented node has the correct namespaces */
|
71
|
-
if (!reparented->ns &&
|
92
|
+
if (!reparented->ns &&
|
93
|
+
(reparented->doc != (xmlDocPtr)reparented->parent) &&
|
94
|
+
(rb_iv_get(DOC_RUBY_OBJECT(reparented->doc), "@namespace_inheritance") == Qtrue)) {
|
72
95
|
xmlSetNs(reparented, reparented->parent->ns);
|
73
96
|
}
|
74
97
|
|
@@ -91,7 +114,7 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
91
114
|
} else {
|
92
115
|
reparented->nsDef = curr->next;
|
93
116
|
}
|
94
|
-
|
117
|
+
noko_xml_document_pin_namespace(curr, reparented->doc);
|
95
118
|
} else {
|
96
119
|
prev = curr;
|
97
120
|
}
|
@@ -99,6 +122,25 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
99
122
|
}
|
100
123
|
}
|
101
124
|
|
125
|
+
/*
|
126
|
+
* Search our parents for an existing definition of current namespace,
|
127
|
+
* because the definition it's pointing to may have just been removed nsDef.
|
128
|
+
*
|
129
|
+
* And although that would technically probably be OK, I'd feel better if we
|
130
|
+
* referred to a namespace that's still present in a node's nsDef somewhere
|
131
|
+
* in the doc.
|
132
|
+
*/
|
133
|
+
if (reparented->ns) {
|
134
|
+
xmlNsPtr ns = xmlSearchNs(reparented->doc, reparented, reparented->ns->prefix);
|
135
|
+
if (ns
|
136
|
+
&& ns != reparented->ns
|
137
|
+
&& xmlStrEqual(ns->prefix, reparented->ns->prefix)
|
138
|
+
&& xmlStrEqual(ns->href, reparented->ns->href)
|
139
|
+
) {
|
140
|
+
xmlSetNs(reparented, ns);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
102
144
|
/* Only walk all children if there actually is a namespace we need to */
|
103
145
|
/* reparent. */
|
104
146
|
if (NULL == reparented->ns) { return; }
|
@@ -112,16 +154,19 @@ static void relink_namespace(xmlNodePtr reparented)
|
|
112
154
|
}
|
113
155
|
|
114
156
|
if (reparented->type == XML_ELEMENT_NODE) {
|
115
|
-
|
116
|
-
while(NULL !=
|
117
|
-
relink_namespace(
|
118
|
-
|
157
|
+
attr = reparented->properties;
|
158
|
+
while (NULL != attr) {
|
159
|
+
relink_namespace((xmlNodePtr)attr);
|
160
|
+
attr = attr->next;
|
119
161
|
}
|
120
162
|
}
|
121
163
|
}
|
122
164
|
|
123
|
-
|
124
|
-
|
165
|
+
|
166
|
+
/* internal function meant to wrap xmlReplaceNode
|
167
|
+
and fix some issues we have with libxml2 merging nodes */
|
168
|
+
static xmlNodePtr
|
169
|
+
xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
|
125
170
|
{
|
126
171
|
xmlNodePtr retval ;
|
127
172
|
|
@@ -144,22 +189,34 @@ static xmlNodePtr xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
|
|
144
189
|
return retval ;
|
145
190
|
}
|
146
191
|
|
147
|
-
|
148
|
-
static
|
192
|
+
|
193
|
+
static void
|
194
|
+
raise_if_ancestor_of_self(xmlNodePtr self)
|
195
|
+
{
|
196
|
+
for (xmlNodePtr ancestor = self->parent ; ancestor ; ancestor = ancestor->parent) {
|
197
|
+
if (self == ancestor) {
|
198
|
+
rb_raise(rb_eRuntimeError, "cycle detected: node '%s' is an ancestor of itself", self->name);
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
|
204
|
+
static VALUE
|
205
|
+
reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
|
149
206
|
{
|
150
207
|
VALUE reparented_obj ;
|
151
|
-
xmlNodePtr reparentee, pivot, reparented, next_text, new_next_text, parent ;
|
208
|
+
xmlNodePtr reparentee, original_reparentee, pivot, reparented, next_text, new_next_text, parent ;
|
152
209
|
int original_ns_prefix_is_default = 0 ;
|
153
210
|
|
154
|
-
if(!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) {
|
211
|
+
if (!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode)) {
|
155
212
|
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
|
156
213
|
}
|
157
|
-
if(rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument)) {
|
214
|
+
if (rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument)) {
|
158
215
|
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
|
159
216
|
}
|
160
217
|
|
161
|
-
|
162
|
-
|
218
|
+
Noko_Node_Get_Struct(reparentee_obj, xmlNode, reparentee);
|
219
|
+
Noko_Node_Get_Struct(pivot_obj, xmlNode, pivot);
|
163
220
|
|
164
221
|
/*
|
165
222
|
* Check if nodes given are appropriate to have a parent-child
|
@@ -175,66 +232,66 @@ static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_rep
|
|
175
232
|
|
176
233
|
if (parent) {
|
177
234
|
switch (parent->type) {
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
235
|
+
case XML_DOCUMENT_NODE:
|
236
|
+
case XML_HTML_DOCUMENT_NODE:
|
237
|
+
switch (reparentee->type) {
|
238
|
+
case XML_ELEMENT_NODE:
|
239
|
+
case XML_PI_NODE:
|
240
|
+
case XML_COMMENT_NODE:
|
241
|
+
case XML_DOCUMENT_TYPE_NODE:
|
242
|
+
/*
|
243
|
+
* The DOM specification says no to adding text-like nodes
|
244
|
+
* directly to a document, but we allow it for compatibility.
|
245
|
+
*/
|
246
|
+
case XML_TEXT_NODE:
|
247
|
+
case XML_CDATA_SECTION_NODE:
|
248
|
+
case XML_ENTITY_REF_NODE:
|
249
|
+
goto ok;
|
250
|
+
default:
|
251
|
+
break;
|
252
|
+
}
|
194
253
|
break;
|
195
|
-
|
196
|
-
break;
|
197
|
-
case XML_DOCUMENT_FRAG_NODE:
|
198
|
-
case XML_ENTITY_REF_NODE:
|
199
|
-
case XML_ELEMENT_NODE:
|
200
|
-
switch (reparentee->type) {
|
201
|
-
case XML_ELEMENT_NODE:
|
202
|
-
case XML_PI_NODE:
|
203
|
-
case XML_COMMENT_NODE:
|
204
|
-
case XML_TEXT_NODE:
|
205
|
-
case XML_CDATA_SECTION_NODE:
|
254
|
+
case XML_DOCUMENT_FRAG_NODE:
|
206
255
|
case XML_ENTITY_REF_NODE:
|
207
|
-
|
208
|
-
|
256
|
+
case XML_ELEMENT_NODE:
|
257
|
+
switch (reparentee->type) {
|
258
|
+
case XML_ELEMENT_NODE:
|
259
|
+
case XML_PI_NODE:
|
260
|
+
case XML_COMMENT_NODE:
|
261
|
+
case XML_TEXT_NODE:
|
262
|
+
case XML_CDATA_SECTION_NODE:
|
263
|
+
case XML_ENTITY_REF_NODE:
|
264
|
+
goto ok;
|
265
|
+
default:
|
266
|
+
break;
|
267
|
+
}
|
268
|
+
break;
|
269
|
+
case XML_ATTRIBUTE_NODE:
|
270
|
+
switch (reparentee->type) {
|
271
|
+
case XML_TEXT_NODE:
|
272
|
+
case XML_ENTITY_REF_NODE:
|
273
|
+
goto ok;
|
274
|
+
default:
|
275
|
+
break;
|
276
|
+
}
|
209
277
|
break;
|
210
|
-
}
|
211
|
-
break;
|
212
|
-
case XML_ATTRIBUTE_NODE:
|
213
|
-
switch (reparentee->type) {
|
214
278
|
case XML_TEXT_NODE:
|
215
|
-
|
216
|
-
|
279
|
+
/*
|
280
|
+
* xmlAddChild() breaks the DOM specification in that it allows
|
281
|
+
* adding a text node to another, in which case text nodes are
|
282
|
+
* coalesced, but since our JRuby version does not support such
|
283
|
+
* operation, we should inhibit it.
|
284
|
+
*/
|
285
|
+
break;
|
217
286
|
default:
|
218
287
|
break;
|
219
|
-
}
|
220
|
-
break;
|
221
|
-
case XML_TEXT_NODE:
|
222
|
-
/*
|
223
|
-
* xmlAddChild() breaks the DOM specification in that it allows
|
224
|
-
* adding a text node to another, in which case text nodes are
|
225
|
-
* coalesced, but since our JRuby version does not support such
|
226
|
-
* operation, we should inhibit it.
|
227
|
-
*/
|
228
|
-
break;
|
229
|
-
default:
|
230
|
-
break;
|
231
288
|
}
|
232
289
|
|
233
290
|
rb_raise(rb_eArgError, "cannot reparent %s there", rb_obj_classname(reparentee_obj));
|
234
291
|
}
|
235
292
|
|
236
293
|
ok:
|
237
|
-
|
294
|
+
original_reparentee = reparentee;
|
238
295
|
|
239
296
|
if (reparentee->doc != pivot->doc || reparentee->type == XML_TEXT_NODE) {
|
240
297
|
/*
|
@@ -275,19 +332,25 @@ ok:
|
|
275
332
|
original_ns_prefix_is_default = 1;
|
276
333
|
}
|
277
334
|
|
278
|
-
|
335
|
+
noko_xml_document_pin_node(reparentee);
|
279
336
|
|
280
337
|
if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) {
|
281
338
|
rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
|
282
339
|
}
|
283
340
|
|
284
341
|
if (original_ns_prefix_is_default && reparentee->ns != NULL && reparentee->ns->prefix != NULL) {
|
285
|
-
/*
|
342
|
+
/*
|
343
|
+
* issue #391, where new node's prefix may become the string "default"
|
344
|
+
* see libxml2 tree.c xmlNewReconciliedNs which implements this behavior.
|
345
|
+
*/
|
346
|
+
xmlFree(DISCARD_CONST_QUAL_XMLCHAR(reparentee->ns->prefix));
|
286
347
|
reparentee->ns->prefix = NULL;
|
287
348
|
}
|
288
349
|
}
|
289
350
|
|
290
|
-
|
351
|
+
xmlUnlinkNode(original_reparentee);
|
352
|
+
|
353
|
+
if (prf != xmlAddPrevSibling && prf != xmlAddNextSibling && prf != xmlAddChild
|
291
354
|
&& reparentee->type == XML_TEXT_NODE && pivot->next && pivot->next->type == XML_TEXT_NODE) {
|
292
355
|
/*
|
293
356
|
* libxml merges text nodes in a right-to-left fashion, meaning that if
|
@@ -311,12 +374,12 @@ ok:
|
|
311
374
|
new_next_text = xmlDocCopyNode(next_text, pivot->doc, 1) ;
|
312
375
|
|
313
376
|
xmlUnlinkNode(next_text);
|
314
|
-
|
377
|
+
noko_xml_document_pin_node(next_text);
|
315
378
|
|
316
379
|
xmlAddNextSibling(pivot, new_next_text);
|
317
380
|
}
|
318
381
|
|
319
|
-
if(!(reparented = (*prf)(pivot, reparentee))) {
|
382
|
+
if (!(reparented = (*prf)(pivot, reparentee))) {
|
320
383
|
rb_raise(rb_eRuntimeError, "Could not reparent node");
|
321
384
|
}
|
322
385
|
|
@@ -326,57 +389,432 @@ ok:
|
|
326
389
|
* adjacent text nodes.
|
327
390
|
*/
|
328
391
|
DATA_PTR(reparentee_obj) = reparented ;
|
392
|
+
reparented_obj = noko_xml_node_wrap(Qnil, reparented);
|
329
393
|
|
330
|
-
|
394
|
+
rb_funcall(reparented_obj, id_decorate_bang, 0);
|
331
395
|
|
332
|
-
|
396
|
+
/* if we've created a cycle, raise an exception */
|
397
|
+
raise_if_ancestor_of_self(reparented);
|
333
398
|
|
334
|
-
|
399
|
+
relink_namespace(reparented);
|
335
400
|
|
336
401
|
return reparented_obj ;
|
337
402
|
}
|
338
403
|
|
404
|
+
// :startdoc:
|
339
405
|
|
340
406
|
/*
|
341
|
-
* call-seq:
|
342
|
-
*
|
407
|
+
* :call-seq:
|
408
|
+
* add_namespace_definition(prefix, href) → Nokogiri::XML::Namespace
|
409
|
+
* add_namespace(prefix, href) → Nokogiri::XML::Namespace
|
410
|
+
*
|
411
|
+
* :category: Manipulating Document Structure
|
412
|
+
*
|
413
|
+
* Adds a namespace definition to this node with +prefix+ using +href+ value, as if this node had
|
414
|
+
* included an attribute "xmlns:prefix=href".
|
415
|
+
*
|
416
|
+
* A default namespace definition for this node can be added by passing +nil+ for +prefix+.
|
417
|
+
*
|
418
|
+
* [Parameters]
|
419
|
+
* - +prefix+ (String, +nil+) An {XML Name}[https://www.w3.org/TR/xml-names/#ns-decl]
|
420
|
+
* - +href+ (String) The {URI reference}[https://www.w3.org/TR/xml-names/#sec-namespaces]
|
421
|
+
*
|
422
|
+
* [Returns] The new Nokogiri::XML::Namespace
|
423
|
+
*
|
424
|
+
* *Example:* adding a non-default namespace definition
|
425
|
+
*
|
426
|
+
* doc = Nokogiri::XML("<store><inventory></inventory></store>")
|
427
|
+
* inventory = doc.at_css("inventory")
|
428
|
+
* inventory.add_namespace_definition("automobile", "http://alices-autos.com/")
|
429
|
+
* inventory.add_namespace_definition("bicycle", "http://bobs-bikes.com/")
|
430
|
+
* inventory.add_child("<automobile:tire>Michelin model XGV, size 75R</automobile:tire>")
|
431
|
+
* doc.to_xml
|
432
|
+
* # => "<?xml version=\"1.0\"?>\n" +
|
433
|
+
* # "<store>\n" +
|
434
|
+
* # " <inventory xmlns:automobile=\"http://alices-autos.com/\" xmlns:bicycle=\"http://bobs-bikes.com/\">\n" +
|
435
|
+
* # " <automobile:tire>Michelin model XGV, size 75R</automobile:tire>\n" +
|
436
|
+
* # " </inventory>\n" +
|
437
|
+
* # "</store>\n"
|
438
|
+
*
|
439
|
+
* *Example:* adding a default namespace definition
|
440
|
+
*
|
441
|
+
* doc = Nokogiri::XML("<store><inventory><tire>Michelin model XGV, size 75R</tire></inventory></store>")
|
442
|
+
* doc.at_css("tire").add_namespace_definition(nil, "http://bobs-bikes.com/")
|
443
|
+
* doc.to_xml
|
444
|
+
* # => "<?xml version=\"1.0\"?>\n" +
|
445
|
+
* # "<store>\n" +
|
446
|
+
* # " <inventory>\n" +
|
447
|
+
* # " <tire xmlns=\"http://bobs-bikes.com/\">Michelin model XGV, size 75R</tire>\n" +
|
448
|
+
* # " </inventory>\n" +
|
449
|
+
* # "</store>\n"
|
450
|
+
*
|
451
|
+
*/
|
452
|
+
static VALUE
|
453
|
+
rb_xml_node_add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
|
454
|
+
{
|
455
|
+
xmlNodePtr c_node, element;
|
456
|
+
xmlNsPtr c_namespace;
|
457
|
+
const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix));
|
458
|
+
|
459
|
+
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
|
460
|
+
element = c_node ;
|
461
|
+
|
462
|
+
c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix);
|
463
|
+
|
464
|
+
if (!c_namespace) {
|
465
|
+
if (c_node->type != XML_ELEMENT_NODE) {
|
466
|
+
element = c_node->parent;
|
467
|
+
}
|
468
|
+
c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
|
469
|
+
}
|
470
|
+
|
471
|
+
if (!c_namespace) {
|
472
|
+
return Qnil ;
|
473
|
+
}
|
474
|
+
|
475
|
+
if (NIL_P(rb_prefix) || c_node != element) {
|
476
|
+
xmlSetNs(c_node, c_namespace);
|
477
|
+
}
|
478
|
+
|
479
|
+
return noko_xml_namespace_wrap(c_namespace, c_node->doc);
|
480
|
+
}
|
481
|
+
|
482
|
+
|
483
|
+
/*
|
484
|
+
* :call-seq: attribute(name) → Nokogiri::XML::Attr
|
485
|
+
*
|
486
|
+
* :category: Working With Node Attributes
|
487
|
+
*
|
488
|
+
* [Returns] Attribute (Nokogiri::XML::Attr) belonging to this node with name +name+.
|
489
|
+
*
|
490
|
+
* ⚠ Note that attribute namespaces are ignored and only the simple (non-namespace-prefixed) name is
|
491
|
+
* used to find a matching attribute. In case of a simple name collision, only one of the matching
|
492
|
+
* attributes will be returned. In this case, you will need to use #attribute_with_ns.
|
493
|
+
*
|
494
|
+
* *Example:*
|
495
|
+
*
|
496
|
+
* doc = Nokogiri::XML("<root><child size='large' class='big wide tall'/></root>")
|
497
|
+
* child = doc.at_css("child")
|
498
|
+
* child.attribute("size") # => #<Nokogiri::XML::Attr:0x550 name="size" value="large">
|
499
|
+
* child.attribute("class") # => #<Nokogiri::XML::Attr:0x564 name="class" value="big wide tall">
|
500
|
+
*
|
501
|
+
* *Example* showing that namespaced attributes will not be returned:
|
502
|
+
*
|
503
|
+
* ⚠ Note that only one of the two matching attributes is returned.
|
504
|
+
*
|
505
|
+
* doc = Nokogiri::XML(<<~EOF)
|
506
|
+
* <root xmlns:width='http://example.com/widths'
|
507
|
+
* xmlns:height='http://example.com/heights'>
|
508
|
+
* <child width:size='broad' height:size='tall'/>
|
509
|
+
* </root>
|
510
|
+
* EOF
|
511
|
+
* doc.at_css("child").attribute("size")
|
512
|
+
* # => #(Attr:0x550 {
|
513
|
+
* # name = "size",
|
514
|
+
* # namespace = #(Namespace:0x564 {
|
515
|
+
* # prefix = "width",
|
516
|
+
* # href = "http://example.com/widths"
|
517
|
+
* # }),
|
518
|
+
* # value = "broad"
|
519
|
+
* # })
|
520
|
+
*/
|
521
|
+
static VALUE
|
522
|
+
rb_xml_node_attribute(VALUE self, VALUE name)
|
523
|
+
{
|
524
|
+
xmlNodePtr node;
|
525
|
+
xmlAttrPtr prop;
|
526
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
527
|
+
prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
|
528
|
+
|
529
|
+
if (! prop) { return Qnil; }
|
530
|
+
return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
|
531
|
+
}
|
532
|
+
|
533
|
+
|
534
|
+
/*
|
535
|
+
* :call-seq: attribute_nodes() → Array<Nokogiri::XML::Attr>
|
536
|
+
*
|
537
|
+
* :category: Working With Node Attributes
|
538
|
+
*
|
539
|
+
* [Returns] Attributes (an Array of Nokogiri::XML::Attr) belonging to this node.
|
540
|
+
*
|
541
|
+
* Note that this is the preferred alternative to #attributes when the simple
|
542
|
+
* (non-namespace-prefixed) attribute names may collide.
|
543
|
+
*
|
544
|
+
* *Example:*
|
545
|
+
*
|
546
|
+
* Contrast this with the colliding-name example from #attributes.
|
547
|
+
*
|
548
|
+
* doc = Nokogiri::XML(<<~EOF)
|
549
|
+
* <root xmlns:width='http://example.com/widths'
|
550
|
+
* xmlns:height='http://example.com/heights'>
|
551
|
+
* <child width:size='broad' height:size='tall'/>
|
552
|
+
* </root>
|
553
|
+
* EOF
|
554
|
+
* doc.at_css("child").attribute_nodes
|
555
|
+
* # => [#(Attr:0x550 {
|
556
|
+
* # name = "size",
|
557
|
+
* # namespace = #(Namespace:0x564 {
|
558
|
+
* # prefix = "width",
|
559
|
+
* # href = "http://example.com/widths"
|
560
|
+
* # }),
|
561
|
+
* # value = "broad"
|
562
|
+
* # }),
|
563
|
+
* # #(Attr:0x578 {
|
564
|
+
* # name = "size",
|
565
|
+
* # namespace = #(Namespace:0x58c {
|
566
|
+
* # prefix = "height",
|
567
|
+
* # href = "http://example.com/heights"
|
568
|
+
* # }),
|
569
|
+
* # value = "tall"
|
570
|
+
* # })]
|
571
|
+
*/
|
572
|
+
static VALUE
|
573
|
+
rb_xml_node_attribute_nodes(VALUE rb_node)
|
574
|
+
{
|
575
|
+
xmlNodePtr c_node;
|
576
|
+
|
577
|
+
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
|
578
|
+
|
579
|
+
return noko_xml_node_attrs(c_node);
|
580
|
+
}
|
581
|
+
|
582
|
+
|
583
|
+
/*
|
584
|
+
* :call-seq: attribute_with_ns(name, namespace) → Nokogiri::XML::Attr
|
585
|
+
*
|
586
|
+
* :category: Working With Node Attributes
|
587
|
+
*
|
588
|
+
* [Returns]
|
589
|
+
* Attribute (Nokogiri::XML::Attr) belonging to this node with matching +name+ and +namespace+.
|
590
|
+
*
|
591
|
+
* [Parameters]
|
592
|
+
* - +name+ (String): the simple (non-namespace-prefixed) name of the attribute
|
593
|
+
* - +namespace+ (String): the URI of the attribute's namespace
|
594
|
+
*
|
595
|
+
* See related: #attribute
|
596
|
+
*
|
597
|
+
* *Example:*
|
598
|
+
*
|
599
|
+
* doc = Nokogiri::XML(<<~EOF)
|
600
|
+
* <root xmlns:width='http://example.com/widths'
|
601
|
+
* xmlns:height='http://example.com/heights'>
|
602
|
+
* <child width:size='broad' height:size='tall'/>
|
603
|
+
* </root>
|
604
|
+
* EOF
|
605
|
+
* doc.at_css("child").attribute_with_ns("size", "http://example.com/widths")
|
606
|
+
* # => #(Attr:0x550 {
|
607
|
+
* # name = "size",
|
608
|
+
* # namespace = #(Namespace:0x564 {
|
609
|
+
* # prefix = "width",
|
610
|
+
* # href = "http://example.com/widths"
|
611
|
+
* # }),
|
612
|
+
* # value = "broad"
|
613
|
+
* # })
|
614
|
+
* doc.at_css("child").attribute_with_ns("size", "http://example.com/heights")
|
615
|
+
* # => #(Attr:0x578 {
|
616
|
+
* # name = "size",
|
617
|
+
* # namespace = #(Namespace:0x58c {
|
618
|
+
* # prefix = "height",
|
619
|
+
* # href = "http://example.com/heights"
|
620
|
+
* # }),
|
621
|
+
* # value = "tall"
|
622
|
+
* # })
|
623
|
+
*/
|
624
|
+
static VALUE
|
625
|
+
rb_xml_node_attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
|
626
|
+
{
|
627
|
+
xmlNodePtr node;
|
628
|
+
xmlAttrPtr prop;
|
629
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
630
|
+
prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
|
631
|
+
NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
|
632
|
+
|
633
|
+
if (! prop) { return Qnil; }
|
634
|
+
return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
|
635
|
+
}
|
636
|
+
|
637
|
+
|
638
|
+
|
639
|
+
/*
|
640
|
+
* call-seq: blank? → Boolean
|
641
|
+
*
|
642
|
+
* [Returns] +true+ if the node is an empty or whitespace-only text or cdata node, else +false+.
|
643
|
+
*
|
644
|
+
* *Example:*
|
645
|
+
*
|
646
|
+
* Nokogiri("<root><child/></root>").root.child.blank? # => false
|
647
|
+
* Nokogiri("<root>\t \n</root>").root.child.blank? # => true
|
648
|
+
* Nokogiri("<root><![CDATA[\t \n]]></root>").root.child.blank? # => true
|
649
|
+
* Nokogiri("<root>not-blank</root>").root.child
|
650
|
+
* .tap { |n| n.content = "" }.blank # => true
|
651
|
+
*/
|
652
|
+
static VALUE
|
653
|
+
rb_xml_node_blank_eh(VALUE self)
|
654
|
+
{
|
655
|
+
xmlNodePtr node;
|
656
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
657
|
+
return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
|
658
|
+
}
|
659
|
+
|
660
|
+
|
661
|
+
/*
|
662
|
+
* :call-seq: child() → Nokogiri::XML::Node
|
663
|
+
*
|
664
|
+
* :category: Traversing Document Structure
|
665
|
+
*
|
666
|
+
* [Returns] First of this node's children, or +nil+ if there are no children
|
667
|
+
*
|
668
|
+
* This is a convenience method and is equivalent to:
|
669
|
+
*
|
670
|
+
* node.children.first
|
671
|
+
*
|
672
|
+
* See related: #children
|
673
|
+
*/
|
674
|
+
static VALUE
|
675
|
+
rb_xml_node_child(VALUE self)
|
676
|
+
{
|
677
|
+
xmlNodePtr node, child;
|
678
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
679
|
+
|
680
|
+
child = node->children;
|
681
|
+
if (!child) { return Qnil; }
|
682
|
+
|
683
|
+
return noko_xml_node_wrap(Qnil, child);
|
684
|
+
}
|
685
|
+
|
686
|
+
|
687
|
+
/*
|
688
|
+
* :call-seq: children() → Nokogiri::XML::NodeSet
|
689
|
+
*
|
690
|
+
* :category: Traversing Document Structure
|
691
|
+
*
|
692
|
+
* [Returns] Nokogiri::XML::NodeSet containing this node's children.
|
693
|
+
*/
|
694
|
+
static VALUE
|
695
|
+
rb_xml_node_children(VALUE self)
|
696
|
+
{
|
697
|
+
xmlNodePtr node;
|
698
|
+
xmlNodePtr child;
|
699
|
+
xmlNodeSetPtr set;
|
700
|
+
VALUE document;
|
701
|
+
VALUE node_set;
|
702
|
+
|
703
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
704
|
+
|
705
|
+
child = node->children;
|
706
|
+
set = xmlXPathNodeSetCreate(child);
|
707
|
+
|
708
|
+
document = DOC_RUBY_OBJECT(node->doc);
|
709
|
+
|
710
|
+
if (!child) { return noko_xml_node_set_wrap(set, document); }
|
711
|
+
|
712
|
+
child = child->next;
|
713
|
+
while (NULL != child) {
|
714
|
+
xmlXPathNodeSetAddUnique(set, child);
|
715
|
+
child = child->next;
|
716
|
+
}
|
717
|
+
|
718
|
+
node_set = noko_xml_node_set_wrap(set, document);
|
719
|
+
|
720
|
+
return node_set;
|
721
|
+
}
|
722
|
+
|
723
|
+
|
724
|
+
/*
|
725
|
+
* :call-seq:
|
726
|
+
* content() → String
|
727
|
+
* inner_text() → String
|
728
|
+
* text() → String
|
729
|
+
* to_str() → String
|
730
|
+
*
|
731
|
+
* [Returns]
|
732
|
+
* Contents of all the text nodes in this node's subtree, concatenated together into a single
|
733
|
+
* String.
|
734
|
+
*
|
735
|
+
* ⚠ Note that entities will _always_ be expanded in the returned String.
|
736
|
+
*
|
737
|
+
* See related: #inner_html
|
738
|
+
*
|
739
|
+
* *Example* of how entities are handled:
|
740
|
+
*
|
741
|
+
* Note that <tt><</tt> becomes <tt><</tt> in the returned String.
|
343
742
|
*
|
344
|
-
*
|
743
|
+
* doc = Nokogiri::XML.fragment("<child>a < b</child>")
|
744
|
+
* doc.at_css("child").content
|
745
|
+
* # => "a < b"
|
746
|
+
*
|
747
|
+
* *Example* of how a subtree is handled:
|
748
|
+
*
|
749
|
+
* Note that the <tt><span></tt> tags are omitted and only the text node contents are returned,
|
750
|
+
* concatenated into a single string.
|
751
|
+
*
|
752
|
+
* doc = Nokogiri::XML.fragment("<child><span>first</span> <span>second</span></child>")
|
753
|
+
* doc.at_css("child").content
|
754
|
+
* # => "first second"
|
345
755
|
*/
|
346
|
-
static VALUE
|
756
|
+
static VALUE
|
757
|
+
rb_xml_node_content(VALUE self)
|
347
758
|
{
|
348
759
|
xmlNodePtr node;
|
349
|
-
|
760
|
+
xmlChar *content;
|
761
|
+
|
762
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
763
|
+
|
764
|
+
content = xmlNodeGetContent(node);
|
765
|
+
if (content) {
|
766
|
+
VALUE rval = NOKOGIRI_STR_NEW2(content);
|
767
|
+
xmlFree(content);
|
768
|
+
return rval;
|
769
|
+
}
|
770
|
+
return Qnil;
|
771
|
+
}
|
772
|
+
|
773
|
+
|
774
|
+
/*
|
775
|
+
* :call-seq: document() → Nokogiri::XML::Document
|
776
|
+
*
|
777
|
+
* :category: Traversing Document Structure
|
778
|
+
*
|
779
|
+
* [Returns] Parent Nokogiri::XML::Document for this node
|
780
|
+
*/
|
781
|
+
static VALUE
|
782
|
+
rb_xml_node_document(VALUE self)
|
783
|
+
{
|
784
|
+
xmlNodePtr node;
|
785
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
350
786
|
return DOC_RUBY_OBJECT(node->doc);
|
351
787
|
}
|
352
788
|
|
353
789
|
/*
|
354
|
-
* call-seq:
|
355
|
-
* pointer_id
|
790
|
+
* :call-seq: pointer_id() → Integer
|
356
791
|
*
|
357
|
-
*
|
792
|
+
* [Returns]
|
793
|
+
* A unique id for this node based on the internal memory structures. This method is used by #==
|
794
|
+
* to determine node identity.
|
358
795
|
*/
|
359
|
-
static VALUE
|
796
|
+
static VALUE
|
797
|
+
rb_xml_node_pointer_id(VALUE self)
|
360
798
|
{
|
361
799
|
xmlNodePtr node;
|
362
|
-
|
800
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
363
801
|
|
364
|
-
return
|
802
|
+
return rb_uint2inum((uintptr_t)(node));
|
365
803
|
}
|
366
804
|
|
367
805
|
/*
|
368
|
-
* call-seq:
|
369
|
-
* encode_special_chars(string)
|
806
|
+
* :call-seq: encode_special_chars(string) → String
|
370
807
|
*
|
371
808
|
* Encode any special characters in +string+
|
372
809
|
*/
|
373
|
-
static VALUE
|
810
|
+
static VALUE
|
811
|
+
encode_special_chars(VALUE self, VALUE string)
|
374
812
|
{
|
375
813
|
xmlNodePtr node;
|
376
814
|
xmlChar *encoded;
|
377
815
|
VALUE encoded_str;
|
378
816
|
|
379
|
-
|
817
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
380
818
|
encoded = xmlEncodeSpecialChars(
|
381
819
|
node->doc,
|
382
820
|
(const xmlChar *)StringValueCStr(string)
|
@@ -389,8 +827,8 @@ static VALUE encode_special_chars(VALUE self, VALUE string)
|
|
389
827
|
}
|
390
828
|
|
391
829
|
/*
|
392
|
-
* call-seq:
|
393
|
-
*
|
830
|
+
* :call-seq:
|
831
|
+
* create_internal_subset(name, external_id, system_id)
|
394
832
|
*
|
395
833
|
* Create the internal subset of a document.
|
396
834
|
*
|
@@ -400,17 +838,18 @@ static VALUE encode_special_chars(VALUE self, VALUE string)
|
|
400
838
|
* doc.create_internal_subset("chapter", nil, "chapter.dtd")
|
401
839
|
* # => <!DOCTYPE chapter SYSTEM "chapter.dtd">
|
402
840
|
*/
|
403
|
-
static VALUE
|
841
|
+
static VALUE
|
842
|
+
create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
|
404
843
|
{
|
405
844
|
xmlNodePtr node;
|
406
845
|
xmlDocPtr doc;
|
407
846
|
xmlDtdPtr dtd;
|
408
847
|
|
409
|
-
|
848
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
410
849
|
|
411
850
|
doc = node->doc;
|
412
851
|
|
413
|
-
if(xmlGetIntSubset(doc)) {
|
852
|
+
if (xmlGetIntSubset(doc)) {
|
414
853
|
rb_raise(rb_eRuntimeError, "Document already has an internal subset");
|
415
854
|
}
|
416
855
|
|
@@ -421,28 +860,29 @@ static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, V
|
|
421
860
|
NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
|
422
861
|
);
|
423
862
|
|
424
|
-
if(!dtd) { return Qnil; }
|
863
|
+
if (!dtd) { return Qnil; }
|
425
864
|
|
426
|
-
return
|
865
|
+
return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
|
427
866
|
}
|
428
867
|
|
429
868
|
/*
|
430
|
-
* call-seq:
|
431
|
-
*
|
869
|
+
* :call-seq:
|
870
|
+
* create_external_subset(name, external_id, system_id)
|
432
871
|
*
|
433
872
|
* Create an external subset
|
434
873
|
*/
|
435
|
-
static VALUE
|
874
|
+
static VALUE
|
875
|
+
create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
|
436
876
|
{
|
437
877
|
xmlNodePtr node;
|
438
878
|
xmlDocPtr doc;
|
439
879
|
xmlDtdPtr dtd;
|
440
880
|
|
441
|
-
|
881
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
442
882
|
|
443
883
|
doc = node->doc;
|
444
884
|
|
445
|
-
if(doc->extSubset) {
|
885
|
+
if (doc->extSubset) {
|
446
886
|
rb_raise(rb_eRuntimeError, "Document already has an external subset");
|
447
887
|
}
|
448
888
|
|
@@ -453,112 +893,124 @@ static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, V
|
|
453
893
|
NIL_P(system_id) ? NULL : (const xmlChar *)StringValueCStr(system_id)
|
454
894
|
);
|
455
895
|
|
456
|
-
if(!dtd) { return Qnil; }
|
896
|
+
if (!dtd) { return Qnil; }
|
457
897
|
|
458
|
-
return
|
898
|
+
return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
|
459
899
|
}
|
460
900
|
|
461
901
|
/*
|
462
|
-
* call-seq:
|
463
|
-
*
|
902
|
+
* :call-seq:
|
903
|
+
* external_subset()
|
464
904
|
*
|
465
905
|
* Get the external subset
|
466
906
|
*/
|
467
|
-
static VALUE
|
907
|
+
static VALUE
|
908
|
+
external_subset(VALUE self)
|
468
909
|
{
|
469
910
|
xmlNodePtr node;
|
470
911
|
xmlDocPtr doc;
|
471
912
|
xmlDtdPtr dtd;
|
472
913
|
|
473
|
-
|
914
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
474
915
|
|
475
|
-
if(!node->doc) { return Qnil; }
|
916
|
+
if (!node->doc) { return Qnil; }
|
476
917
|
|
477
918
|
doc = node->doc;
|
478
919
|
dtd = doc->extSubset;
|
479
920
|
|
480
|
-
if(!dtd) { return Qnil; }
|
921
|
+
if (!dtd) { return Qnil; }
|
481
922
|
|
482
|
-
return
|
923
|
+
return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
|
483
924
|
}
|
484
925
|
|
485
926
|
/*
|
486
|
-
* call-seq:
|
487
|
-
*
|
927
|
+
* :call-seq:
|
928
|
+
* internal_subset()
|
488
929
|
*
|
489
930
|
* Get the internal subset
|
490
931
|
*/
|
491
|
-
static VALUE
|
932
|
+
static VALUE
|
933
|
+
internal_subset(VALUE self)
|
492
934
|
{
|
493
935
|
xmlNodePtr node;
|
494
936
|
xmlDocPtr doc;
|
495
937
|
xmlDtdPtr dtd;
|
496
938
|
|
497
|
-
|
939
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
498
940
|
|
499
|
-
if(!node->doc) { return Qnil; }
|
941
|
+
if (!node->doc) { return Qnil; }
|
500
942
|
|
501
943
|
doc = node->doc;
|
502
944
|
dtd = xmlGetIntSubset(doc);
|
503
945
|
|
504
|
-
if(!dtd) { return Qnil; }
|
946
|
+
if (!dtd) { return Qnil; }
|
505
947
|
|
506
|
-
return
|
948
|
+
return noko_xml_node_wrap(Qnil, (xmlNodePtr)dtd);
|
507
949
|
}
|
508
950
|
|
509
951
|
/*
|
510
|
-
* call-seq:
|
511
|
-
*
|
952
|
+
* :call-seq:
|
953
|
+
* dup → Nokogiri::XML::Node
|
954
|
+
* dup(depth) → Nokogiri::XML::Node
|
955
|
+
* dup(depth, new_parent_doc) → Nokogiri::XML::Node
|
956
|
+
*
|
957
|
+
* Copy this node.
|
512
958
|
*
|
513
|
-
*
|
514
|
-
*
|
959
|
+
* [Parameters]
|
960
|
+
* - +depth+ 0 is a shallow copy, 1 (the default) is a deep copy.
|
961
|
+
* - +new_parent_doc+
|
962
|
+
* The new node's parent Document. Defaults to the this node's document.
|
963
|
+
*
|
964
|
+
* [Returns] The new Nokgiri::XML::Node
|
515
965
|
*/
|
516
|
-
static VALUE
|
966
|
+
static VALUE
|
967
|
+
duplicate_node(int argc, VALUE *argv, VALUE self)
|
517
968
|
{
|
518
|
-
VALUE
|
969
|
+
VALUE r_level, r_new_parent_doc;
|
970
|
+
int level;
|
971
|
+
int n_args;
|
972
|
+
xmlDocPtr new_parent_doc;
|
519
973
|
xmlNodePtr node, dup;
|
520
974
|
|
521
|
-
|
522
|
-
|
975
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
976
|
+
|
977
|
+
n_args = rb_scan_args(argc, argv, "02", &r_level, &r_new_parent_doc);
|
978
|
+
|
979
|
+
if (n_args < 1) {
|
980
|
+
r_level = INT2NUM((long)1);
|
523
981
|
}
|
982
|
+
level = (int)NUM2INT(r_level);
|
524
983
|
|
525
|
-
|
984
|
+
if (n_args < 2) {
|
985
|
+
new_parent_doc = node->doc;
|
986
|
+
} else {
|
987
|
+
new_parent_doc = noko_xml_document_unwrap(r_new_parent_doc);
|
988
|
+
}
|
526
989
|
|
527
|
-
dup = xmlDocCopyNode(node,
|
528
|
-
if(dup == NULL) { return Qnil; }
|
990
|
+
dup = xmlDocCopyNode(node, new_parent_doc, level);
|
991
|
+
if (dup == NULL) { return Qnil; }
|
529
992
|
|
530
|
-
|
993
|
+
noko_xml_document_pin_node(dup);
|
531
994
|
|
532
|
-
return
|
995
|
+
return noko_xml_node_wrap(rb_obj_class(self), dup);
|
533
996
|
}
|
534
997
|
|
535
998
|
/*
|
536
|
-
* call-seq:
|
537
|
-
*
|
999
|
+
* :call-seq:
|
1000
|
+
* unlink() → self
|
538
1001
|
*
|
539
1002
|
* Unlink this node from its current context.
|
540
1003
|
*/
|
541
|
-
static VALUE
|
1004
|
+
static VALUE
|
1005
|
+
unlink_node(VALUE self)
|
542
1006
|
{
|
543
1007
|
xmlNodePtr node;
|
544
|
-
|
1008
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
545
1009
|
xmlUnlinkNode(node);
|
546
|
-
|
1010
|
+
noko_xml_document_pin_node(node);
|
547
1011
|
return self;
|
548
1012
|
}
|
549
1013
|
|
550
|
-
/*
|
551
|
-
* call-seq:
|
552
|
-
* blank?
|
553
|
-
*
|
554
|
-
* Is this node blank?
|
555
|
-
*/
|
556
|
-
static VALUE blank_eh(VALUE self)
|
557
|
-
{
|
558
|
-
xmlNodePtr node;
|
559
|
-
Data_Get_Struct(self, xmlNode, node);
|
560
|
-
return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
|
561
|
-
}
|
562
1014
|
|
563
1015
|
/*
|
564
1016
|
* call-seq:
|
@@ -566,15 +1018,16 @@ static VALUE blank_eh(VALUE self)
|
|
566
1018
|
*
|
567
1019
|
* Returns the next sibling node
|
568
1020
|
*/
|
569
|
-
static VALUE
|
1021
|
+
static VALUE
|
1022
|
+
next_sibling(VALUE self)
|
570
1023
|
{
|
571
1024
|
xmlNodePtr node, sibling;
|
572
|
-
|
1025
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
573
1026
|
|
574
1027
|
sibling = node->next;
|
575
|
-
if(!sibling) { return Qnil; }
|
1028
|
+
if (!sibling) { return Qnil; }
|
576
1029
|
|
577
|
-
return
|
1030
|
+
return noko_xml_node_wrap(Qnil, sibling) ;
|
578
1031
|
}
|
579
1032
|
|
580
1033
|
/*
|
@@ -583,15 +1036,16 @@ static VALUE next_sibling(VALUE self)
|
|
583
1036
|
*
|
584
1037
|
* Returns the previous sibling node
|
585
1038
|
*/
|
586
|
-
static VALUE
|
1039
|
+
static VALUE
|
1040
|
+
previous_sibling(VALUE self)
|
587
1041
|
{
|
588
1042
|
xmlNodePtr node, sibling;
|
589
|
-
|
1043
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
590
1044
|
|
591
1045
|
sibling = node->prev;
|
592
|
-
if(!sibling) { return Qnil; }
|
1046
|
+
if (!sibling) { return Qnil; }
|
593
1047
|
|
594
|
-
return
|
1048
|
+
return noko_xml_node_wrap(Qnil, sibling);
|
595
1049
|
}
|
596
1050
|
|
597
1051
|
/*
|
@@ -600,15 +1054,16 @@ static VALUE previous_sibling(VALUE self)
|
|
600
1054
|
*
|
601
1055
|
* Returns the next Nokogiri::XML::Element type sibling node.
|
602
1056
|
*/
|
603
|
-
static VALUE
|
1057
|
+
static VALUE
|
1058
|
+
next_element(VALUE self)
|
604
1059
|
{
|
605
1060
|
xmlNodePtr node, sibling;
|
606
|
-
|
1061
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
607
1062
|
|
608
1063
|
sibling = xmlNextElementSibling(node);
|
609
|
-
if(!sibling) { return Qnil; }
|
1064
|
+
if (!sibling) { return Qnil; }
|
610
1065
|
|
611
|
-
return
|
1066
|
+
return noko_xml_node_wrap(Qnil, sibling);
|
612
1067
|
}
|
613
1068
|
|
614
1069
|
/*
|
@@ -617,82 +1072,60 @@ static VALUE next_element(VALUE self)
|
|
617
1072
|
*
|
618
1073
|
* Returns the previous Nokogiri::XML::Element type sibling node.
|
619
1074
|
*/
|
620
|
-
static VALUE
|
1075
|
+
static VALUE
|
1076
|
+
previous_element(VALUE self)
|
621
1077
|
{
|
622
1078
|
xmlNodePtr node, sibling;
|
623
|
-
|
1079
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
624
1080
|
|
625
1081
|
/*
|
626
1082
|
* note that we don't use xmlPreviousElementSibling here because it's buggy pre-2.7.7.
|
627
1083
|
*/
|
628
1084
|
sibling = node->prev;
|
629
|
-
if(!sibling) { return Qnil; }
|
1085
|
+
if (!sibling) { return Qnil; }
|
630
1086
|
|
631
|
-
while(sibling && sibling->type != XML_ELEMENT_NODE) {
|
1087
|
+
while (sibling && sibling->type != XML_ELEMENT_NODE) {
|
632
1088
|
sibling = sibling->prev;
|
633
1089
|
}
|
634
1090
|
|
635
|
-
return sibling ?
|
1091
|
+
return sibling ? noko_xml_node_wrap(Qnil, sibling) : Qnil ;
|
636
1092
|
}
|
637
1093
|
|
638
1094
|
/* :nodoc: */
|
639
|
-
static VALUE
|
1095
|
+
static VALUE
|
1096
|
+
replace(VALUE self, VALUE new_node)
|
640
1097
|
{
|
641
1098
|
VALUE reparent = reparent_node_with(self, new_node, xmlReplaceNodeWrapper);
|
642
1099
|
|
643
1100
|
xmlNodePtr pivot;
|
644
|
-
|
645
|
-
|
1101
|
+
Noko_Node_Get_Struct(self, xmlNode, pivot);
|
1102
|
+
noko_xml_document_pin_node(pivot);
|
646
1103
|
|
647
1104
|
return reparent;
|
648
1105
|
}
|
649
1106
|
|
650
1107
|
/*
|
651
|
-
* call-seq:
|
652
|
-
*
|
1108
|
+
* :call-seq:
|
1109
|
+
* element_children() → NodeSet
|
1110
|
+
* elements() → NodeSet
|
653
1111
|
*
|
654
|
-
*
|
655
|
-
|
656
|
-
|
657
|
-
{
|
658
|
-
xmlNodePtr node;
|
659
|
-
xmlNodePtr child;
|
660
|
-
xmlNodeSetPtr set;
|
661
|
-
VALUE document;
|
662
|
-
VALUE node_set;
|
663
|
-
|
664
|
-
Data_Get_Struct(self, xmlNode, node);
|
665
|
-
|
666
|
-
child = node->children;
|
667
|
-
set = xmlXPathNodeSetCreate(child);
|
668
|
-
|
669
|
-
document = DOC_RUBY_OBJECT(node->doc);
|
670
|
-
|
671
|
-
if(!child) { return Nokogiri_wrap_xml_node_set(set, document); }
|
672
|
-
|
673
|
-
child = child->next;
|
674
|
-
while(NULL != child) {
|
675
|
-
xmlXPathNodeSetAddUnique(set, child);
|
676
|
-
child = child->next;
|
677
|
-
}
|
678
|
-
|
679
|
-
node_set = Nokogiri_wrap_xml_node_set(set, document);
|
680
|
-
|
681
|
-
return node_set;
|
682
|
-
}
|
683
|
-
|
684
|
-
/*
|
685
|
-
* call-seq:
|
686
|
-
* element_children
|
1112
|
+
* [Returns]
|
1113
|
+
* The node's child elements as a NodeSet. Only children that are elements will be returned, which
|
1114
|
+
* notably excludes Text nodes.
|
687
1115
|
*
|
688
|
-
*
|
689
|
-
* element nodes.
|
1116
|
+
* *Example:*
|
690
1117
|
*
|
691
|
-
*
|
1118
|
+
* Note that #children returns the Text node "hello" while #element_children does not.
|
692
1119
|
*
|
693
|
-
*
|
1120
|
+
* div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
|
1121
|
+
* div.element_children
|
1122
|
+
* # => [#<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
|
1123
|
+
* div.children
|
1124
|
+
* # => [#<Nokogiri::XML::Text:0x64 "hello">,
|
1125
|
+
* # #<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
|
694
1126
|
*/
|
695
|
-
static VALUE
|
1127
|
+
static VALUE
|
1128
|
+
rb_xml_node_element_children(VALUE self)
|
696
1129
|
{
|
697
1130
|
xmlNodePtr node;
|
698
1131
|
xmlNodePtr child;
|
@@ -700,83 +1133,78 @@ static VALUE element_children(VALUE self)
|
|
700
1133
|
VALUE document;
|
701
1134
|
VALUE node_set;
|
702
1135
|
|
703
|
-
|
1136
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
704
1137
|
|
705
1138
|
child = xmlFirstElementChild(node);
|
706
1139
|
set = xmlXPathNodeSetCreate(child);
|
707
1140
|
|
708
1141
|
document = DOC_RUBY_OBJECT(node->doc);
|
709
1142
|
|
710
|
-
if(!child) { return
|
711
|
-
|
712
|
-
child = xmlNextElementSibling(child);
|
713
|
-
while(NULL != child) {
|
714
|
-
xmlXPathNodeSetAddUnique(set, child);
|
715
|
-
child = xmlNextElementSibling(child);
|
716
|
-
}
|
717
|
-
|
718
|
-
node_set = Nokogiri_wrap_xml_node_set(set, document);
|
1143
|
+
if (!child) { return noko_xml_node_set_wrap(set, document); }
|
719
1144
|
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
* child
|
726
|
-
*
|
727
|
-
* Returns the child node
|
728
|
-
*/
|
729
|
-
static VALUE child(VALUE self)
|
730
|
-
{
|
731
|
-
xmlNodePtr node, child;
|
732
|
-
Data_Get_Struct(self, xmlNode, node);
|
1145
|
+
child = xmlNextElementSibling(child);
|
1146
|
+
while (NULL != child) {
|
1147
|
+
xmlXPathNodeSetAddUnique(set, child);
|
1148
|
+
child = xmlNextElementSibling(child);
|
1149
|
+
}
|
733
1150
|
|
734
|
-
|
735
|
-
if(!child) { return Qnil; }
|
1151
|
+
node_set = noko_xml_node_set_wrap(set, document);
|
736
1152
|
|
737
|
-
return
|
1153
|
+
return node_set;
|
738
1154
|
}
|
739
1155
|
|
740
1156
|
/*
|
741
|
-
* call-seq:
|
742
|
-
*
|
1157
|
+
* :call-seq:
|
1158
|
+
* first_element_child() → Node
|
743
1159
|
*
|
744
|
-
* Returns
|
1160
|
+
* [Returns] The first child Node that is an element.
|
745
1161
|
*
|
746
|
-
* Example
|
1162
|
+
* *Example:*
|
747
1163
|
*
|
748
|
-
*
|
1164
|
+
* Note that the "hello" child, which is a Text node, is skipped and the <tt><span></tt> element is
|
1165
|
+
* returned.
|
1166
|
+
*
|
1167
|
+
* div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
|
1168
|
+
* div.first_element_child
|
1169
|
+
* # => #(Element:0x3c { name = "span", children = [ #(Text "world")] })
|
749
1170
|
*/
|
750
|
-
static VALUE
|
1171
|
+
static VALUE
|
1172
|
+
rb_xml_node_first_element_child(VALUE self)
|
751
1173
|
{
|
752
1174
|
xmlNodePtr node, child;
|
753
|
-
|
1175
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
754
1176
|
|
755
1177
|
child = xmlFirstElementChild(node);
|
756
|
-
if(!child) { return Qnil; }
|
1178
|
+
if (!child) { return Qnil; }
|
757
1179
|
|
758
|
-
return
|
1180
|
+
return noko_xml_node_wrap(Qnil, child);
|
759
1181
|
}
|
760
1182
|
|
761
1183
|
/*
|
762
|
-
* call-seq:
|
763
|
-
*
|
1184
|
+
* :call-seq:
|
1185
|
+
* last_element_child() → Node
|
764
1186
|
*
|
765
|
-
* Returns
|
1187
|
+
* [Returns] The last child Node that is an element.
|
766
1188
|
*
|
767
|
-
* Example
|
1189
|
+
* *Example:*
|
768
1190
|
*
|
769
|
-
*
|
1191
|
+
* Note that the "hello" child, which is a Text node, is skipped and the <tt><span>yes</span></tt>
|
1192
|
+
* element is returned.
|
1193
|
+
*
|
1194
|
+
* div = Nokogiri::HTML5("<div><span>no</span><span>yes</span>skip</div>").at_css("div")
|
1195
|
+
* div.last_element_child
|
1196
|
+
* # => #(Element:0x3c { name = "span", children = [ #(Text "yes")] })
|
770
1197
|
*/
|
771
|
-
static VALUE
|
1198
|
+
static VALUE
|
1199
|
+
rb_xml_node_last_element_child(VALUE self)
|
772
1200
|
{
|
773
1201
|
xmlNodePtr node, child;
|
774
|
-
|
1202
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
775
1203
|
|
776
1204
|
child = xmlLastElementChild(node);
|
777
|
-
if(!child) { return Qnil; }
|
1205
|
+
if (!child) { return Qnil; }
|
778
1206
|
|
779
|
-
return
|
1207
|
+
return noko_xml_node_wrap(Qnil, child);
|
780
1208
|
}
|
781
1209
|
|
782
1210
|
/*
|
@@ -785,11 +1213,12 @@ static VALUE last_element_child(VALUE self)
|
|
785
1213
|
*
|
786
1214
|
* Returns true if +attribute+ is set
|
787
1215
|
*/
|
788
|
-
static VALUE
|
1216
|
+
static VALUE
|
1217
|
+
key_eh(VALUE self, VALUE attribute)
|
789
1218
|
{
|
790
1219
|
xmlNodePtr node;
|
791
|
-
|
792
|
-
if(xmlHasProp(node, (xmlChar *)StringValueCStr(attribute))) {
|
1220
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1221
|
+
if (xmlHasProp(node, (xmlChar *)StringValueCStr(attribute))) {
|
793
1222
|
return Qtrue;
|
794
1223
|
}
|
795
1224
|
return Qfalse;
|
@@ -801,12 +1230,13 @@ static VALUE key_eh(VALUE self, VALUE attribute)
|
|
801
1230
|
*
|
802
1231
|
* Returns true if +attribute+ is set with +namespace+
|
803
1232
|
*/
|
804
|
-
static VALUE
|
1233
|
+
static VALUE
|
1234
|
+
namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
|
805
1235
|
{
|
806
1236
|
xmlNodePtr node;
|
807
|
-
|
808
|
-
if(xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute),
|
809
|
-
|
1237
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1238
|
+
if (xmlHasNsProp(node, (xmlChar *)StringValueCStr(attribute),
|
1239
|
+
NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace))) {
|
810
1240
|
return Qtrue;
|
811
1241
|
}
|
812
1242
|
return Qfalse;
|
@@ -818,11 +1248,12 @@ static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
|
|
818
1248
|
*
|
819
1249
|
* Set the +property+ to +value+
|
820
1250
|
*/
|
821
|
-
static VALUE
|
1251
|
+
static VALUE
|
1252
|
+
set(VALUE self, VALUE property, VALUE value)
|
822
1253
|
{
|
823
1254
|
xmlNodePtr node, cur;
|
824
1255
|
xmlAttrPtr prop;
|
825
|
-
|
1256
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
826
1257
|
|
827
1258
|
/* If a matching attribute node already exists, then xmlSetProp will destroy
|
828
1259
|
* the existing node's children. However, if Nokogiri has a node object
|
@@ -831,13 +1262,13 @@ static VALUE set(VALUE self, VALUE property, VALUE value)
|
|
831
1262
|
* We can avoid this by unlinking these nodes first.
|
832
1263
|
*/
|
833
1264
|
if (node->type != XML_ELEMENT_NODE) {
|
834
|
-
return(Qnil);
|
1265
|
+
return (Qnil);
|
835
1266
|
}
|
836
1267
|
prop = xmlHasProp(node, (xmlChar *)StringValueCStr(property));
|
837
1268
|
if (prop && prop->children) {
|
838
1269
|
for (cur = prop->children; cur; cur = cur->next) {
|
839
1270
|
if (cur->_private) {
|
840
|
-
|
1271
|
+
noko_xml_document_pin_node(cur);
|
841
1272
|
xmlUnlinkNode(cur);
|
842
1273
|
}
|
843
1274
|
}
|
@@ -855,7 +1286,8 @@ static VALUE set(VALUE self, VALUE property, VALUE value)
|
|
855
1286
|
*
|
856
1287
|
* Get the value for +attribute+
|
857
1288
|
*/
|
858
|
-
static VALUE
|
1289
|
+
static VALUE
|
1290
|
+
get(VALUE self, VALUE rattribute)
|
859
1291
|
{
|
860
1292
|
xmlNodePtr node;
|
861
1293
|
xmlChar *value = 0;
|
@@ -866,10 +1298,10 @@ static VALUE get(VALUE self, VALUE rattribute)
|
|
866
1298
|
|
867
1299
|
if (NIL_P(rattribute)) { return Qnil; }
|
868
1300
|
|
869
|
-
|
1301
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
870
1302
|
attribute = xmlCharStrdup(StringValueCStr(rattribute));
|
871
1303
|
|
872
|
-
colon = (
|
1304
|
+
colon = DISCARD_CONST_QUAL_XMLCHAR(xmlStrchr(attribute, (const xmlChar)':'));
|
873
1305
|
if (colon) {
|
874
1306
|
/* split the attribute string into separate prefix and name by
|
875
1307
|
* null-terminating the prefix at the colon */
|
@@ -881,7 +1313,7 @@ static VALUE get(VALUE self, VALUE rattribute)
|
|
881
1313
|
if (ns) {
|
882
1314
|
value = xmlGetNsProp(node, attr_name, ns->href);
|
883
1315
|
} else {
|
884
|
-
value = xmlGetProp(node, (xmlChar*)StringValueCStr(rattribute));
|
1316
|
+
value = xmlGetProp(node, (xmlChar *)StringValueCStr(rattribute));
|
885
1317
|
}
|
886
1318
|
} else {
|
887
1319
|
value = xmlGetNoNsProp(node, attribute);
|
@@ -902,15 +1334,16 @@ static VALUE get(VALUE self, VALUE rattribute)
|
|
902
1334
|
*
|
903
1335
|
* Set the namespace to +namespace+
|
904
1336
|
*/
|
905
|
-
static VALUE
|
1337
|
+
static VALUE
|
1338
|
+
set_namespace(VALUE self, VALUE namespace)
|
906
1339
|
{
|
907
1340
|
xmlNodePtr node;
|
908
1341
|
xmlNsPtr ns = NULL;
|
909
1342
|
|
910
|
-
|
1343
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
911
1344
|
|
912
|
-
if(!NIL_P(namespace)) {
|
913
|
-
|
1345
|
+
if (!NIL_P(namespace)) {
|
1346
|
+
Noko_Namespace_Get_Struct(namespace, xmlNs, ns);
|
914
1347
|
}
|
915
1348
|
|
916
1349
|
xmlSetNs(node, ns);
|
@@ -919,138 +1352,140 @@ static VALUE set_namespace(VALUE self, VALUE namespace)
|
|
919
1352
|
}
|
920
1353
|
|
921
1354
|
/*
|
922
|
-
* call-seq:
|
923
|
-
*
|
1355
|
+
* :call-seq:
|
1356
|
+
* namespace() → Namespace
|
924
1357
|
*
|
925
|
-
*
|
926
|
-
*/
|
927
|
-
static VALUE attr(VALUE self, VALUE name)
|
928
|
-
{
|
929
|
-
xmlNodePtr node;
|
930
|
-
xmlAttrPtr prop;
|
931
|
-
Data_Get_Struct(self, xmlNode, node);
|
932
|
-
prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
|
933
|
-
|
934
|
-
if(! prop) { return Qnil; }
|
935
|
-
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
|
936
|
-
}
|
937
|
-
|
938
|
-
/*
|
939
|
-
* call-seq:
|
940
|
-
* attribute_with_ns(name, namespace)
|
1358
|
+
* [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace.
|
941
1359
|
*
|
942
|
-
*
|
943
|
-
*/
|
944
|
-
static VALUE attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
|
945
|
-
{
|
946
|
-
xmlNodePtr node;
|
947
|
-
xmlAttrPtr prop;
|
948
|
-
Data_Get_Struct(self, xmlNode, node);
|
949
|
-
prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
|
950
|
-
NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
|
951
|
-
|
952
|
-
if(! prop) { return Qnil; }
|
953
|
-
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
|
954
|
-
}
|
955
|
-
|
956
|
-
/*
|
957
|
-
* call-seq:
|
958
|
-
* attribute_nodes()
|
1360
|
+
* *Example:*
|
959
1361
|
*
|
960
|
-
*
|
1362
|
+
* doc = Nokogiri::XML(<<~EOF)
|
1363
|
+
* <root>
|
1364
|
+
* <first/>
|
1365
|
+
* <second xmlns="http://example.com/child"/>
|
1366
|
+
* <foo:third xmlns:foo="http://example.com/foo"/>
|
1367
|
+
* </root>
|
1368
|
+
* EOF
|
1369
|
+
* doc.at_xpath("//first").namespace
|
1370
|
+
* # => nil
|
1371
|
+
* doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace
|
1372
|
+
* # => #(Namespace:0x3c { href = "http://example.com/child" })
|
1373
|
+
* doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace
|
1374
|
+
* # => #(Namespace:0x50 { prefix = "foo", href = "http://example.com/foo" })
|
961
1375
|
*/
|
962
|
-
static VALUE
|
1376
|
+
static VALUE
|
1377
|
+
rb_xml_node_namespace(VALUE rb_node)
|
963
1378
|
{
|
964
|
-
|
965
|
-
|
966
|
-
VALUE attr;
|
1379
|
+
xmlNodePtr c_node ;
|
1380
|
+
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
|
967
1381
|
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
Nokogiri_xml_node_properties(node, attr);
|
1382
|
+
if (c_node->ns) {
|
1383
|
+
return noko_xml_namespace_wrap(c_node->ns, c_node->doc);
|
1384
|
+
}
|
972
1385
|
|
973
|
-
return
|
1386
|
+
return Qnil ;
|
974
1387
|
}
|
975
1388
|
|
976
|
-
|
977
1389
|
/*
|
978
|
-
*
|
979
|
-
*
|
1390
|
+
* :call-seq:
|
1391
|
+
* namespace_definitions() → Array<Nokogiri::XML::Namespace>
|
980
1392
|
*
|
981
|
-
*
|
982
|
-
*
|
983
|
-
|
984
|
-
static VALUE namespace(VALUE self)
|
985
|
-
{
|
986
|
-
xmlNodePtr node ;
|
987
|
-
Data_Get_Struct(self, xmlNode, node);
|
988
|
-
|
989
|
-
if (node->ns) {
|
990
|
-
return Nokogiri_wrap_xml_namespace(node->doc, node->ns);
|
991
|
-
}
|
992
|
-
|
993
|
-
return Qnil ;
|
994
|
-
}
|
995
|
-
|
996
|
-
/*
|
997
|
-
* call-seq:
|
998
|
-
* namespace_definitions()
|
1393
|
+
* [Returns]
|
1394
|
+
* Namespaces that are defined directly on this node, as an Array of Namespace objects. The array
|
1395
|
+
* will be empty if no namespaces are defined on this node.
|
999
1396
|
*
|
1000
|
-
*
|
1397
|
+
* *Example:*
|
1398
|
+
*
|
1399
|
+
* doc = Nokogiri::XML(<<~EOF)
|
1400
|
+
* <root xmlns="http://example.com/root">
|
1401
|
+
* <first/>
|
1402
|
+
* <second xmlns="http://example.com/child" xmlns:unused="http://example.com/unused"/>
|
1403
|
+
* <foo:third xmlns:foo="http://example.com/foo"/>
|
1404
|
+
* </root>
|
1405
|
+
* EOF
|
1406
|
+
* doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_definitions
|
1407
|
+
* # => []
|
1408
|
+
* doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace_definitions
|
1409
|
+
* # => [#(Namespace:0x3c { href = "http://example.com/child" }),
|
1410
|
+
* # #(Namespace:0x50 {
|
1411
|
+
* # prefix = "unused",
|
1412
|
+
* # href = "http://example.com/unused"
|
1413
|
+
* # })]
|
1414
|
+
* doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace_definitions
|
1415
|
+
* # => [#(Namespace:0x64 { prefix = "foo", href = "http://example.com/foo" })]
|
1001
1416
|
*/
|
1002
|
-
static VALUE
|
1417
|
+
static VALUE
|
1418
|
+
namespace_definitions(VALUE rb_node)
|
1003
1419
|
{
|
1004
1420
|
/* this code in the mode of xmlHasProp() */
|
1005
|
-
xmlNodePtr
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
Data_Get_Struct(self, xmlNode, node);
|
1421
|
+
xmlNodePtr c_node ;
|
1422
|
+
xmlNsPtr c_namespace;
|
1423
|
+
VALUE definitions = rb_ary_new();
|
1010
1424
|
|
1011
|
-
|
1425
|
+
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
|
1012
1426
|
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1427
|
+
c_namespace = c_node->nsDef;
|
1428
|
+
if (!c_namespace) {
|
1429
|
+
return definitions;
|
1430
|
+
}
|
1016
1431
|
|
1017
|
-
while(
|
1018
|
-
rb_ary_push(
|
1019
|
-
|
1432
|
+
while (c_namespace != NULL) {
|
1433
|
+
rb_ary_push(definitions, noko_xml_namespace_wrap(c_namespace, c_node->doc));
|
1434
|
+
c_namespace = c_namespace->next;
|
1020
1435
|
}
|
1021
1436
|
|
1022
|
-
return
|
1437
|
+
return definitions;
|
1023
1438
|
}
|
1024
1439
|
|
1025
1440
|
/*
|
1026
|
-
*
|
1027
|
-
*
|
1441
|
+
* :call-seq:
|
1442
|
+
* namespace_scopes() → Array<Nokogiri::XML::Namespace>
|
1028
1443
|
*
|
1029
|
-
*
|
1030
|
-
*
|
1031
|
-
*
|
1032
|
-
*
|
1444
|
+
* [Returns] Array of all the Namespaces on this node and its ancestors.
|
1445
|
+
*
|
1446
|
+
* See also #namespaces
|
1447
|
+
*
|
1448
|
+
* *Example:*
|
1449
|
+
*
|
1450
|
+
* doc = Nokogiri::XML(<<~EOF)
|
1451
|
+
* <root xmlns="http://example.com/root" xmlns:bar="http://example.com/bar">
|
1452
|
+
* <first/>
|
1453
|
+
* <second xmlns="http://example.com/child"/>
|
1454
|
+
* <third xmlns:foo="http://example.com/foo"/>
|
1455
|
+
* </root>
|
1456
|
+
* EOF
|
1457
|
+
* doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_scopes
|
1458
|
+
* # => [#(Namespace:0x3c { href = "http://example.com/root" }),
|
1459
|
+
* # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
|
1460
|
+
* doc.at_xpath("//child:second", "child" => "http://example.com/child").namespace_scopes
|
1461
|
+
* # => [#(Namespace:0x64 { href = "http://example.com/child" }),
|
1462
|
+
* # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
|
1463
|
+
* doc.at_xpath("//root:third", "root" => "http://example.com/root").namespace_scopes
|
1464
|
+
* # => [#(Namespace:0x78 { prefix = "foo", href = "http://example.com/foo" }),
|
1465
|
+
* # #(Namespace:0x3c { href = "http://example.com/root" }),
|
1466
|
+
* # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
|
1033
1467
|
*/
|
1034
|
-
static VALUE
|
1468
|
+
static VALUE
|
1469
|
+
rb_xml_node_namespace_scopes(VALUE rb_node)
|
1035
1470
|
{
|
1036
|
-
xmlNodePtr
|
1037
|
-
|
1038
|
-
|
1471
|
+
xmlNodePtr c_node ;
|
1472
|
+
xmlNsPtr *namespaces;
|
1473
|
+
VALUE scopes = rb_ary_new();
|
1039
1474
|
int j;
|
1040
1475
|
|
1041
|
-
|
1476
|
+
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
|
1042
1477
|
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1478
|
+
namespaces = xmlGetNsList(c_node->doc, c_node);
|
1479
|
+
if (!namespaces) {
|
1480
|
+
return scopes;
|
1481
|
+
}
|
1047
1482
|
|
1048
|
-
for (j = 0 ;
|
1049
|
-
rb_ary_push(
|
1483
|
+
for (j = 0 ; namespaces[j] != NULL ; ++j) {
|
1484
|
+
rb_ary_push(scopes, noko_xml_namespace_wrap(namespaces[j], c_node->doc));
|
1050
1485
|
}
|
1051
1486
|
|
1052
|
-
xmlFree(
|
1053
|
-
return
|
1487
|
+
xmlFree(namespaces);
|
1488
|
+
return scopes;
|
1054
1489
|
}
|
1055
1490
|
|
1056
1491
|
/*
|
@@ -1059,11 +1494,12 @@ static VALUE namespace_scopes(VALUE self)
|
|
1059
1494
|
*
|
1060
1495
|
* Get the type for this Node
|
1061
1496
|
*/
|
1062
|
-
static VALUE
|
1497
|
+
static VALUE
|
1498
|
+
node_type(VALUE self)
|
1063
1499
|
{
|
1064
1500
|
xmlNodePtr node;
|
1065
|
-
|
1066
|
-
return INT2NUM(
|
1501
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1502
|
+
return INT2NUM(node->type);
|
1067
1503
|
}
|
1068
1504
|
|
1069
1505
|
/*
|
@@ -1072,16 +1508,17 @@ static VALUE node_type(VALUE self)
|
|
1072
1508
|
*
|
1073
1509
|
* Set the content for this Node
|
1074
1510
|
*/
|
1075
|
-
static VALUE
|
1511
|
+
static VALUE
|
1512
|
+
set_native_content(VALUE self, VALUE content)
|
1076
1513
|
{
|
1077
1514
|
xmlNodePtr node, child, next ;
|
1078
|
-
|
1515
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1079
1516
|
|
1080
1517
|
child = node->children;
|
1081
1518
|
while (NULL != child) {
|
1082
1519
|
next = child->next ;
|
1083
1520
|
xmlUnlinkNode(child) ;
|
1084
|
-
|
1521
|
+
noko_xml_document_pin_node(child);
|
1085
1522
|
child = next ;
|
1086
1523
|
}
|
1087
1524
|
|
@@ -1089,41 +1526,20 @@ static VALUE set_native_content(VALUE self, VALUE content)
|
|
1089
1526
|
return content;
|
1090
1527
|
}
|
1091
1528
|
|
1092
|
-
/*
|
1093
|
-
* call-seq:
|
1094
|
-
* content
|
1095
|
-
*
|
1096
|
-
* Returns the content for this Node
|
1097
|
-
*/
|
1098
|
-
static VALUE get_native_content(VALUE self)
|
1099
|
-
{
|
1100
|
-
xmlNodePtr node;
|
1101
|
-
xmlChar * content;
|
1102
|
-
|
1103
|
-
Data_Get_Struct(self, xmlNode, node);
|
1104
|
-
|
1105
|
-
content = xmlNodeGetContent(node);
|
1106
|
-
if(content) {
|
1107
|
-
VALUE rval = NOKOGIRI_STR_NEW2(content);
|
1108
|
-
xmlFree(content);
|
1109
|
-
return rval;
|
1110
|
-
}
|
1111
|
-
return Qnil;
|
1112
|
-
}
|
1113
|
-
|
1114
1529
|
/*
|
1115
1530
|
* call-seq:
|
1116
1531
|
* lang=
|
1117
1532
|
*
|
1118
1533
|
* Set the language of a node, i.e. the values of the xml:lang attribute.
|
1119
1534
|
*/
|
1120
|
-
static VALUE
|
1535
|
+
static VALUE
|
1536
|
+
set_lang(VALUE self_rb, VALUE lang_rb)
|
1121
1537
|
{
|
1122
1538
|
xmlNodePtr self ;
|
1123
|
-
xmlChar*
|
1539
|
+
xmlChar *lang ;
|
1124
1540
|
|
1125
|
-
|
1126
|
-
lang = (xmlChar*)StringValueCStr(lang_rb);
|
1541
|
+
Noko_Node_Get_Struct(self_rb, xmlNode, self);
|
1542
|
+
lang = (xmlChar *)StringValueCStr(lang_rb);
|
1127
1543
|
|
1128
1544
|
xmlNodeSetLang(self, lang);
|
1129
1545
|
|
@@ -1137,13 +1553,14 @@ static VALUE set_lang(VALUE self_rb, VALUE lang_rb)
|
|
1137
1553
|
* Searches the language of a node, i.e. the values of the xml:lang attribute or
|
1138
1554
|
* the one carried by the nearest ancestor.
|
1139
1555
|
*/
|
1140
|
-
static VALUE
|
1556
|
+
static VALUE
|
1557
|
+
get_lang(VALUE self_rb)
|
1141
1558
|
{
|
1142
1559
|
xmlNodePtr self ;
|
1143
|
-
xmlChar*
|
1560
|
+
xmlChar *lang ;
|
1144
1561
|
VALUE lang_rb ;
|
1145
1562
|
|
1146
|
-
|
1563
|
+
Noko_Node_Get_Struct(self_rb, xmlNode, self);
|
1147
1564
|
|
1148
1565
|
lang = xmlNodeGetLang(self);
|
1149
1566
|
if (lang) {
|
@@ -1156,7 +1573,8 @@ static VALUE get_lang(VALUE self_rb)
|
|
1156
1573
|
}
|
1157
1574
|
|
1158
1575
|
/* :nodoc: */
|
1159
|
-
static VALUE
|
1576
|
+
static VALUE
|
1577
|
+
add_child(VALUE self, VALUE new_child)
|
1160
1578
|
{
|
1161
1579
|
return reparent_node_with(self, new_child, xmlAddChild);
|
1162
1580
|
}
|
@@ -1167,15 +1585,16 @@ static VALUE add_child(VALUE self, VALUE new_child)
|
|
1167
1585
|
*
|
1168
1586
|
* Get the parent Node for this Node
|
1169
1587
|
*/
|
1170
|
-
static VALUE
|
1588
|
+
static VALUE
|
1589
|
+
get_parent(VALUE self)
|
1171
1590
|
{
|
1172
1591
|
xmlNodePtr node, parent;
|
1173
|
-
|
1592
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1174
1593
|
|
1175
1594
|
parent = node->parent;
|
1176
|
-
if(!parent) { return Qnil; }
|
1595
|
+
if (!parent) { return Qnil; }
|
1177
1596
|
|
1178
|
-
return
|
1597
|
+
return noko_xml_node_wrap(Qnil, parent) ;
|
1179
1598
|
}
|
1180
1599
|
|
1181
1600
|
/*
|
@@ -1184,11 +1603,12 @@ static VALUE get_parent(VALUE self)
|
|
1184
1603
|
*
|
1185
1604
|
* Set the name for this Node
|
1186
1605
|
*/
|
1187
|
-
static VALUE
|
1606
|
+
static VALUE
|
1607
|
+
set_name(VALUE self, VALUE new_name)
|
1188
1608
|
{
|
1189
1609
|
xmlNodePtr node;
|
1190
|
-
|
1191
|
-
xmlNodeSetName(node, (xmlChar*)StringValueCStr(new_name));
|
1610
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1611
|
+
xmlNodeSetName(node, (xmlChar *)StringValueCStr(new_name));
|
1192
1612
|
return new_name;
|
1193
1613
|
}
|
1194
1614
|
|
@@ -1198,11 +1618,12 @@ static VALUE set_name(VALUE self, VALUE new_name)
|
|
1198
1618
|
*
|
1199
1619
|
* Returns the name for this Node
|
1200
1620
|
*/
|
1201
|
-
static VALUE
|
1621
|
+
static VALUE
|
1622
|
+
get_name(VALUE self)
|
1202
1623
|
{
|
1203
1624
|
xmlNodePtr node;
|
1204
|
-
|
1205
|
-
if(node->name) {
|
1625
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1626
|
+
if (node->name) {
|
1206
1627
|
return NOKOGIRI_STR_NEW2(node->name);
|
1207
1628
|
}
|
1208
1629
|
return Qnil;
|
@@ -1214,28 +1635,39 @@ static VALUE get_name(VALUE self)
|
|
1214
1635
|
*
|
1215
1636
|
* Returns the path associated with this Node
|
1216
1637
|
*/
|
1217
|
-
static VALUE
|
1638
|
+
static VALUE
|
1639
|
+
rb_xml_node_path(VALUE rb_node)
|
1218
1640
|
{
|
1219
|
-
xmlNodePtr
|
1220
|
-
xmlChar *
|
1641
|
+
xmlNodePtr c_node;
|
1642
|
+
xmlChar *c_path ;
|
1221
1643
|
VALUE rval;
|
1222
1644
|
|
1223
|
-
|
1645
|
+
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
|
1646
|
+
|
1647
|
+
c_path = xmlGetNodePath(c_node);
|
1648
|
+
if (c_path == NULL) {
|
1649
|
+
// see https://github.com/sparklemotion/nokogiri/issues/2250
|
1650
|
+
// this behavior is clearly undesirable, but is what libxml <= 2.9.10 returned, and so we
|
1651
|
+
// do this for now to preserve the behavior across libxml2 versions.
|
1652
|
+
rval = NOKOGIRI_STR_NEW2("?");
|
1653
|
+
} else {
|
1654
|
+
rval = NOKOGIRI_STR_NEW2(c_path);
|
1655
|
+
xmlFree(c_path);
|
1656
|
+
}
|
1224
1657
|
|
1225
|
-
path = xmlGetNodePath(node);
|
1226
|
-
rval = NOKOGIRI_STR_NEW2(path);
|
1227
|
-
xmlFree(path);
|
1228
1658
|
return rval ;
|
1229
1659
|
}
|
1230
1660
|
|
1231
1661
|
/* :nodoc: */
|
1232
|
-
static VALUE
|
1662
|
+
static VALUE
|
1663
|
+
add_next_sibling(VALUE self, VALUE new_sibling)
|
1233
1664
|
{
|
1234
1665
|
return reparent_node_with(self, new_sibling, xmlAddNextSibling) ;
|
1235
1666
|
}
|
1236
1667
|
|
1237
1668
|
/* :nodoc: */
|
1238
|
-
static VALUE
|
1669
|
+
static VALUE
|
1670
|
+
add_previous_sibling(VALUE self, VALUE new_sibling)
|
1239
1671
|
{
|
1240
1672
|
return reparent_node_with(self, new_sibling, xmlAddPrevSibling) ;
|
1241
1673
|
}
|
@@ -1246,7 +1678,8 @@ static VALUE add_previous_sibling(VALUE self, VALUE new_sibling)
|
|
1246
1678
|
*
|
1247
1679
|
* Write this Node to +io+ with +encoding+ and +options+
|
1248
1680
|
*/
|
1249
|
-
static VALUE
|
1681
|
+
static VALUE
|
1682
|
+
native_write_to(
|
1250
1683
|
VALUE self,
|
1251
1684
|
VALUE io,
|
1252
1685
|
VALUE encoding,
|
@@ -1255,10 +1688,10 @@ static VALUE native_write_to(
|
|
1255
1688
|
)
|
1256
1689
|
{
|
1257
1690
|
xmlNodePtr node;
|
1258
|
-
const char *
|
1691
|
+
const char *before_indent;
|
1259
1692
|
xmlSaveCtxtPtr savectx;
|
1260
1693
|
|
1261
|
-
|
1694
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1262
1695
|
|
1263
1696
|
xmlIndentTreeOutput = 1;
|
1264
1697
|
|
@@ -1267,8 +1700,8 @@ static VALUE native_write_to(
|
|
1267
1700
|
xmlTreeIndentString = StringValueCStr(indent_string);
|
1268
1701
|
|
1269
1702
|
savectx = xmlSaveToIO(
|
1270
|
-
(xmlOutputWriteCallback)
|
1271
|
-
(xmlOutputCloseCallback)
|
1703
|
+
(xmlOutputWriteCallback)noko_io_write,
|
1704
|
+
(xmlOutputCloseCallback)noko_io_close,
|
1272
1705
|
(void *)io,
|
1273
1706
|
RTEST(encoding) ? StringValueCStr(encoding) : NULL,
|
1274
1707
|
(int)NUM2INT(options)
|
@@ -1281,93 +1714,366 @@ static VALUE native_write_to(
|
|
1281
1714
|
return io;
|
1282
1715
|
}
|
1283
1716
|
|
1284
|
-
|
1285
|
-
|
1286
|
-
*
|
1287
|
-
*
|
1288
|
-
* Returns the line for this Node
|
1289
|
-
*/
|
1290
|
-
static VALUE line(VALUE self)
|
1717
|
+
|
1718
|
+
static inline void
|
1719
|
+
output_partial_string(VALUE out, char const *str, size_t length)
|
1291
1720
|
{
|
1292
|
-
|
1293
|
-
|
1721
|
+
if (length) {
|
1722
|
+
rb_enc_str_buf_cat(out, str, (long)length, rb_utf8_encoding());
|
1723
|
+
}
|
1724
|
+
}
|
1294
1725
|
|
1295
|
-
|
1726
|
+
static inline void
|
1727
|
+
output_char(VALUE out, char ch)
|
1728
|
+
{
|
1729
|
+
output_partial_string(out, &ch, 1);
|
1296
1730
|
}
|
1297
1731
|
|
1298
|
-
|
1299
|
-
*
|
1300
|
-
* add_namespace_definition(prefix, href)
|
1301
|
-
*
|
1302
|
-
* Adds a namespace definition with +prefix+ using +href+ value. The result is
|
1303
|
-
* as if parsed XML for this node had included an attribute
|
1304
|
-
* 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
|
1305
|
-
* added by passing 'nil' for prefix. Namespaces added this way will not
|
1306
|
-
* show up in #attributes, but they will be included as an xmlns attribute
|
1307
|
-
* when the node is serialized to XML.
|
1308
|
-
*/
|
1309
|
-
static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
|
1732
|
+
static inline void
|
1733
|
+
output_string(VALUE out, char const *str)
|
1310
1734
|
{
|
1311
|
-
|
1312
|
-
|
1735
|
+
output_partial_string(out, str, strlen(str));
|
1736
|
+
}
|
1737
|
+
|
1738
|
+
static inline void
|
1739
|
+
output_tagname(VALUE out, xmlNodePtr elem)
|
1740
|
+
{
|
1741
|
+
// Elements in the HTML, MathML, and SVG namespaces do not use a namespace
|
1742
|
+
// prefix in the HTML syntax.
|
1743
|
+
char const *name = (char const *)elem->name;
|
1744
|
+
xmlNsPtr ns = elem->ns;
|
1745
|
+
if (ns && ns->href && ns->prefix
|
1746
|
+
&& strcmp((char const *)ns->href, "http://www.w3.org/1999/xhtml")
|
1747
|
+
&& strcmp((char const *)ns->href, "http://www.w3.org/1998/Math/MathML")
|
1748
|
+
&& strcmp((char const *)ns->href, "http://www.w3.org/2000/svg")) {
|
1749
|
+
output_string(out, (char const *)elem->ns->prefix);
|
1750
|
+
output_char(out, ':');
|
1751
|
+
char const *colon = strchr(name, ':');
|
1752
|
+
if (colon) {
|
1753
|
+
name = colon + 1;
|
1754
|
+
}
|
1755
|
+
}
|
1756
|
+
output_string(out, name);
|
1757
|
+
}
|
1758
|
+
|
1759
|
+
static inline void
|
1760
|
+
output_attr_name(VALUE out, xmlAttrPtr attr)
|
1761
|
+
{
|
1762
|
+
xmlNsPtr ns = attr->ns;
|
1763
|
+
char const *name = (char const *)attr->name;
|
1764
|
+
if (ns && ns->href) {
|
1765
|
+
char const *uri = (char const *)ns->href;
|
1766
|
+
char const *localname = strchr(name, ':');
|
1767
|
+
if (localname) {
|
1768
|
+
++localname;
|
1769
|
+
} else {
|
1770
|
+
localname = name;
|
1771
|
+
}
|
1772
|
+
|
1773
|
+
if (!strcmp(uri, "http://www.w3.org/XML/1998/namespace")) {
|
1774
|
+
output_string(out, "xml:");
|
1775
|
+
name = localname;
|
1776
|
+
} else if (!strcmp(uri, "http://www.w3.org/2000/xmlns/")) {
|
1777
|
+
// xmlns:xmlns -> xmlns
|
1778
|
+
// xmlns:foo -> xmlns:foo
|
1779
|
+
if (strcmp(localname, "xmlns")) {
|
1780
|
+
output_string(out, "xmlns:");
|
1781
|
+
}
|
1782
|
+
name = localname;
|
1783
|
+
} else if (!strcmp(uri, "http://www.w3.org/1999/xlink")) {
|
1784
|
+
output_string(out, "xlink:");
|
1785
|
+
name = localname;
|
1786
|
+
} else if (ns->prefix) {
|
1787
|
+
output_string(out, (char const *)ns->prefix);
|
1788
|
+
output_char(out, ':');
|
1789
|
+
name = localname;
|
1790
|
+
}
|
1791
|
+
}
|
1792
|
+
output_string(out, name);
|
1793
|
+
}
|
1794
|
+
|
1795
|
+
static void
|
1796
|
+
output_escaped_string(VALUE out, xmlChar const *start, bool attr)
|
1797
|
+
{
|
1798
|
+
xmlChar const *next = start;
|
1799
|
+
int ch;
|
1800
|
+
|
1801
|
+
while ((ch = *next) != 0) {
|
1802
|
+
char const *replacement = NULL;
|
1803
|
+
size_t replaced_bytes = 1;
|
1804
|
+
if (ch == '&') {
|
1805
|
+
replacement = "&";
|
1806
|
+
} else if (ch == 0xC2 && next[1] == 0xA0) {
|
1807
|
+
// U+00A0 NO-BREAK SPACE has the UTF-8 encoding C2 A0.
|
1808
|
+
replacement = " ";
|
1809
|
+
replaced_bytes = 2;
|
1810
|
+
} else if (attr && ch == '"') {
|
1811
|
+
replacement = """;
|
1812
|
+
} else if (!attr && ch == '<') {
|
1813
|
+
replacement = "<";
|
1814
|
+
} else if (!attr && ch == '>') {
|
1815
|
+
replacement = ">";
|
1816
|
+
} else {
|
1817
|
+
++next;
|
1818
|
+
continue;
|
1819
|
+
}
|
1820
|
+
output_partial_string(out, (char const *)start, next - start);
|
1821
|
+
output_string(out, replacement);
|
1822
|
+
next += replaced_bytes;
|
1823
|
+
start = next;
|
1824
|
+
}
|
1825
|
+
output_partial_string(out, (char const *)start, next - start);
|
1826
|
+
}
|
1313
1827
|
|
1314
|
-
|
1315
|
-
|
1828
|
+
static bool
|
1829
|
+
should_prepend_newline(xmlNodePtr node)
|
1830
|
+
{
|
1831
|
+
char const *name = (char const *)node->name;
|
1832
|
+
xmlNodePtr child = node->children;
|
1833
|
+
|
1834
|
+
if (!name || !child || (strcmp(name, "pre") && strcmp(name, "textarea") && strcmp(name, "listing"))) {
|
1835
|
+
return false;
|
1836
|
+
}
|
1837
|
+
|
1838
|
+
return child->type == XML_TEXT_NODE && child->content && child->content[0] == '\n';
|
1839
|
+
}
|
1316
1840
|
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1841
|
+
static VALUE
|
1842
|
+
rb_prepend_newline(VALUE self)
|
1843
|
+
{
|
1844
|
+
xmlNodePtr node;
|
1845
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1846
|
+
return should_prepend_newline(node) ? Qtrue : Qfalse;
|
1847
|
+
}
|
1322
1848
|
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1849
|
+
static bool
|
1850
|
+
is_one_of(xmlNodePtr node, char const *const *tagnames, size_t num_tagnames)
|
1851
|
+
{
|
1852
|
+
char const *name = (char const *)node->name;
|
1853
|
+
if (name == NULL) { // fragments don't have a name
|
1854
|
+
return false;
|
1855
|
+
}
|
1856
|
+
for (size_t idx = 0; idx < num_tagnames; ++idx) {
|
1857
|
+
if (!strcmp(name, tagnames[idx])) {
|
1858
|
+
return true;
|
1326
1859
|
}
|
1327
|
-
ns = xmlNewNs(
|
1328
|
-
namespacee,
|
1329
|
-
(const xmlChar *)StringValueCStr(href),
|
1330
|
-
(const xmlChar *)(NIL_P(prefix) ? NULL : StringValueCStr(prefix))
|
1331
|
-
);
|
1332
1860
|
}
|
1861
|
+
return false;
|
1862
|
+
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
static void
|
1866
|
+
output_node(
|
1867
|
+
VALUE out,
|
1868
|
+
xmlNodePtr node,
|
1869
|
+
bool preserve_newline
|
1870
|
+
)
|
1871
|
+
{
|
1872
|
+
static char const *const VOID_ELEMENTS[] = {
|
1873
|
+
"area", "base", "basefont", "bgsound", "br", "col", "embed", "frame", "hr",
|
1874
|
+
"img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr",
|
1875
|
+
};
|
1876
|
+
|
1877
|
+
static char const *const UNESCAPED_TEXT_ELEMENTS[] = {
|
1878
|
+
"style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext", "noscript",
|
1879
|
+
};
|
1880
|
+
|
1881
|
+
switch (node->type) {
|
1882
|
+
case XML_ELEMENT_NODE:
|
1883
|
+
// Serialize the start tag.
|
1884
|
+
output_char(out, '<');
|
1885
|
+
output_tagname(out, node);
|
1886
|
+
|
1887
|
+
// Add attributes.
|
1888
|
+
for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) {
|
1889
|
+
output_char(out, ' ');
|
1890
|
+
output_attr_name(out, attr);
|
1891
|
+
if (attr->children) {
|
1892
|
+
output_string(out, "=\"");
|
1893
|
+
xmlChar *value = xmlNodeListGetString(attr->doc, attr->children, 1);
|
1894
|
+
output_escaped_string(out, value, true);
|
1895
|
+
xmlFree(value);
|
1896
|
+
output_char(out, '"');
|
1897
|
+
} else {
|
1898
|
+
// Output name=""
|
1899
|
+
output_string(out, "=\"\"");
|
1900
|
+
}
|
1901
|
+
}
|
1902
|
+
output_char(out, '>');
|
1903
|
+
|
1904
|
+
// Add children and end tag if element is not void.
|
1905
|
+
if (!is_one_of(node, VOID_ELEMENTS, sizeof VOID_ELEMENTS / sizeof VOID_ELEMENTS[0])) {
|
1906
|
+
if (preserve_newline && should_prepend_newline(node)) {
|
1907
|
+
output_char(out, '\n');
|
1908
|
+
}
|
1909
|
+
for (xmlNodePtr child = node->children; child; child = child->next) {
|
1910
|
+
output_node(out, child, preserve_newline);
|
1911
|
+
}
|
1912
|
+
output_string(out, "</");
|
1913
|
+
output_tagname(out, node);
|
1914
|
+
output_char(out, '>');
|
1915
|
+
}
|
1916
|
+
break;
|
1917
|
+
|
1918
|
+
case XML_TEXT_NODE:
|
1919
|
+
if (node->parent
|
1920
|
+
&& is_one_of(node->parent, UNESCAPED_TEXT_ELEMENTS,
|
1921
|
+
sizeof UNESCAPED_TEXT_ELEMENTS / sizeof UNESCAPED_TEXT_ELEMENTS[0])) {
|
1922
|
+
output_string(out, (char const *)node->content);
|
1923
|
+
} else {
|
1924
|
+
output_escaped_string(out, node->content, false);
|
1925
|
+
}
|
1926
|
+
break;
|
1927
|
+
|
1928
|
+
case XML_CDATA_SECTION_NODE:
|
1929
|
+
output_string(out, "<![CDATA[");
|
1930
|
+
output_string(out, (char const *)node->content);
|
1931
|
+
output_string(out, "]]>");
|
1932
|
+
break;
|
1933
|
+
|
1934
|
+
case XML_COMMENT_NODE:
|
1935
|
+
output_string(out, "<!--");
|
1936
|
+
output_string(out, (char const *)node->content);
|
1937
|
+
output_string(out, "-->");
|
1938
|
+
break;
|
1939
|
+
|
1940
|
+
case XML_PI_NODE:
|
1941
|
+
output_string(out, "<?");
|
1942
|
+
output_string(out, (char const *)node->content);
|
1943
|
+
output_char(out, '>');
|
1944
|
+
break;
|
1945
|
+
|
1946
|
+
case XML_DOCUMENT_TYPE_NODE:
|
1947
|
+
case XML_DTD_NODE:
|
1948
|
+
output_string(out, "<!DOCTYPE ");
|
1949
|
+
output_string(out, (char const *)node->name);
|
1950
|
+
output_string(out, ">");
|
1951
|
+
break;
|
1952
|
+
|
1953
|
+
case XML_DOCUMENT_NODE:
|
1954
|
+
case XML_DOCUMENT_FRAG_NODE:
|
1955
|
+
case XML_HTML_DOCUMENT_NODE:
|
1956
|
+
for (xmlNodePtr child = node->children; child; child = child->next) {
|
1957
|
+
output_node(out, child, preserve_newline);
|
1958
|
+
}
|
1959
|
+
break;
|
1960
|
+
|
1961
|
+
default:
|
1962
|
+
rb_raise(rb_eRuntimeError, "Unsupported document node (%d); this is a bug in Nokogiri", node->type);
|
1963
|
+
break;
|
1964
|
+
}
|
1965
|
+
}
|
1333
1966
|
|
1334
|
-
|
1967
|
+
static VALUE
|
1968
|
+
html_standard_serialize(
|
1969
|
+
VALUE self,
|
1970
|
+
VALUE preserve_newline
|
1971
|
+
)
|
1972
|
+
{
|
1973
|
+
xmlNodePtr node;
|
1974
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1975
|
+
VALUE output = rb_str_buf_new(4096);
|
1976
|
+
output_node(output, node, RTEST(preserve_newline));
|
1977
|
+
return output;
|
1978
|
+
}
|
1335
1979
|
|
1336
|
-
|
1980
|
+
/*
|
1981
|
+
* :call-seq:
|
1982
|
+
* line() → Integer
|
1983
|
+
*
|
1984
|
+
* [Returns] The line number of this Node.
|
1985
|
+
*
|
1986
|
+
* ---
|
1987
|
+
*
|
1988
|
+
* <b> ⚠ The CRuby and JRuby implementations differ in important ways! </b>
|
1989
|
+
*
|
1990
|
+
* Semantic differences:
|
1991
|
+
* - The CRuby method reflects the node's line number <i>in the parsed string</i>
|
1992
|
+
* - The JRuby method reflects the node's line number <i>in the final DOM structure</i> after
|
1993
|
+
* corrections have been applied
|
1994
|
+
*
|
1995
|
+
* Performance differences:
|
1996
|
+
* - The CRuby method is {O(1)}[https://en.wikipedia.org/wiki/Time_complexity#Constant_time]
|
1997
|
+
* (constant time)
|
1998
|
+
* - The JRuby method is {O(n)}[https://en.wikipedia.org/wiki/Time_complexity#Linear_time] (linear
|
1999
|
+
* time, where n is the number of nodes before/above the element in the DOM)
|
2000
|
+
*
|
2001
|
+
* If you'd like to help improve the JRuby implementation, please review these issues and reach out
|
2002
|
+
* to the maintainers:
|
2003
|
+
* - https://github.com/sparklemotion/nokogiri/issues/1223
|
2004
|
+
* - https://github.com/sparklemotion/nokogiri/pull/2177
|
2005
|
+
* - https://github.com/sparklemotion/nokogiri/issues/2380
|
2006
|
+
*/
|
2007
|
+
static VALUE
|
2008
|
+
rb_xml_node_line(VALUE rb_node)
|
2009
|
+
{
|
2010
|
+
xmlNodePtr c_node;
|
2011
|
+
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
|
1337
2012
|
|
1338
|
-
return
|
2013
|
+
return LONG2NUM(xmlGetLineNo(c_node));
|
1339
2014
|
}
|
1340
2015
|
|
1341
2016
|
/*
|
1342
2017
|
* call-seq:
|
1343
|
-
*
|
2018
|
+
* line=(num)
|
1344
2019
|
*
|
1345
|
-
*
|
2020
|
+
* Sets the line for this Node. num must be less than 65535.
|
1346
2021
|
*/
|
1347
|
-
static VALUE
|
2022
|
+
static VALUE
|
2023
|
+
rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number)
|
1348
2024
|
{
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
2025
|
+
xmlNodePtr c_node;
|
2026
|
+
int line_number = NUM2INT(rb_line_number);
|
2027
|
+
|
2028
|
+
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);
|
2029
|
+
|
2030
|
+
// libxml2 optionally uses xmlNode.psvi to store longer line numbers, but only for text nodes.
|
2031
|
+
// search for "psvi" in SAX2.c and tree.c to learn more.
|
2032
|
+
if (line_number < 65535) {
|
2033
|
+
c_node->line = (short) line_number;
|
2034
|
+
} else {
|
2035
|
+
c_node->line = 65535;
|
2036
|
+
if (c_node->type == XML_TEXT_NODE) {
|
2037
|
+
c_node->psvi = (void *)(ptrdiff_t) line_number;
|
2038
|
+
}
|
2039
|
+
}
|
2040
|
+
|
2041
|
+
return rb_line_number;
|
2042
|
+
}
|
2043
|
+
|
2044
|
+
/* :nodoc: documented in lib/nokogiri/xml/node.rb */
|
2045
|
+
static VALUE
|
2046
|
+
rb_xml_node_new(int argc, VALUE *argv, VALUE klass)
|
2047
|
+
{
|
2048
|
+
xmlNodePtr c_document_node;
|
2049
|
+
xmlNodePtr c_node;
|
2050
|
+
VALUE rb_name;
|
2051
|
+
VALUE rb_document_node;
|
1353
2052
|
VALUE rest;
|
1354
2053
|
VALUE rb_node;
|
1355
2054
|
|
1356
|
-
rb_scan_args(argc, argv, "2*", &
|
2055
|
+
rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest);
|
1357
2056
|
|
1358
|
-
|
2057
|
+
if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlNode)) {
|
2058
|
+
rb_raise(rb_eArgError, "document must be a Nokogiri::XML::Node");
|
2059
|
+
}
|
2060
|
+
if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlDocument)) {
|
2061
|
+
// TODO: deprecate allowing Node
|
2062
|
+
NOKO_WARN_DEPRECATION("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.");
|
2063
|
+
}
|
2064
|
+
Noko_Node_Get_Struct(rb_document_node, xmlNode, c_document_node);
|
1359
2065
|
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
2066
|
+
c_node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(rb_name));
|
2067
|
+
c_node->doc = c_document_node->doc;
|
2068
|
+
noko_xml_document_pin_node(c_node);
|
1363
2069
|
|
1364
|
-
rb_node =
|
2070
|
+
rb_node = noko_xml_node_wrap(
|
1365
2071
|
klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
|
1366
|
-
|
2072
|
+
c_node
|
1367
2073
|
);
|
1368
2074
|
rb_obj_call_init(rb_node, argc, argv);
|
1369
2075
|
|
1370
|
-
if(rb_block_given_p()) { rb_yield(rb_node); }
|
2076
|
+
if (rb_block_given_p()) { rb_yield(rb_node); }
|
1371
2077
|
|
1372
2078
|
return rb_node;
|
1373
2079
|
}
|
@@ -1378,13 +2084,14 @@ static VALUE new(int argc, VALUE *argv, VALUE klass)
|
|
1378
2084
|
*
|
1379
2085
|
* Returns the Node as html.
|
1380
2086
|
*/
|
1381
|
-
static VALUE
|
2087
|
+
static VALUE
|
2088
|
+
dump_html(VALUE self)
|
1382
2089
|
{
|
1383
2090
|
xmlBufferPtr buf ;
|
1384
2091
|
xmlNodePtr node ;
|
1385
2092
|
VALUE html;
|
1386
2093
|
|
1387
|
-
|
2094
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1388
2095
|
|
1389
2096
|
buf = xmlBufferCreate() ;
|
1390
2097
|
htmlNodeDump(buf, node->doc, node);
|
@@ -1399,13 +2106,14 @@ static VALUE dump_html(VALUE self)
|
|
1399
2106
|
*
|
1400
2107
|
* Compare this Node to +other+ with respect to their Document
|
1401
2108
|
*/
|
1402
|
-
static VALUE
|
2109
|
+
static VALUE
|
2110
|
+
compare(VALUE self, VALUE _other)
|
1403
2111
|
{
|
1404
2112
|
xmlNodePtr node, other;
|
1405
|
-
|
1406
|
-
|
2113
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
2114
|
+
Noko_Node_Get_Struct(_other, xmlNode, other);
|
1407
2115
|
|
1408
|
-
return INT2NUM(
|
2116
|
+
return INT2NUM(xmlXPathCmpNodes(other, node));
|
1409
2117
|
}
|
1410
2118
|
|
1411
2119
|
|
@@ -1416,13 +2124,14 @@ static VALUE compare(VALUE self, VALUE _other)
|
|
1416
2124
|
* Loads and substitutes all xinclude elements below the node. The
|
1417
2125
|
* parser context will be initialized with +options+.
|
1418
2126
|
*/
|
1419
|
-
static VALUE
|
2127
|
+
static VALUE
|
2128
|
+
process_xincludes(VALUE self, VALUE options)
|
1420
2129
|
{
|
1421
2130
|
int rcode ;
|
1422
2131
|
xmlNodePtr node;
|
1423
2132
|
VALUE error_list = rb_ary_new();
|
1424
2133
|
|
1425
|
-
|
2134
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1426
2135
|
|
1427
2136
|
xmlSetStructuredErrorFunc((void *)error_list, Nokogiri_error_array_pusher);
|
1428
2137
|
rcode = xmlXIncludeProcessTreeFlags(node, (int)NUM2INT(options));
|
@@ -1432,7 +2141,7 @@ static VALUE process_xincludes(VALUE self, VALUE options)
|
|
1432
2141
|
xmlErrorPtr error;
|
1433
2142
|
|
1434
2143
|
error = xmlGetLastError();
|
1435
|
-
if(error) {
|
2144
|
+
if (error) {
|
1436
2145
|
rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
|
1437
2146
|
} else {
|
1438
2147
|
rb_raise(rb_eRuntimeError, "Could not perform xinclude substitution");
|
@@ -1444,7 +2153,8 @@ static VALUE process_xincludes(VALUE self, VALUE options)
|
|
1444
2153
|
|
1445
2154
|
|
1446
2155
|
/* TODO: DOCUMENT ME */
|
1447
|
-
static VALUE
|
2156
|
+
static VALUE
|
2157
|
+
in_context(VALUE self, VALUE _str, VALUE _options)
|
1448
2158
|
{
|
1449
2159
|
xmlNodePtr node, list = 0, tmp, child_iter, node_children, doc_children;
|
1450
2160
|
xmlNodeSetPtr set;
|
@@ -1452,7 +2162,7 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
|
|
1452
2162
|
VALUE doc, err;
|
1453
2163
|
int doc_is_empty;
|
1454
2164
|
|
1455
|
-
|
2165
|
+
Noko_Node_Get_Struct(self, xmlNode, node);
|
1456
2166
|
|
1457
2167
|
doc = DOC_RUBY_OBJECT(node->doc);
|
1458
2168
|
err = rb_iv_get(doc, "@errors");
|
@@ -1493,9 +2203,7 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
|
|
1493
2203
|
*/
|
1494
2204
|
child_iter = node->doc->children ;
|
1495
2205
|
while (child_iter) {
|
1496
|
-
|
1497
|
-
child_iter->parent = (xmlNodePtr)node->doc;
|
1498
|
-
}
|
2206
|
+
child_iter->parent = (xmlNodePtr)node->doc;
|
1499
2207
|
child_iter = child_iter->next;
|
1500
2208
|
}
|
1501
2209
|
|
@@ -1505,12 +2213,17 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
|
|
1505
2213
|
|
1506
2214
|
xmlSetStructuredErrorFunc(NULL, NULL);
|
1507
2215
|
|
1508
|
-
/*
|
2216
|
+
/*
|
2217
|
+
* Workaround for a libxml2 bug where a parsing error may leave a broken
|
1509
2218
|
* node reference in node->doc->children.
|
2219
|
+
*
|
2220
|
+
* https://bugzilla.gnome.org/show_bug.cgi?id=668155
|
2221
|
+
*
|
1510
2222
|
* This workaround is limited to when a parse error occurs, the document
|
1511
2223
|
* went from having no children to having children, and the context node is
|
1512
2224
|
* part of a document fragment.
|
1513
|
-
*
|
2225
|
+
*
|
2226
|
+
* TODO: This was fixed in libxml 2.8.0 by 71a243d
|
1514
2227
|
*/
|
1515
2228
|
if (error != XML_ERR_OK && doc_is_empty && node->doc->children != NULL) {
|
1516
2229
|
child_iter = node;
|
@@ -1525,12 +2238,12 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
|
|
1525
2238
|
|
1526
2239
|
/* FIXME: This probably needs to handle more constants... */
|
1527
2240
|
switch (error) {
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
2241
|
+
case XML_ERR_INTERNAL_ERROR:
|
2242
|
+
case XML_ERR_NO_MEMORY:
|
2243
|
+
rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
|
2244
|
+
break;
|
2245
|
+
default:
|
2246
|
+
break;
|
1534
2247
|
}
|
1535
2248
|
|
1536
2249
|
set = xmlXPathNodeSetCreate(NULL);
|
@@ -1539,178 +2252,174 @@ static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
|
|
1539
2252
|
tmp = list->next;
|
1540
2253
|
list->next = NULL;
|
1541
2254
|
xmlXPathNodeSetAddUnique(set, list);
|
1542
|
-
|
2255
|
+
noko_xml_document_pin_node(list);
|
1543
2256
|
list = tmp;
|
1544
2257
|
}
|
1545
2258
|
|
1546
|
-
return
|
2259
|
+
return noko_xml_node_set_wrap(set, doc);
|
1547
2260
|
}
|
1548
2261
|
|
1549
|
-
|
1550
|
-
|
2262
|
+
VALUE
|
2263
|
+
noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
|
1551
2264
|
{
|
1552
|
-
VALUE
|
1553
|
-
VALUE node_cache = Qnil ;
|
1554
|
-
VALUE rb_node = Qnil ;
|
2265
|
+
VALUE rb_document, rb_node_cache, rb_node;
|
1555
2266
|
nokogiriTuplePtr node_has_a_document;
|
1556
|
-
xmlDocPtr
|
1557
|
-
void (*mark_method)(xmlNodePtr) = NULL ;
|
2267
|
+
xmlDocPtr c_doc;
|
1558
2268
|
|
1559
|
-
assert(
|
2269
|
+
assert(c_node);
|
1560
2270
|
|
1561
|
-
if(
|
1562
|
-
return DOC_RUBY_OBJECT(
|
2271
|
+
if (c_node->type == XML_DOCUMENT_NODE || c_node->type == XML_HTML_DOCUMENT_NODE) {
|
2272
|
+
return DOC_RUBY_OBJECT(c_node->doc);
|
1563
2273
|
}
|
1564
2274
|
|
1565
|
-
|
1566
|
-
|
1567
|
-
|
1568
|
-
|
1569
|
-
if (doc->type == XML_DOCUMENT_FRAG_NODE) { doc = doc->doc; }
|
1570
|
-
node_has_a_document = DOC_RUBY_OBJECT_TEST(doc);
|
2275
|
+
c_doc = c_node->doc;
|
2276
|
+
|
2277
|
+
// Nodes yielded from XML::Reader don't have a fully-realized Document
|
2278
|
+
node_has_a_document = DOC_RUBY_OBJECT_TEST(c_doc);
|
1571
2279
|
|
1572
|
-
if(
|
1573
|
-
return (VALUE)
|
2280
|
+
if (c_node->_private && node_has_a_document) {
|
2281
|
+
return (VALUE)c_node->_private;
|
1574
2282
|
}
|
1575
2283
|
|
1576
|
-
if(!RTEST(
|
1577
|
-
switch(
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
2284
|
+
if (!RTEST(rb_class)) {
|
2285
|
+
switch (c_node->type) {
|
2286
|
+
case XML_ELEMENT_NODE:
|
2287
|
+
rb_class = cNokogiriXmlElement;
|
2288
|
+
break;
|
2289
|
+
case XML_TEXT_NODE:
|
2290
|
+
rb_class = cNokogiriXmlText;
|
2291
|
+
break;
|
2292
|
+
case XML_ATTRIBUTE_NODE:
|
2293
|
+
rb_class = cNokogiriXmlAttr;
|
2294
|
+
break;
|
2295
|
+
case XML_ENTITY_REF_NODE:
|
2296
|
+
rb_class = cNokogiriXmlEntityReference;
|
2297
|
+
break;
|
2298
|
+
case XML_COMMENT_NODE:
|
2299
|
+
rb_class = cNokogiriXmlComment;
|
2300
|
+
break;
|
2301
|
+
case XML_DOCUMENT_FRAG_NODE:
|
2302
|
+
rb_class = cNokogiriXmlDocumentFragment;
|
2303
|
+
break;
|
2304
|
+
case XML_PI_NODE:
|
2305
|
+
rb_class = cNokogiriXmlProcessingInstruction;
|
2306
|
+
break;
|
2307
|
+
case XML_ENTITY_DECL:
|
2308
|
+
rb_class = cNokogiriXmlEntityDecl;
|
2309
|
+
break;
|
2310
|
+
case XML_CDATA_SECTION_NODE:
|
2311
|
+
rb_class = cNokogiriXmlCData;
|
2312
|
+
break;
|
2313
|
+
case XML_DTD_NODE:
|
2314
|
+
rb_class = cNokogiriXmlDtd;
|
2315
|
+
break;
|
2316
|
+
case XML_ATTRIBUTE_DECL:
|
2317
|
+
rb_class = cNokogiriXmlAttributeDecl;
|
2318
|
+
break;
|
2319
|
+
case XML_ELEMENT_DECL:
|
2320
|
+
rb_class = cNokogiriXmlElementDecl;
|
2321
|
+
break;
|
2322
|
+
default:
|
2323
|
+
rb_class = cNokogiriXmlNode;
|
1616
2324
|
}
|
1617
2325
|
}
|
1618
2326
|
|
1619
|
-
|
1620
|
-
|
1621
|
-
rb_node = Data_Wrap_Struct(klass, mark_method, debug_node_dealloc, node) ;
|
1622
|
-
node->_private = (void *)rb_node;
|
2327
|
+
rb_node = TypedData_Wrap_Struct(rb_class, &nokogiri_node_type, c_node) ;
|
2328
|
+
c_node->_private = (void *)rb_node;
|
1623
2329
|
|
1624
2330
|
if (node_has_a_document) {
|
1625
|
-
|
1626
|
-
|
1627
|
-
rb_ary_push(
|
1628
|
-
rb_funcall(
|
2331
|
+
rb_document = DOC_RUBY_OBJECT(c_doc);
|
2332
|
+
rb_node_cache = DOC_NODE_CACHE(c_doc);
|
2333
|
+
rb_ary_push(rb_node_cache, rb_node);
|
2334
|
+
rb_funcall(rb_document, id_decorate, 1, rb_node);
|
1629
2335
|
}
|
1630
2336
|
|
1631
2337
|
return rb_node ;
|
1632
2338
|
}
|
1633
2339
|
|
1634
2340
|
|
1635
|
-
|
2341
|
+
/*
|
2342
|
+
* return Array<Nokogiri::XML::Attr> containing the node's attributes
|
2343
|
+
*/
|
2344
|
+
VALUE
|
2345
|
+
noko_xml_node_attrs(xmlNodePtr c_node)
|
1636
2346
|
{
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
2347
|
+
VALUE rb_properties = rb_ary_new();
|
2348
|
+
xmlAttrPtr c_property;
|
2349
|
+
|
2350
|
+
c_property = c_node->properties ;
|
2351
|
+
while (c_property != NULL) {
|
2352
|
+
rb_ary_push(rb_properties, noko_xml_node_wrap(Qnil, (xmlNodePtr)c_property));
|
2353
|
+
c_property = c_property->next ;
|
1642
2354
|
}
|
2355
|
+
|
2356
|
+
return rb_properties;
|
1643
2357
|
}
|
1644
2358
|
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
cNokogiriXmlNode
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
rb_define_method(
|
1661
|
-
rb_define_method(
|
1662
|
-
rb_define_method(
|
1663
|
-
rb_define_method(
|
1664
|
-
rb_define_method(
|
1665
|
-
rb_define_method(
|
1666
|
-
rb_define_method(
|
1667
|
-
rb_define_method(
|
1668
|
-
rb_define_method(
|
1669
|
-
rb_define_method(
|
1670
|
-
rb_define_method(
|
1671
|
-
rb_define_method(
|
1672
|
-
rb_define_method(
|
1673
|
-
rb_define_method(
|
1674
|
-
rb_define_method(
|
1675
|
-
rb_define_method(
|
1676
|
-
rb_define_method(
|
1677
|
-
rb_define_method(
|
1678
|
-
rb_define_method(
|
1679
|
-
rb_define_method(
|
1680
|
-
rb_define_method(
|
1681
|
-
rb_define_method(
|
1682
|
-
rb_define_method(
|
1683
|
-
rb_define_method(
|
1684
|
-
rb_define_method(
|
1685
|
-
rb_define_method(
|
1686
|
-
rb_define_method(
|
1687
|
-
rb_define_method(
|
1688
|
-
rb_define_method(
|
1689
|
-
rb_define_method(
|
1690
|
-
rb_define_method(
|
1691
|
-
rb_define_method(
|
1692
|
-
rb_define_method(
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
rb_define_private_method(
|
1700
|
-
rb_define_private_method(
|
1701
|
-
rb_define_private_method(
|
1702
|
-
rb_define_private_method(
|
1703
|
-
rb_define_private_method(
|
1704
|
-
rb_define_private_method(
|
1705
|
-
rb_define_private_method(
|
1706
|
-
rb_define_private_method(
|
1707
|
-
rb_define_private_method(
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
decorate = rb_intern("decorate");
|
1713
|
-
decorate_bang = rb_intern("decorate!");
|
1714
|
-
}
|
1715
|
-
|
1716
|
-
/* vim: set noet sw=4 sws=4 */
|
2359
|
+
void
|
2360
|
+
noko_init_xml_node(void)
|
2361
|
+
{
|
2362
|
+
cNokogiriXmlNode = rb_define_class_under(mNokogiriXml, "Node", rb_cObject);
|
2363
|
+
|
2364
|
+
rb_undef_alloc_func(cNokogiriXmlNode);
|
2365
|
+
|
2366
|
+
rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1);
|
2367
|
+
|
2368
|
+
rb_define_method(cNokogiriXmlNode, "add_namespace_definition", rb_xml_node_add_namespace_definition, 2);
|
2369
|
+
rb_define_method(cNokogiriXmlNode, "attribute", rb_xml_node_attribute, 1);
|
2370
|
+
rb_define_method(cNokogiriXmlNode, "attribute_nodes", rb_xml_node_attribute_nodes, 0);
|
2371
|
+
rb_define_method(cNokogiriXmlNode, "attribute_with_ns", rb_xml_node_attribute_with_ns, 2);
|
2372
|
+
rb_define_method(cNokogiriXmlNode, "blank?", rb_xml_node_blank_eh, 0);
|
2373
|
+
rb_define_method(cNokogiriXmlNode, "child", rb_xml_node_child, 0);
|
2374
|
+
rb_define_method(cNokogiriXmlNode, "children", rb_xml_node_children, 0);
|
2375
|
+
rb_define_method(cNokogiriXmlNode, "content", rb_xml_node_content, 0);
|
2376
|
+
rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
|
2377
|
+
rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
|
2378
|
+
rb_define_method(cNokogiriXmlNode, "document", rb_xml_node_document, 0);
|
2379
|
+
rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
|
2380
|
+
rb_define_method(cNokogiriXmlNode, "element_children", rb_xml_node_element_children, 0);
|
2381
|
+
rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
|
2382
|
+
rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
|
2383
|
+
rb_define_method(cNokogiriXmlNode, "first_element_child", rb_xml_node_first_element_child, 0);
|
2384
|
+
rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
|
2385
|
+
rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
|
2386
|
+
rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
|
2387
|
+
rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
|
2388
|
+
rb_define_method(cNokogiriXmlNode, "last_element_child", rb_xml_node_last_element_child, 0);
|
2389
|
+
rb_define_method(cNokogiriXmlNode, "line", rb_xml_node_line, 0);
|
2390
|
+
rb_define_method(cNokogiriXmlNode, "line=", rb_xml_node_line_set, 1);
|
2391
|
+
rb_define_method(cNokogiriXmlNode, "namespace", rb_xml_node_namespace, 0);
|
2392
|
+
rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
|
2393
|
+
rb_define_method(cNokogiriXmlNode, "namespace_scopes", rb_xml_node_namespace_scopes, 0);
|
2394
|
+
rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
|
2395
|
+
rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
|
2396
|
+
rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0);
|
2397
|
+
rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
|
2398
|
+
rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0);
|
2399
|
+
rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1);
|
2400
|
+
rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
|
2401
|
+
rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0);
|
2402
|
+
rb_define_method(cNokogiriXmlNode, "path", rb_xml_node_path, 0);
|
2403
|
+
rb_define_method(cNokogiriXmlNode, "pointer_id", rb_xml_node_pointer_id, 0);
|
2404
|
+
rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0);
|
2405
|
+
rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
|
2406
|
+
rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
|
2407
|
+
|
2408
|
+
rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
|
2409
|
+
rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1);
|
2410
|
+
rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
|
2411
|
+
rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
|
2412
|
+
rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0);
|
2413
|
+
rb_define_private_method(cNokogiriXmlNode, "get", get, 1);
|
2414
|
+
rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
|
2415
|
+
rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
|
2416
|
+
rb_define_private_method(cNokogiriXmlNode, "prepend_newline?", rb_prepend_newline, 0);
|
2417
|
+
rb_define_private_method(cNokogiriXmlNode, "html_standard_serialize", html_standard_serialize, 1);
|
2418
|
+
rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
|
2419
|
+
rb_define_private_method(cNokogiriXmlNode, "replace_node", replace, 1);
|
2420
|
+
rb_define_private_method(cNokogiriXmlNode, "set", set, 2);
|
2421
|
+
rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1);
|
2422
|
+
|
2423
|
+
id_decorate = rb_intern("decorate");
|
2424
|
+
id_decorate_bang = rb_intern("decorate!");
|
2425
|
+
}
|