nokogiri 1.2.3-x86-mswin32-60 → 1.4.5-x86-mswin32-60
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.
- data/.autotest +18 -7
- data/.gemtest +0 -0
- data/CHANGELOG.ja.rdoc +297 -3
- data/CHANGELOG.rdoc +289 -0
- data/Manifest.txt +148 -37
- data/README.ja.rdoc +20 -20
- data/README.rdoc +53 -22
- data/Rakefile +127 -211
- data/bin/nokogiri +54 -0
- data/ext/nokogiri/depend +358 -0
- data/ext/nokogiri/extconf.rb +89 -54
- data/ext/nokogiri/html_document.c +34 -27
- data/ext/nokogiri/html_document.h +1 -1
- data/ext/nokogiri/html_element_description.c +276 -0
- data/ext/nokogiri/html_element_description.h +10 -0
- data/ext/nokogiri/html_entity_lookup.c +7 -5
- data/ext/nokogiri/html_entity_lookup.h +1 -1
- data/ext/nokogiri/html_sax_parser_context.c +94 -0
- data/ext/nokogiri/html_sax_parser_context.h +11 -0
- data/ext/nokogiri/{native.c → nokogiri.c} +31 -7
- data/ext/nokogiri/{native.h → nokogiri.h} +68 -41
- data/ext/nokogiri/xml_attr.c +20 -9
- data/ext/nokogiri/xml_attr.h +1 -1
- data/ext/nokogiri/xml_attribute_decl.c +70 -0
- data/ext/nokogiri/xml_attribute_decl.h +9 -0
- data/ext/nokogiri/xml_cdata.c +21 -9
- data/ext/nokogiri/xml_cdata.h +1 -1
- data/ext/nokogiri/xml_comment.c +18 -6
- data/ext/nokogiri/xml_comment.h +1 -1
- data/ext/nokogiri/xml_document.c +247 -68
- data/ext/nokogiri/xml_document.h +5 -3
- data/ext/nokogiri/xml_document_fragment.c +15 -7
- data/ext/nokogiri/xml_document_fragment.h +1 -1
- data/ext/nokogiri/xml_dtd.c +110 -10
- data/ext/nokogiri/xml_dtd.h +3 -1
- data/ext/nokogiri/xml_element_content.c +123 -0
- data/ext/nokogiri/xml_element_content.h +10 -0
- data/ext/nokogiri/xml_element_decl.c +69 -0
- data/ext/nokogiri/xml_element_decl.h +9 -0
- data/ext/nokogiri/xml_encoding_handler.c +79 -0
- data/ext/nokogiri/xml_encoding_handler.h +8 -0
- data/ext/nokogiri/xml_entity_decl.c +110 -0
- data/ext/nokogiri/xml_entity_decl.h +10 -0
- data/ext/nokogiri/xml_entity_reference.c +16 -5
- data/ext/nokogiri/xml_entity_reference.h +1 -1
- data/ext/nokogiri/xml_io.c +40 -8
- data/ext/nokogiri/xml_io.h +2 -1
- data/ext/nokogiri/xml_libxml2_hacks.c +112 -0
- data/ext/nokogiri/xml_libxml2_hacks.h +12 -0
- data/ext/nokogiri/xml_namespace.c +84 -0
- data/ext/nokogiri/xml_namespace.h +13 -0
- data/ext/nokogiri/xml_node.c +782 -225
- data/ext/nokogiri/xml_node.h +2 -4
- data/ext/nokogiri/xml_node_set.c +253 -34
- data/ext/nokogiri/xml_node_set.h +2 -2
- data/ext/nokogiri/xml_processing_instruction.c +17 -5
- data/ext/nokogiri/xml_processing_instruction.h +1 -1
- data/ext/nokogiri/xml_reader.c +277 -85
- data/ext/nokogiri/xml_reader.h +1 -1
- data/ext/nokogiri/xml_relax_ng.c +168 -0
- data/ext/nokogiri/xml_relax_ng.h +9 -0
- data/ext/nokogiri/xml_sax_parser.c +183 -111
- data/ext/nokogiri/xml_sax_parser.h +30 -1
- data/ext/nokogiri/xml_sax_parser_context.c +199 -0
- data/ext/nokogiri/xml_sax_parser_context.h +10 -0
- data/ext/nokogiri/xml_sax_push_parser.c +42 -12
- data/ext/nokogiri/xml_sax_push_parser.h +1 -1
- data/ext/nokogiri/xml_schema.c +205 -0
- data/ext/nokogiri/xml_schema.h +9 -0
- data/ext/nokogiri/xml_syntax_error.c +28 -173
- data/ext/nokogiri/xml_syntax_error.h +2 -1
- data/ext/nokogiri/xml_text.c +16 -6
- data/ext/nokogiri/xml_text.h +1 -1
- data/ext/nokogiri/xml_xpath_context.c +104 -47
- data/ext/nokogiri/xml_xpath_context.h +1 -1
- data/ext/nokogiri/xslt_stylesheet.c +161 -19
- data/ext/nokogiri/xslt_stylesheet.h +1 -1
- data/lib/nokogiri.rb +47 -8
- data/lib/nokogiri/1.8/nokogiri.so +0 -0
- data/lib/nokogiri/1.9/nokogiri.so +0 -0
- data/lib/nokogiri/css.rb +6 -3
- data/lib/nokogiri/css/node.rb +14 -12
- data/lib/nokogiri/css/parser.rb +665 -62
- data/lib/nokogiri/css/parser.y +20 -10
- data/lib/nokogiri/css/parser_extras.rb +91 -0
- data/lib/nokogiri/css/tokenizer.rb +148 -5
- data/lib/nokogiri/css/tokenizer.rex +10 -9
- data/lib/nokogiri/css/xpath_visitor.rb +47 -44
- data/lib/nokogiri/decorators/slop.rb +8 -4
- data/lib/nokogiri/ffi/encoding_handler.rb +42 -0
- data/lib/nokogiri/ffi/html/document.rb +28 -0
- data/lib/nokogiri/ffi/html/element_description.rb +81 -0
- data/lib/nokogiri/ffi/html/entity_lookup.rb +16 -0
- data/lib/nokogiri/ffi/html/sax/parser_context.rb +38 -0
- data/lib/nokogiri/ffi/io_callbacks.rb +42 -0
- data/lib/nokogiri/ffi/libxml.rb +420 -0
- data/lib/nokogiri/ffi/structs/common_node.rb +38 -0
- data/lib/nokogiri/ffi/structs/html_elem_desc.rb +24 -0
- data/lib/nokogiri/ffi/structs/html_entity_desc.rb +13 -0
- data/lib/nokogiri/ffi/structs/xml_alloc.rb +16 -0
- data/lib/nokogiri/ffi/structs/xml_attr.rb +20 -0
- data/lib/nokogiri/ffi/structs/xml_attribute.rb +27 -0
- data/lib/nokogiri/ffi/structs/xml_buffer.rb +16 -0
- data/lib/nokogiri/ffi/structs/xml_char_encoding_handler.rb +11 -0
- data/lib/nokogiri/ffi/structs/xml_document.rb +117 -0
- data/lib/nokogiri/ffi/structs/xml_dtd.rb +28 -0
- data/lib/nokogiri/ffi/structs/xml_element.rb +26 -0
- data/lib/nokogiri/ffi/structs/xml_element_content.rb +17 -0
- data/lib/nokogiri/ffi/structs/xml_entity.rb +32 -0
- data/lib/nokogiri/ffi/structs/xml_enumeration.rb +12 -0
- data/lib/nokogiri/ffi/structs/xml_node.rb +28 -0
- data/lib/nokogiri/ffi/structs/xml_node_set.rb +53 -0
- data/lib/nokogiri/ffi/structs/xml_notation.rb +11 -0
- data/lib/nokogiri/ffi/structs/xml_ns.rb +15 -0
- data/lib/nokogiri/ffi/structs/xml_parser_context.rb +20 -0
- data/lib/nokogiri/ffi/structs/xml_parser_input.rb +19 -0
- data/lib/nokogiri/ffi/structs/xml_relax_ng.rb +14 -0
- data/lib/nokogiri/ffi/structs/xml_sax_handler.rb +51 -0
- data/lib/nokogiri/ffi/structs/xml_sax_push_parser_context.rb +124 -0
- data/lib/nokogiri/ffi/structs/xml_schema.rb +13 -0
- data/lib/nokogiri/ffi/structs/xml_syntax_error.rb +31 -0
- data/lib/nokogiri/ffi/structs/xml_text_reader.rb +12 -0
- data/lib/nokogiri/ffi/structs/xml_xpath_context.rb +38 -0
- data/lib/nokogiri/ffi/structs/xml_xpath_object.rb +35 -0
- data/lib/nokogiri/ffi/structs/xml_xpath_parser_context.rb +20 -0
- data/lib/nokogiri/ffi/structs/xslt_stylesheet.rb +13 -0
- data/lib/nokogiri/ffi/weak_bucket.rb +40 -0
- data/lib/nokogiri/ffi/xml/attr.rb +41 -0
- data/lib/nokogiri/ffi/xml/attribute_decl.rb +27 -0
- data/lib/nokogiri/ffi/xml/cdata.rb +19 -0
- data/lib/nokogiri/ffi/xml/comment.rb +18 -0
- data/lib/nokogiri/ffi/xml/document.rb +174 -0
- data/lib/nokogiri/ffi/xml/document_fragment.rb +21 -0
- data/lib/nokogiri/ffi/xml/dtd.rb +67 -0
- data/lib/nokogiri/ffi/xml/element_content.rb +43 -0
- data/lib/nokogiri/ffi/xml/element_decl.rb +19 -0
- data/lib/nokogiri/ffi/xml/entity_decl.rb +36 -0
- data/lib/nokogiri/ffi/xml/entity_reference.rb +19 -0
- data/lib/nokogiri/ffi/xml/namespace.rb +44 -0
- data/lib/nokogiri/ffi/xml/node.rb +559 -0
- data/lib/nokogiri/ffi/xml/node_set.rb +150 -0
- data/lib/nokogiri/ffi/xml/processing_instruction.rb +20 -0
- data/lib/nokogiri/ffi/xml/reader.rb +236 -0
- data/lib/nokogiri/ffi/xml/relax_ng.rb +85 -0
- data/lib/nokogiri/ffi/xml/sax/parser.rb +143 -0
- data/lib/nokogiri/ffi/xml/sax/parser_context.rb +79 -0
- data/lib/nokogiri/ffi/xml/sax/push_parser.rb +51 -0
- data/lib/nokogiri/ffi/xml/schema.rb +109 -0
- data/lib/nokogiri/ffi/xml/syntax_error.rb +98 -0
- data/lib/nokogiri/ffi/xml/text.rb +18 -0
- data/lib/nokogiri/ffi/xml/xpath.rb +9 -0
- data/lib/nokogiri/ffi/xml/xpath_context.rb +153 -0
- data/lib/nokogiri/ffi/xslt/stylesheet.rb +77 -0
- data/lib/nokogiri/html.rb +13 -47
- data/lib/nokogiri/html/builder.rb +27 -1
- data/lib/nokogiri/html/document.rb +201 -7
- data/lib/nokogiri/html/document_fragment.rb +41 -0
- data/lib/nokogiri/html/element_description.rb +23 -0
- data/lib/nokogiri/html/entity_lookup.rb +2 -0
- data/lib/nokogiri/html/sax/parser.rb +34 -3
- data/lib/nokogiri/html/sax/parser_context.rb +16 -0
- data/lib/nokogiri/nokogiri.rb +1 -0
- data/lib/nokogiri/version.rb +40 -1
- data/lib/nokogiri/version_warning.rb +14 -0
- data/lib/nokogiri/xml.rb +32 -53
- data/lib/nokogiri/xml/attr.rb +5 -0
- data/lib/nokogiri/xml/attribute_decl.rb +18 -0
- data/lib/nokogiri/xml/builder.rb +349 -29
- data/lib/nokogiri/xml/cdata.rb +3 -1
- data/lib/nokogiri/xml/character_data.rb +7 -0
- data/lib/nokogiri/xml/document.rb +166 -14
- data/lib/nokogiri/xml/document_fragment.rb +76 -1
- data/lib/nokogiri/xml/dtd.rb +16 -3
- data/lib/nokogiri/xml/element_content.rb +36 -0
- data/lib/nokogiri/xml/element_decl.rb +13 -0
- data/lib/nokogiri/xml/entity_decl.rb +19 -0
- data/lib/nokogiri/xml/namespace.rb +13 -0
- data/lib/nokogiri/xml/node.rb +561 -166
- data/lib/nokogiri/xml/node/save_options.rb +22 -2
- data/lib/nokogiri/xml/node_set.rb +202 -40
- data/lib/nokogiri/xml/parse_options.rb +93 -0
- data/lib/nokogiri/xml/pp.rb +2 -0
- data/lib/nokogiri/xml/pp/character_data.rb +18 -0
- data/lib/nokogiri/xml/pp/node.rb +56 -0
- data/lib/nokogiri/xml/processing_instruction.rb +2 -0
- data/lib/nokogiri/xml/reader.rb +93 -8
- data/lib/nokogiri/xml/relax_ng.rb +32 -0
- data/lib/nokogiri/xml/sax.rb +1 -7
- data/lib/nokogiri/xml/sax/document.rb +107 -2
- data/lib/nokogiri/xml/sax/parser.rb +57 -7
- data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
- data/lib/nokogiri/xml/sax/push_parser.rb +13 -1
- data/lib/nokogiri/xml/schema.rb +63 -0
- data/lib/nokogiri/xml/syntax_error.rb +25 -1
- data/lib/nokogiri/xml/text.rb +4 -1
- data/lib/nokogiri/xml/xpath.rb +1 -1
- data/lib/nokogiri/xml/xpath/syntax_error.rb +3 -0
- data/lib/nokogiri/xml/xpath_context.rb +2 -0
- data/lib/nokogiri/xslt.rb +26 -2
- data/lib/nokogiri/xslt/stylesheet.rb +19 -0
- data/lib/xsd/xmlparser/nokogiri.rb +45 -9
- data/tasks/cross_compile.rb +173 -0
- data/tasks/test.rb +25 -69
- data/test/css/test_nthiness.rb +3 -4
- data/test/css/test_parser.rb +75 -20
- data/test/css/test_tokenizer.rb +23 -1
- data/test/css/test_xpath_visitor.rb +10 -1
- data/test/decorators/test_slop.rb +16 -0
- data/test/ffi/test_document.rb +35 -0
- data/test/files/2ch.html +108 -0
- data/test/files/address_book.rlx +12 -0
- data/test/files/address_book.xml +10 -0
- data/test/files/bar/bar.xsd +4 -0
- data/test/files/encoding.html +82 -0
- data/test/files/encoding.xhtml +84 -0
- data/test/files/foo/foo.xsd +4 -0
- data/test/files/po.xml +32 -0
- data/test/files/po.xsd +66 -0
- data/test/files/shift_jis.html +10 -0
- data/test/files/shift_jis.xml +5 -0
- data/test/files/snuggles.xml +3 -0
- data/test/files/staff.dtd +10 -0
- data/test/files/valid_bar.xml +2 -0
- data/test/helper.rb +101 -23
- data/test/html/sax/test_parser.rb +81 -2
- data/test/html/sax/test_parser_context.rb +48 -0
- data/test/html/test_builder.rb +39 -8
- data/test/html/test_document.rb +186 -23
- data/test/html/test_document_encoding.rb +78 -1
- data/test/html/test_document_fragment.rb +253 -0
- data/test/html/test_element_description.rb +98 -0
- data/test/html/test_named_characters.rb +1 -1
- data/test/html/test_node.rb +124 -36
- data/test/html/test_node_encoding.rb +27 -0
- data/test/test_convert_xpath.rb +1 -52
- data/test/test_css_cache.rb +2 -13
- data/test/test_encoding_handler.rb +46 -0
- data/test/test_memory_leak.rb +88 -19
- data/test/test_nokogiri.rb +38 -5
- data/test/test_reader.rb +188 -6
- data/test/test_soap4r_sax.rb +52 -0
- data/test/test_xslt_transforms.rb +183 -83
- data/test/xml/node/test_save_options.rb +1 -1
- data/test/xml/node/test_subclass.rb +44 -0
- data/test/xml/sax/test_parser.rb +175 -4
- data/test/xml/sax/test_parser_context.rb +113 -0
- data/test/xml/sax/test_push_parser.rb +90 -2
- data/test/xml/test_attr.rb +35 -1
- data/test/xml/test_attribute_decl.rb +82 -0
- data/test/xml/test_builder.rb +186 -1
- data/test/xml/test_cdata.rb +32 -1
- data/test/xml/test_comment.rb +13 -1
- data/test/xml/test_document.rb +415 -43
- data/test/xml/test_document_encoding.rb +1 -1
- data/test/xml/test_document_fragment.rb +173 -5
- data/test/xml/test_dtd.rb +61 -6
- data/test/xml/test_dtd_encoding.rb +3 -1
- data/test/xml/test_element_content.rb +56 -0
- data/test/xml/test_element_decl.rb +73 -0
- data/test/xml/test_entity_decl.rb +120 -0
- data/test/xml/test_entity_reference.rb +5 -1
- data/test/xml/test_namespace.rb +68 -0
- data/test/xml/test_node.rb +546 -201
- data/test/xml/test_node_attributes.rb +34 -0
- data/test/xml/test_node_encoding.rb +33 -3
- data/test/xml/test_node_reparenting.rb +321 -0
- data/test/xml/test_node_set.rb +538 -2
- data/test/xml/test_parse_options.rb +52 -0
- data/test/xml/test_processing_instruction.rb +6 -1
- data/test/xml/test_reader_encoding.rb +1 -1
- data/test/xml/test_relax_ng.rb +60 -0
- data/test/xml/test_schema.rb +94 -0
- data/test/xml/test_syntax_error.rb +12 -0
- data/test/xml/test_text.rb +35 -1
- data/test/xml/test_unparented_node.rb +5 -5
- data/test/xml/test_xpath.rb +142 -11
- data/test/xslt/test_custom_functions.rb +94 -0
- metadata +328 -92
- data/ext/nokogiri/html_sax_parser.c +0 -57
- data/ext/nokogiri/html_sax_parser.h +0 -11
- data/ext/nokogiri/iconv.dll +0 -0
- data/ext/nokogiri/libexslt.dll +0 -0
- data/ext/nokogiri/libxml2.dll +0 -0
- data/ext/nokogiri/libxslt.dll +0 -0
- data/ext/nokogiri/native.so +0 -0
- data/ext/nokogiri/xml_xpath.c +0 -53
- data/ext/nokogiri/xml_xpath.h +0 -11
- data/ext/nokogiri/zlib1.dll +0 -0
- data/lib/action-nokogiri.rb +0 -30
- data/lib/nokogiri/css/generated_parser.rb +0 -713
- data/lib/nokogiri/css/generated_tokenizer.rb +0 -144
- data/lib/nokogiri/decorators.rb +0 -2
- data/lib/nokogiri/decorators/hpricot.rb +0 -3
- data/lib/nokogiri/decorators/hpricot/node.rb +0 -56
- data/lib/nokogiri/decorators/hpricot/node_set.rb +0 -54
- data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +0 -28
- data/lib/nokogiri/hpricot.rb +0 -51
- data/lib/nokogiri/xml/comment.rb +0 -6
- data/lib/nokogiri/xml/element.rb +0 -6
- data/lib/nokogiri/xml/entity_declaration.rb +0 -9
- data/lib/nokogiri/xml/fragment_handler.rb +0 -34
- data/test/hpricot/files/basic.xhtml +0 -17
- data/test/hpricot/files/boingboing.html +0 -2266
- data/test/hpricot/files/cy0.html +0 -3653
- data/test/hpricot/files/immob.html +0 -400
- data/test/hpricot/files/pace_application.html +0 -1320
- data/test/hpricot/files/tenderlove.html +0 -16
- data/test/hpricot/files/uswebgen.html +0 -220
- data/test/hpricot/files/utf8.html +0 -1054
- data/test/hpricot/files/week9.html +0 -1723
- data/test/hpricot/files/why.xml +0 -19
- data/test/hpricot/load_files.rb +0 -11
- data/test/hpricot/test_alter.rb +0 -68
- data/test/hpricot/test_builder.rb +0 -20
- data/test/hpricot/test_parser.rb +0 -426
- data/test/hpricot/test_paths.rb +0 -15
- data/test/hpricot/test_preserved.rb +0 -77
- data/test/hpricot/test_xml.rb +0 -30
- data/test/test_gc.rb +0 -15
@@ -0,0 +1,12 @@
|
|
1
|
+
#ifndef HAVE_XMLFIRSTELEMENTCHILD
|
2
|
+
|
3
|
+
#ifndef XML_LIBXML2_HACKS
|
4
|
+
#define XML_LIBXML2_HACKS
|
5
|
+
|
6
|
+
xmlNodePtr xmlFirstElementChild(xmlNodePtr parent);
|
7
|
+
xmlNodePtr xmlNextElementSibling(xmlNodePtr node);
|
8
|
+
xmlNodePtr xmlLastElementChild(xmlNodePtr parent);
|
9
|
+
|
10
|
+
#endif
|
11
|
+
|
12
|
+
#endif
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#include <xml_namespace.h>
|
2
|
+
|
3
|
+
VALUE cNokogiriXmlNamespace ;
|
4
|
+
|
5
|
+
/*
|
6
|
+
* call-seq:
|
7
|
+
* prefix
|
8
|
+
*
|
9
|
+
* Get the prefix for this namespace. Returns +nil+ if there is no prefix.
|
10
|
+
*/
|
11
|
+
static VALUE prefix(VALUE self)
|
12
|
+
{
|
13
|
+
xmlNsPtr ns;
|
14
|
+
xmlDocPtr doc;
|
15
|
+
|
16
|
+
Data_Get_Struct(self, xmlNs, ns);
|
17
|
+
if(!ns->prefix) return Qnil;
|
18
|
+
|
19
|
+
Data_Get_Struct(rb_iv_get(self, "@document"), xmlDoc, doc);
|
20
|
+
|
21
|
+
return NOKOGIRI_STR_NEW2(ns->prefix);
|
22
|
+
}
|
23
|
+
|
24
|
+
/*
|
25
|
+
* call-seq:
|
26
|
+
* href
|
27
|
+
*
|
28
|
+
* Get the href for this namespace
|
29
|
+
*/
|
30
|
+
static VALUE href(VALUE self)
|
31
|
+
{
|
32
|
+
xmlNsPtr ns;
|
33
|
+
xmlDocPtr doc;
|
34
|
+
|
35
|
+
Data_Get_Struct(self, xmlNs, ns);
|
36
|
+
if(!ns->href) return Qnil;
|
37
|
+
|
38
|
+
Data_Get_Struct(rb_iv_get(self, "@document"), xmlDoc, doc);
|
39
|
+
|
40
|
+
return NOKOGIRI_STR_NEW2(ns->href);
|
41
|
+
}
|
42
|
+
|
43
|
+
VALUE Nokogiri_wrap_xml_namespace(xmlDocPtr doc, xmlNsPtr node)
|
44
|
+
{
|
45
|
+
VALUE ns, document, node_cache;
|
46
|
+
|
47
|
+
assert(doc->_private);
|
48
|
+
|
49
|
+
if(node->_private)
|
50
|
+
return (VALUE)node->_private;
|
51
|
+
|
52
|
+
ns = Data_Wrap_Struct(cNokogiriXmlNamespace, 0, 0, node);
|
53
|
+
|
54
|
+
document = DOC_RUBY_OBJECT(doc);
|
55
|
+
|
56
|
+
node_cache = rb_iv_get(document, "@node_cache");
|
57
|
+
rb_ary_push(node_cache, ns);
|
58
|
+
|
59
|
+
rb_iv_set(ns, "@document", DOC_RUBY_OBJECT(doc));
|
60
|
+
|
61
|
+
node->_private = (void *)ns;
|
62
|
+
|
63
|
+
return ns;
|
64
|
+
}
|
65
|
+
|
66
|
+
VALUE Nokogiri_wrap_xml_namespace2(VALUE document, xmlNsPtr node)
|
67
|
+
{
|
68
|
+
xmlDocPtr doc;
|
69
|
+
Data_Get_Struct(document, xmlDoc, doc) ;
|
70
|
+
return Nokogiri_wrap_xml_namespace(doc, node);
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
void init_xml_namespace()
|
75
|
+
{
|
76
|
+
VALUE nokogiri = rb_define_module("Nokogiri");
|
77
|
+
VALUE xml = rb_define_module_under(nokogiri, "XML");
|
78
|
+
VALUE klass = rb_define_class_under(xml, "Namespace", rb_cObject);
|
79
|
+
|
80
|
+
cNokogiriXmlNamespace = klass;
|
81
|
+
|
82
|
+
rb_define_method(klass, "prefix", prefix, 0);
|
83
|
+
rb_define_method(klass, "href", href, 0);
|
84
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef NOKOGIRI_XML_NAMESPACE
|
2
|
+
#define NOKOGIRI_XML_NAMESPACE
|
3
|
+
|
4
|
+
#include <nokogiri.h>
|
5
|
+
|
6
|
+
void init_xml_namespace();
|
7
|
+
|
8
|
+
extern VALUE cNokogiriXmlNamespace ;
|
9
|
+
|
10
|
+
VALUE Nokogiri_wrap_xml_namespace(xmlDocPtr doc, xmlNsPtr node) ;
|
11
|
+
VALUE Nokogiri_wrap_xml_namespace2(VALUE document, xmlNsPtr node) ;
|
12
|
+
|
13
|
+
#endif
|
data/ext/nokogiri/xml_node.c
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
#include <xml_node.h>
|
2
2
|
|
3
|
+
static ID decorate, decorate_bang;
|
4
|
+
|
3
5
|
#ifdef DEBUG
|
4
6
|
static void debug_node_dealloc(xmlNodePtr x)
|
5
7
|
{
|
@@ -10,65 +12,200 @@ static void debug_node_dealloc(xmlNodePtr x)
|
|
10
12
|
# define debug_node_dealloc 0
|
11
13
|
#endif
|
12
14
|
|
15
|
+
static void mark(xmlNodePtr node)
|
16
|
+
{
|
17
|
+
rb_gc_mark(DOC_RUBY_OBJECT(node->doc));
|
18
|
+
}
|
19
|
+
|
13
20
|
/* :nodoc: */
|
14
|
-
typedef xmlNodePtr (*
|
21
|
+
typedef xmlNodePtr (*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
|
15
22
|
|
16
23
|
/* :nodoc: */
|
17
|
-
static
|
24
|
+
static void relink_namespace(xmlNodePtr reparented)
|
18
25
|
{
|
19
|
-
|
20
|
-
|
26
|
+
xmlNodePtr child;
|
27
|
+
|
28
|
+
/* Avoid segv when relinking against unlinked nodes. */
|
29
|
+
if(!reparented->parent) return;
|
21
30
|
|
22
|
-
|
23
|
-
|
31
|
+
/* Make sure that our reparented node has the correct namespaces */
|
32
|
+
if(!reparented->ns && reparented->doc != (xmlDocPtr)reparented->parent)
|
33
|
+
xmlSetNs(reparented, reparented->parent->ns);
|
24
34
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
35
|
+
/* Search our parents for an existing definition */
|
36
|
+
if(reparented->nsDef) {
|
37
|
+
xmlNsPtr curr = reparented->nsDef;
|
38
|
+
xmlNsPtr prev = NULL;
|
39
|
+
|
40
|
+
while(curr) {
|
41
|
+
xmlNsPtr ns = xmlSearchNsByHref(
|
42
|
+
reparented->doc,
|
43
|
+
reparented->parent,
|
44
|
+
curr->href
|
45
|
+
);
|
46
|
+
/* If we find the namespace is already declared, remove it from this
|
47
|
+
* definition list. */
|
48
|
+
if(ns && ns != curr) {
|
49
|
+
if (prev) {
|
50
|
+
prev->next = curr->next;
|
51
|
+
} else {
|
52
|
+
reparented->nsDef = curr->next;
|
53
|
+
}
|
54
|
+
NOKOGIRI_ROOT_NSDEF(curr, reparented->doc);
|
55
|
+
} else {
|
56
|
+
prev = curr;
|
57
|
+
}
|
58
|
+
curr = curr->next;
|
29
59
|
}
|
60
|
+
}
|
30
61
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
62
|
+
/* Only walk all children if there actually is a namespace we need to */
|
63
|
+
/* reparent. */
|
64
|
+
if(NULL == reparented->ns) return;
|
65
|
+
|
66
|
+
/* When a node gets reparented, walk it's children to make sure that */
|
67
|
+
/* their namespaces are reparented as well. */
|
68
|
+
child = reparented->children;
|
69
|
+
while(NULL != child) {
|
70
|
+
relink_namespace(child);
|
71
|
+
child = child->next;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
/* :nodoc: */
|
76
|
+
static xmlNodePtr xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
|
77
|
+
{
|
78
|
+
xmlNodePtr retval ;
|
79
|
+
|
80
|
+
retval = xmlReplaceNode(pivot, new_node) ;
|
81
|
+
|
82
|
+
if (retval == pivot) {
|
83
|
+
retval = new_node ; /* return semantics for reparent_node_with */
|
84
|
+
}
|
85
|
+
|
86
|
+
/* work around libxml2 issue: https://bugzilla.gnome.org/show_bug.cgi?id=615612 */
|
87
|
+
if (retval->type == XML_TEXT_NODE) {
|
88
|
+
if (retval->prev && retval->prev->type == XML_TEXT_NODE) {
|
89
|
+
retval = xmlTextMerge(retval->prev, retval);
|
36
90
|
}
|
37
|
-
if(
|
38
|
-
|
91
|
+
if (retval->next && retval->next->type == XML_TEXT_NODE) {
|
92
|
+
retval = xmlTextMerge(retval, retval->next);
|
39
93
|
}
|
40
|
-
xmlUnlinkNode(node);
|
41
|
-
NOKOGIRI_ROOT_NODE(node);
|
42
94
|
}
|
43
95
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
96
|
+
return retval ;
|
97
|
+
}
|
98
|
+
|
99
|
+
/* :nodoc: */
|
100
|
+
static VALUE reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
|
101
|
+
{
|
102
|
+
VALUE reparented_obj ;
|
103
|
+
xmlNodePtr reparentee, pivot, reparented, next_text, new_next_text ;
|
104
|
+
|
105
|
+
if(!rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlNode))
|
106
|
+
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
|
107
|
+
if(rb_obj_is_kind_of(reparentee_obj, cNokogiriXmlDocument))
|
108
|
+
rb_raise(rb_eArgError, "node must be a Nokogiri::XML::Node");
|
109
|
+
|
110
|
+
Data_Get_Struct(reparentee_obj, xmlNode, reparentee);
|
111
|
+
Data_Get_Struct(pivot_obj, xmlNode, pivot);
|
112
|
+
|
113
|
+
if(XML_DOCUMENT_NODE == reparentee->type || XML_HTML_DOCUMENT_NODE == reparentee->type)
|
114
|
+
rb_raise(rb_eArgError, "cannot reparent a document node");
|
115
|
+
|
116
|
+
xmlUnlinkNode(reparentee);
|
117
|
+
|
118
|
+
if (reparentee->doc != pivot->doc || reparentee->type == XML_TEXT_NODE) {
|
119
|
+
/*
|
120
|
+
* if the reparentee is a text node, there's a very good chance it will be
|
121
|
+
* merged with an adjacent text node after being reparented, and in that case
|
122
|
+
* libxml will free the underlying C struct.
|
123
|
+
*
|
124
|
+
* since we clearly have a ruby object which references the underlying
|
125
|
+
* memory, we can't let the C struct get freed. let's pickle the original
|
126
|
+
* reparentee by rooting it; and then we'll reparent a duplicate of the
|
127
|
+
* node that we don't care about preserving.
|
128
|
+
*
|
129
|
+
* alternatively, if the reparentee is from a different document than the
|
130
|
+
* pivot node, libxml2 is going to get confused about which document's
|
131
|
+
* "dictionary" the node's strings belong to (this is an otherwise
|
132
|
+
* uninteresting libxml2 implementation detail). as a result, we cannot
|
133
|
+
* reparent the actual reparentee, so we reparent a duplicate.
|
134
|
+
*/
|
135
|
+
NOKOGIRI_ROOT_NODE(reparentee);
|
136
|
+
if (!(reparentee = xmlDocCopyNode(reparentee, pivot->doc, 1))) {
|
137
|
+
rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
|
138
|
+
}
|
48
139
|
}
|
49
140
|
|
50
|
-
|
51
|
-
|
52
|
-
|
141
|
+
if (reparentee->type == XML_TEXT_NODE && pivot->next && pivot->next->type == XML_TEXT_NODE) {
|
142
|
+
/*
|
143
|
+
* libxml merges text nodes in a right-to-left fashion, meaning that if
|
144
|
+
* there are two text nodes who would be adjacent, the right (or following,
|
145
|
+
* or next) node will be merged into the left (or preceding, or previous)
|
146
|
+
* node.
|
147
|
+
*
|
148
|
+
* and by "merged" I mean the string contents will be concatenated onto the
|
149
|
+
* left node's contents, and then the node will be freed.
|
150
|
+
*
|
151
|
+
* which means that if we have a ruby object wrapped around the right node,
|
152
|
+
* its memory would be freed out from under it.
|
153
|
+
*
|
154
|
+
* so, we detect this edge case and unlink-and-root the text node before it gets
|
155
|
+
* merged. then we dup the node and insert that duplicate back into the
|
156
|
+
* document where the real node was.
|
157
|
+
*
|
158
|
+
* yes, this is totally lame.
|
159
|
+
*/
|
160
|
+
next_text = pivot->next ;
|
161
|
+
new_next_text = xmlDocCopyNode(next_text, pivot->doc, 1) ;
|
162
|
+
|
163
|
+
xmlUnlinkNode(next_text);
|
164
|
+
NOKOGIRI_ROOT_NODE(next_text);
|
165
|
+
|
166
|
+
xmlAddNextSibling(pivot, new_next_text);
|
167
|
+
}
|
53
168
|
|
54
|
-
|
55
|
-
if(
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
169
|
+
/* TODO: I really want to remove this. We shouldn't support 2.6.16 anymore */
|
170
|
+
if ( reparentee->type == XML_TEXT_NODE && pivot->type == XML_TEXT_NODE && is_2_6_16() ) {
|
171
|
+
/* work around a string-handling bug in libxml 2.6.16. we'd rather leak than segfault. */
|
172
|
+
pivot->content = xmlStrdup(pivot->content);
|
173
|
+
}
|
174
|
+
|
175
|
+
if(!(reparented = (*prf)(pivot, reparentee))) {
|
176
|
+
rb_raise(rb_eRuntimeError, "Could not reparent node");
|
62
177
|
}
|
63
178
|
|
64
|
-
|
179
|
+
/*
|
180
|
+
* make sure the ruby object is pointed at the just-reparented node, which
|
181
|
+
* might be a duplicate (see above) or might be the result of merging
|
182
|
+
* adjacent text nodes.
|
183
|
+
*/
|
184
|
+
DATA_PTR(reparentee_obj) = reparented ;
|
185
|
+
|
186
|
+
relink_namespace(reparented);
|
187
|
+
|
188
|
+
reparented_obj = Nokogiri_wrap_xml_node(Qnil, reparented);
|
65
189
|
|
66
|
-
rb_funcall(reparented_obj,
|
190
|
+
rb_funcall(reparented_obj, decorate_bang, 0);
|
67
191
|
|
68
192
|
return reparented_obj ;
|
69
193
|
}
|
70
194
|
|
71
195
|
|
196
|
+
/*
|
197
|
+
* call-seq:
|
198
|
+
* document
|
199
|
+
*
|
200
|
+
* Get the document for this Node
|
201
|
+
*/
|
202
|
+
static VALUE document(VALUE self)
|
203
|
+
{
|
204
|
+
xmlNodePtr node;
|
205
|
+
Data_Get_Struct(self, xmlNode, node);
|
206
|
+
return DOC_RUBY_OBJECT(node->doc);
|
207
|
+
}
|
208
|
+
|
72
209
|
/*
|
73
210
|
* call-seq:
|
74
211
|
* pointer_id
|
@@ -80,7 +217,7 @@ static VALUE pointer_id(VALUE self)
|
|
80
217
|
xmlNodePtr node;
|
81
218
|
Data_Get_Struct(self, xmlNode, node);
|
82
219
|
|
83
|
-
return INT2NUM((
|
220
|
+
return INT2NUM((long)(node));
|
84
221
|
}
|
85
222
|
|
86
223
|
/*
|
@@ -92,18 +229,113 @@ static VALUE pointer_id(VALUE self)
|
|
92
229
|
static VALUE encode_special_chars(VALUE self, VALUE string)
|
93
230
|
{
|
94
231
|
xmlNodePtr node;
|
232
|
+
xmlChar *encoded;
|
233
|
+
VALUE encoded_str;
|
234
|
+
|
95
235
|
Data_Get_Struct(self, xmlNode, node);
|
96
|
-
|
236
|
+
encoded = xmlEncodeSpecialChars(
|
97
237
|
node->doc,
|
98
238
|
(const xmlChar *)StringValuePtr(string)
|
99
239
|
);
|
100
240
|
|
101
|
-
|
241
|
+
encoded_str = NOKOGIRI_STR_NEW2(encoded);
|
102
242
|
xmlFree(encoded);
|
103
243
|
|
104
244
|
return encoded_str;
|
105
245
|
}
|
106
246
|
|
247
|
+
/*
|
248
|
+
* call-seq:
|
249
|
+
* create_internal_subset(name, external_id, system_id)
|
250
|
+
*
|
251
|
+
* Create the internal subset of a document.
|
252
|
+
*
|
253
|
+
* doc.create_internal_subset("chapter", "-//OASIS//DTD DocBook XML//EN", "chapter.dtd")
|
254
|
+
* # => <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML//EN" "chapter.dtd">
|
255
|
+
*
|
256
|
+
* doc.create_internal_subset("chapter", nil, "chapter.dtd")
|
257
|
+
* # => <!DOCTYPE chapter SYSTEM "chapter.dtd">
|
258
|
+
*/
|
259
|
+
static VALUE create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
|
260
|
+
{
|
261
|
+
xmlNodePtr node;
|
262
|
+
xmlDocPtr doc;
|
263
|
+
xmlDtdPtr dtd;
|
264
|
+
|
265
|
+
Data_Get_Struct(self, xmlNode, node);
|
266
|
+
|
267
|
+
doc = node->doc;
|
268
|
+
|
269
|
+
if(xmlGetIntSubset(doc))
|
270
|
+
rb_raise(rb_eRuntimeError, "Document already has an internal subset");
|
271
|
+
|
272
|
+
dtd = xmlCreateIntSubset(
|
273
|
+
doc,
|
274
|
+
NIL_P(name) ? NULL : (const xmlChar *)StringValuePtr(name),
|
275
|
+
NIL_P(external_id) ? NULL : (const xmlChar *)StringValuePtr(external_id),
|
276
|
+
NIL_P(system_id) ? NULL : (const xmlChar *)StringValuePtr(system_id)
|
277
|
+
);
|
278
|
+
|
279
|
+
if(!dtd) return Qnil;
|
280
|
+
|
281
|
+
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
|
282
|
+
}
|
283
|
+
|
284
|
+
/*
|
285
|
+
* call-seq:
|
286
|
+
* create_external_subset(name, external_id, system_id)
|
287
|
+
*
|
288
|
+
* Create an external subset
|
289
|
+
*/
|
290
|
+
static VALUE create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_id)
|
291
|
+
{
|
292
|
+
xmlNodePtr node;
|
293
|
+
xmlDocPtr doc;
|
294
|
+
xmlDtdPtr dtd;
|
295
|
+
|
296
|
+
Data_Get_Struct(self, xmlNode, node);
|
297
|
+
|
298
|
+
doc = node->doc;
|
299
|
+
|
300
|
+
if(doc->extSubset)
|
301
|
+
rb_raise(rb_eRuntimeError, "Document already has an external subset");
|
302
|
+
|
303
|
+
dtd = xmlNewDtd(
|
304
|
+
doc,
|
305
|
+
NIL_P(name) ? NULL : (const xmlChar *)StringValuePtr(name),
|
306
|
+
NIL_P(external_id) ? NULL : (const xmlChar *)StringValuePtr(external_id),
|
307
|
+
NIL_P(system_id) ? NULL : (const xmlChar *)StringValuePtr(system_id)
|
308
|
+
);
|
309
|
+
|
310
|
+
if(!dtd) return Qnil;
|
311
|
+
|
312
|
+
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
|
313
|
+
}
|
314
|
+
|
315
|
+
/*
|
316
|
+
* call-seq:
|
317
|
+
* external_subset
|
318
|
+
*
|
319
|
+
* Get the external subset
|
320
|
+
*/
|
321
|
+
static VALUE external_subset(VALUE self)
|
322
|
+
{
|
323
|
+
xmlNodePtr node;
|
324
|
+
xmlDocPtr doc;
|
325
|
+
xmlDtdPtr dtd;
|
326
|
+
|
327
|
+
Data_Get_Struct(self, xmlNode, node);
|
328
|
+
|
329
|
+
if(!node->doc) return Qnil;
|
330
|
+
|
331
|
+
doc = node->doc;
|
332
|
+
dtd = doc->extSubset;
|
333
|
+
|
334
|
+
if(!dtd) return Qnil;
|
335
|
+
|
336
|
+
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
|
337
|
+
}
|
338
|
+
|
107
339
|
/*
|
108
340
|
* call-seq:
|
109
341
|
* internal_subset
|
@@ -114,16 +346,18 @@ static VALUE internal_subset(VALUE self)
|
|
114
346
|
{
|
115
347
|
xmlNodePtr node;
|
116
348
|
xmlDocPtr doc;
|
349
|
+
xmlDtdPtr dtd;
|
350
|
+
|
117
351
|
Data_Get_Struct(self, xmlNode, node);
|
118
352
|
|
119
353
|
if(!node->doc) return Qnil;
|
120
354
|
|
121
355
|
doc = node->doc;
|
122
|
-
|
356
|
+
dtd = xmlGetIntSubset(doc);
|
123
357
|
|
124
358
|
if(!dtd) return Qnil;
|
125
359
|
|
126
|
-
return Nokogiri_wrap_xml_node((xmlNodePtr)dtd);
|
360
|
+
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)dtd);
|
127
361
|
}
|
128
362
|
|
129
363
|
/*
|
@@ -136,17 +370,19 @@ static VALUE internal_subset(VALUE self)
|
|
136
370
|
static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
|
137
371
|
{
|
138
372
|
VALUE level;
|
373
|
+
xmlNodePtr node, dup;
|
139
374
|
|
140
375
|
if(rb_scan_args(argc, argv, "01", &level) == 0)
|
141
|
-
level = INT2NUM(1);
|
376
|
+
level = INT2NUM((long)1);
|
142
377
|
|
143
|
-
xmlNodePtr node, dup;
|
144
378
|
Data_Get_Struct(self, xmlNode, node);
|
145
379
|
|
146
|
-
dup = xmlDocCopyNode(node, node->doc, NUM2INT(level));
|
380
|
+
dup = xmlDocCopyNode(node, node->doc, (int)NUM2INT(level));
|
147
381
|
if(dup == NULL) return Qnil;
|
148
382
|
|
149
|
-
|
383
|
+
NOKOGIRI_ROOT_NODE(dup);
|
384
|
+
|
385
|
+
return Nokogiri_wrap_xml_node(rb_obj_class(self), dup);
|
150
386
|
}
|
151
387
|
|
152
388
|
/*
|
@@ -174,9 +410,7 @@ static VALUE blank_eh(VALUE self)
|
|
174
410
|
{
|
175
411
|
xmlNodePtr node;
|
176
412
|
Data_Get_Struct(self, xmlNode, node);
|
177
|
-
|
178
|
-
return Qtrue;
|
179
|
-
return Qfalse;
|
413
|
+
return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
|
180
414
|
}
|
181
415
|
|
182
416
|
/*
|
@@ -193,7 +427,7 @@ static VALUE next_sibling(VALUE self)
|
|
193
427
|
sibling = node->next;
|
194
428
|
if(!sibling) return Qnil;
|
195
429
|
|
196
|
-
return Nokogiri_wrap_xml_node(sibling) ;
|
430
|
+
return Nokogiri_wrap_xml_node(Qnil, sibling) ;
|
197
431
|
}
|
198
432
|
|
199
433
|
/*
|
@@ -210,18 +444,53 @@ static VALUE previous_sibling(VALUE self)
|
|
210
444
|
sibling = node->prev;
|
211
445
|
if(!sibling) return Qnil;
|
212
446
|
|
213
|
-
return Nokogiri_wrap_xml_node(sibling);
|
447
|
+
return Nokogiri_wrap_xml_node(Qnil, sibling);
|
214
448
|
}
|
215
449
|
|
216
|
-
/*
|
217
|
-
|
450
|
+
/*
|
451
|
+
* call-seq:
|
452
|
+
* next_element
|
453
|
+
*
|
454
|
+
* Returns the next Nokogiri::XML::Element type sibling node.
|
455
|
+
*/
|
456
|
+
static VALUE next_element(VALUE self)
|
218
457
|
{
|
219
|
-
xmlNodePtr node,
|
458
|
+
xmlNodePtr node, sibling;
|
220
459
|
Data_Get_Struct(self, xmlNode, node);
|
221
|
-
Data_Get_Struct(_new_node, xmlNode, new_node);
|
222
460
|
|
223
|
-
|
224
|
-
return
|
461
|
+
sibling = xmlNextElementSibling(node);
|
462
|
+
if(!sibling) return Qnil;
|
463
|
+
|
464
|
+
return Nokogiri_wrap_xml_node(Qnil, sibling);
|
465
|
+
}
|
466
|
+
|
467
|
+
/*
|
468
|
+
* call-seq:
|
469
|
+
* previous_element
|
470
|
+
*
|
471
|
+
* Returns the previous Nokogiri::XML::Element type sibling node.
|
472
|
+
*/
|
473
|
+
static VALUE previous_element(VALUE self)
|
474
|
+
{
|
475
|
+
xmlNodePtr node, sibling;
|
476
|
+
Data_Get_Struct(self, xmlNode, node);
|
477
|
+
|
478
|
+
/*
|
479
|
+
* note that we don't use xmlPreviousElementSibling here because it's buggy pre-2.7.7.
|
480
|
+
*/
|
481
|
+
sibling = node->prev;
|
482
|
+
if(!sibling) return Qnil;
|
483
|
+
|
484
|
+
while(sibling && sibling->type != XML_ELEMENT_NODE)
|
485
|
+
sibling = sibling->prev;
|
486
|
+
|
487
|
+
return sibling ? Nokogiri_wrap_xml_node(Qnil, sibling) : Qnil ;
|
488
|
+
}
|
489
|
+
|
490
|
+
/* :nodoc: */
|
491
|
+
static VALUE replace(VALUE self, VALUE new_node)
|
492
|
+
{
|
493
|
+
return reparent_node_with(self, new_node, xmlReplaceNodeWrapper) ;
|
225
494
|
}
|
226
495
|
|
227
496
|
/*
|
@@ -233,20 +502,68 @@ static VALUE replace(VALUE self, VALUE _new_node)
|
|
233
502
|
static VALUE children(VALUE self)
|
234
503
|
{
|
235
504
|
xmlNodePtr node;
|
505
|
+
xmlNodePtr child;
|
506
|
+
xmlNodeSetPtr set;
|
507
|
+
VALUE document;
|
508
|
+
VALUE node_set;
|
509
|
+
|
236
510
|
Data_Get_Struct(self, xmlNode, node);
|
237
511
|
|
238
|
-
|
239
|
-
|
512
|
+
child = node->children;
|
513
|
+
set = xmlXPathNodeSetCreate(child);
|
514
|
+
|
515
|
+
document = DOC_RUBY_OBJECT(node->doc);
|
240
516
|
|
241
|
-
if(!child) return Nokogiri_wrap_xml_node_set(set);
|
517
|
+
if(!child) return Nokogiri_wrap_xml_node_set(set, document);
|
242
518
|
|
243
519
|
child = child->next;
|
244
520
|
while(NULL != child) {
|
245
|
-
|
521
|
+
xmlXPathNodeSetAddUnique(set, child);
|
246
522
|
child = child->next;
|
247
523
|
}
|
248
524
|
|
249
|
-
|
525
|
+
node_set = Nokogiri_wrap_xml_node_set(set, document);
|
526
|
+
|
527
|
+
return node_set;
|
528
|
+
}
|
529
|
+
|
530
|
+
/*
|
531
|
+
* call-seq:
|
532
|
+
* element_children
|
533
|
+
*
|
534
|
+
* Get the list of children for this node as a NodeSet. All nodes will be
|
535
|
+
* element nodes.
|
536
|
+
*
|
537
|
+
* Example:
|
538
|
+
*
|
539
|
+
* @doc.root.element_children.all? { |x| x.element? } # => true
|
540
|
+
*/
|
541
|
+
static VALUE element_children(VALUE self)
|
542
|
+
{
|
543
|
+
xmlNodePtr node;
|
544
|
+
xmlNodePtr child;
|
545
|
+
xmlNodeSetPtr set;
|
546
|
+
VALUE document;
|
547
|
+
VALUE node_set;
|
548
|
+
|
549
|
+
Data_Get_Struct(self, xmlNode, node);
|
550
|
+
|
551
|
+
child = xmlFirstElementChild(node);
|
552
|
+
set = xmlXPathNodeSetCreate(child);
|
553
|
+
|
554
|
+
document = DOC_RUBY_OBJECT(node->doc);
|
555
|
+
|
556
|
+
if(!child) return Nokogiri_wrap_xml_node_set(set, document);
|
557
|
+
|
558
|
+
child = xmlNextElementSibling(child);
|
559
|
+
while(NULL != child) {
|
560
|
+
xmlXPathNodeSetAddUnique(set, child);
|
561
|
+
child = xmlNextElementSibling(child);
|
562
|
+
}
|
563
|
+
|
564
|
+
node_set = Nokogiri_wrap_xml_node_set(set, document);
|
565
|
+
|
566
|
+
return node_set;
|
250
567
|
}
|
251
568
|
|
252
569
|
/*
|
@@ -263,7 +580,49 @@ static VALUE child(VALUE self)
|
|
263
580
|
child = node->children;
|
264
581
|
if(!child) return Qnil;
|
265
582
|
|
266
|
-
return Nokogiri_wrap_xml_node(child);
|
583
|
+
return Nokogiri_wrap_xml_node(Qnil, child);
|
584
|
+
}
|
585
|
+
|
586
|
+
/*
|
587
|
+
* call-seq:
|
588
|
+
* first_element_child
|
589
|
+
*
|
590
|
+
* Returns the first child node of this node that is an element.
|
591
|
+
*
|
592
|
+
* Example:
|
593
|
+
*
|
594
|
+
* @doc.root.first_element_child.element? # => true
|
595
|
+
*/
|
596
|
+
static VALUE first_element_child(VALUE self)
|
597
|
+
{
|
598
|
+
xmlNodePtr node, child;
|
599
|
+
Data_Get_Struct(self, xmlNode, node);
|
600
|
+
|
601
|
+
child = xmlFirstElementChild(node);
|
602
|
+
if(!child) return Qnil;
|
603
|
+
|
604
|
+
return Nokogiri_wrap_xml_node(Qnil, child);
|
605
|
+
}
|
606
|
+
|
607
|
+
/*
|
608
|
+
* call-seq:
|
609
|
+
* last_element_child
|
610
|
+
*
|
611
|
+
* Returns the last child node of this node that is an element.
|
612
|
+
*
|
613
|
+
* Example:
|
614
|
+
*
|
615
|
+
* @doc.root.last_element_child.element? # => true
|
616
|
+
*/
|
617
|
+
static VALUE last_element_child(VALUE self)
|
618
|
+
{
|
619
|
+
xmlNodePtr node, child;
|
620
|
+
Data_Get_Struct(self, xmlNode, node);
|
621
|
+
|
622
|
+
child = xmlLastElementChild(node);
|
623
|
+
if(!child) return Qnil;
|
624
|
+
|
625
|
+
return Nokogiri_wrap_xml_node(Qnil, child);
|
267
626
|
}
|
268
627
|
|
269
628
|
/*
|
@@ -281,6 +640,22 @@ static VALUE key_eh(VALUE self, VALUE attribute)
|
|
281
640
|
return Qfalse;
|
282
641
|
}
|
283
642
|
|
643
|
+
/*
|
644
|
+
* call-seq:
|
645
|
+
* namespaced_key?(attribute, namespace)
|
646
|
+
*
|
647
|
+
* Returns true if +attribute+ is set with +namespace+
|
648
|
+
*/
|
649
|
+
static VALUE namespaced_key_eh(VALUE self, VALUE attribute, VALUE namespace)
|
650
|
+
{
|
651
|
+
xmlNodePtr node;
|
652
|
+
Data_Get_Struct(self, xmlNode, node);
|
653
|
+
if(xmlHasNsProp(node, (xmlChar *)StringValuePtr(attribute),
|
654
|
+
NIL_P(namespace) ? NULL : (xmlChar *)StringValuePtr(namespace)))
|
655
|
+
return Qtrue;
|
656
|
+
return Qfalse;
|
657
|
+
}
|
658
|
+
|
284
659
|
/*
|
285
660
|
* call-seq:
|
286
661
|
* []=(property, value)
|
@@ -311,18 +686,39 @@ static VALUE get(VALUE self, VALUE attribute)
|
|
311
686
|
VALUE rval ;
|
312
687
|
Data_Get_Struct(self, xmlNode, node);
|
313
688
|
|
314
|
-
if(attribute
|
689
|
+
if(NIL_P(attribute)) return Qnil;
|
315
690
|
|
316
691
|
propstr = xmlGetProp(node, (xmlChar *)StringValuePtr(attribute));
|
317
692
|
|
318
|
-
if(
|
693
|
+
if(!propstr) return Qnil;
|
319
694
|
|
320
|
-
rval = NOKOGIRI_STR_NEW2(propstr
|
695
|
+
rval = NOKOGIRI_STR_NEW2(propstr);
|
321
696
|
|
322
697
|
xmlFree(propstr);
|
323
698
|
return rval ;
|
324
699
|
}
|
325
700
|
|
701
|
+
/*
|
702
|
+
* call-seq:
|
703
|
+
* set_namespace(namespace)
|
704
|
+
*
|
705
|
+
* Set the namespace to +namespace+
|
706
|
+
*/
|
707
|
+
static VALUE set_namespace(VALUE self, VALUE namespace)
|
708
|
+
{
|
709
|
+
xmlNodePtr node;
|
710
|
+
xmlNsPtr ns = NULL;
|
711
|
+
|
712
|
+
Data_Get_Struct(self, xmlNode, node);
|
713
|
+
|
714
|
+
if(!NIL_P(namespace))
|
715
|
+
Data_Get_Struct(namespace, xmlNs, ns);
|
716
|
+
|
717
|
+
xmlSetNs(node, ns);
|
718
|
+
|
719
|
+
return self;
|
720
|
+
}
|
721
|
+
|
326
722
|
/*
|
327
723
|
* call-seq:
|
328
724
|
* attribute(name)
|
@@ -337,7 +733,25 @@ static VALUE attr(VALUE self, VALUE name)
|
|
337
733
|
prop = xmlHasProp(node, (xmlChar *)StringValuePtr(name));
|
338
734
|
|
339
735
|
if(! prop) return Qnil;
|
340
|
-
return Nokogiri_wrap_xml_node((xmlNodePtr)prop);
|
736
|
+
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
|
737
|
+
}
|
738
|
+
|
739
|
+
/*
|
740
|
+
* call-seq:
|
741
|
+
* attribute_with_ns(name, namespace)
|
742
|
+
*
|
743
|
+
* Get the attribute node with +name+ and +namespace+
|
744
|
+
*/
|
745
|
+
static VALUE attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
|
746
|
+
{
|
747
|
+
xmlNodePtr node;
|
748
|
+
xmlAttrPtr prop;
|
749
|
+
Data_Get_Struct(self, xmlNode, node);
|
750
|
+
prop = xmlHasNsProp(node, (xmlChar *)StringValuePtr(name),
|
751
|
+
NIL_P(namespace) ? NULL : (xmlChar *)StringValuePtr(namespace));
|
752
|
+
|
753
|
+
if(! prop) return Qnil;
|
754
|
+
return Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop);
|
341
755
|
}
|
342
756
|
|
343
757
|
/*
|
@@ -349,12 +763,12 @@ static VALUE attr(VALUE self, VALUE name)
|
|
349
763
|
static VALUE attribute_nodes(VALUE self)
|
350
764
|
{
|
351
765
|
/* this code in the mode of xmlHasProp() */
|
352
|
-
xmlNodePtr node
|
353
|
-
VALUE attr
|
766
|
+
xmlNodePtr node;
|
767
|
+
VALUE attr;
|
354
768
|
|
355
|
-
attr = rb_ary_new() ;
|
356
769
|
Data_Get_Struct(self, xmlNode, node);
|
357
770
|
|
771
|
+
attr = rb_ary_new();
|
358
772
|
Nokogiri_xml_node_properties(node, attr);
|
359
773
|
|
360
774
|
return attr ;
|
@@ -365,36 +779,78 @@ static VALUE attribute_nodes(VALUE self)
|
|
365
779
|
* call-seq:
|
366
780
|
* namespace()
|
367
781
|
*
|
368
|
-
* returns the namespace
|
782
|
+
* returns the default namespace set on this node (as with an "xmlns="
|
783
|
+
* attribute), as a Namespace object.
|
369
784
|
*/
|
370
785
|
static VALUE namespace(VALUE self)
|
371
786
|
{
|
372
787
|
xmlNodePtr node ;
|
373
788
|
Data_Get_Struct(self, xmlNode, node);
|
374
|
-
|
375
|
-
|
376
|
-
|
789
|
+
|
790
|
+
if (node->ns)
|
791
|
+
return Nokogiri_wrap_xml_namespace(node->doc, node->ns);
|
792
|
+
|
377
793
|
return Qnil ;
|
378
794
|
}
|
379
795
|
|
380
796
|
/*
|
381
797
|
* call-seq:
|
382
|
-
*
|
798
|
+
* namespace_definitions()
|
383
799
|
*
|
384
|
-
* returns a
|
800
|
+
* returns namespaces defined on self element directly, as an array of Namespace objects. Includes both a default namespace (as in"xmlns="), and prefixed namespaces (as in "xmlns:prefix=").
|
385
801
|
*/
|
386
|
-
static VALUE
|
802
|
+
static VALUE namespace_definitions(VALUE self)
|
387
803
|
{
|
388
|
-
|
389
|
-
|
390
|
-
|
804
|
+
/* this code in the mode of xmlHasProp() */
|
805
|
+
xmlNodePtr node ;
|
806
|
+
VALUE list;
|
807
|
+
xmlNsPtr ns;
|
391
808
|
|
392
|
-
|
393
|
-
Data_Get_Struct(self, xmlNode, node);
|
809
|
+
Data_Get_Struct(self, xmlNode, node);
|
394
810
|
|
395
|
-
|
811
|
+
list = rb_ary_new();
|
396
812
|
|
397
|
-
|
813
|
+
ns = node->nsDef;
|
814
|
+
|
815
|
+
if(!ns) return list;
|
816
|
+
|
817
|
+
while(NULL != ns) {
|
818
|
+
rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns));
|
819
|
+
ns = ns->next;
|
820
|
+
}
|
821
|
+
|
822
|
+
return list;
|
823
|
+
}
|
824
|
+
|
825
|
+
/*
|
826
|
+
* call-seq:
|
827
|
+
* namespace_scopes()
|
828
|
+
*
|
829
|
+
* returns namespaces in scope for self -- those defined on self element
|
830
|
+
* directly or any ancestor node -- as an array of Namespace objects. Default
|
831
|
+
* namespaces ("xmlns=" style) for self are included in this array; Default
|
832
|
+
* namespaces for ancestors, however, are not. See also #namespaces
|
833
|
+
*/
|
834
|
+
static VALUE namespace_scopes(VALUE self)
|
835
|
+
{
|
836
|
+
xmlNodePtr node ;
|
837
|
+
VALUE list;
|
838
|
+
xmlNsPtr *ns_list;
|
839
|
+
int j;
|
840
|
+
|
841
|
+
Data_Get_Struct(self, xmlNode, node);
|
842
|
+
|
843
|
+
list = rb_ary_new();
|
844
|
+
ns_list = xmlGetNsList(node->doc, node);
|
845
|
+
|
846
|
+
if(!ns_list) return list;
|
847
|
+
|
848
|
+
for (j = 0 ; ns_list[j] != NULL ; ++j) {
|
849
|
+
rb_ary_push(list, Nokogiri_wrap_xml_namespace(node->doc, ns_list[j]));
|
850
|
+
}
|
851
|
+
|
852
|
+
xmlFree(ns_list);
|
853
|
+
return list;
|
398
854
|
}
|
399
855
|
|
400
856
|
/*
|
@@ -407,7 +863,7 @@ static VALUE node_type(VALUE self)
|
|
407
863
|
{
|
408
864
|
xmlNodePtr node;
|
409
865
|
Data_Get_Struct(self, xmlNode, node);
|
410
|
-
return INT2NUM((
|
866
|
+
return INT2NUM((long)node->type);
|
411
867
|
}
|
412
868
|
|
413
869
|
/*
|
@@ -418,8 +874,17 @@ static VALUE node_type(VALUE self)
|
|
418
874
|
*/
|
419
875
|
static VALUE set_content(VALUE self, VALUE content)
|
420
876
|
{
|
421
|
-
xmlNodePtr node;
|
877
|
+
xmlNodePtr node, child, next ;
|
422
878
|
Data_Get_Struct(self, xmlNode, node);
|
879
|
+
|
880
|
+
child = node->children;
|
881
|
+
while (NULL != child) {
|
882
|
+
next = child->next ;
|
883
|
+
xmlUnlinkNode(child) ;
|
884
|
+
NOKOGIRI_ROOT_NODE(child) ;
|
885
|
+
child = next ;
|
886
|
+
}
|
887
|
+
|
423
888
|
xmlNodeSetContent(node, (xmlChar *)StringValuePtr(content));
|
424
889
|
return content;
|
425
890
|
}
|
@@ -433,26 +898,23 @@ static VALUE set_content(VALUE self, VALUE content)
|
|
433
898
|
static VALUE get_content(VALUE self)
|
434
899
|
{
|
435
900
|
xmlNodePtr node;
|
901
|
+
xmlChar * content;
|
902
|
+
|
436
903
|
Data_Get_Struct(self, xmlNode, node);
|
437
904
|
|
438
|
-
|
905
|
+
content = xmlNodeGetContent(node);
|
439
906
|
if(content) {
|
440
|
-
VALUE rval = NOKOGIRI_STR_NEW2(content
|
907
|
+
VALUE rval = NOKOGIRI_STR_NEW2(content);
|
441
908
|
xmlFree(content);
|
442
909
|
return rval;
|
443
910
|
}
|
444
911
|
return Qnil;
|
445
912
|
}
|
446
913
|
|
447
|
-
/*
|
448
|
-
|
449
|
-
* add_child(node)
|
450
|
-
*
|
451
|
-
* Add +node+ as a child of this node. Returns the new child node.
|
452
|
-
*/
|
453
|
-
static VALUE add_child(VALUE self, VALUE child)
|
914
|
+
/* :nodoc: */
|
915
|
+
static VALUE add_child(VALUE self, VALUE new_child)
|
454
916
|
{
|
455
|
-
return reparent_node_with(
|
917
|
+
return reparent_node_with(self, new_child, xmlAddChild);
|
456
918
|
}
|
457
919
|
|
458
920
|
/*
|
@@ -469,7 +931,7 @@ static VALUE get_parent(VALUE self)
|
|
469
931
|
parent = node->parent;
|
470
932
|
if(!parent) return Qnil;
|
471
933
|
|
472
|
-
return Nokogiri_wrap_xml_node(parent) ;
|
934
|
+
return Nokogiri_wrap_xml_node(Qnil, parent) ;
|
473
935
|
}
|
474
936
|
|
475
937
|
/*
|
@@ -497,7 +959,7 @@ static VALUE get_name(VALUE self)
|
|
497
959
|
xmlNodePtr node;
|
498
960
|
Data_Get_Struct(self, xmlNode, node);
|
499
961
|
if(node->name)
|
500
|
-
return NOKOGIRI_STR_NEW2(node->name
|
962
|
+
return NOKOGIRI_STR_NEW2(node->name);
|
501
963
|
return Qnil;
|
502
964
|
}
|
503
965
|
|
@@ -511,34 +973,26 @@ static VALUE path(VALUE self)
|
|
511
973
|
{
|
512
974
|
xmlNodePtr node;
|
513
975
|
xmlChar *path ;
|
976
|
+
VALUE rval;
|
977
|
+
|
514
978
|
Data_Get_Struct(self, xmlNode, node);
|
515
|
-
|
979
|
+
|
516
980
|
path = xmlGetNodePath(node);
|
517
|
-
|
981
|
+
rval = NOKOGIRI_STR_NEW2(path);
|
518
982
|
xmlFree(path);
|
519
983
|
return rval ;
|
520
984
|
}
|
521
985
|
|
522
|
-
/*
|
523
|
-
|
524
|
-
* add_next_sibling(node)
|
525
|
-
*
|
526
|
-
* Insert +node+ after this node (as a sibling).
|
527
|
-
*/
|
528
|
-
static VALUE add_next_sibling(VALUE self, VALUE rb_node)
|
986
|
+
/* :nodoc: */
|
987
|
+
static VALUE add_next_sibling(VALUE self, VALUE new_sibling)
|
529
988
|
{
|
530
|
-
return reparent_node_with(
|
989
|
+
return reparent_node_with(self, new_sibling, xmlAddNextSibling) ;
|
531
990
|
}
|
532
991
|
|
533
|
-
/*
|
534
|
-
|
535
|
-
* add_previous_sibling(node)
|
536
|
-
*
|
537
|
-
* Insert +node+ before this node (as a sibling).
|
538
|
-
*/
|
539
|
-
static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
|
992
|
+
/* :nodoc: */
|
993
|
+
static VALUE add_previous_sibling(VALUE self, VALUE new_sibling)
|
540
994
|
{
|
541
|
-
return reparent_node_with(
|
995
|
+
return reparent_node_with(self, new_sibling, xmlAddPrevSibling) ;
|
542
996
|
}
|
543
997
|
|
544
998
|
/*
|
@@ -547,22 +1001,37 @@ static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
|
|
547
1001
|
*
|
548
1002
|
* Write this Node to +io+ with +encoding+ and +options+
|
549
1003
|
*/
|
550
|
-
static VALUE native_write_to(
|
551
|
-
|
1004
|
+
static VALUE native_write_to(
|
1005
|
+
VALUE self,
|
1006
|
+
VALUE io,
|
1007
|
+
VALUE encoding,
|
1008
|
+
VALUE indent_string,
|
1009
|
+
VALUE options
|
1010
|
+
) {
|
552
1011
|
xmlNodePtr node;
|
1012
|
+
const char * before_indent;
|
1013
|
+
xmlSaveCtxtPtr savectx;
|
553
1014
|
|
554
1015
|
Data_Get_Struct(self, xmlNode, node);
|
555
1016
|
|
556
|
-
|
1017
|
+
xmlIndentTreeOutput = 1;
|
1018
|
+
|
1019
|
+
before_indent = xmlTreeIndentString;
|
1020
|
+
|
1021
|
+
xmlTreeIndentString = StringValuePtr(indent_string);
|
1022
|
+
|
1023
|
+
savectx = xmlSaveToIO(
|
557
1024
|
(xmlOutputWriteCallback)io_write_callback,
|
558
1025
|
(xmlOutputCloseCallback)io_close_callback,
|
559
1026
|
(void *)io,
|
560
1027
|
RTEST(encoding) ? StringValuePtr(encoding) : NULL,
|
561
|
-
NUM2INT(options)
|
1028
|
+
(int)NUM2INT(options)
|
562
1029
|
);
|
563
1030
|
|
564
1031
|
xmlSaveTree(savectx, node);
|
565
1032
|
xmlSaveClose(savectx);
|
1033
|
+
|
1034
|
+
xmlTreeIndentString = before_indent;
|
566
1035
|
return io;
|
567
1036
|
}
|
568
1037
|
|
@@ -577,56 +1046,80 @@ static VALUE line(VALUE self)
|
|
577
1046
|
xmlNodePtr node;
|
578
1047
|
Data_Get_Struct(self, xmlNode, node);
|
579
1048
|
|
580
|
-
return INT2NUM(node
|
1049
|
+
return INT2NUM(xmlGetLineNo(node));
|
581
1050
|
}
|
582
1051
|
|
583
1052
|
/*
|
584
1053
|
* call-seq:
|
585
|
-
*
|
1054
|
+
* add_namespace_definition(prefix, href)
|
586
1055
|
*
|
587
|
-
*
|
1056
|
+
* Adds a namespace definition with +prefix+ using +href+ value. The result is
|
1057
|
+
* as if parsed XML for this node had included an attribute
|
1058
|
+
* 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
|
1059
|
+
* added by passing 'nil' for prefix. Namespaces added this way will not
|
1060
|
+
* show up in #attributes, but they will be included as an xmlns attribute
|
1061
|
+
* when the node is serialized to XML.
|
588
1062
|
*/
|
589
|
-
static VALUE
|
1063
|
+
static VALUE add_namespace_definition(VALUE self, VALUE prefix, VALUE href)
|
590
1064
|
{
|
591
|
-
xmlNodePtr node;
|
1065
|
+
xmlNodePtr node, namespacee;
|
1066
|
+
xmlNsPtr ns;
|
1067
|
+
|
592
1068
|
Data_Get_Struct(self, xmlNode, node);
|
1069
|
+
namespacee = node ;
|
593
1070
|
|
594
|
-
|
1071
|
+
ns = xmlSearchNs(
|
1072
|
+
node->doc,
|
595
1073
|
node,
|
596
|
-
(const xmlChar *)StringValuePtr(
|
597
|
-
(const xmlChar *)StringValuePtr(prefix)
|
1074
|
+
(const xmlChar *)(NIL_P(prefix) ? NULL : StringValuePtr(prefix))
|
598
1075
|
);
|
599
1076
|
|
600
|
-
if(
|
1077
|
+
if(!ns) {
|
1078
|
+
if (node->type != XML_ELEMENT_NODE) {
|
1079
|
+
namespacee = node->parent;
|
1080
|
+
}
|
1081
|
+
ns = xmlNewNs(
|
1082
|
+
namespacee,
|
1083
|
+
(const xmlChar *)StringValuePtr(href),
|
1084
|
+
(const xmlChar *)(NIL_P(prefix) ? NULL : StringValuePtr(prefix))
|
1085
|
+
);
|
1086
|
+
}
|
601
1087
|
|
602
|
-
|
603
|
-
xmlNewNsProp(
|
604
|
-
node,
|
605
|
-
ns,
|
606
|
-
(const xmlChar *)StringValuePtr(href),
|
607
|
-
(const xmlChar *)StringValuePtr(prefix)
|
608
|
-
);
|
609
|
-
*/
|
1088
|
+
if (!ns) return Qnil ;
|
610
1089
|
|
611
|
-
|
1090
|
+
if(NIL_P(prefix) || node != namespacee) xmlSetNs(node, ns);
|
1091
|
+
|
1092
|
+
return Nokogiri_wrap_xml_namespace(node->doc, ns);
|
612
1093
|
}
|
613
1094
|
|
614
1095
|
/*
|
615
1096
|
* call-seq:
|
616
|
-
* new(name)
|
1097
|
+
* new(name, document)
|
617
1098
|
*
|
618
|
-
* Create a new node with +name+
|
1099
|
+
* Create a new node with +name+ sharing GC lifecycle with +document+
|
619
1100
|
*/
|
620
|
-
static VALUE new(
|
1101
|
+
static VALUE new(int argc, VALUE *argv, VALUE klass)
|
621
1102
|
{
|
622
1103
|
xmlDocPtr doc;
|
1104
|
+
xmlNodePtr node;
|
1105
|
+
VALUE name;
|
1106
|
+
VALUE document;
|
1107
|
+
VALUE rest;
|
1108
|
+
VALUE rb_node;
|
1109
|
+
|
1110
|
+
rb_scan_args(argc, argv, "2*", &name, &document, &rest);
|
623
1111
|
|
624
1112
|
Data_Get_Struct(document, xmlDoc, doc);
|
625
1113
|
|
626
|
-
|
1114
|
+
node = xmlNewNode(NULL, (xmlChar *)StringValuePtr(name));
|
627
1115
|
node->doc = doc->doc;
|
1116
|
+
NOKOGIRI_ROOT_NODE(node);
|
628
1117
|
|
629
|
-
|
1118
|
+
rb_node = Nokogiri_wrap_xml_node(
|
1119
|
+
klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
|
1120
|
+
node
|
1121
|
+
);
|
1122
|
+
rb_obj_call_init(rb_node, argc, argv);
|
630
1123
|
|
631
1124
|
if(rb_block_given_p()) rb_yield(rb_node);
|
632
1125
|
|
@@ -643,91 +1136,178 @@ static VALUE dump_html(VALUE self)
|
|
643
1136
|
{
|
644
1137
|
xmlBufferPtr buf ;
|
645
1138
|
xmlNodePtr node ;
|
646
|
-
|
1139
|
+
VALUE html;
|
647
1140
|
|
648
|
-
|
649
|
-
return rb_funcall(self, rb_intern("to_xml"), 0);
|
1141
|
+
Data_Get_Struct(self, xmlNode, node);
|
650
1142
|
|
651
1143
|
buf = xmlBufferCreate() ;
|
652
1144
|
htmlNodeDump(buf, node->doc, node);
|
653
|
-
|
1145
|
+
html = NOKOGIRI_STR_NEW2(buf->content);
|
654
1146
|
xmlBufferFree(buf);
|
655
1147
|
return html ;
|
656
1148
|
}
|
657
1149
|
|
658
|
-
|
1150
|
+
/*
|
1151
|
+
* call-seq:
|
1152
|
+
* compare(other)
|
1153
|
+
*
|
1154
|
+
* Compare this Node to +other+ with respect to their Document
|
1155
|
+
*/
|
1156
|
+
static VALUE compare(VALUE self, VALUE _other)
|
659
1157
|
{
|
660
|
-
|
1158
|
+
xmlNodePtr node, other;
|
1159
|
+
Data_Get_Struct(self, xmlNode, node);
|
1160
|
+
Data_Get_Struct(_other, xmlNode, other);
|
1161
|
+
|
1162
|
+
return INT2NUM((long)xmlXPathCmpNodes(other, node));
|
1163
|
+
}
|
1164
|
+
|
1165
|
+
|
1166
|
+
/* TODO: DOCUMENT ME */
|
1167
|
+
static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
|
1168
|
+
{
|
1169
|
+
xmlNodePtr node;
|
1170
|
+
xmlNodePtr list;
|
1171
|
+
xmlNodePtr child_iter;
|
1172
|
+
xmlNodeSetPtr set;
|
1173
|
+
xmlParserErrors error;
|
1174
|
+
VALUE doc, err;
|
1175
|
+
|
1176
|
+
Data_Get_Struct(self, xmlNode, node);
|
661
1177
|
|
662
|
-
|
1178
|
+
doc = DOC_RUBY_OBJECT(node->doc);
|
1179
|
+
err = rb_iv_get(doc, "@errors");
|
1180
|
+
|
1181
|
+
xmlSetStructuredErrorFunc((void *)err, Nokogiri_error_array_pusher);
|
1182
|
+
|
1183
|
+
/* Twiddle global variable because of a bug in libxml2.
|
1184
|
+
* http://git.gnome.org/browse/libxml2/commit/?id=e20fb5a72c83cbfc8e4a8aa3943c6be8febadab7
|
1185
|
+
*/
|
1186
|
+
#ifndef HTML_PARSE_NOIMPLIED
|
1187
|
+
htmlHandleOmittedElem(0);
|
1188
|
+
#endif
|
1189
|
+
|
1190
|
+
error = xmlParseInNodeContext(
|
1191
|
+
node,
|
1192
|
+
StringValuePtr(_str),
|
1193
|
+
(int)RSTRING_LEN(_str),
|
1194
|
+
(int)NUM2INT(_options),
|
1195
|
+
&list);
|
1196
|
+
|
1197
|
+
/* make sure parent/child pointers are coherent so an unlink will work properly (#331) */
|
1198
|
+
child_iter = node->doc->children ;
|
1199
|
+
while (child_iter) {
|
1200
|
+
if (child_iter->parent != (xmlNodePtr)node->doc)
|
1201
|
+
child_iter->parent = (xmlNodePtr)node->doc ;
|
1202
|
+
child_iter = child_iter->next ;
|
1203
|
+
}
|
1204
|
+
|
1205
|
+
#ifndef HTML_PARSE_NOIMPLIED
|
1206
|
+
htmlHandleOmittedElem(1);
|
1207
|
+
#endif
|
1208
|
+
|
1209
|
+
xmlSetStructuredErrorFunc(NULL, NULL);
|
1210
|
+
|
1211
|
+
/* FIXME: This probably needs to handle more constants... */
|
1212
|
+
switch(error) {
|
1213
|
+
case XML_ERR_OK:
|
1214
|
+
break;
|
1215
|
+
|
1216
|
+
case XML_ERR_INTERNAL_ERROR:
|
1217
|
+
case XML_ERR_NO_MEMORY:
|
1218
|
+
rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
|
1219
|
+
break;
|
1220
|
+
|
1221
|
+
default:
|
1222
|
+
break;
|
1223
|
+
}
|
1224
|
+
|
1225
|
+
set = xmlXPathNodeSetCreate(NULL);
|
1226
|
+
|
1227
|
+
while(list) {
|
1228
|
+
xmlXPathNodeSetAddUnique(set, list);
|
1229
|
+
list = list->next;
|
1230
|
+
}
|
1231
|
+
|
1232
|
+
return Nokogiri_wrap_xml_node_set(set, doc);
|
1233
|
+
}
|
1234
|
+
|
1235
|
+
|
1236
|
+
VALUE Nokogiri_wrap_xml_node(VALUE klass, xmlNodePtr node)
|
1237
|
+
{
|
663
1238
|
VALUE document = Qnil ;
|
664
1239
|
VALUE node_cache = Qnil ;
|
665
1240
|
VALUE rb_node = Qnil ;
|
1241
|
+
int node_has_a_document = 0 ;
|
1242
|
+
void (*mark_method)(xmlNodePtr) = NULL ;
|
1243
|
+
|
1244
|
+
assert(node);
|
666
1245
|
|
667
1246
|
if(node->type == XML_DOCUMENT_NODE || node->type == XML_HTML_DOCUMENT_NODE)
|
668
1247
|
return DOC_RUBY_OBJECT(node->doc);
|
669
1248
|
|
670
1249
|
if(NULL != node->_private) return (VALUE)node->_private;
|
671
1250
|
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
1251
|
+
if(!RTEST(klass)) {
|
1252
|
+
switch(node->type)
|
1253
|
+
{
|
676
1254
|
case XML_ELEMENT_NODE:
|
677
1255
|
klass = cNokogiriXmlElement;
|
678
|
-
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
679
1256
|
break;
|
680
1257
|
case XML_TEXT_NODE:
|
681
1258
|
klass = cNokogiriXmlText;
|
682
|
-
|
1259
|
+
break;
|
1260
|
+
case XML_ATTRIBUTE_NODE:
|
1261
|
+
klass = cNokogiriXmlAttr;
|
683
1262
|
break;
|
684
1263
|
case XML_ENTITY_REF_NODE:
|
685
1264
|
klass = cNokogiriXmlEntityReference;
|
686
|
-
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
687
1265
|
break;
|
688
1266
|
case XML_COMMENT_NODE:
|
689
1267
|
klass = cNokogiriXmlComment;
|
690
|
-
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
691
1268
|
break;
|
692
1269
|
case XML_DOCUMENT_FRAG_NODE:
|
693
1270
|
klass = cNokogiriXmlDocumentFragment;
|
694
|
-
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
695
1271
|
break;
|
696
1272
|
case XML_PI_NODE:
|
697
1273
|
klass = cNokogiriXmlProcessingInstruction;
|
698
|
-
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
699
|
-
break;
|
700
|
-
case XML_ATTRIBUTE_NODE:
|
701
|
-
klass = cNokogiriXmlAttr;
|
702
|
-
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
703
1274
|
break;
|
704
1275
|
case XML_ENTITY_DECL:
|
705
|
-
klass =
|
706
|
-
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
1276
|
+
klass = cNokogiriXmlEntityDecl;
|
707
1277
|
break;
|
708
1278
|
case XML_CDATA_SECTION_NODE:
|
709
1279
|
klass = cNokogiriXmlCData;
|
710
|
-
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
711
1280
|
break;
|
712
1281
|
case XML_DTD_NODE:
|
713
|
-
klass =
|
714
|
-
|
1282
|
+
klass = cNokogiriXmlDtd;
|
1283
|
+
break;
|
1284
|
+
case XML_ATTRIBUTE_DECL:
|
1285
|
+
klass = cNokogiriXmlAttributeDecl;
|
1286
|
+
break;
|
1287
|
+
case XML_ELEMENT_DECL:
|
1288
|
+
klass = cNokogiriXmlElementDecl;
|
715
1289
|
break;
|
716
1290
|
default:
|
717
|
-
|
1291
|
+
klass = cNokogiriXmlNode;
|
1292
|
+
}
|
718
1293
|
}
|
719
1294
|
|
1295
|
+
/* It's OK if the node doesn't have a fully-realized document (as in XML::Reader). */
|
1296
|
+
/* see https://github.com/tenderlove/nokogiri/issues/95 */
|
1297
|
+
/* and https://github.com/tenderlove/nokogiri/issues/439 */
|
1298
|
+
node_has_a_document = (DOC_RUBY_OBJECT_TEST(node->doc) && DOC_RUBY_OBJECT(node->doc)) ? 1 : 0 ;
|
1299
|
+
mark_method = node_has_a_document ? mark : NULL ;
|
1300
|
+
|
1301
|
+
rb_node = Data_Wrap_Struct(klass, mark_method, debug_node_dealloc, node) ;
|
720
1302
|
node->_private = (void *)rb_node;
|
721
1303
|
|
722
|
-
if (
|
1304
|
+
if (node_has_a_document) {
|
723
1305
|
document = DOC_RUBY_OBJECT(node->doc);
|
724
|
-
node_cache =
|
1306
|
+
node_cache = DOC_NODE_CACHE(node->doc);
|
1307
|
+
rb_ary_push(node_cache, rb_node);
|
1308
|
+
rb_funcall(document, decorate, 1, rb_node);
|
725
1309
|
}
|
726
1310
|
|
727
|
-
if (node_cache != Qnil) rb_hash_aset(node_cache, index, rb_node);
|
728
|
-
rb_iv_set(rb_node, "@document", document);
|
729
|
-
rb_funcall(rb_node, rb_intern("decorate!"), 0);
|
730
|
-
|
731
1311
|
return rb_node ;
|
732
1312
|
}
|
733
1313
|
|
@@ -737,52 +1317,11 @@ void Nokogiri_xml_node_properties(xmlNodePtr node, VALUE attr_list)
|
|
737
1317
|
xmlAttrPtr prop;
|
738
1318
|
prop = node->properties ;
|
739
1319
|
while (prop != NULL) {
|
740
|
-
rb_ary_push(attr_list, Nokogiri_wrap_xml_node((xmlNodePtr)prop));
|
1320
|
+
rb_ary_push(attr_list, Nokogiri_wrap_xml_node(Qnil, (xmlNodePtr)prop));
|
741
1321
|
prop = prop->next ;
|
742
1322
|
}
|
743
1323
|
}
|
744
1324
|
|
745
|
-
|
746
|
-
#define XMLNS_PREFIX "xmlns"
|
747
|
-
#define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */
|
748
|
-
#define XMLNS_BUFFER_LEN 128
|
749
|
-
void Nokogiri_xml_node_namespaces(xmlNodePtr node, VALUE attr_hash)
|
750
|
-
{
|
751
|
-
xmlNsPtr ns;
|
752
|
-
static char buffer[XMLNS_BUFFER_LEN] ;
|
753
|
-
char *key ;
|
754
|
-
size_t keylen ;
|
755
|
-
|
756
|
-
if (node->type != XML_ELEMENT_NODE) return ;
|
757
|
-
|
758
|
-
ns = node->nsDef;
|
759
|
-
while (ns != NULL) {
|
760
|
-
|
761
|
-
keylen = XMLNS_PREFIX_LEN + (ns->prefix ? (strlen((const char*)ns->prefix) + 1) : 0) ;
|
762
|
-
if (keylen > XMLNS_BUFFER_LEN) {
|
763
|
-
key = (char*)malloc(keylen) ;
|
764
|
-
} else {
|
765
|
-
key = buffer ;
|
766
|
-
}
|
767
|
-
|
768
|
-
if (ns->prefix) {
|
769
|
-
sprintf(key, "%s:%s", XMLNS_PREFIX, ns->prefix);
|
770
|
-
} else {
|
771
|
-
sprintf(key, "%s", XMLNS_PREFIX);
|
772
|
-
}
|
773
|
-
|
774
|
-
rb_hash_aset(attr_hash,
|
775
|
-
NOKOGIRI_STR_NEW2(key, node->doc->encoding),
|
776
|
-
NOKOGIRI_STR_NEW2(ns->href, node->doc->encoding)
|
777
|
-
);
|
778
|
-
if (key != buffer) {
|
779
|
-
free(key);
|
780
|
-
}
|
781
|
-
ns = ns->next ;
|
782
|
-
}
|
783
|
-
}
|
784
|
-
|
785
|
-
|
786
1325
|
VALUE cNokogiriXmlNode ;
|
787
1326
|
VALUE cNokogiriXmlElement ;
|
788
1327
|
|
@@ -796,39 +1335,57 @@ void init_xml_node()
|
|
796
1335
|
|
797
1336
|
cNokogiriXmlElement = rb_define_class_under(xml, "Element", klass);
|
798
1337
|
|
799
|
-
rb_define_singleton_method(klass, "new", new,
|
1338
|
+
rb_define_singleton_method(klass, "new", new, -1);
|
800
1339
|
|
801
|
-
rb_define_method(klass, "
|
1340
|
+
rb_define_method(klass, "add_namespace_definition", add_namespace_definition, 2);
|
802
1341
|
rb_define_method(klass, "node_name", get_name, 0);
|
1342
|
+
rb_define_method(klass, "document", document, 0);
|
803
1343
|
rb_define_method(klass, "node_name=", set_name, 1);
|
804
|
-
rb_define_method(klass, "add_child", add_child, 1);
|
805
1344
|
rb_define_method(klass, "parent", get_parent, 0);
|
806
1345
|
rb_define_method(klass, "child", child, 0);
|
1346
|
+
rb_define_method(klass, "first_element_child", first_element_child, 0);
|
1347
|
+
rb_define_method(klass, "last_element_child", last_element_child, 0);
|
807
1348
|
rb_define_method(klass, "children", children, 0);
|
1349
|
+
rb_define_method(klass, "element_children", element_children, 0);
|
808
1350
|
rb_define_method(klass, "next_sibling", next_sibling, 0);
|
809
1351
|
rb_define_method(klass, "previous_sibling", previous_sibling, 0);
|
1352
|
+
rb_define_method(klass, "next_element", next_element, 0);
|
1353
|
+
rb_define_method(klass, "previous_element", previous_element, 0);
|
810
1354
|
rb_define_method(klass, "node_type", node_type, 0);
|
811
1355
|
rb_define_method(klass, "content", get_content, 0);
|
812
1356
|
rb_define_method(klass, "path", path, 0);
|
813
1357
|
rb_define_method(klass, "key?", key_eh, 1);
|
1358
|
+
rb_define_method(klass, "namespaced_key?", namespaced_key_eh, 2);
|
814
1359
|
rb_define_method(klass, "blank?", blank_eh, 0);
|
815
1360
|
rb_define_method(klass, "[]=", set, 2);
|
816
1361
|
rb_define_method(klass, "attribute_nodes", attribute_nodes, 0);
|
817
1362
|
rb_define_method(klass, "attribute", attr, 1);
|
1363
|
+
rb_define_method(klass, "attribute_with_ns", attribute_with_ns, 2);
|
818
1364
|
rb_define_method(klass, "namespace", namespace, 0);
|
819
|
-
rb_define_method(klass, "
|
820
|
-
rb_define_method(klass, "
|
821
|
-
rb_define_method(klass, "add_next_sibling", add_next_sibling, 1);
|
1365
|
+
rb_define_method(klass, "namespace_definitions", namespace_definitions, 0);
|
1366
|
+
rb_define_method(klass, "namespace_scopes", namespace_scopes, 0);
|
822
1367
|
rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
|
823
1368
|
rb_define_method(klass, "dup", duplicate_node, -1);
|
824
1369
|
rb_define_method(klass, "unlink", unlink_node, 0);
|
825
1370
|
rb_define_method(klass, "internal_subset", internal_subset, 0);
|
1371
|
+
rb_define_method(klass, "external_subset", external_subset, 0);
|
1372
|
+
rb_define_method(klass, "create_internal_subset", create_internal_subset, 3);
|
1373
|
+
rb_define_method(klass, "create_external_subset", create_external_subset, 3);
|
826
1374
|
rb_define_method(klass, "pointer_id", pointer_id, 0);
|
827
1375
|
rb_define_method(klass, "line", line, 0);
|
828
1376
|
|
1377
|
+
rb_define_private_method(klass, "in_context", in_context, 2);
|
1378
|
+
rb_define_private_method(klass, "add_child_node", add_child, 1);
|
1379
|
+
rb_define_private_method(klass, "add_previous_sibling_node", add_previous_sibling, 1);
|
1380
|
+
rb_define_private_method(klass, "add_next_sibling_node", add_next_sibling, 1);
|
1381
|
+
rb_define_private_method(klass, "replace_node", replace, 1);
|
829
1382
|
rb_define_private_method(klass, "dump_html", dump_html, 0);
|
830
|
-
rb_define_private_method(klass, "native_write_to", native_write_to,
|
831
|
-
rb_define_private_method(klass, "replace_with_node", replace, 1);
|
1383
|
+
rb_define_private_method(klass, "native_write_to", native_write_to, 4);
|
832
1384
|
rb_define_private_method(klass, "native_content=", set_content, 1);
|
833
1385
|
rb_define_private_method(klass, "get", get, 1);
|
1386
|
+
rb_define_private_method(klass, "set_namespace", set_namespace, 1);
|
1387
|
+
rb_define_private_method(klass, "compare", compare, 1);
|
1388
|
+
|
1389
|
+
decorate = rb_intern("decorate");
|
1390
|
+
decorate_bang = rb_intern("decorate!");
|
834
1391
|
}
|