nokogiri 1.2.1-x86-mswin32-60 → 1.2.2-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.

Files changed (76) hide show
  1. data/.autotest +15 -0
  2. data/{History.ja.txt → CHANGELOG.ja.rdoc} +30 -2
  3. data/{History.txt → CHANGELOG.rdoc} +28 -2
  4. data/Manifest.txt +13 -7
  5. data/{README.ja.txt → README.ja.rdoc} +3 -1
  6. data/{README.txt → README.rdoc} +7 -1
  7. data/Rakefile +8 -25
  8. data/ext/nokogiri/extconf.rb +4 -4
  9. data/ext/nokogiri/html_entity_lookup.c +30 -0
  10. data/ext/nokogiri/html_entity_lookup.h +8 -0
  11. data/ext/nokogiri/native.c +22 -0
  12. data/ext/nokogiri/native.h +27 -4
  13. data/ext/nokogiri/native.so +0 -0
  14. data/ext/nokogiri/xml_document.c +31 -4
  15. data/ext/nokogiri/xml_document.h +11 -0
  16. data/ext/nokogiri/xml_document_fragment.c +1 -1
  17. data/ext/nokogiri/xml_node.c +71 -58
  18. data/ext/nokogiri/xml_node_set.c +26 -0
  19. data/ext/nokogiri/xml_reader.c +4 -2
  20. data/ext/nokogiri/xml_sax_parser.c +0 -37
  21. data/ext/nokogiri/xml_sax_push_parser.c +2 -2
  22. data/ext/nokogiri/xml_xpath_context.c +34 -7
  23. data/lib/nokogiri.rb +25 -0
  24. data/lib/nokogiri/css/generated_tokenizer.rb +2 -2
  25. data/lib/nokogiri/css/node.rb +2 -0
  26. data/lib/nokogiri/css/parser.rb +3 -2
  27. data/lib/nokogiri/html.rb +9 -52
  28. data/lib/nokogiri/html/document.rb +2 -0
  29. data/lib/nokogiri/html/entity_lookup.rb +11 -0
  30. data/lib/nokogiri/version.rb +1 -1
  31. data/lib/nokogiri/xml.rb +1 -2
  32. data/lib/nokogiri/xml/builder.rb +18 -5
  33. data/lib/nokogiri/xml/document.rb +15 -1
  34. data/lib/nokogiri/xml/fragment_handler.rb +34 -0
  35. data/lib/nokogiri/xml/node.rb +104 -29
  36. data/lib/nokogiri/xml/node_set.rb +12 -10
  37. data/lib/nokogiri/xml/sax/parser.rb +3 -3
  38. data/lib/xsd/xmlparser/nokogiri.rb +53 -0
  39. data/tasks/test.rb +7 -5
  40. data/test/css/test_nthiness.rb +1 -0
  41. data/test/css/test_parser.rb +1 -0
  42. data/test/css/test_tokenizer.rb +1 -0
  43. data/test/css/test_xpath_visitor.rb +1 -0
  44. data/test/helper.rb +4 -0
  45. data/test/hpricot/test_alter.rb +1 -0
  46. data/test/html/sax/test_parser.rb +13 -0
  47. data/test/html/test_builder.rb +21 -0
  48. data/test/html/test_document.rb +36 -0
  49. data/test/html/test_document_encoding.rb +46 -0
  50. data/test/html/test_named_characters.rb +14 -0
  51. data/test/html/test_node.rb +80 -0
  52. data/test/test_convert_xpath.rb +1 -0
  53. data/test/test_css_cache.rb +1 -0
  54. data/test/test_nokogiri.rb +8 -0
  55. data/test/xml/sax/test_parser.rb +6 -0
  56. data/test/xml/sax/test_push_parser.rb +1 -0
  57. data/test/xml/test_builder.rb +9 -0
  58. data/test/xml/test_cdata.rb +1 -0
  59. data/test/xml/test_comment.rb +1 -0
  60. data/test/xml/test_document.rb +58 -0
  61. data/test/xml/test_document_encoding.rb +15 -14
  62. data/test/xml/test_document_fragment.rb +6 -0
  63. data/test/xml/test_dtd.rb +1 -0
  64. data/test/xml/test_dtd_encoding.rb +1 -0
  65. data/test/xml/test_entity_reference.rb +1 -0
  66. data/test/xml/test_node.rb +52 -4
  67. data/test/xml/test_node_encoding.rb +1 -0
  68. data/test/xml/test_node_set.rb +21 -1
  69. data/test/xml/test_processing_instruction.rb +1 -0
  70. data/test/xml/test_reader_encoding.rb +1 -0
  71. data/test/xml/test_unparented_node.rb +381 -0
  72. data/test/xml/test_xpath.rb +1 -0
  73. metadata +34 -16
  74. data/lib/nokogiri/xml/after_handler.rb +0 -18
  75. data/lib/nokogiri/xml/before_handler.rb +0 -33
  76. data/vendor/hoe.rb +0 -1020
@@ -3,8 +3,19 @@
3
3
 
4
4
  #include <native.h>
5
5
 
6
+ struct _nokogiriTuple {
7
+ xmlDocPtr doc;
8
+ xmlNodeSetPtr unlinkedNodes;
9
+ };
10
+ typedef struct _nokogiriTuple nokogiriTuple;
11
+ typedef nokogiriTuple * nokogiriTuplePtr;
12
+
6
13
  void init_xml_document();
7
14
  VALUE Nokogiri_wrap_xml_document(VALUE klass, xmlDocPtr doc);
8
15
 
16
+ #define DOC_RUBY_OBJECT_TEST(x) ((nokogiriTuplePtr)(x->_private))
17
+ #define DOC_RUBY_OBJECT(x) ((VALUE)((nokogiriTuplePtr)(x->_private))->doc)
18
+ #define DOC_UNLINKED_NODE_SET(x) ((xmlNodeSetPtr)((nokogiriTuplePtr)(x->_private))->unlinkedNodes)
19
+
9
20
  extern VALUE cNokogiriXmlDocument ;
10
21
  #endif
@@ -11,7 +11,7 @@ static VALUE new(VALUE klass, VALUE doc)
11
11
  xmlDocPtr xml_doc;
12
12
  Data_Get_Struct(doc, xmlDoc, xml_doc);
13
13
 
14
- xmlNodePtr node = xmlNewDocFragment(xml_doc);
14
+ xmlNodePtr node = xmlNewDocFragment(xml_doc->doc);
15
15
 
16
16
  VALUE rb_node = Nokogiri_wrap_xml_node(node);
17
17
 
@@ -10,6 +10,55 @@ static void debug_node_dealloc(xmlNodePtr x)
10
10
  # define debug_node_dealloc 0
11
11
  #endif
12
12
 
13
+ /* :nodoc: */
14
+ typedef xmlNodePtr (*node_other_func)(xmlNodePtr, xmlNodePtr);
15
+
16
+ /* :nodoc: */
17
+ static VALUE reparent_node_with(VALUE node_obj, VALUE other_obj, node_other_func func)
18
+ {
19
+ VALUE reparented_obj ;
20
+ xmlNodePtr node, other, reparented ;
21
+
22
+ Data_Get_Struct(node_obj, xmlNode, node);
23
+ Data_Get_Struct(other_obj, xmlNode, other);
24
+
25
+ if (node->doc == other->doc) {
26
+ xmlUnlinkNode(node) ;
27
+ if(!(reparented = (*func)(other, node))) {
28
+ rb_raise(rb_eRuntimeError, "Could not reparent node (1)");
29
+ }
30
+
31
+ } else {
32
+ xmlNodePtr duped_node ;
33
+ // recursively copy to the new document
34
+ if (!(duped_node = xmlDocCopyNode(node, other->doc, 1))) {
35
+ rb_raise(rb_eRuntimeError, "Could not reparent node (xmlDocCopyNode)");
36
+ }
37
+ if(!(reparented = (*func)(other, duped_node))) {
38
+ rb_raise(rb_eRuntimeError, "Could not reparent node (2)");
39
+ }
40
+ xmlUnlinkNode(node);
41
+ NOKOGIRI_ROOT_NODE(node);
42
+ }
43
+
44
+ // the child was a text node that was coalesced. we need to have the object
45
+ // point at SOMETHING, or we'll totally bomb out.
46
+ if (reparented != node) {
47
+ DATA_PTR(node_obj) = reparented ;
48
+ }
49
+
50
+ // Make sure that our reparented node has the correct namespaces
51
+ if(reparented->doc != reparented->parent)
52
+ reparented->ns = reparented->parent->ns;
53
+
54
+ reparented_obj = Nokogiri_wrap_xml_node(reparented);
55
+
56
+ rb_funcall(reparented_obj, rb_intern("decorate!"), 0);
57
+
58
+ return reparented_obj ;
59
+ }
60
+
61
+
13
62
  /*
14
63
  * call-seq:
15
64
  * pointer_id
@@ -101,6 +150,7 @@ static VALUE unlink_node(VALUE self)
101
150
  xmlNodePtr node;
102
151
  Data_Get_Struct(self, xmlNode, node);
103
152
  xmlUnlinkNode(node);
153
+ NOKOGIRI_ROOT_NODE(node);
104
154
  return self;
105
155
  }
106
156
 
@@ -208,12 +258,9 @@ static VALUE set(VALUE self, VALUE property, VALUE value)
208
258
  xmlNodePtr node;
209
259
  Data_Get_Struct(self, xmlNode, node);
210
260
 
211
- xmlChar *buffer = xmlEncodeEntitiesReentrant(node->doc,
261
+ xmlSetProp(node, (xmlChar *)StringValuePtr(property),
212
262
  (xmlChar *)StringValuePtr(value));
213
263
 
214
- xmlSetProp(node, (xmlChar *)StringValuePtr(property), buffer);
215
- xmlFree(buffer);
216
-
217
264
  return value;
218
265
  }
219
266
 
@@ -371,21 +418,7 @@ static VALUE get_content(VALUE self)
371
418
  */
372
419
  static VALUE add_child(VALUE self, VALUE child)
373
420
  {
374
- xmlNodePtr node, parent, new_child;
375
- Data_Get_Struct(child, xmlNode, node);
376
- Data_Get_Struct(self, xmlNode, parent);
377
-
378
- xmlUnlinkNode(node) ;
379
-
380
- if(!(new_child = xmlAddChild(parent, node)))
381
- rb_raise(rb_eRuntimeError, "Could not add new child");
382
-
383
- // the child was a text node that was coalesced. we need to have the object
384
- // point at SOMETHING, or we'll totally bomb out.
385
- if (new_child != node)
386
- DATA_PTR(child) = new_child ;
387
-
388
- return Nokogiri_wrap_xml_node(new_child);
421
+ return reparent_node_with(child, self, xmlAddChild);
389
422
  }
390
423
 
391
424
  /*
@@ -460,20 +493,7 @@ static VALUE path(VALUE self)
460
493
  */
461
494
  static VALUE add_next_sibling(VALUE self, VALUE rb_node)
462
495
  {
463
- xmlNodePtr node, _new_sibling, new_sibling;
464
- Data_Get_Struct(self, xmlNode, node);
465
- Data_Get_Struct(rb_node, xmlNode, _new_sibling);
466
-
467
- if(!(new_sibling = xmlAddNextSibling(node, _new_sibling)))
468
- rb_raise(rb_eRuntimeError, "Could not add next sibling");
469
-
470
- // the sibling was a text node that was coalesced. we need to have the object
471
- // point at SOMETHING, or we'll totally bomb out.
472
- if(new_sibling != _new_sibling) DATA_PTR(rb_node) = new_sibling;
473
-
474
- rb_funcall(rb_node, rb_intern("decorate!"), 0);
475
-
476
- return rb_node;
496
+ return reparent_node_with(rb_node, self, xmlAddNextSibling) ;
477
497
  }
478
498
 
479
499
  /*
@@ -484,22 +504,7 @@ static VALUE add_next_sibling(VALUE self, VALUE rb_node)
484
504
  */
485
505
  static VALUE add_previous_sibling(VALUE self, VALUE rb_node)
486
506
  {
487
- xmlNodePtr node, sibling, new_sibling;
488
- Check_Type(rb_node, T_DATA);
489
-
490
- Data_Get_Struct(self, xmlNode, node);
491
- Data_Get_Struct(rb_node, xmlNode, sibling);
492
-
493
- if(!(new_sibling = xmlAddPrevSibling(node, sibling)))
494
- rb_raise(rb_eRuntimeError, "Could not add previous sibling");
495
-
496
- // the sibling was a text node that was coalesced. we need to have the object
497
- // point at SOMETHING, or we'll totally bomb out.
498
- if(sibling != new_sibling) DATA_PTR(rb_node) = new_sibling;
499
-
500
- rb_funcall(rb_node, rb_intern("decorate!"), 0);
501
-
502
- return rb_node;
507
+ return reparent_node_with(rb_node, self, xmlAddPrevSibling) ;
503
508
  }
504
509
 
505
510
  /*
@@ -560,12 +565,14 @@ static VALUE add_namespace(VALUE self, VALUE prefix, VALUE href)
560
565
 
561
566
  if(NULL == ns) return self;
562
567
 
568
+ /*
563
569
  xmlNewNsProp(
564
570
  node,
565
571
  ns,
566
572
  (const xmlChar *)StringValuePtr(href),
567
573
  (const xmlChar *)StringValuePtr(prefix)
568
574
  );
575
+ */
569
576
 
570
577
  return self;
571
578
  }
@@ -617,16 +624,18 @@ static VALUE dump_html(VALUE self)
617
624
  VALUE Nokogiri_wrap_xml_node(xmlNodePtr node)
618
625
  {
619
626
  assert(node);
620
- assert(node->doc);
621
- assert(node->doc->_private);
622
627
 
623
628
  VALUE index = INT2NUM((int)node);
624
- VALUE document = (VALUE)node->doc->_private;
625
-
626
- VALUE node_cache = rb_funcall(document, rb_intern("node_cache"), 0);
627
- VALUE rb_node = rb_hash_aref(node_cache, index);
628
-
629
- if(rb_node != Qnil) return rb_node;
629
+ VALUE document = Qnil ;
630
+ VALUE node_cache = Qnil ;
631
+ VALUE rb_node = Qnil ;
632
+
633
+ if (DOC_RUBY_OBJECT_TEST(node->doc) && DOC_RUBY_OBJECT(node->doc)) {
634
+ document = DOC_RUBY_OBJECT(node->doc);
635
+ node_cache = rb_funcall(document, rb_intern("node_cache"), 0);
636
+ rb_node = rb_hash_aref(node_cache, index);
637
+ if(rb_node != Qnil) return rb_node;
638
+ }
630
639
 
631
640
  switch(node->type)
632
641
  {
@@ -672,11 +681,15 @@ VALUE Nokogiri_wrap_xml_node(xmlNodePtr node)
672
681
  klass = rb_const_get(mNokogiriXml, rb_intern("DTD"));
673
682
  rb_node = Data_Wrap_Struct(klass, 0, debug_node_dealloc, node) ;
674
683
  break;
684
+ case XML_DOCUMENT_NODE:
685
+ return DOC_RUBY_OBJECT(node->doc);
686
+ case XML_HTML_DOCUMENT_NODE:
687
+ return DOC_RUBY_OBJECT(node->doc);
675
688
  default:
676
689
  rb_node = Data_Wrap_Struct(cNokogiriXmlNode, 0, debug_node_dealloc, node) ;
677
690
  }
678
691
 
679
- rb_hash_aset(node_cache, index, rb_node);
692
+ if (node_cache != Qnil) rb_hash_aset(node_cache, index, rb_node);
680
693
  rb_iv_set(rb_node, "@document", document);
681
694
  rb_funcall(rb_node, rb_intern("decorate!"), 0);
682
695
  return rb_node ;
@@ -58,6 +58,31 @@ static VALUE index_at(VALUE self, VALUE number)
58
58
  return Nokogiri_wrap_xml_node(node_set->nodeTab[i]);
59
59
  }
60
60
 
61
+ /*
62
+ * call-seq:
63
+ * unlink
64
+ *
65
+ * Unlink this NodeSet and all Node objects it contains from their current context.
66
+ */
67
+ static VALUE unlink_nodeset(VALUE self)
68
+ {
69
+ xmlNodeSetPtr node_set;
70
+ int j, nodeNr ;
71
+
72
+ Data_Get_Struct(self, xmlNodeSet, node_set);
73
+ nodeNr = node_set->nodeNr ;
74
+ for (j = 0 ; j < nodeNr ; j++) {
75
+ VALUE node ;
76
+ xmlNodePtr node_ptr;
77
+ node = Nokogiri_wrap_xml_node(node_set->nodeTab[j]);
78
+ rb_funcall(node, rb_intern("unlink"), 0); /* modifies the C struct out from under the object */
79
+ Data_Get_Struct(node, xmlNode, node_ptr);
80
+ node_set->nodeTab[j] = node_ptr ;
81
+ }
82
+ return self ;
83
+ }
84
+
85
+
61
86
  static void deallocate(xmlNodeSetPtr node_set)
62
87
  {
63
88
  /*
@@ -119,4 +144,5 @@ void init_xml_node_set(void)
119
144
  rb_define_method(klass, "length", length, 0);
120
145
  rb_define_method(klass, "[]", index_at, 1);
121
146
  rb_define_method(klass, "push", push, 1);
147
+ rb_define_method(klass, "unlink", unlink_nodeset, 0);
122
148
  }
@@ -126,10 +126,12 @@ static VALUE attribute_nodes(VALUE self)
126
126
  // FIXME I'm not sure if this is correct..... I don't really like pointing
127
127
  // at this document, but I have to because of the assertions in
128
128
  // the node wrapping code.
129
- if(!ptr->doc->_private) {
129
+ if(! DOC_RUBY_OBJECT_TEST(ptr->doc)) {
130
130
  VALUE rb_doc = Data_Wrap_Struct(cNokogiriXmlDocument, 0, 0, ptr->doc);
131
+ ptr->doc->_private = malloc(sizeof(nokogiriTuple));
131
132
  rb_iv_set(rb_doc, "@decorators", Qnil);
132
- ptr->doc->_private = (void *)rb_doc;
133
+ ((nokogiriTuplePtr)(ptr->doc->_private))->doc = (void *)rb_doc;
134
+ ((nokogiriTuplePtr)(ptr->doc->_private))->unlinkedNodes = xmlXPathNodeSetCreate(NULL);
133
135
  }
134
136
  VALUE enc = rb_iv_get(self, "@encoding");
135
137
 
@@ -129,43 +129,6 @@ static void comment_func(void * ctx, const xmlChar * value)
129
129
  rb_funcall(doc, rb_intern("comment"), 1, str);
130
130
  }
131
131
 
132
- #ifdef XP_WIN
133
- /*
134
- * I srsly hate windows. it doesn't have vasprintf.
135
- * This is stolen from here:
136
- * http://eleves.ec-lille.fr/~couprieg/index.php?2008/06/17/39-first-issues-when-porting-an-application-on-windows-ce
137
- * and slightly modified
138
- */
139
- static inline int vasprintf(char **strp, const char *fmt, va_list ap) {
140
- int n;
141
- size_t size = 4096;
142
- char *res, *np;
143
-
144
- if ( (res = (char *) malloc(size)) == NULL )
145
- return -1;
146
-
147
- while (1) {
148
- n = vsnprintf (res, size, fmt, ap);
149
- /* If that worked, return the string. */
150
- if (n > -1 && n < size) {
151
- *strp = res;
152
- return n;
153
- }
154
-
155
- /* Else try again with more space. */
156
- if (n == -1)
157
- size *= 2; /* twice the old size */
158
-
159
- if ( (np = (char *) realloc(res, size)) == NULL ) {
160
- free(res);
161
- return -1;
162
- } else {
163
- res = np;
164
- }
165
- }
166
- }
167
- #endif
168
-
169
132
  static void warning_func(void * ctx, const char *msg, ...)
170
133
  {
171
134
  VALUE self = (VALUE)ctx;
@@ -2,9 +2,9 @@
2
2
 
3
3
  static void deallocate(xmlParserCtxtPtr ctx)
4
4
  {
5
- NOKOGIRI_DEBUG_START(handler);
5
+ NOKOGIRI_DEBUG_START(ctx);
6
6
  if(ctx != NULL) xmlFreeParserCtxt(ctx);
7
- NOKOGIRI_DEBUG_END(handler);
7
+ NOKOGIRI_DEBUG_END(ctx);
8
8
  }
9
9
 
10
10
  static VALUE allocate(VALUE klass)
@@ -34,12 +34,12 @@ static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
34
34
  assert(ctx->context);
35
35
  assert(ctx->context->userData);
36
36
  assert(ctx->context->doc);
37
- assert(ctx->context->doc->_private);
37
+ assert(DOC_RUBY_OBJECT_TEST(ctx->context->doc));
38
38
 
39
39
  xpath_handler = (VALUE)(ctx->context->userData);
40
40
 
41
41
  VALUE * argv = (VALUE *)calloc((unsigned int)nargs, sizeof(VALUE));
42
- VALUE doc = (VALUE)ctx->context->doc->_private;
42
+ VALUE doc = DOC_RUBY_OBJECT(ctx->context->doc);
43
43
 
44
44
  int i = nargs - 1;
45
45
  do {
@@ -130,6 +130,28 @@ static xmlXPathFunction lookup( void *ctx,
130
130
  return NULL;
131
131
  }
132
132
 
133
+ static void xpath_exception_handler(void * ctx, xmlErrorPtr error)
134
+ {
135
+ VALUE xpath = rb_const_get(mNokogiriXml, rb_intern("XPath"));
136
+ VALUE klass = rb_const_get(xpath, rb_intern("SyntaxError"));
137
+
138
+ rb_funcall(rb_mKernel, rb_intern("raise"), 1,
139
+ Nokogiri_wrap_xml_syntax_error(klass, error)
140
+ );
141
+ }
142
+
143
+ static void xpath_generic_exception_handler(void * ctx, const char *msg, ...)
144
+ {
145
+ char * message;
146
+
147
+ va_list args;
148
+ va_start(args, msg);
149
+ vasprintf(&message, msg, args);
150
+ va_end(args);
151
+
152
+ rb_raise(rb_eRuntimeError, message);
153
+ }
154
+
133
155
  /*
134
156
  * call-seq:
135
157
  * evaluate(search_path)
@@ -141,7 +163,6 @@ static VALUE evaluate(int argc, VALUE *argv, VALUE self)
141
163
  VALUE search_path, xpath_handler;
142
164
  xmlXPathContextPtr ctx;
143
165
  Data_Get_Struct(self, xmlXPathContext, ctx);
144
- VALUE error_list = rb_ary_new();
145
166
 
146
167
  if(rb_scan_args(argc, argv, "11", &search_path, &xpath_handler) == 1)
147
168
  xpath_handler = Qnil;
@@ -155,9 +176,15 @@ static VALUE evaluate(int argc, VALUE *argv, VALUE self)
155
176
  }
156
177
 
157
178
  xmlResetLastError();
158
- xmlSetStructuredErrorFunc((void *)error_list, Nokogiri_error_array_pusher);
179
+ xmlSetStructuredErrorFunc(NULL, xpath_exception_handler);
180
+
181
+ // For some reason, xmlXPathEvalExpression will blow up with a generic error
182
+ // when there is a non existent function.
183
+ xmlSetGenericErrorFunc(NULL, xpath_generic_exception_handler);
184
+
159
185
  xmlXPathObjectPtr xpath = xmlXPathEvalExpression(query, ctx);
160
186
  xmlSetStructuredErrorFunc(NULL, NULL);
187
+ xmlSetGenericErrorFunc(NULL, NULL);
161
188
 
162
189
  if(xpath == NULL) {
163
190
  VALUE xpath = rb_const_get(mNokogiriXml, rb_intern("XPath"));
@@ -172,13 +199,13 @@ static VALUE evaluate(int argc, VALUE *argv, VALUE self)
172
199
  VALUE xpath_object = Nokogiri_wrap_xml_xpath(xpath);
173
200
 
174
201
  assert(ctx->doc);
175
- assert(ctx->doc->_private);
202
+ assert(DOC_RUBY_OBJECT_TEST(ctx->doc));
176
203
 
177
204
  rb_funcall( xpath_object,
178
205
  rb_intern("document="),
179
206
  1,
180
- (VALUE)ctx->doc->_private
181
- );
207
+ DOC_RUBY_OBJECT(ctx->doc)
208
+ );
182
209
  return xpath_object;
183
210
  }
184
211
 
data/lib/nokogiri.rb CHANGED
@@ -15,6 +15,31 @@ require 'nokogiri/css'
15
15
  require 'nokogiri/html/builder'
16
16
  require 'nokogiri/hpricot'
17
17
 
18
+ # Nokogiri parses and searches XML/HTML very quickly, and also has
19
+ # correctly implemented CSS3 selector support as well as XPath support.
20
+ #
21
+ # Parsing a document returns either a Nokogiri::XML::Document, or a
22
+ # Nokogiri::HTML::Document depending on the kind of document you parse.
23
+ #
24
+ # Here is an example:
25
+ #
26
+ # require 'nokogiri'
27
+ # require 'open-uri'
28
+ #
29
+ # # Get a Nokogiri::HTML:Document for the page we’re interested in...
30
+ #
31
+ # doc = Nokogiri::HTML(open('http://www.google.com/search?q=tenderlove'))
32
+ #
33
+ # # Do funky things with it using Nokogiri::XML::Node methods...
34
+ #
35
+ # ####
36
+ # # Search for nodes by css
37
+ # doc.css('h3.r a.l').each do |link|
38
+ # puts link.content
39
+ # end
40
+ #
41
+ # See Nokogiri::XML::Node#css for more information about CSS searching.
42
+ # See Nokogiri::XML::Node#xpath for more information about XPath searching.
18
43
  module Nokogiri
19
44
  class << self
20
45
  ###