nokogiri 1.1.1-java
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/History.ja.txt +99 -0
- data/History.txt +99 -0
- data/Manifest.txt +141 -0
- data/README.ja.txt +100 -0
- data/README.txt +109 -0
- data/Rakefile +354 -0
- data/ext/nokogiri/extconf.rb +93 -0
- data/ext/nokogiri/html_document.c +86 -0
- data/ext/nokogiri/html_document.h +10 -0
- data/ext/nokogiri/html_sax_parser.c +36 -0
- data/ext/nokogiri/html_sax_parser.h +11 -0
- data/ext/nokogiri/native.c +41 -0
- data/ext/nokogiri/native.h +50 -0
- data/ext/nokogiri/xml_cdata.c +44 -0
- data/ext/nokogiri/xml_cdata.h +9 -0
- data/ext/nokogiri/xml_comment.c +42 -0
- data/ext/nokogiri/xml_comment.h +9 -0
- data/ext/nokogiri/xml_document.c +206 -0
- data/ext/nokogiri/xml_document.h +10 -0
- data/ext/nokogiri/xml_dtd.c +121 -0
- data/ext/nokogiri/xml_dtd.h +8 -0
- data/ext/nokogiri/xml_io.c +17 -0
- data/ext/nokogiri/xml_io.h +9 -0
- data/ext/nokogiri/xml_node.c +727 -0
- data/ext/nokogiri/xml_node.h +13 -0
- data/ext/nokogiri/xml_node_set.c +118 -0
- data/ext/nokogiri/xml_node_set.h +9 -0
- data/ext/nokogiri/xml_reader.c +465 -0
- data/ext/nokogiri/xml_reader.h +10 -0
- data/ext/nokogiri/xml_sax_parser.c +201 -0
- data/ext/nokogiri/xml_sax_parser.h +10 -0
- data/ext/nokogiri/xml_syntax_error.c +199 -0
- data/ext/nokogiri/xml_syntax_error.h +11 -0
- data/ext/nokogiri/xml_text.c +40 -0
- data/ext/nokogiri/xml_text.h +9 -0
- data/ext/nokogiri/xml_xpath.c +53 -0
- data/ext/nokogiri/xml_xpath.h +11 -0
- data/ext/nokogiri/xml_xpath_context.c +214 -0
- data/ext/nokogiri/xml_xpath_context.h +9 -0
- data/ext/nokogiri/xslt_stylesheet.c +123 -0
- data/ext/nokogiri/xslt_stylesheet.h +9 -0
- data/lib/action-nokogiri.rb +30 -0
- data/lib/nokogiri.rb +72 -0
- data/lib/nokogiri/css.rb +25 -0
- data/lib/nokogiri/css/generated_parser.rb +721 -0
- data/lib/nokogiri/css/generated_tokenizer.rb +159 -0
- data/lib/nokogiri/css/node.rb +97 -0
- data/lib/nokogiri/css/parser.rb +64 -0
- data/lib/nokogiri/css/parser.y +216 -0
- data/lib/nokogiri/css/syntax_error.rb +6 -0
- data/lib/nokogiri/css/tokenizer.rb +9 -0
- data/lib/nokogiri/css/tokenizer.rex +63 -0
- data/lib/nokogiri/css/xpath_visitor.rb +168 -0
- data/lib/nokogiri/decorators.rb +2 -0
- data/lib/nokogiri/decorators/hpricot.rb +3 -0
- data/lib/nokogiri/decorators/hpricot/node.rb +56 -0
- data/lib/nokogiri/decorators/hpricot/node_set.rb +54 -0
- data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +28 -0
- data/lib/nokogiri/decorators/slop.rb +31 -0
- data/lib/nokogiri/hpricot.rb +51 -0
- data/lib/nokogiri/html.rb +105 -0
- data/lib/nokogiri/html/builder.rb +9 -0
- data/lib/nokogiri/html/document.rb +9 -0
- data/lib/nokogiri/html/sax/parser.rb +21 -0
- data/lib/nokogiri/version.rb +3 -0
- data/lib/nokogiri/xml.rb +83 -0
- data/lib/nokogiri/xml/after_handler.rb +18 -0
- data/lib/nokogiri/xml/attr.rb +10 -0
- data/lib/nokogiri/xml/before_handler.rb +33 -0
- data/lib/nokogiri/xml/builder.rb +84 -0
- data/lib/nokogiri/xml/cdata.rb +9 -0
- data/lib/nokogiri/xml/comment.rb +6 -0
- data/lib/nokogiri/xml/document.rb +55 -0
- data/lib/nokogiri/xml/dtd.rb +6 -0
- data/lib/nokogiri/xml/element.rb +6 -0
- data/lib/nokogiri/xml/entity_declaration.rb +9 -0
- data/lib/nokogiri/xml/node.rb +333 -0
- data/lib/nokogiri/xml/node_set.rb +197 -0
- data/lib/nokogiri/xml/notation.rb +6 -0
- data/lib/nokogiri/xml/reader.rb +20 -0
- data/lib/nokogiri/xml/sax.rb +9 -0
- data/lib/nokogiri/xml/sax/document.rb +59 -0
- data/lib/nokogiri/xml/sax/parser.rb +37 -0
- data/lib/nokogiri/xml/syntax_error.rb +21 -0
- data/lib/nokogiri/xml/text.rb +6 -0
- data/lib/nokogiri/xml/xpath.rb +10 -0
- data/lib/nokogiri/xml/xpath/syntax_error.rb +8 -0
- data/lib/nokogiri/xml/xpath_context.rb +14 -0
- data/lib/nokogiri/xslt.rb +28 -0
- data/lib/nokogiri/xslt/stylesheet.rb +6 -0
- data/test/css/test_nthiness.rb +159 -0
- data/test/css/test_parser.rb +237 -0
- data/test/css/test_tokenizer.rb +162 -0
- data/test/css/test_xpath_visitor.rb +64 -0
- data/test/files/dont_hurt_em_why.xml +422 -0
- data/test/files/exslt.xml +8 -0
- data/test/files/exslt.xslt +35 -0
- data/test/files/staff.xml +59 -0
- data/test/files/staff.xslt +32 -0
- data/test/files/tlm.html +850 -0
- data/test/helper.rb +78 -0
- data/test/hpricot/files/basic.xhtml +17 -0
- data/test/hpricot/files/boingboing.html +2266 -0
- data/test/hpricot/files/cy0.html +3653 -0
- data/test/hpricot/files/immob.html +400 -0
- data/test/hpricot/files/pace_application.html +1320 -0
- data/test/hpricot/files/tenderlove.html +16 -0
- data/test/hpricot/files/uswebgen.html +220 -0
- data/test/hpricot/files/utf8.html +1054 -0
- data/test/hpricot/files/week9.html +1723 -0
- data/test/hpricot/files/why.xml +19 -0
- data/test/hpricot/load_files.rb +11 -0
- data/test/hpricot/test_alter.rb +67 -0
- data/test/hpricot/test_builder.rb +27 -0
- data/test/hpricot/test_parser.rb +426 -0
- data/test/hpricot/test_paths.rb +15 -0
- data/test/hpricot/test_preserved.rb +77 -0
- data/test/hpricot/test_xml.rb +30 -0
- data/test/html/sax/test_parser.rb +27 -0
- data/test/html/test_builder.rb +89 -0
- data/test/html/test_document.rb +150 -0
- data/test/html/test_node.rb +21 -0
- data/test/test_convert_xpath.rb +185 -0
- data/test/test_css_cache.rb +57 -0
- data/test/test_gc.rb +15 -0
- data/test/test_memory_leak.rb +38 -0
- data/test/test_nokogiri.rb +97 -0
- data/test/test_reader.rb +222 -0
- data/test/test_xslt_transforms.rb +93 -0
- data/test/xml/sax/test_parser.rb +95 -0
- data/test/xml/test_attr.rb +15 -0
- data/test/xml/test_builder.rb +16 -0
- data/test/xml/test_cdata.rb +18 -0
- data/test/xml/test_comment.rb +16 -0
- data/test/xml/test_document.rb +195 -0
- data/test/xml/test_dtd.rb +43 -0
- data/test/xml/test_node.rb +394 -0
- data/test/xml/test_node_set.rb +143 -0
- data/test/xml/test_text.rb +13 -0
- data/test/xml/test_xpath.rb +105 -0
- data/vendor/hoe.rb +1020 -0
- metadata +233 -0
@@ -0,0 +1,121 @@
|
|
1
|
+
#include <xml_dtd.h>
|
2
|
+
|
3
|
+
static void notation_copier(void *payload, void *data, xmlChar *name)
|
4
|
+
{
|
5
|
+
VALUE hash = (VALUE)data;
|
6
|
+
VALUE klass = rb_const_get(mNokogiriXml, rb_intern("Notation"));
|
7
|
+
|
8
|
+
xmlNotationPtr c_notation = (xmlNotationPtr)payload;
|
9
|
+
|
10
|
+
VALUE notation = rb_funcall(klass, rb_intern("new"), 3,
|
11
|
+
c_notation->name ? rb_str_new2((const char *)c_notation->name) : Qnil,
|
12
|
+
c_notation->PublicID ? rb_str_new2((const char *)c_notation->PublicID) : Qnil,
|
13
|
+
c_notation->SystemID ? rb_str_new2((const char *)c_notation->SystemID) : Qnil);
|
14
|
+
|
15
|
+
rb_hash_aset(hash, rb_str_new2((const char *)name), notation);
|
16
|
+
}
|
17
|
+
|
18
|
+
static void element_copier(void *payload, void *data, xmlChar *name)
|
19
|
+
{
|
20
|
+
VALUE hash = (VALUE)data;
|
21
|
+
|
22
|
+
VALUE element = Nokogiri_wrap_xml_node((xmlNodePtr)payload);
|
23
|
+
|
24
|
+
rb_hash_aset(hash, rb_str_new2((const char *)name), element);
|
25
|
+
}
|
26
|
+
|
27
|
+
/*
|
28
|
+
* call-seq:
|
29
|
+
* entities
|
30
|
+
*
|
31
|
+
* Get a hash of the elements for this DTD.
|
32
|
+
*/
|
33
|
+
static VALUE entities(VALUE self)
|
34
|
+
{
|
35
|
+
xmlDtdPtr dtd;
|
36
|
+
Data_Get_Struct(self, xmlDtd, dtd);
|
37
|
+
|
38
|
+
if(!dtd->entities) return Qnil;
|
39
|
+
|
40
|
+
VALUE hash = rb_hash_new();
|
41
|
+
|
42
|
+
xmlHashScan((xmlHashTablePtr)dtd->entities, element_copier, (void *)hash);
|
43
|
+
|
44
|
+
return hash;
|
45
|
+
}
|
46
|
+
|
47
|
+
/*
|
48
|
+
* call-seq:
|
49
|
+
* attributes
|
50
|
+
*
|
51
|
+
* Get a hash of the attributes for this DTD.
|
52
|
+
*/
|
53
|
+
static VALUE attributes(VALUE self)
|
54
|
+
{
|
55
|
+
xmlDtdPtr dtd;
|
56
|
+
Data_Get_Struct(self, xmlDtd, dtd);
|
57
|
+
|
58
|
+
if(!dtd->attributes) return Qnil;
|
59
|
+
|
60
|
+
VALUE hash = rb_hash_new();
|
61
|
+
|
62
|
+
xmlHashScan((xmlHashTablePtr)dtd->attributes, element_copier, (void *)hash);
|
63
|
+
|
64
|
+
return hash;
|
65
|
+
}
|
66
|
+
|
67
|
+
/*
|
68
|
+
* call-seq:
|
69
|
+
* notations
|
70
|
+
*
|
71
|
+
* Get a hash of the notations for this DTD.
|
72
|
+
*/
|
73
|
+
static VALUE notations(VALUE self)
|
74
|
+
{
|
75
|
+
xmlDtdPtr dtd;
|
76
|
+
Data_Get_Struct(self, xmlDtd, dtd);
|
77
|
+
|
78
|
+
if(!dtd->notations) return Qnil;
|
79
|
+
|
80
|
+
VALUE hash = rb_hash_new();
|
81
|
+
|
82
|
+
xmlHashScan((xmlHashTablePtr)dtd->notations, notation_copier, (void *)hash);
|
83
|
+
|
84
|
+
return hash;
|
85
|
+
}
|
86
|
+
|
87
|
+
/*
|
88
|
+
* call-seq:
|
89
|
+
* elements
|
90
|
+
*
|
91
|
+
* Get a hash of the elements for this DTD.
|
92
|
+
*/
|
93
|
+
static VALUE elements(VALUE self)
|
94
|
+
{
|
95
|
+
xmlDtdPtr dtd;
|
96
|
+
Data_Get_Struct(self, xmlDtd, dtd);
|
97
|
+
|
98
|
+
if(!dtd->elements) return Qnil;
|
99
|
+
|
100
|
+
VALUE hash = rb_hash_new();
|
101
|
+
|
102
|
+
xmlHashScan((xmlHashTablePtr)dtd->elements, element_copier, (void *)hash);
|
103
|
+
|
104
|
+
return hash;
|
105
|
+
}
|
106
|
+
|
107
|
+
void init_xml_dtd()
|
108
|
+
{
|
109
|
+
VALUE nokogiri = rb_define_module("Nokogiri");
|
110
|
+
VALUE xml = rb_define_module_under(nokogiri, "XML");
|
111
|
+
|
112
|
+
/*
|
113
|
+
* Nokogiri::XML::DTD wraps DTD nodes in an XML document
|
114
|
+
*/
|
115
|
+
VALUE klass = rb_define_class_under(xml, "DTD", cNokogiriXmlNode);
|
116
|
+
|
117
|
+
rb_define_method(klass, "notations", notations, 0);
|
118
|
+
rb_define_method(klass, "elements", elements, 0);
|
119
|
+
rb_define_method(klass, "attributes", attributes, 0);
|
120
|
+
rb_define_method(klass, "entities", entities, 0);
|
121
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#include <xml_io.h>
|
2
|
+
|
3
|
+
int io_read_callback(void * ctx, char * buffer, int len) {
|
4
|
+
VALUE io = (VALUE)ctx;
|
5
|
+
VALUE string = rb_funcall(io, rb_intern("read"), 1, INT2NUM(len));
|
6
|
+
|
7
|
+
if(Qnil == string) return 0;
|
8
|
+
VALUE length = rb_funcall(string, rb_intern("length"), 0);
|
9
|
+
|
10
|
+
memcpy(buffer, StringValuePtr(string), (unsigned int)NUM2INT(length));
|
11
|
+
|
12
|
+
return NUM2INT(length);
|
13
|
+
}
|
14
|
+
|
15
|
+
int io_close_callback(void * ctx) {
|
16
|
+
return 0;
|
17
|
+
}
|
@@ -0,0 +1,727 @@
|
|
1
|
+
#include <xml_node.h>
|
2
|
+
|
3
|
+
#ifdef DEBUG
|
4
|
+
static void debug_node_dealloc(xmlNodePtr x)
|
5
|
+
{
|
6
|
+
NOKOGIRI_DEBUG_START(x)
|
7
|
+
NOKOGIRI_DEBUG_END(x)
|
8
|
+
}
|
9
|
+
#else
|
10
|
+
# define debug_node_dealloc 0
|
11
|
+
#endif
|
12
|
+
|
13
|
+
/*
|
14
|
+
* call-seq:
|
15
|
+
* pointer_id
|
16
|
+
*
|
17
|
+
* Get the internal pointer number
|
18
|
+
*/
|
19
|
+
static VALUE pointer_id(VALUE self)
|
20
|
+
{
|
21
|
+
xmlNodePtr node;
|
22
|
+
Data_Get_Struct(self, xmlNode, node);
|
23
|
+
|
24
|
+
return INT2NUM((int)(node));
|
25
|
+
}
|
26
|
+
|
27
|
+
/*
|
28
|
+
* call-seq:
|
29
|
+
* encode_special_chars(string)
|
30
|
+
*
|
31
|
+
* Encode any special characters in +string+
|
32
|
+
*/
|
33
|
+
static VALUE encode_special_chars(VALUE self, VALUE string)
|
34
|
+
{
|
35
|
+
xmlNodePtr node;
|
36
|
+
Data_Get_Struct(self, xmlNode, node);
|
37
|
+
xmlChar * encoded = xmlEncodeSpecialChars(
|
38
|
+
node->doc,
|
39
|
+
(const xmlChar *)StringValuePtr(string)
|
40
|
+
);
|
41
|
+
|
42
|
+
VALUE encoded_str = rb_str_new2((const char *)encoded);
|
43
|
+
xmlFree(encoded);
|
44
|
+
|
45
|
+
return encoded_str;
|
46
|
+
}
|
47
|
+
|
48
|
+
/*
|
49
|
+
* call-seq:
|
50
|
+
* internal_subset
|
51
|
+
*
|
52
|
+
* Get the internal subset
|
53
|
+
*/
|
54
|
+
static VALUE internal_subset(VALUE self)
|
55
|
+
{
|
56
|
+
xmlNodePtr node;
|
57
|
+
xmlDocPtr doc;
|
58
|
+
Data_Get_Struct(self, xmlNode, node);
|
59
|
+
|
60
|
+
if(!node->doc) return Qnil;
|
61
|
+
|
62
|
+
doc = node->doc;
|
63
|
+
xmlDtdPtr dtd = xmlGetIntSubset(doc);
|
64
|
+
|
65
|
+
if(!dtd) return Qnil;
|
66
|
+
|
67
|
+
return Nokogiri_wrap_xml_node((xmlNodePtr)dtd);
|
68
|
+
}
|
69
|
+
|
70
|
+
/*
|
71
|
+
* call-seq:
|
72
|
+
* dup
|
73
|
+
*
|
74
|
+
* Copy this node. An optional depth may be passed in, but it defaults
|
75
|
+
* to a deep copy. 0 is a shallow copy, 1 is a deep copy.
|
76
|
+
*/
|
77
|
+
static VALUE duplicate_node(int argc, VALUE *argv, VALUE self)
|
78
|
+
{
|
79
|
+
VALUE level;
|
80
|
+
|
81
|
+
if(rb_scan_args(argc, argv, "01", &level) == 0)
|
82
|
+
level = INT2NUM(1);
|
83
|
+
|
84
|
+
xmlNodePtr node, dup;
|
85
|
+
Data_Get_Struct(self, xmlNode, node);
|
86
|
+
|
87
|
+
dup = xmlCopyNode(node, NUM2INT(level));
|
88
|
+
if(dup == NULL) return Qnil;
|
89
|
+
dup->doc = node->doc;
|
90
|
+
assert(node->parent);
|
91
|
+
|
92
|
+
xmlAddChild(node->parent, dup);
|
93
|
+
|
94
|
+
return Nokogiri_wrap_xml_node(dup);
|
95
|
+
}
|
96
|
+
|
97
|
+
/*
|
98
|
+
* call-seq:
|
99
|
+
* unlink
|
100
|
+
*
|
101
|
+
* Unlink this node from its current context.
|
102
|
+
*/
|
103
|
+
static VALUE unlink_node(VALUE self)
|
104
|
+
{
|
105
|
+
xmlNodePtr node;
|
106
|
+
Data_Get_Struct(self, xmlNode, node);
|
107
|
+
xmlUnlinkNode(node);
|
108
|
+
return self;
|
109
|
+
}
|
110
|
+
|
111
|
+
/*
|
112
|
+
* call-seq:
|
113
|
+
* blank?
|
114
|
+
*
|
115
|
+
* Is this node blank?
|
116
|
+
*/
|
117
|
+
static VALUE blank_eh(VALUE self)
|
118
|
+
{
|
119
|
+
xmlNodePtr node;
|
120
|
+
Data_Get_Struct(self, xmlNode, node);
|
121
|
+
if(1 == xmlIsBlankNode(node))
|
122
|
+
return Qtrue;
|
123
|
+
return Qfalse;
|
124
|
+
}
|
125
|
+
|
126
|
+
/*
|
127
|
+
* call-seq:
|
128
|
+
* next_sibling
|
129
|
+
*
|
130
|
+
* Returns the next sibling node
|
131
|
+
*/
|
132
|
+
static VALUE next_sibling(VALUE self)
|
133
|
+
{
|
134
|
+
xmlNodePtr node, sibling;
|
135
|
+
Data_Get_Struct(self, xmlNode, node);
|
136
|
+
|
137
|
+
sibling = node->next;
|
138
|
+
if(!sibling) return Qnil;
|
139
|
+
|
140
|
+
return Nokogiri_wrap_xml_node(sibling) ;
|
141
|
+
}
|
142
|
+
|
143
|
+
/*
|
144
|
+
* call-seq:
|
145
|
+
* previous_sibling
|
146
|
+
*
|
147
|
+
* Returns the previous sibling node
|
148
|
+
*/
|
149
|
+
static VALUE previous_sibling(VALUE self)
|
150
|
+
{
|
151
|
+
xmlNodePtr node, sibling;
|
152
|
+
Data_Get_Struct(self, xmlNode, node);
|
153
|
+
|
154
|
+
sibling = node->prev;
|
155
|
+
if(!sibling) return Qnil;
|
156
|
+
|
157
|
+
return Nokogiri_wrap_xml_node(sibling);
|
158
|
+
}
|
159
|
+
|
160
|
+
/* :nodoc: */
|
161
|
+
static VALUE replace(VALUE self, VALUE _new_node)
|
162
|
+
{
|
163
|
+
xmlNodePtr node, new_node;
|
164
|
+
Data_Get_Struct(self, xmlNode, node);
|
165
|
+
Data_Get_Struct(_new_node, xmlNode, new_node);
|
166
|
+
|
167
|
+
xmlReplaceNode(node, new_node);
|
168
|
+
return self ;
|
169
|
+
}
|
170
|
+
|
171
|
+
|
172
|
+
/*
|
173
|
+
* call-seq:
|
174
|
+
* child
|
175
|
+
*
|
176
|
+
* Returns the child node
|
177
|
+
*/
|
178
|
+
static VALUE child(VALUE self)
|
179
|
+
{
|
180
|
+
xmlNodePtr node, child;
|
181
|
+
Data_Get_Struct(self, xmlNode, node);
|
182
|
+
|
183
|
+
child = node->children;
|
184
|
+
if(!child) return Qnil;
|
185
|
+
|
186
|
+
return Nokogiri_wrap_xml_node(child);
|
187
|
+
}
|
188
|
+
|
189
|
+
/*
|
190
|
+
* call-seq:
|
191
|
+
* key?(attribute)
|
192
|
+
*
|
193
|
+
* Returns true if +attribute+ is set
|
194
|
+
*/
|
195
|
+
static VALUE key_eh(VALUE self, VALUE attribute)
|
196
|
+
{
|
197
|
+
xmlNodePtr node;
|
198
|
+
Data_Get_Struct(self, xmlNode, node);
|
199
|
+
if(xmlHasProp(node, (xmlChar *)StringValuePtr(attribute)))
|
200
|
+
return Qtrue;
|
201
|
+
return Qfalse;
|
202
|
+
}
|
203
|
+
|
204
|
+
/*
|
205
|
+
* call-seq:
|
206
|
+
* []=(property, value)
|
207
|
+
*
|
208
|
+
* Set the +property+ to +value+
|
209
|
+
*/
|
210
|
+
static VALUE set(VALUE self, VALUE property, VALUE value)
|
211
|
+
{
|
212
|
+
xmlNodePtr node;
|
213
|
+
Data_Get_Struct(self, xmlNode, node);
|
214
|
+
xmlSetProp(node, (xmlChar *)StringValuePtr(property),
|
215
|
+
(xmlChar *)StringValuePtr(value));
|
216
|
+
|
217
|
+
return value;
|
218
|
+
}
|
219
|
+
|
220
|
+
/*
|
221
|
+
* call-seq:
|
222
|
+
* get(attribute)
|
223
|
+
*
|
224
|
+
* Get the value for +attribute+
|
225
|
+
*/
|
226
|
+
static VALUE get(VALUE self, VALUE attribute)
|
227
|
+
{
|
228
|
+
xmlNodePtr node;
|
229
|
+
xmlChar* propstr ;
|
230
|
+
VALUE rval ;
|
231
|
+
Data_Get_Struct(self, xmlNode, node);
|
232
|
+
propstr = xmlGetProp(node, (xmlChar *)StringValuePtr(attribute));
|
233
|
+
rval = rb_str_new2((char *)propstr) ;
|
234
|
+
xmlFree(propstr);
|
235
|
+
return rval ;
|
236
|
+
}
|
237
|
+
|
238
|
+
/*
|
239
|
+
* call-seq:
|
240
|
+
* attribute_nodes()
|
241
|
+
*
|
242
|
+
* returns a list containing the Node attributes.
|
243
|
+
*/
|
244
|
+
static VALUE attribute_nodes(VALUE self)
|
245
|
+
{
|
246
|
+
/* this code in the mode of xmlHasProp() */
|
247
|
+
xmlNodePtr node ;
|
248
|
+
VALUE attr ;
|
249
|
+
|
250
|
+
attr = rb_ary_new() ;
|
251
|
+
Data_Get_Struct(self, xmlNode, node);
|
252
|
+
|
253
|
+
Nokogiri_xml_node_properties(node, attr);
|
254
|
+
|
255
|
+
return attr ;
|
256
|
+
}
|
257
|
+
|
258
|
+
|
259
|
+
/*
|
260
|
+
* call-seq:
|
261
|
+
* namespace()
|
262
|
+
*
|
263
|
+
* returns the namespace prefix for the node, if one exists.
|
264
|
+
*/
|
265
|
+
static VALUE namespace(VALUE self)
|
266
|
+
{
|
267
|
+
xmlNodePtr node ;
|
268
|
+
Data_Get_Struct(self, xmlNode, node);
|
269
|
+
if (node->ns && node->ns->prefix)
|
270
|
+
return rb_str_new2((const char *)node->ns->prefix) ;
|
271
|
+
return Qnil ;
|
272
|
+
}
|
273
|
+
|
274
|
+
/*
|
275
|
+
* call-seq:
|
276
|
+
* namespaces()
|
277
|
+
*
|
278
|
+
* returns a hash containing the node's namespaces.
|
279
|
+
*/
|
280
|
+
static VALUE namespaces(VALUE self)
|
281
|
+
{
|
282
|
+
/* this code in the mode of xmlHasProp() */
|
283
|
+
xmlNodePtr node ;
|
284
|
+
VALUE attr ;
|
285
|
+
|
286
|
+
attr = rb_hash_new() ;
|
287
|
+
Data_Get_Struct(self, xmlNode, node);
|
288
|
+
|
289
|
+
Nokogiri_xml_node_namespaces(node, attr);
|
290
|
+
|
291
|
+
return attr ;
|
292
|
+
}
|
293
|
+
|
294
|
+
/*
|
295
|
+
* call-seq:
|
296
|
+
* type
|
297
|
+
*
|
298
|
+
* Get the type for this node
|
299
|
+
*/
|
300
|
+
static VALUE type(VALUE self)
|
301
|
+
{
|
302
|
+
xmlNodePtr node;
|
303
|
+
Data_Get_Struct(self, xmlNode, node);
|
304
|
+
return INT2NUM((int)node->type);
|
305
|
+
}
|
306
|
+
|
307
|
+
/*
|
308
|
+
* call-seq:
|
309
|
+
* content=
|
310
|
+
*
|
311
|
+
* Set the content for this Node
|
312
|
+
*/
|
313
|
+
static VALUE set_content(VALUE self, VALUE content)
|
314
|
+
{
|
315
|
+
xmlNodePtr node;
|
316
|
+
Data_Get_Struct(self, xmlNode, node);
|
317
|
+
xmlNodeSetContent(node, (xmlChar *)StringValuePtr(content));
|
318
|
+
return content;
|
319
|
+
}
|
320
|
+
|
321
|
+
/*
|
322
|
+
* call-seq:
|
323
|
+
* content
|
324
|
+
*
|
325
|
+
* Returns the content for this Node
|
326
|
+
*/
|
327
|
+
static VALUE get_content(VALUE self)
|
328
|
+
{
|
329
|
+
xmlNodePtr node;
|
330
|
+
Data_Get_Struct(self, xmlNode, node);
|
331
|
+
|
332
|
+
xmlChar * content = xmlNodeGetContent(node);
|
333
|
+
if(content) {
|
334
|
+
VALUE rval = rb_str_new2((char *)content);
|
335
|
+
xmlFree(content);
|
336
|
+
return rval;
|
337
|
+
}
|
338
|
+
return Qnil;
|
339
|
+
}
|
340
|
+
|
341
|
+
/*
|
342
|
+
* call-seq:
|
343
|
+
* add_child(node)
|
344
|
+
*
|
345
|
+
* Add +node+ as a child of this node. Returns the new child node.
|
346
|
+
*/
|
347
|
+
static VALUE add_child(VALUE self, VALUE child)
|
348
|
+
{
|
349
|
+
xmlNodePtr node, parent, new_child;
|
350
|
+
Data_Get_Struct(child, xmlNode, node);
|
351
|
+
Data_Get_Struct(self, xmlNode, parent);
|
352
|
+
|
353
|
+
xmlUnlinkNode(node) ;
|
354
|
+
|
355
|
+
if(!(new_child = xmlAddChild(parent, node)))
|
356
|
+
rb_raise(rb_eRuntimeError, "Could not add new child");
|
357
|
+
|
358
|
+
// the child was a text node that was coalesced. we need to have the object
|
359
|
+
// point at SOMETHING, or we'll totally bomb out.
|
360
|
+
if (new_child != node)
|
361
|
+
DATA_PTR(child) = new_child ;
|
362
|
+
|
363
|
+
return Nokogiri_wrap_xml_node(new_child);
|
364
|
+
}
|
365
|
+
|
366
|
+
/*
|
367
|
+
* call-seq:
|
368
|
+
* parent
|
369
|
+
*
|
370
|
+
* Get the parent Node for this Node
|
371
|
+
*/
|
372
|
+
static VALUE get_parent(VALUE self)
|
373
|
+
{
|
374
|
+
xmlNodePtr node, parent;
|
375
|
+
Data_Get_Struct(self, xmlNode, node);
|
376
|
+
|
377
|
+
parent = node->parent;
|
378
|
+
if(!parent) return Qnil;
|
379
|
+
|
380
|
+
return Nokogiri_wrap_xml_node(parent) ;
|
381
|
+
}
|
382
|
+
|
383
|
+
/*
|
384
|
+
* call-seq:
|
385
|
+
* name=(new_name)
|
386
|
+
*
|
387
|
+
* Set the name for this Node
|
388
|
+
*/
|
389
|
+
static VALUE set_name(VALUE self, VALUE new_name)
|
390
|
+
{
|
391
|
+
xmlNodePtr node;
|
392
|
+
Data_Get_Struct(self, xmlNode, node);
|
393
|
+
xmlNodeSetName(node, (xmlChar*)StringValuePtr(new_name));
|
394
|
+
return new_name;
|
395
|
+
}
|
396
|
+
|
397
|
+
/*
|
398
|
+
* call-seq:
|
399
|
+
* name
|
400
|
+
*
|
401
|
+
* Returns the name for this Node
|
402
|
+
*/
|
403
|
+
static VALUE get_name(VALUE self)
|
404
|
+
{
|
405
|
+
xmlNodePtr node;
|
406
|
+
Data_Get_Struct(self, xmlNode, node);
|
407
|
+
if(node->name) return rb_str_new2((const char *)node->name);
|
408
|
+
return Qnil;
|
409
|
+
}
|
410
|
+
|
411
|
+
/*
|
412
|
+
* call-seq:
|
413
|
+
* path
|
414
|
+
*
|
415
|
+
* Returns the path associated with this Node
|
416
|
+
*/
|
417
|
+
static VALUE path(VALUE self)
|
418
|
+
{
|
419
|
+
xmlNodePtr node;
|
420
|
+
xmlChar *path ;
|
421
|
+
VALUE rval ;
|
422
|
+
Data_Get_Struct(self, xmlNode, node);
|
423
|
+
|
424
|
+
path = xmlGetNodePath(node);
|
425
|
+
rval = rb_str_new2((char *)path);
|
426
|
+
xmlFree(path);
|
427
|
+
return rval ;
|
428
|
+
}
|
429
|
+
|
430
|
+
/*
|
431
|
+
* call-seq:
|
432
|
+
* add_next_sibling(node)
|
433
|
+
*
|
434
|
+
* Insert +node+ after this node (as a sibling).
|
435
|
+
*/
|
436
|
+
static VALUE add_next_sibling(VALUE self, VALUE rb_node)
|
437
|
+
{
|
438
|
+
xmlNodePtr node, _new_sibling, new_sibling;
|
439
|
+
Data_Get_Struct(self, xmlNode, node);
|
440
|
+
Data_Get_Struct(rb_node, xmlNode, _new_sibling);
|
441
|
+
|
442
|
+
if(!(new_sibling = xmlAddNextSibling(node, _new_sibling)))
|
443
|
+
rb_raise(rb_eRuntimeError, "Could not add next sibling");
|
444
|
+
|
445
|
+
// the sibling was a text node that was coalesced. we need to have the object
|
446
|
+
// point at SOMETHING, or we'll totally bomb out.
|
447
|
+
if(new_sibling != _new_sibling) DATA_PTR(rb_node) = new_sibling;
|
448
|
+
|
449
|
+
rb_funcall(rb_node, rb_intern("decorate!"), 0);
|
450
|
+
|
451
|
+
return rb_node;
|
452
|
+
}
|
453
|
+
|
454
|
+
/*
|
455
|
+
* call-seq:
|
456
|
+
* add_previous_sibling(node)
|
457
|
+
*
|
458
|
+
* Insert +node+ before this node (as a sibling).
|
459
|
+
*/
|
460
|
+
static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
|
461
|
+
{
|
462
|
+
xmlNodePtr node, sibling, new_sibling;
|
463
|
+
Check_Type(rb_node, T_DATA);
|
464
|
+
|
465
|
+
Data_Get_Struct(self, xmlNode, node);
|
466
|
+
Data_Get_Struct(rb_node, xmlNode, sibling);
|
467
|
+
|
468
|
+
if(!(new_sibling = xmlAddPrevSibling(node, sibling)))
|
469
|
+
rb_raise(rb_eRuntimeError, "Could not add previous sibling");
|
470
|
+
|
471
|
+
// the sibling was a text node that was coalesced. we need to have the object
|
472
|
+
// point at SOMETHING, or we'll totally bomb out.
|
473
|
+
if(sibling != new_sibling) DATA_PTR(rb_node) = new_sibling;
|
474
|
+
|
475
|
+
rb_funcall(rb_node, rb_intern("decorate!"), 0);
|
476
|
+
|
477
|
+
return rb_node;
|
478
|
+
}
|
479
|
+
|
480
|
+
/*
|
481
|
+
* call-seq:
|
482
|
+
* to_html
|
483
|
+
*
|
484
|
+
* Returns this node as HTML
|
485
|
+
*/
|
486
|
+
static VALUE to_html(VALUE self)
|
487
|
+
{
|
488
|
+
xmlBufferPtr buf ;
|
489
|
+
xmlNodePtr node ;
|
490
|
+
Data_Get_Struct(self, xmlNode, node);
|
491
|
+
|
492
|
+
VALUE html;
|
493
|
+
|
494
|
+
if(node->doc->type == XML_DOCUMENT_NODE)
|
495
|
+
return rb_funcall(self, rb_intern("to_xml"), 0);
|
496
|
+
|
497
|
+
buf = xmlBufferCreate() ;
|
498
|
+
htmlNodeDump(buf, node->doc, node);
|
499
|
+
html = rb_str_new2((char*)buf->content);
|
500
|
+
xmlBufferFree(buf);
|
501
|
+
return html ;
|
502
|
+
}
|
503
|
+
|
504
|
+
/*
|
505
|
+
* call-seq:
|
506
|
+
* to_xml
|
507
|
+
*
|
508
|
+
* Returns this node as XML
|
509
|
+
*/
|
510
|
+
static VALUE to_xml(int argc, VALUE *argv, VALUE self)
|
511
|
+
{
|
512
|
+
xmlBufferPtr buf ;
|
513
|
+
xmlNodePtr node ;
|
514
|
+
VALUE xml, level;
|
515
|
+
|
516
|
+
if(rb_scan_args(argc, argv, "01", &level) == 0)
|
517
|
+
level = INT2NUM(1);
|
518
|
+
|
519
|
+
Check_Type(level, T_FIXNUM);
|
520
|
+
|
521
|
+
Data_Get_Struct(self, xmlNode, node);
|
522
|
+
|
523
|
+
buf = xmlBufferCreate() ;
|
524
|
+
xmlNodeDump(buf, node->doc, node, 2, NUM2INT(level));
|
525
|
+
xml = rb_str_new2((char*)buf->content);
|
526
|
+
xmlBufferFree(buf);
|
527
|
+
return xml ;
|
528
|
+
}
|
529
|
+
|
530
|
+
|
531
|
+
/*
|
532
|
+
* call-seq:
|
533
|
+
* new(name)
|
534
|
+
*
|
535
|
+
* Create a new node with +name+
|
536
|
+
*/
|
537
|
+
static VALUE new(VALUE klass, VALUE name, VALUE document)
|
538
|
+
{
|
539
|
+
xmlDocPtr doc;
|
540
|
+
|
541
|
+
Data_Get_Struct(document, xmlDoc, doc);
|
542
|
+
|
543
|
+
xmlNodePtr node = xmlNewNode(NULL, (xmlChar *)StringValuePtr(name));
|
544
|
+
node->doc = doc;
|
545
|
+
|
546
|
+
VALUE rb_node = Nokogiri_wrap_xml_node(node);
|
547
|
+
|
548
|
+
if(rb_block_given_p()) rb_yield(rb_node);
|
549
|
+
|
550
|
+
return rb_node;
|
551
|
+
}
|
552
|
+
|
553
|
+
|
554
|
+
/*
|
555
|
+
* call-seq:
|
556
|
+
* new_from_str(string)
|
557
|
+
*
|
558
|
+
* Create a new node by parsing +string+
|
559
|
+
*/
|
560
|
+
static VALUE new_from_str(VALUE klass, VALUE xml)
|
561
|
+
{
|
562
|
+
/*
|
563
|
+
* I couldn't find a more efficient way to do this. So we create a new
|
564
|
+
* document and copy (recursively) the root node.
|
565
|
+
*/
|
566
|
+
VALUE rb_doc ;
|
567
|
+
xmlDocPtr doc ;
|
568
|
+
xmlNodePtr node ;
|
569
|
+
|
570
|
+
rb_doc = rb_funcall(cNokogiriXmlDocument, rb_intern("read_memory"), 4,
|
571
|
+
xml, Qnil, Qnil, INT2NUM(0));
|
572
|
+
Data_Get_Struct(rb_doc, xmlDoc, doc);
|
573
|
+
node = xmlCopyNode(xmlDocGetRootElement(doc), 1); /* 1 => recursive */
|
574
|
+
node->doc = doc;
|
575
|
+
|
576
|
+
return Nokogiri_wrap_xml_node(node);
|
577
|
+
}
|
578
|
+
|
579
|
+
VALUE Nokogiri_wrap_xml_node(xmlNodePtr node)
|
580
|
+
{
|
581
|
+
assert(node);
|
582
|
+
assert(node->doc);
|
583
|
+
assert(node->doc->_private);
|
584
|
+
|
585
|
+
VALUE index = INT2NUM((int)node);
|
586
|
+
VALUE document = (VALUE)node->doc->_private;
|
587
|
+
|
588
|
+
VALUE node_cache = rb_funcall(document, rb_intern("node_cache"), 0);
|
589
|
+
VALUE rb_node = rb_hash_aref(node_cache, index);
|
590
|
+
|
591
|
+
if(rb_node != Qnil) return rb_node;
|
592
|
+
|
593
|
+
switch(node->type)
|
594
|
+
{
|
595
|
+
VALUE klass;
|
596
|
+
|
597
|
+
case XML_TEXT_NODE:
|
598
|
+
klass = rb_const_get(mNokogiriXml, rb_intern("Text"));
|
599
|
+
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
600
|
+
break;
|
601
|
+
case XML_COMMENT_NODE:
|
602
|
+
klass = cNokogiriXmlComment;
|
603
|
+
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
604
|
+
break;
|
605
|
+
case XML_ELEMENT_NODE:
|
606
|
+
klass = rb_const_get(mNokogiriXml, rb_intern("Element"));
|
607
|
+
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
608
|
+
break;
|
609
|
+
case XML_ATTRIBUTE_NODE:
|
610
|
+
klass = rb_const_get(mNokogiriXml, rb_intern("Attr"));
|
611
|
+
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
612
|
+
break;
|
613
|
+
case XML_ENTITY_DECL:
|
614
|
+
klass = rb_const_get(mNokogiriXml, rb_intern("EntityDeclaration"));
|
615
|
+
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
616
|
+
break;
|
617
|
+
case XML_CDATA_SECTION_NODE:
|
618
|
+
klass = cNokogiriXmlCData;
|
619
|
+
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
620
|
+
break;
|
621
|
+
case XML_DTD_NODE:
|
622
|
+
klass = rb_const_get(mNokogiriXml, rb_intern("DTD"));
|
623
|
+
rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
|
624
|
+
break;
|
625
|
+
default:
|
626
|
+
rb_node = Data_Wrap_Struct(cNokogiriXmlNode, 0, debug_node_dealloc, node) ;
|
627
|
+
}
|
628
|
+
|
629
|
+
rb_hash_aset(node_cache, index, rb_node);
|
630
|
+
rb_iv_set(rb_node, "@document", document);
|
631
|
+
rb_funcall(rb_node, rb_intern("decorate!"), 0);
|
632
|
+
return rb_node ;
|
633
|
+
}
|
634
|
+
|
635
|
+
|
636
|
+
void Nokogiri_xml_node_properties(xmlNodePtr node, VALUE attr_list)
|
637
|
+
{
|
638
|
+
xmlAttrPtr prop;
|
639
|
+
prop = node->properties ;
|
640
|
+
while (prop != NULL) {
|
641
|
+
rb_ary_push(attr_list, Nokogiri_wrap_xml_node((xmlNodePtr)prop));
|
642
|
+
prop = prop->next ;
|
643
|
+
}
|
644
|
+
}
|
645
|
+
|
646
|
+
|
647
|
+
#define XMLNS_PREFIX "xmlns"
|
648
|
+
#define XMLNS_PREFIX_LEN 6 /* including either colon or \0 */
|
649
|
+
#define XMLNS_BUFFER_LEN 128
|
650
|
+
void Nokogiri_xml_node_namespaces(xmlNodePtr node, VALUE attr_hash)
|
651
|
+
{
|
652
|
+
xmlNsPtr ns;
|
653
|
+
static char buffer[XMLNS_BUFFER_LEN] ;
|
654
|
+
char *key ;
|
655
|
+
size_t keylen ;
|
656
|
+
|
657
|
+
if (node->type != XML_ELEMENT_NODE) return ;
|
658
|
+
|
659
|
+
ns = node->nsDef;
|
660
|
+
while (ns != NULL) {
|
661
|
+
|
662
|
+
keylen = XMLNS_PREFIX_LEN + (ns->prefix ? (strlen((const char*)ns->prefix) + 1) : 0) ;
|
663
|
+
if (keylen > XMLNS_BUFFER_LEN) {
|
664
|
+
key = (char*)malloc(keylen) ;
|
665
|
+
} else {
|
666
|
+
key = buffer ;
|
667
|
+
}
|
668
|
+
|
669
|
+
if (ns->prefix) {
|
670
|
+
sprintf(key, "%s:%s", XMLNS_PREFIX, ns->prefix);
|
671
|
+
} else {
|
672
|
+
sprintf(key, "%s", XMLNS_PREFIX);
|
673
|
+
}
|
674
|
+
|
675
|
+
rb_hash_aset(attr_hash, rb_str_new2(key), rb_str_new2((const char*)ns->href)) ;
|
676
|
+
if (key != buffer) {
|
677
|
+
free(key);
|
678
|
+
}
|
679
|
+
ns = ns->next ;
|
680
|
+
}
|
681
|
+
}
|
682
|
+
|
683
|
+
|
684
|
+
VALUE cNokogiriXmlNode ;
|
685
|
+
void init_xml_node()
|
686
|
+
{
|
687
|
+
/*
|
688
|
+
VALUE nokogiri = rb_define_module("Nokogiri");
|
689
|
+
VALUE xml = rb_define_module_under(nokogiri, "XML");
|
690
|
+
VALUE klass = rb_define_class_under(xml, "Node", rb_cObject);
|
691
|
+
*/
|
692
|
+
|
693
|
+
VALUE klass = cNokogiriXmlNode = rb_const_get(mNokogiriXml, rb_intern("Node"));
|
694
|
+
|
695
|
+
rb_define_singleton_method(klass, "new", new, 2);
|
696
|
+
rb_define_singleton_method(klass, "new_from_str", new_from_str, 1);
|
697
|
+
|
698
|
+
rb_define_method(klass, "name", get_name, 0);
|
699
|
+
rb_define_method(klass, "name=", set_name, 1);
|
700
|
+
rb_define_method(klass, "add_child", add_child, 1);
|
701
|
+
rb_define_method(klass, "parent", get_parent, 0);
|
702
|
+
rb_define_method(klass, "child", child, 0);
|
703
|
+
rb_define_method(klass, "next_sibling", next_sibling, 0);
|
704
|
+
rb_define_method(klass, "previous_sibling", previous_sibling, 0);
|
705
|
+
rb_define_method(klass, "type", type, 0);
|
706
|
+
rb_define_method(klass, "content", get_content, 0);
|
707
|
+
rb_define_method(klass, "path", path, 0);
|
708
|
+
rb_define_method(klass, "key?", key_eh, 1);
|
709
|
+
rb_define_method(klass, "blank?", blank_eh, 0);
|
710
|
+
rb_define_method(klass, "[]=", set, 2);
|
711
|
+
rb_define_method(klass, "attribute_nodes", attribute_nodes, 0);
|
712
|
+
rb_define_method(klass, "namespace", namespace, 0);
|
713
|
+
rb_define_method(klass, "namespaces", namespaces, 0);
|
714
|
+
rb_define_method(klass, "add_previous_sibling", add_previous_sibling, 1);
|
715
|
+
rb_define_method(klass, "add_next_sibling", add_next_sibling, 1);
|
716
|
+
rb_define_method(klass, "encode_special_chars", encode_special_chars, 1);
|
717
|
+
rb_define_method(klass, "to_xml", to_xml, -1);
|
718
|
+
rb_define_method(klass, "to_html", to_html, 0);
|
719
|
+
rb_define_method(klass, "dup", duplicate_node, -1);
|
720
|
+
rb_define_method(klass, "unlink", unlink_node, 0);
|
721
|
+
rb_define_method(klass, "internal_subset", internal_subset, 0);
|
722
|
+
rb_define_method(klass, "pointer_id", pointer_id, 0);
|
723
|
+
|
724
|
+
rb_define_private_method(klass, "replace_with_node", replace, 1);
|
725
|
+
rb_define_private_method(klass, "native_content=", set_content, 1);
|
726
|
+
rb_define_private_method(klass, "get", get, 1);
|
727
|
+
}
|