nokogiri 1.12.3 → 1.13.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of nokogiri might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +5 -0
- data/README.md +9 -7
- data/bin/nokogiri +63 -50
- data/dependencies.yml +5 -6
- data/ext/nokogiri/extconf.rb +47 -35
- data/ext/nokogiri/xml_document.c +35 -35
- data/ext/nokogiri/xml_document_fragment.c +0 -2
- data/ext/nokogiri/xml_dtd.c +2 -2
- data/ext/nokogiri/xml_encoding_handler.c +25 -11
- data/ext/nokogiri/xml_node.c +645 -333
- data/ext/nokogiri/xml_reader.c +37 -11
- data/ext/nokogiri/xml_xpath_context.c +72 -49
- data/ext/nokogiri/xslt_stylesheet.c +107 -9
- data/gumbo-parser/src/parser.c +0 -11
- data/lib/nokogiri/class_resolver.rb +67 -0
- data/lib/nokogiri/css/node.rb +9 -8
- data/lib/nokogiri/css/parser.rb +360 -341
- data/lib/nokogiri/css/parser.y +249 -244
- data/lib/nokogiri/css/parser_extras.rb +20 -20
- data/lib/nokogiri/css/syntax_error.rb +1 -0
- data/lib/nokogiri/css/tokenizer.rb +4 -3
- data/lib/nokogiri/css/tokenizer.rex +3 -2
- data/lib/nokogiri/css/xpath_visitor.rb +179 -82
- data/lib/nokogiri/css.rb +38 -6
- data/lib/nokogiri/decorators/slop.rb +8 -7
- data/lib/nokogiri/extension.rb +1 -1
- data/lib/nokogiri/gumbo.rb +1 -0
- data/lib/nokogiri/html.rb +16 -10
- data/lib/nokogiri/html4/builder.rb +1 -0
- data/lib/nokogiri/html4/document.rb +84 -75
- data/lib/nokogiri/html4/document_fragment.rb +11 -7
- data/lib/nokogiri/html4/element_description.rb +1 -0
- data/lib/nokogiri/html4/element_description_defaults.rb +426 -520
- data/lib/nokogiri/html4/entity_lookup.rb +2 -1
- data/lib/nokogiri/html4/sax/parser.rb +2 -1
- data/lib/nokogiri/html4/sax/parser_context.rb +1 -0
- data/lib/nokogiri/html4/sax/push_parser.rb +7 -7
- data/lib/nokogiri/html4.rb +11 -5
- data/lib/nokogiri/html5/document.rb +24 -10
- data/lib/nokogiri/html5/document_fragment.rb +5 -2
- data/lib/nokogiri/html5/node.rb +6 -3
- data/lib/nokogiri/html5.rb +68 -64
- data/lib/nokogiri/jruby/dependencies.rb +10 -9
- data/lib/nokogiri/syntax_error.rb +1 -0
- data/lib/nokogiri/version/constant.rb +2 -1
- data/lib/nokogiri/version/info.rb +19 -13
- data/lib/nokogiri/version.rb +1 -0
- data/lib/nokogiri/xml/attr.rb +5 -3
- data/lib/nokogiri/xml/attribute_decl.rb +2 -1
- data/lib/nokogiri/xml/builder.rb +69 -31
- data/lib/nokogiri/xml/cdata.rb +2 -1
- data/lib/nokogiri/xml/character_data.rb +1 -0
- data/lib/nokogiri/xml/document.rb +178 -96
- data/lib/nokogiri/xml/document_fragment.rb +41 -38
- data/lib/nokogiri/xml/dtd.rb +3 -2
- data/lib/nokogiri/xml/element_content.rb +1 -0
- data/lib/nokogiri/xml/element_decl.rb +2 -1
- data/lib/nokogiri/xml/entity_decl.rb +3 -2
- data/lib/nokogiri/xml/entity_reference.rb +1 -0
- data/lib/nokogiri/xml/namespace.rb +2 -0
- data/lib/nokogiri/xml/node/save_options.rb +7 -4
- data/lib/nokogiri/xml/node.rb +512 -348
- data/lib/nokogiri/xml/node_set.rb +46 -54
- data/lib/nokogiri/xml/notation.rb +12 -0
- data/lib/nokogiri/xml/parse_options.rb +11 -7
- data/lib/nokogiri/xml/pp/character_data.rb +8 -6
- data/lib/nokogiri/xml/pp/node.rb +24 -26
- data/lib/nokogiri/xml/pp.rb +1 -0
- data/lib/nokogiri/xml/processing_instruction.rb +2 -1
- data/lib/nokogiri/xml/reader.rb +17 -19
- data/lib/nokogiri/xml/relax_ng.rb +1 -0
- data/lib/nokogiri/xml/sax/document.rb +20 -19
- data/lib/nokogiri/xml/sax/parser.rb +36 -34
- data/lib/nokogiri/xml/sax/parser_context.rb +7 -3
- data/lib/nokogiri/xml/sax/push_parser.rb +5 -5
- data/lib/nokogiri/xml/sax.rb +1 -0
- data/lib/nokogiri/xml/schema.rb +7 -6
- data/lib/nokogiri/xml/searchable.rb +93 -62
- data/lib/nokogiri/xml/syntax_error.rb +4 -4
- data/lib/nokogiri/xml/text.rb +1 -0
- data/lib/nokogiri/xml/xpath/syntax_error.rb +2 -1
- data/lib/nokogiri/xml/xpath.rb +12 -0
- data/lib/nokogiri/xml/xpath_context.rb +2 -3
- data/lib/nokogiri/xml.rb +3 -3
- data/lib/nokogiri/xslt/stylesheet.rb +1 -0
- data/lib/nokogiri/xslt.rb +21 -13
- data/lib/nokogiri.rb +19 -16
- data/lib/xsd/xmlparser/nokogiri.rb +25 -24
- data/patches/libxml2/0008-htmlParseComment-handle-abruptly-closed-comments.patch +61 -0
- data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
- metadata +101 -27
data/ext/nokogiri/xml_node.c
CHANGED
@@ -1,22 +1,27 @@
|
|
1
1
|
#include <nokogiri.h>
|
2
2
|
|
3
|
-
|
3
|
+
// :stopdoc:
|
4
4
|
|
5
|
+
VALUE cNokogiriXmlNode ;
|
5
6
|
static ID id_decorate, id_decorate_bang;
|
6
7
|
|
8
|
+
typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
|
9
|
+
|
10
|
+
|
7
11
|
#ifdef DEBUG
|
8
12
|
static void
|
9
|
-
|
13
|
+
_xml_node_dealloc(xmlNodePtr x)
|
10
14
|
{
|
11
15
|
NOKOGIRI_DEBUG_START(x)
|
12
16
|
NOKOGIRI_DEBUG_END(x)
|
13
17
|
}
|
14
18
|
#else
|
15
|
-
# define
|
19
|
+
# define _xml_node_dealloc 0
|
16
20
|
#endif
|
17
21
|
|
22
|
+
|
18
23
|
static void
|
19
|
-
|
24
|
+
_xml_node_mark(xmlNodePtr node)
|
20
25
|
{
|
21
26
|
xmlDocPtr doc = node->doc;
|
22
27
|
if (doc->type == XML_DOCUMENT_NODE || doc->type == XML_HTML_DOCUMENT_NODE) {
|
@@ -28,10 +33,7 @@ mark(xmlNodePtr node)
|
|
28
33
|
}
|
29
34
|
}
|
30
35
|
|
31
|
-
/* :nodoc: */
|
32
|
-
typedef xmlNodePtr(*pivot_reparentee_func)(xmlNodePtr, xmlNodePtr);
|
33
36
|
|
34
|
-
/* :nodoc: */
|
35
37
|
static void
|
36
38
|
relink_namespace(xmlNodePtr reparented)
|
37
39
|
{
|
@@ -69,6 +71,13 @@ relink_namespace(xmlNodePtr reparented)
|
|
69
71
|
/* Avoid segv when relinking against unlinked nodes. */
|
70
72
|
if (reparented->type != XML_ELEMENT_NODE || !reparented->parent) { return; }
|
71
73
|
|
74
|
+
/* Make sure that our reparented node has the correct namespaces */
|
75
|
+
if (!reparented->ns &&
|
76
|
+
(reparented->doc != (xmlDocPtr)reparented->parent) &&
|
77
|
+
(rb_iv_get(DOC_RUBY_OBJECT(reparented->doc), "@namespace_inheritance") == Qtrue)) {
|
78
|
+
xmlSetNs(reparented, reparented->parent->ns);
|
79
|
+
}
|
80
|
+
|
72
81
|
/* Search our parents for an existing definition */
|
73
82
|
if (reparented->nsDef) {
|
74
83
|
xmlNsPtr curr = reparented->nsDef;
|
@@ -136,7 +145,9 @@ relink_namespace(xmlNodePtr reparented)
|
|
136
145
|
}
|
137
146
|
}
|
138
147
|
|
139
|
-
|
148
|
+
|
149
|
+
/* internal function meant to wrap xmlReplaceNode
|
150
|
+
and fix some issues we have with libxml2 merging nodes */
|
140
151
|
static xmlNodePtr
|
141
152
|
xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
|
142
153
|
{
|
@@ -161,7 +172,18 @@ xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
|
|
161
172
|
return retval ;
|
162
173
|
}
|
163
174
|
|
164
|
-
|
175
|
+
|
176
|
+
static void
|
177
|
+
raise_if_ancestor_of_self(xmlNodePtr self)
|
178
|
+
{
|
179
|
+
for (xmlNodePtr ancestor = self->parent ; ancestor ; ancestor = ancestor->parent) {
|
180
|
+
if (self == ancestor) {
|
181
|
+
rb_raise(rb_eRuntimeError, "cycle detected: node '%s' is an ancestor of itself", self->name);
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
|
165
187
|
static VALUE
|
166
188
|
reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
|
167
189
|
{
|
@@ -350,25 +372,397 @@ ok:
|
|
350
372
|
* adjacent text nodes.
|
351
373
|
*/
|
352
374
|
DATA_PTR(reparentee_obj) = reparented ;
|
353
|
-
|
354
|
-
relink_namespace(reparented);
|
355
|
-
|
356
375
|
reparented_obj = noko_xml_node_wrap(Qnil, reparented);
|
357
376
|
|
358
377
|
rb_funcall(reparented_obj, id_decorate_bang, 0);
|
359
378
|
|
379
|
+
/* if we've created a cycle, raise an exception */
|
380
|
+
raise_if_ancestor_of_self(reparented);
|
381
|
+
|
382
|
+
relink_namespace(reparented);
|
383
|
+
|
360
384
|
return reparented_obj ;
|
361
385
|
}
|
362
386
|
|
387
|
+
// :startdoc:
|
363
388
|
|
364
389
|
/*
|
365
|
-
* call-seq:
|
366
|
-
*
|
390
|
+
* :call-seq:
|
391
|
+
* add_namespace_definition(prefix, href) → Nokogiri::XML::Namespace
|
392
|
+
* add_namespace(prefix, href) → Nokogiri::XML::Namespace
|
393
|
+
*
|
394
|
+
* :category: Manipulating Document Structure
|
395
|
+
*
|
396
|
+
* Adds a namespace definition to this node with +prefix+ using +href+ value, as if this node had
|
397
|
+
* included an attribute "xmlns:prefix=href".
|
398
|
+
*
|
399
|
+
* A default namespace definition for this node can be added by passing +nil+ for +prefix+.
|
400
|
+
*
|
401
|
+
* [Parameters]
|
402
|
+
* - +prefix+ (String, +nil+) An {XML Name}[https://www.w3.org/TR/xml-names/#ns-decl]
|
403
|
+
* - +href+ (String) The {URI reference}[https://www.w3.org/TR/xml-names/#sec-namespaces]
|
404
|
+
*
|
405
|
+
* [Returns] The new Nokogiri::XML::Namespace
|
406
|
+
*
|
407
|
+
* *Example:* adding a non-default namespace definition
|
408
|
+
*
|
409
|
+
* doc = Nokogiri::XML("<store><inventory></inventory></store>")
|
410
|
+
* inventory = doc.at_css("inventory")
|
411
|
+
* inventory.add_namespace_definition("automobile", "http://alices-autos.com/")
|
412
|
+
* inventory.add_namespace_definition("bicycle", "http://bobs-bikes.com/")
|
413
|
+
* inventory.add_child("<automobile:tire>Michelin model XGV, size 75R</automobile:tire>")
|
414
|
+
* doc.to_xml
|
415
|
+
* # => "<?xml version=\"1.0\"?>\n" +
|
416
|
+
* # "<store>\n" +
|
417
|
+
* # " <inventory xmlns:automobile=\"http://alices-autos.com/\" xmlns:bicycle=\"http://bobs-bikes.com/\">\n" +
|
418
|
+
* # " <automobile:tire>Michelin model XGV, size 75R</automobile:tire>\n" +
|
419
|
+
* # " </inventory>\n" +
|
420
|
+
* # "</store>\n"
|
421
|
+
*
|
422
|
+
* *Example:* adding a default namespace definition
|
423
|
+
*
|
424
|
+
* doc = Nokogiri::XML("<store><inventory><tire>Michelin model XGV, size 75R</tire></inventory></store>")
|
425
|
+
* doc.at_css("tire").add_namespace_definition(nil, "http://bobs-bikes.com/")
|
426
|
+
* doc.to_xml
|
427
|
+
* # => "<?xml version=\"1.0\"?>\n" +
|
428
|
+
* # "<store>\n" +
|
429
|
+
* # " <inventory>\n" +
|
430
|
+
* # " <tire xmlns=\"http://bobs-bikes.com/\">Michelin model XGV, size 75R</tire>\n" +
|
431
|
+
* # " </inventory>\n" +
|
432
|
+
* # "</store>\n"
|
433
|
+
*
|
434
|
+
*/
|
435
|
+
static VALUE
|
436
|
+
rb_xml_node_add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
|
437
|
+
{
|
438
|
+
xmlNodePtr c_node, element;
|
439
|
+
xmlNsPtr c_namespace;
|
440
|
+
const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix));
|
441
|
+
|
442
|
+
Data_Get_Struct(rb_node, xmlNode, c_node);
|
443
|
+
element = c_node ;
|
444
|
+
|
445
|
+
c_namespace = xmlSearchNs(c_node->doc, c_node, c_prefix);
|
446
|
+
|
447
|
+
if (!c_namespace) {
|
448
|
+
if (c_node->type != XML_ELEMENT_NODE) {
|
449
|
+
element = c_node->parent;
|
450
|
+
}
|
451
|
+
c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
|
452
|
+
}
|
453
|
+
|
454
|
+
if (!c_namespace) {
|
455
|
+
return Qnil ;
|
456
|
+
}
|
457
|
+
|
458
|
+
if (NIL_P(rb_prefix) || c_node != element) {
|
459
|
+
xmlSetNs(c_node, c_namespace);
|
460
|
+
}
|
461
|
+
|
462
|
+
return noko_xml_namespace_wrap(c_namespace, c_node->doc);
|
463
|
+
}
|
464
|
+
|
465
|
+
|
466
|
+
/*
|
467
|
+
* :call-seq: attribute(name) → Nokogiri::XML::Attr
|
468
|
+
*
|
469
|
+
* :category: Working With Node Attributes
|
470
|
+
*
|
471
|
+
* [Returns] Attribute (Nokogiri::XML::Attr) belonging to this node with name +name+.
|
472
|
+
*
|
473
|
+
* ⚠ Note that attribute namespaces are ignored and only the simple (non-namespace-prefixed) name is
|
474
|
+
* used to find a matching attribute. In case of a simple name collision, only one of the matching
|
475
|
+
* attributes will be returned. In this case, you will need to use #attribute_with_ns.
|
476
|
+
*
|
477
|
+
* *Example:*
|
478
|
+
*
|
479
|
+
* doc = Nokogiri::XML("<root><child size='large' class='big wide tall'/></root>")
|
480
|
+
* child = doc.at_css("child")
|
481
|
+
* child.attribute("size") # => #<Nokogiri::XML::Attr:0x550 name="size" value="large">
|
482
|
+
* child.attribute("class") # => #<Nokogiri::XML::Attr:0x564 name="class" value="big wide tall">
|
483
|
+
*
|
484
|
+
* *Example* showing that namespaced attributes will not be returned:
|
485
|
+
*
|
486
|
+
* ⚠ Note that only one of the two matching attributes is returned.
|
487
|
+
*
|
488
|
+
* doc = Nokogiri::XML(<<~EOF)
|
489
|
+
* <root xmlns:width='http://example.com/widths'
|
490
|
+
* xmlns:height='http://example.com/heights'>
|
491
|
+
* <child width:size='broad' height:size='tall'/>
|
492
|
+
* </root>
|
493
|
+
* EOF
|
494
|
+
* doc.at_css("child").attribute("size")
|
495
|
+
* # => #(Attr:0x550 {
|
496
|
+
* # name = "size",
|
497
|
+
* # namespace = #(Namespace:0x564 {
|
498
|
+
* # prefix = "width",
|
499
|
+
* # href = "http://example.com/widths"
|
500
|
+
* # }),
|
501
|
+
* # value = "broad"
|
502
|
+
* # })
|
503
|
+
*/
|
504
|
+
static VALUE
|
505
|
+
rb_xml_node_attribute(VALUE self, VALUE name)
|
506
|
+
{
|
507
|
+
xmlNodePtr node;
|
508
|
+
xmlAttrPtr prop;
|
509
|
+
Data_Get_Struct(self, xmlNode, node);
|
510
|
+
prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
|
511
|
+
|
512
|
+
if (! prop) { return Qnil; }
|
513
|
+
return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
|
514
|
+
}
|
515
|
+
|
516
|
+
|
517
|
+
/*
|
518
|
+
* :call-seq: attribute_nodes() → Array<Nokogiri::XML::Attr>
|
519
|
+
*
|
520
|
+
* :category: Working With Node Attributes
|
521
|
+
*
|
522
|
+
* [Returns] Attributes (an Array of Nokogiri::XML::Attr) belonging to this node.
|
523
|
+
*
|
524
|
+
* Note that this is the preferred alternative to #attributes when the simple
|
525
|
+
* (non-namespace-prefixed) attribute names may collide.
|
526
|
+
*
|
527
|
+
* *Example:*
|
528
|
+
*
|
529
|
+
* Contrast this with the colliding-name example from #attributes.
|
530
|
+
*
|
531
|
+
* doc = Nokogiri::XML(<<~EOF)
|
532
|
+
* <root xmlns:width='http://example.com/widths'
|
533
|
+
* xmlns:height='http://example.com/heights'>
|
534
|
+
* <child width:size='broad' height:size='tall'/>
|
535
|
+
* </root>
|
536
|
+
* EOF
|
537
|
+
* doc.at_css("child").attribute_nodes
|
538
|
+
* # => [#(Attr:0x550 {
|
539
|
+
* # name = "size",
|
540
|
+
* # namespace = #(Namespace:0x564 {
|
541
|
+
* # prefix = "width",
|
542
|
+
* # href = "http://example.com/widths"
|
543
|
+
* # }),
|
544
|
+
* # value = "broad"
|
545
|
+
* # }),
|
546
|
+
* # #(Attr:0x578 {
|
547
|
+
* # name = "size",
|
548
|
+
* # namespace = #(Namespace:0x58c {
|
549
|
+
* # prefix = "height",
|
550
|
+
* # href = "http://example.com/heights"
|
551
|
+
* # }),
|
552
|
+
* # value = "tall"
|
553
|
+
* # })]
|
554
|
+
*/
|
555
|
+
static VALUE
|
556
|
+
rb_xml_node_attribute_nodes(VALUE rb_node)
|
557
|
+
{
|
558
|
+
xmlNodePtr c_node;
|
559
|
+
|
560
|
+
Data_Get_Struct(rb_node, xmlNode, c_node);
|
561
|
+
|
562
|
+
return noko_xml_node_attrs(c_node);
|
563
|
+
}
|
564
|
+
|
565
|
+
|
566
|
+
/*
|
567
|
+
* :call-seq: attribute_with_ns(name, namespace) → Nokogiri::XML::Attr
|
568
|
+
*
|
569
|
+
* :category: Working With Node Attributes
|
570
|
+
*
|
571
|
+
* [Returns]
|
572
|
+
* Attribute (Nokogiri::XML::Attr) belonging to this node with matching +name+ and +namespace+.
|
573
|
+
*
|
574
|
+
* [Parameters]
|
575
|
+
* - +name+ (String): the simple (non-namespace-prefixed) name of the attribute
|
576
|
+
* - +namespace+ (String): the URI of the attribute's namespace
|
577
|
+
*
|
578
|
+
* See related: #attribute
|
367
579
|
*
|
368
|
-
*
|
580
|
+
* *Example:*
|
581
|
+
*
|
582
|
+
* doc = Nokogiri::XML(<<~EOF)
|
583
|
+
* <root xmlns:width='http://example.com/widths'
|
584
|
+
* xmlns:height='http://example.com/heights'>
|
585
|
+
* <child width:size='broad' height:size='tall'/>
|
586
|
+
* </root>
|
587
|
+
* EOF
|
588
|
+
* doc.at_css("child").attribute_with_ns("size", "http://example.com/widths")
|
589
|
+
* # => #(Attr:0x550 {
|
590
|
+
* # name = "size",
|
591
|
+
* # namespace = #(Namespace:0x564 {
|
592
|
+
* # prefix = "width",
|
593
|
+
* # href = "http://example.com/widths"
|
594
|
+
* # }),
|
595
|
+
* # value = "broad"
|
596
|
+
* # })
|
597
|
+
* doc.at_css("child").attribute_with_ns("size", "http://example.com/heights")
|
598
|
+
* # => #(Attr:0x578 {
|
599
|
+
* # name = "size",
|
600
|
+
* # namespace = #(Namespace:0x58c {
|
601
|
+
* # prefix = "height",
|
602
|
+
* # href = "http://example.com/heights"
|
603
|
+
* # }),
|
604
|
+
* # value = "tall"
|
605
|
+
* # })
|
606
|
+
*/
|
607
|
+
static VALUE
|
608
|
+
rb_xml_node_attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
|
609
|
+
{
|
610
|
+
xmlNodePtr node;
|
611
|
+
xmlAttrPtr prop;
|
612
|
+
Data_Get_Struct(self, xmlNode, node);
|
613
|
+
prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
|
614
|
+
NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
|
615
|
+
|
616
|
+
if (! prop) { return Qnil; }
|
617
|
+
return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
|
618
|
+
}
|
619
|
+
|
620
|
+
|
621
|
+
|
622
|
+
/*
|
623
|
+
* call-seq: blank? → Boolean
|
624
|
+
*
|
625
|
+
* [Returns] +true+ if the node is an empty or whitespace-only text or cdata node, else +false+.
|
626
|
+
*
|
627
|
+
* *Example:*
|
628
|
+
*
|
629
|
+
* Nokogiri("<root><child/></root>").root.child.blank? # => false
|
630
|
+
* Nokogiri("<root>\t \n</root>").root.child.blank? # => true
|
631
|
+
* Nokogiri("<root><![CDATA[\t \n]]></root>").root.child.blank? # => true
|
632
|
+
* Nokogiri("<root>not-blank</root>").root.child
|
633
|
+
* .tap { |n| n.content = "" }.blank # => true
|
634
|
+
*/
|
635
|
+
static VALUE
|
636
|
+
rb_xml_node_blank_eh(VALUE self)
|
637
|
+
{
|
638
|
+
xmlNodePtr node;
|
639
|
+
Data_Get_Struct(self, xmlNode, node);
|
640
|
+
return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
|
641
|
+
}
|
642
|
+
|
643
|
+
|
644
|
+
/*
|
645
|
+
* :call-seq: child() → Nokogiri::XML::Node
|
646
|
+
*
|
647
|
+
* :category: Traversing Document Structure
|
648
|
+
*
|
649
|
+
* [Returns] First of this node's children, or +nil+ if there are no children
|
650
|
+
*
|
651
|
+
* This is a convenience method and is equivalent to:
|
652
|
+
*
|
653
|
+
* node.children.first
|
654
|
+
*
|
655
|
+
* See related: #children
|
369
656
|
*/
|
370
657
|
static VALUE
|
371
|
-
|
658
|
+
rb_xml_node_child(VALUE self)
|
659
|
+
{
|
660
|
+
xmlNodePtr node, child;
|
661
|
+
Data_Get_Struct(self, xmlNode, node);
|
662
|
+
|
663
|
+
child = node->children;
|
664
|
+
if (!child) { return Qnil; }
|
665
|
+
|
666
|
+
return noko_xml_node_wrap(Qnil, child);
|
667
|
+
}
|
668
|
+
|
669
|
+
|
670
|
+
/*
|
671
|
+
* :call-seq: children() → Nokogiri::XML::NodeSet
|
672
|
+
*
|
673
|
+
* :category: Traversing Document Structure
|
674
|
+
*
|
675
|
+
* [Returns] Nokogiri::XML::NodeSet containing this node's children.
|
676
|
+
*/
|
677
|
+
static VALUE
|
678
|
+
rb_xml_node_children(VALUE self)
|
679
|
+
{
|
680
|
+
xmlNodePtr node;
|
681
|
+
xmlNodePtr child;
|
682
|
+
xmlNodeSetPtr set;
|
683
|
+
VALUE document;
|
684
|
+
VALUE node_set;
|
685
|
+
|
686
|
+
Data_Get_Struct(self, xmlNode, node);
|
687
|
+
|
688
|
+
child = node->children;
|
689
|
+
set = xmlXPathNodeSetCreate(child);
|
690
|
+
|
691
|
+
document = DOC_RUBY_OBJECT(node->doc);
|
692
|
+
|
693
|
+
if (!child) { return noko_xml_node_set_wrap(set, document); }
|
694
|
+
|
695
|
+
child = child->next;
|
696
|
+
while (NULL != child) {
|
697
|
+
xmlXPathNodeSetAddUnique(set, child);
|
698
|
+
child = child->next;
|
699
|
+
}
|
700
|
+
|
701
|
+
node_set = noko_xml_node_set_wrap(set, document);
|
702
|
+
|
703
|
+
return node_set;
|
704
|
+
}
|
705
|
+
|
706
|
+
|
707
|
+
/*
|
708
|
+
* :call-seq:
|
709
|
+
* content() → String
|
710
|
+
* inner_text() → String
|
711
|
+
* text() → String
|
712
|
+
* to_str() → String
|
713
|
+
*
|
714
|
+
* [Returns]
|
715
|
+
* Contents of all the text nodes in this node's subtree, concatenated together into a single
|
716
|
+
* String.
|
717
|
+
*
|
718
|
+
* ⚠ Note that entities will _always_ be expanded in the returned String.
|
719
|
+
*
|
720
|
+
* See related: #inner_html
|
721
|
+
*
|
722
|
+
* *Example* of how entities are handled:
|
723
|
+
*
|
724
|
+
* Note that <tt><</tt> becomes <tt><</tt> in the returned String.
|
725
|
+
*
|
726
|
+
* doc = Nokogiri::XML.fragment("<child>a < b</child>")
|
727
|
+
* doc.at_css("child").content
|
728
|
+
* # => "a < b"
|
729
|
+
*
|
730
|
+
* *Example* of how a subtree is handled:
|
731
|
+
*
|
732
|
+
* Note that the <tt><span></tt> tags are omitted and only the text node contents are returned,
|
733
|
+
* concatenated into a single string.
|
734
|
+
*
|
735
|
+
* doc = Nokogiri::XML.fragment("<child><span>first</span> <span>second</span></child>")
|
736
|
+
* doc.at_css("child").content
|
737
|
+
* # => "first second"
|
738
|
+
*/
|
739
|
+
static VALUE
|
740
|
+
rb_xml_node_content(VALUE self)
|
741
|
+
{
|
742
|
+
xmlNodePtr node;
|
743
|
+
xmlChar *content;
|
744
|
+
|
745
|
+
Data_Get_Struct(self, xmlNode, node);
|
746
|
+
|
747
|
+
content = xmlNodeGetContent(node);
|
748
|
+
if (content) {
|
749
|
+
VALUE rval = NOKOGIRI_STR_NEW2(content);
|
750
|
+
xmlFree(content);
|
751
|
+
return rval;
|
752
|
+
}
|
753
|
+
return Qnil;
|
754
|
+
}
|
755
|
+
|
756
|
+
|
757
|
+
/*
|
758
|
+
* :call-seq: document() → Nokogiri::XML::Document
|
759
|
+
*
|
760
|
+
* :category: Traversing Document Structure
|
761
|
+
*
|
762
|
+
* [Returns] Parent Nokogiri::XML::Document for this node
|
763
|
+
*/
|
764
|
+
static VALUE
|
765
|
+
rb_xml_node_document(VALUE self)
|
372
766
|
{
|
373
767
|
xmlNodePtr node;
|
374
768
|
Data_Get_Struct(self, xmlNode, node);
|
@@ -376,13 +770,14 @@ document(VALUE self)
|
|
376
770
|
}
|
377
771
|
|
378
772
|
/*
|
379
|
-
* call-seq:
|
380
|
-
* pointer_id
|
773
|
+
* :call-seq: pointer_id() → Integer
|
381
774
|
*
|
382
|
-
*
|
775
|
+
* [Returns]
|
776
|
+
* A unique id for this node based on the internal memory structures. This method is used by #==
|
777
|
+
* to determine node identity.
|
383
778
|
*/
|
384
779
|
static VALUE
|
385
|
-
|
780
|
+
rb_xml_node_pointer_id(VALUE self)
|
386
781
|
{
|
387
782
|
xmlNodePtr node;
|
388
783
|
Data_Get_Struct(self, xmlNode, node);
|
@@ -391,8 +786,7 @@ pointer_id(VALUE self)
|
|
391
786
|
}
|
392
787
|
|
393
788
|
/*
|
394
|
-
* call-seq:
|
395
|
-
* encode_special_chars(string)
|
789
|
+
* :call-seq: encode_special_chars(string) → String
|
396
790
|
*
|
397
791
|
* Encode any special characters in +string+
|
398
792
|
*/
|
@@ -416,8 +810,8 @@ encode_special_chars(VALUE self, VALUE string)
|
|
416
810
|
}
|
417
811
|
|
418
812
|
/*
|
419
|
-
* call-seq:
|
420
|
-
*
|
813
|
+
* :call-seq:
|
814
|
+
* create_internal_subset(name, external_id, system_id)
|
421
815
|
*
|
422
816
|
* Create the internal subset of a document.
|
423
817
|
*
|
@@ -455,8 +849,8 @@ create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_i
|
|
455
849
|
}
|
456
850
|
|
457
851
|
/*
|
458
|
-
* call-seq:
|
459
|
-
*
|
852
|
+
* :call-seq:
|
853
|
+
* create_external_subset(name, external_id, system_id)
|
460
854
|
*
|
461
855
|
* Create an external subset
|
462
856
|
*/
|
@@ -488,8 +882,8 @@ create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_i
|
|
488
882
|
}
|
489
883
|
|
490
884
|
/*
|
491
|
-
* call-seq:
|
492
|
-
*
|
885
|
+
* :call-seq:
|
886
|
+
* external_subset()
|
493
887
|
*
|
494
888
|
* Get the external subset
|
495
889
|
*/
|
@@ -513,8 +907,8 @@ external_subset(VALUE self)
|
|
513
907
|
}
|
514
908
|
|
515
909
|
/*
|
516
|
-
* call-seq:
|
517
|
-
*
|
910
|
+
* :call-seq:
|
911
|
+
* internal_subset()
|
518
912
|
*
|
519
913
|
* Get the internal subset
|
520
914
|
*/
|
@@ -538,16 +932,19 @@ internal_subset(VALUE self)
|
|
538
932
|
}
|
539
933
|
|
540
934
|
/*
|
541
|
-
* call-seq:
|
542
|
-
*
|
543
|
-
*
|
544
|
-
*
|
935
|
+
* :call-seq:
|
936
|
+
* dup → Nokogiri::XML::Node
|
937
|
+
* dup(depth) → Nokogiri::XML::Node
|
938
|
+
* dup(depth, new_parent_doc) → Nokogiri::XML::Node
|
545
939
|
*
|
546
940
|
* Copy this node.
|
547
|
-
*
|
548
|
-
*
|
549
|
-
*
|
550
|
-
*
|
941
|
+
*
|
942
|
+
* [Parameters]
|
943
|
+
* - +depth+ 0 is a shallow copy, 1 (the default) is a deep copy.
|
944
|
+
* - +new_parent_doc+
|
945
|
+
* The new node's parent Document. Defaults to the this node's document.
|
946
|
+
*
|
947
|
+
* [Returns] The new Nokgiri::XML::Node
|
551
948
|
*/
|
552
949
|
static VALUE
|
553
950
|
duplicate_node(int argc, VALUE *argv, VALUE self)
|
@@ -582,8 +979,8 @@ duplicate_node(int argc, VALUE *argv, VALUE self)
|
|
582
979
|
}
|
583
980
|
|
584
981
|
/*
|
585
|
-
* call-seq:
|
586
|
-
*
|
982
|
+
* :call-seq:
|
983
|
+
* unlink() → self
|
587
984
|
*
|
588
985
|
* Unlink this node from its current context.
|
589
986
|
*/
|
@@ -597,19 +994,6 @@ unlink_node(VALUE self)
|
|
597
994
|
return self;
|
598
995
|
}
|
599
996
|
|
600
|
-
/*
|
601
|
-
* call-seq:
|
602
|
-
* blank?
|
603
|
-
*
|
604
|
-
* Is this node blank?
|
605
|
-
*/
|
606
|
-
static VALUE
|
607
|
-
blank_eh(VALUE self)
|
608
|
-
{
|
609
|
-
xmlNodePtr node;
|
610
|
-
Data_Get_Struct(self, xmlNode, node);
|
611
|
-
return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
|
612
|
-
}
|
613
997
|
|
614
998
|
/*
|
615
999
|
* call-seq:
|
@@ -704,53 +1088,27 @@ replace(VALUE self, VALUE new_node)
|
|
704
1088
|
}
|
705
1089
|
|
706
1090
|
/*
|
707
|
-
* call-seq:
|
708
|
-
*
|
1091
|
+
* :call-seq:
|
1092
|
+
* element_children() → NodeSet
|
1093
|
+
* elements() → NodeSet
|
709
1094
|
*
|
710
|
-
*
|
711
|
-
|
712
|
-
|
713
|
-
children(VALUE self)
|
714
|
-
{
|
715
|
-
xmlNodePtr node;
|
716
|
-
xmlNodePtr child;
|
717
|
-
xmlNodeSetPtr set;
|
718
|
-
VALUE document;
|
719
|
-
VALUE node_set;
|
720
|
-
|
721
|
-
Data_Get_Struct(self, xmlNode, node);
|
722
|
-
|
723
|
-
child = node->children;
|
724
|
-
set = xmlXPathNodeSetCreate(child);
|
725
|
-
|
726
|
-
document = DOC_RUBY_OBJECT(node->doc);
|
727
|
-
|
728
|
-
if (!child) { return noko_xml_node_set_wrap(set, document); }
|
729
|
-
|
730
|
-
child = child->next;
|
731
|
-
while (NULL != child) {
|
732
|
-
xmlXPathNodeSetAddUnique(set, child);
|
733
|
-
child = child->next;
|
734
|
-
}
|
735
|
-
|
736
|
-
node_set = noko_xml_node_set_wrap(set, document);
|
737
|
-
|
738
|
-
return node_set;
|
739
|
-
}
|
740
|
-
|
741
|
-
/*
|
742
|
-
* call-seq:
|
743
|
-
* element_children
|
1095
|
+
* [Returns]
|
1096
|
+
* The node's child elements as a NodeSet. Only children that are elements will be returned, which
|
1097
|
+
* notably excludes Text nodes.
|
744
1098
|
*
|
745
|
-
*
|
746
|
-
* element nodes.
|
1099
|
+
* *Example:*
|
747
1100
|
*
|
748
|
-
*
|
1101
|
+
* Note that #children returns the Text node "hello" while #element_children does not.
|
749
1102
|
*
|
750
|
-
*
|
1103
|
+
* div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
|
1104
|
+
* div.element_children
|
1105
|
+
* # => [#<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
|
1106
|
+
* div.children
|
1107
|
+
* # => [#<Nokogiri::XML::Text:0x64 "hello">,
|
1108
|
+
* # #<Nokogiri::XML::Element:0x50 name="span" children=[#<Nokogiri::XML::Text:0x3c "world">]>]
|
751
1109
|
*/
|
752
1110
|
static VALUE
|
753
|
-
|
1111
|
+
rb_xml_node_element_children(VALUE self)
|
754
1112
|
{
|
755
1113
|
xmlNodePtr node;
|
756
1114
|
xmlNodePtr child;
|
@@ -779,35 +1137,22 @@ element_children(VALUE self)
|
|
779
1137
|
}
|
780
1138
|
|
781
1139
|
/*
|
782
|
-
* call-seq:
|
783
|
-
*
|
1140
|
+
* :call-seq:
|
1141
|
+
* first_element_child() → Node
|
784
1142
|
*
|
785
|
-
* Returns
|
786
|
-
*/
|
787
|
-
static VALUE
|
788
|
-
child(VALUE self)
|
789
|
-
{
|
790
|
-
xmlNodePtr node, child;
|
791
|
-
Data_Get_Struct(self, xmlNode, node);
|
792
|
-
|
793
|
-
child = node->children;
|
794
|
-
if (!child) { return Qnil; }
|
795
|
-
|
796
|
-
return noko_xml_node_wrap(Qnil, child);
|
797
|
-
}
|
798
|
-
|
799
|
-
/*
|
800
|
-
* call-seq:
|
801
|
-
* first_element_child
|
1143
|
+
* [Returns] The first child Node that is an element.
|
802
1144
|
*
|
803
|
-
*
|
1145
|
+
* *Example:*
|
804
1146
|
*
|
805
|
-
*
|
1147
|
+
* Note that the "hello" child, which is a Text node, is skipped and the <tt><span></tt> element is
|
1148
|
+
* returned.
|
806
1149
|
*
|
807
|
-
*
|
1150
|
+
* div = Nokogiri::HTML5("<div>hello<span>world</span>").at_css("div")
|
1151
|
+
* div.first_element_child
|
1152
|
+
* # => #(Element:0x3c { name = "span", children = [ #(Text "world")] })
|
808
1153
|
*/
|
809
1154
|
static VALUE
|
810
|
-
|
1155
|
+
rb_xml_node_first_element_child(VALUE self)
|
811
1156
|
{
|
812
1157
|
xmlNodePtr node, child;
|
813
1158
|
Data_Get_Struct(self, xmlNode, node);
|
@@ -819,17 +1164,22 @@ first_element_child(VALUE self)
|
|
819
1164
|
}
|
820
1165
|
|
821
1166
|
/*
|
822
|
-
* call-seq:
|
823
|
-
*
|
1167
|
+
* :call-seq:
|
1168
|
+
* last_element_child() → Node
|
1169
|
+
*
|
1170
|
+
* [Returns] The last child Node that is an element.
|
824
1171
|
*
|
825
|
-
*
|
1172
|
+
* *Example:*
|
826
1173
|
*
|
827
|
-
*
|
1174
|
+
* Note that the "hello" child, which is a Text node, is skipped and the <tt><span>yes</span></tt>
|
1175
|
+
* element is returned.
|
828
1176
|
*
|
829
|
-
*
|
1177
|
+
* div = Nokogiri::HTML5("<div><span>no</span><span>yes</span>skip</div>").at_css("div")
|
1178
|
+
* div.last_element_child
|
1179
|
+
* # => #(Element:0x3c { name = "span", children = [ #(Text "yes")] })
|
830
1180
|
*/
|
831
1181
|
static VALUE
|
832
|
-
|
1182
|
+
rb_xml_node_last_element_child(VALUE self)
|
833
1183
|
{
|
834
1184
|
xmlNodePtr node, child;
|
835
1185
|
Data_Get_Struct(self, xmlNode, node);
|
@@ -985,67 +1335,29 @@ set_namespace(VALUE self, VALUE namespace)
|
|
985
1335
|
}
|
986
1336
|
|
987
1337
|
/*
|
988
|
-
* call-seq:
|
989
|
-
*
|
1338
|
+
* :call-seq:
|
1339
|
+
* namespace() → Namespace
|
990
1340
|
*
|
991
|
-
*
|
992
|
-
*/
|
993
|
-
static VALUE
|
994
|
-
attr(VALUE self, VALUE name)
|
995
|
-
{
|
996
|
-
xmlNodePtr node;
|
997
|
-
xmlAttrPtr prop;
|
998
|
-
Data_Get_Struct(self, xmlNode, node);
|
999
|
-
prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
|
1000
|
-
|
1001
|
-
if (! prop) { return Qnil; }
|
1002
|
-
return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
|
1003
|
-
}
|
1004
|
-
|
1005
|
-
/*
|
1006
|
-
* call-seq:
|
1007
|
-
* attribute_with_ns(name, namespace)
|
1341
|
+
* [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace.
|
1008
1342
|
*
|
1009
|
-
*
|
1010
|
-
*/
|
1011
|
-
static VALUE
|
1012
|
-
attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
|
1013
|
-
{
|
1014
|
-
xmlNodePtr node;
|
1015
|
-
xmlAttrPtr prop;
|
1016
|
-
Data_Get_Struct(self, xmlNode, node);
|
1017
|
-
prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
|
1018
|
-
NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
|
1019
|
-
|
1020
|
-
if (! prop) { return Qnil; }
|
1021
|
-
return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
|
1022
|
-
}
|
1023
|
-
|
1024
|
-
/*
|
1025
|
-
* @overload attribute_nodes()
|
1026
|
-
* Get the attributes for a Node
|
1027
|
-
* @return [Array<Nokogiri::XML::Attr>] containing the Node's attributes.
|
1028
|
-
*/
|
1029
|
-
static VALUE
|
1030
|
-
attribute_nodes(VALUE rb_node)
|
1031
|
-
{
|
1032
|
-
xmlNodePtr c_node;
|
1033
|
-
|
1034
|
-
Data_Get_Struct(rb_node, xmlNode, c_node);
|
1035
|
-
|
1036
|
-
return noko_xml_node_attrs(c_node);
|
1037
|
-
}
|
1038
|
-
|
1039
|
-
|
1040
|
-
/*
|
1041
|
-
* call-seq:
|
1042
|
-
* namespace()
|
1343
|
+
* *Example:*
|
1043
1344
|
*
|
1044
|
-
*
|
1045
|
-
*
|
1345
|
+
* doc = Nokogiri::XML(<<~EOF)
|
1346
|
+
* <root>
|
1347
|
+
* <first/>
|
1348
|
+
* <second xmlns="http://example.com/child"/>
|
1349
|
+
* <foo:third xmlns:foo="http://example.com/foo"/>
|
1350
|
+
* </root>
|
1351
|
+
* EOF
|
1352
|
+
* doc.at_xpath("//first").namespace
|
1353
|
+
* # => nil
|
1354
|
+
* doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace
|
1355
|
+
* # => #(Namespace:0x3c { href = "http://example.com/child" })
|
1356
|
+
* doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace
|
1357
|
+
* # => #(Namespace:0x50 { prefix = "foo", href = "http://example.com/foo" })
|
1046
1358
|
*/
|
1047
1359
|
static VALUE
|
1048
|
-
|
1360
|
+
rb_xml_node_namespace(VALUE rb_node)
|
1049
1361
|
{
|
1050
1362
|
xmlNodePtr c_node ;
|
1051
1363
|
Data_Get_Struct(rb_node, xmlNode, c_node);
|
@@ -1058,10 +1370,32 @@ noko_xml_node_namespace(VALUE rb_node)
|
|
1058
1370
|
}
|
1059
1371
|
|
1060
1372
|
/*
|
1061
|
-
*
|
1062
|
-
*
|
1373
|
+
* :call-seq:
|
1374
|
+
* namespace_definitions() → Array<Nokogiri::XML::Namespace>
|
1375
|
+
*
|
1376
|
+
* [Returns]
|
1377
|
+
* Namespaces that are defined directly on this node, as an Array of Namespace objects. The array
|
1378
|
+
* will be empty if no namespaces are defined on this node.
|
1063
1379
|
*
|
1064
|
-
*
|
1380
|
+
* *Example:*
|
1381
|
+
*
|
1382
|
+
* doc = Nokogiri::XML(<<~EOF)
|
1383
|
+
* <root xmlns="http://example.com/root">
|
1384
|
+
* <first/>
|
1385
|
+
* <second xmlns="http://example.com/child" xmlns:unused="http://example.com/unused"/>
|
1386
|
+
* <foo:third xmlns:foo="http://example.com/foo"/>
|
1387
|
+
* </root>
|
1388
|
+
* EOF
|
1389
|
+
* doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_definitions
|
1390
|
+
* # => []
|
1391
|
+
* doc.at_xpath("//xmlns:second", "xmlns" => "http://example.com/child").namespace_definitions
|
1392
|
+
* # => [#(Namespace:0x3c { href = "http://example.com/child" }),
|
1393
|
+
* # #(Namespace:0x50 {
|
1394
|
+
* # prefix = "unused",
|
1395
|
+
* # href = "http://example.com/unused"
|
1396
|
+
* # })]
|
1397
|
+
* doc.at_xpath("//foo:third", "foo" => "http://example.com/foo").namespace_definitions
|
1398
|
+
* # => [#(Namespace:0x64 { prefix = "foo", href = "http://example.com/foo" })]
|
1065
1399
|
*/
|
1066
1400
|
static VALUE
|
1067
1401
|
namespace_definitions(VALUE rb_node)
|
@@ -1087,16 +1421,35 @@ namespace_definitions(VALUE rb_node)
|
|
1087
1421
|
}
|
1088
1422
|
|
1089
1423
|
/*
|
1090
|
-
*
|
1091
|
-
*
|
1424
|
+
* :call-seq:
|
1425
|
+
* namespace_scopes() → Array<Nokogiri::XML::Namespace>
|
1426
|
+
*
|
1427
|
+
* [Returns] Array of all the Namespaces on this node and its ancestors.
|
1428
|
+
*
|
1429
|
+
* See also #namespaces
|
1430
|
+
*
|
1431
|
+
* *Example:*
|
1092
1432
|
*
|
1093
|
-
*
|
1094
|
-
*
|
1095
|
-
*
|
1096
|
-
*
|
1433
|
+
* doc = Nokogiri::XML(<<~EOF)
|
1434
|
+
* <root xmlns="http://example.com/root" xmlns:bar="http://example.com/bar">
|
1435
|
+
* <first/>
|
1436
|
+
* <second xmlns="http://example.com/child"/>
|
1437
|
+
* <third xmlns:foo="http://example.com/foo"/>
|
1438
|
+
* </root>
|
1439
|
+
* EOF
|
1440
|
+
* doc.at_xpath("//root:first", "root" => "http://example.com/root").namespace_scopes
|
1441
|
+
* # => [#(Namespace:0x3c { href = "http://example.com/root" }),
|
1442
|
+
* # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
|
1443
|
+
* doc.at_xpath("//child:second", "child" => "http://example.com/child").namespace_scopes
|
1444
|
+
* # => [#(Namespace:0x64 { href = "http://example.com/child" }),
|
1445
|
+
* # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
|
1446
|
+
* doc.at_xpath("//root:third", "root" => "http://example.com/root").namespace_scopes
|
1447
|
+
* # => [#(Namespace:0x78 { prefix = "foo", href = "http://example.com/foo" }),
|
1448
|
+
* # #(Namespace:0x3c { href = "http://example.com/root" }),
|
1449
|
+
* # #(Namespace:0x50 { prefix = "bar", href = "http://example.com/bar" })]
|
1097
1450
|
*/
|
1098
1451
|
static VALUE
|
1099
|
-
|
1452
|
+
rb_xml_node_namespace_scopes(VALUE rb_node)
|
1100
1453
|
{
|
1101
1454
|
xmlNodePtr c_node ;
|
1102
1455
|
xmlNsPtr *namespaces;
|
@@ -1156,30 +1509,6 @@ set_native_content(VALUE self, VALUE content)
|
|
1156
1509
|
return content;
|
1157
1510
|
}
|
1158
1511
|
|
1159
|
-
/*
|
1160
|
-
* call-seq:
|
1161
|
-
* content
|
1162
|
-
*
|
1163
|
-
* Returns the plaintext content for this Node. Note that entities will always
|
1164
|
-
* be expanded in the returned string.
|
1165
|
-
*/
|
1166
|
-
static VALUE
|
1167
|
-
get_native_content(VALUE self)
|
1168
|
-
{
|
1169
|
-
xmlNodePtr node;
|
1170
|
-
xmlChar *content;
|
1171
|
-
|
1172
|
-
Data_Get_Struct(self, xmlNode, node);
|
1173
|
-
|
1174
|
-
content = xmlNodeGetContent(node);
|
1175
|
-
if (content) {
|
1176
|
-
VALUE rval = NOKOGIRI_STR_NEW2(content);
|
1177
|
-
xmlFree(content);
|
1178
|
-
return rval;
|
1179
|
-
}
|
1180
|
-
return Qnil;
|
1181
|
-
}
|
1182
|
-
|
1183
1512
|
/*
|
1184
1513
|
* call-seq:
|
1185
1514
|
* lang=
|
@@ -1290,7 +1619,7 @@ get_name(VALUE self)
|
|
1290
1619
|
* Returns the path associated with this Node
|
1291
1620
|
*/
|
1292
1621
|
static VALUE
|
1293
|
-
|
1622
|
+
rb_xml_node_path(VALUE rb_node)
|
1294
1623
|
{
|
1295
1624
|
xmlNodePtr c_node;
|
1296
1625
|
xmlChar *c_path ;
|
@@ -1369,18 +1698,39 @@ native_write_to(
|
|
1369
1698
|
}
|
1370
1699
|
|
1371
1700
|
/*
|
1372
|
-
* call-seq:
|
1373
|
-
*
|
1701
|
+
* :call-seq:
|
1702
|
+
* line() → Integer
|
1703
|
+
*
|
1704
|
+
* [Returns] The line number of this Node.
|
1705
|
+
*
|
1706
|
+
* ---
|
1707
|
+
*
|
1708
|
+
* <b> ⚠ The CRuby and JRuby implementations differ in important ways! </b>
|
1709
|
+
*
|
1710
|
+
* Semantic differences:
|
1711
|
+
* - The CRuby method reflects the node's line number <i>in the parsed string</i>
|
1712
|
+
* - The JRuby method reflects the node's line number <i>in the final DOM structure</i> after
|
1713
|
+
* corrections have been applied
|
1374
1714
|
*
|
1375
|
-
*
|
1715
|
+
* Performance differences:
|
1716
|
+
* - The CRuby method is {O(1)}[https://en.wikipedia.org/wiki/Time_complexity#Constant_time]
|
1717
|
+
* (constant time)
|
1718
|
+
* - The JRuby method is {O(n)}[https://en.wikipedia.org/wiki/Time_complexity#Linear_time] (linear
|
1719
|
+
* time, where n is the number of nodes before/above the element in the DOM)
|
1720
|
+
*
|
1721
|
+
* If you'd like to help improve the JRuby implementation, please review these issues and reach out
|
1722
|
+
* to the maintainers:
|
1723
|
+
* - https://github.com/sparklemotion/nokogiri/issues/1223
|
1724
|
+
* - https://github.com/sparklemotion/nokogiri/pull/2177
|
1725
|
+
* - https://github.com/sparklemotion/nokogiri/issues/2380
|
1376
1726
|
*/
|
1377
1727
|
static VALUE
|
1378
|
-
|
1728
|
+
rb_xml_node_line(VALUE rb_node)
|
1379
1729
|
{
|
1380
|
-
xmlNodePtr
|
1381
|
-
Data_Get_Struct(
|
1730
|
+
xmlNodePtr c_node;
|
1731
|
+
Data_Get_Struct(rb_node, xmlNode, c_node);
|
1382
1732
|
|
1383
|
-
return INT2NUM(xmlGetLineNo(
|
1733
|
+
return INT2NUM(xmlGetLineNo(c_node));
|
1384
1734
|
}
|
1385
1735
|
|
1386
1736
|
/*
|
@@ -1390,90 +1740,56 @@ line(VALUE self)
|
|
1390
1740
|
* Sets the line for this Node. num must be less than 65535.
|
1391
1741
|
*/
|
1392
1742
|
static VALUE
|
1393
|
-
|
1394
|
-
{
|
1395
|
-
xmlNodePtr node;
|
1396
|
-
int value = NUM2INT(num);
|
1397
|
-
|
1398
|
-
Data_Get_Struct(self, xmlNode, node);
|
1399
|
-
if (value < 65535) {
|
1400
|
-
node->line = value;
|
1401
|
-
}
|
1402
|
-
|
1403
|
-
return num;
|
1404
|
-
}
|
1405
|
-
|
1406
|
-
/*
|
1407
|
-
* call-seq:
|
1408
|
-
* add_namespace_definition(prefix, href)
|
1409
|
-
*
|
1410
|
-
* Adds a namespace definition with +prefix+ using +href+ value. The result is
|
1411
|
-
* as if parsed XML for this node had included an attribute
|
1412
|
-
* 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
|
1413
|
-
* added by passing 'nil' for prefix. Namespaces added this way will not
|
1414
|
-
* show up in #attributes, but they will be included as an xmlns attribute
|
1415
|
-
* when the node is serialized to XML.
|
1416
|
-
*/
|
1417
|
-
static VALUE
|
1418
|
-
add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
|
1743
|
+
rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number)
|
1419
1744
|
{
|
1420
|
-
xmlNodePtr c_node
|
1421
|
-
|
1422
|
-
const xmlChar *c_prefix = (const xmlChar *)(NIL_P(rb_prefix) ? NULL : StringValueCStr(rb_prefix));
|
1745
|
+
xmlNodePtr c_node;
|
1746
|
+
int line_number = NUM2INT(rb_line_number);
|
1423
1747
|
|
1424
1748
|
Data_Get_Struct(rb_node, xmlNode, c_node);
|
1425
|
-
element = c_node ;
|
1426
1749
|
|
1427
|
-
|
1428
|
-
|
1429
|
-
if (
|
1430
|
-
|
1431
|
-
|
1750
|
+
// libxml2 optionally uses xmlNode.psvi to store longer line numbers, but only for text nodes.
|
1751
|
+
// search for "psvi" in SAX2.c and tree.c to learn more.
|
1752
|
+
if (line_number < 65535) {
|
1753
|
+
c_node->line = (short) line_number;
|
1754
|
+
} else {
|
1755
|
+
c_node->line = 65535;
|
1756
|
+
if (c_node->type == XML_TEXT_NODE) {
|
1757
|
+
c_node->psvi = (void *)(ptrdiff_t) line_number;
|
1432
1758
|
}
|
1433
|
-
c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
|
1434
1759
|
}
|
1435
1760
|
|
1436
|
-
|
1437
|
-
return Qnil ;
|
1438
|
-
}
|
1439
|
-
|
1440
|
-
if (NIL_P(rb_prefix) || c_node != element) {
|
1441
|
-
xmlSetNs(c_node, c_namespace);
|
1442
|
-
}
|
1443
|
-
|
1444
|
-
return noko_xml_namespace_wrap(c_namespace, c_node->doc);
|
1761
|
+
return rb_line_number;
|
1445
1762
|
}
|
1446
1763
|
|
1447
|
-
/*
|
1448
|
-
* @overload new(name, document)
|
1449
|
-
* Create a new node with +name+ sharing GC lifecycle with +document+.
|
1450
|
-
* @param name [String]
|
1451
|
-
* @param document [Nokogiri::XML::Document]
|
1452
|
-
* @yieldparam node [Nokogiri::XML::Node]
|
1453
|
-
* @return [Nokogiri::XML::Node]
|
1454
|
-
* @see Nokogiri::XML::Node#initialize
|
1455
|
-
*/
|
1764
|
+
/* :nodoc: documented in lib/nokogiri/xml/node.rb */
|
1456
1765
|
static VALUE
|
1457
1766
|
rb_xml_node_new(int argc, VALUE *argv, VALUE klass)
|
1458
1767
|
{
|
1459
|
-
|
1460
|
-
xmlNodePtr
|
1461
|
-
VALUE
|
1462
|
-
VALUE
|
1768
|
+
xmlNodePtr c_document_node;
|
1769
|
+
xmlNodePtr c_node;
|
1770
|
+
VALUE rb_name;
|
1771
|
+
VALUE rb_document_node;
|
1463
1772
|
VALUE rest;
|
1464
1773
|
VALUE rb_node;
|
1465
1774
|
|
1466
|
-
rb_scan_args(argc, argv, "2*", &
|
1775
|
+
rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest);
|
1467
1776
|
|
1468
|
-
|
1777
|
+
if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlNode)) {
|
1778
|
+
rb_raise(rb_eArgError, "document must be a Nokogiri::XML::Node");
|
1779
|
+
}
|
1780
|
+
if (!rb_obj_is_kind_of(rb_document_node, cNokogiriXmlDocument)) {
|
1781
|
+
// TODO: deprecate allowing Node
|
1782
|
+
rb_warn("Passing a Node as the second parameter to Node.new is deprecated. Please pass a Document instead, or prefer an alternative constructor like Node#add_child. This will become an error in a future release of Nokogiri.");
|
1783
|
+
}
|
1784
|
+
Data_Get_Struct(rb_document_node, xmlNode, c_document_node);
|
1469
1785
|
|
1470
|
-
|
1471
|
-
|
1472
|
-
noko_xml_document_pin_node(
|
1786
|
+
c_node = xmlNewNode(NULL, (xmlChar *)StringValueCStr(rb_name));
|
1787
|
+
c_node->doc = c_document_node->doc;
|
1788
|
+
noko_xml_document_pin_node(c_node);
|
1473
1789
|
|
1474
1790
|
rb_node = noko_xml_node_wrap(
|
1475
1791
|
klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
|
1476
|
-
|
1792
|
+
c_node
|
1477
1793
|
);
|
1478
1794
|
rb_obj_call_init(rb_node, argc, argv);
|
1479
1795
|
|
@@ -1607,9 +1923,7 @@ in_context(VALUE self, VALUE _str, VALUE _options)
|
|
1607
1923
|
*/
|
1608
1924
|
child_iter = node->doc->children ;
|
1609
1925
|
while (child_iter) {
|
1610
|
-
|
1611
|
-
child_iter->parent = (xmlNodePtr)node->doc;
|
1612
|
-
}
|
1926
|
+
child_iter->parent = (xmlNodePtr)node->doc;
|
1613
1927
|
child_iter = child_iter->next;
|
1614
1928
|
}
|
1615
1929
|
|
@@ -1667,7 +1981,7 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
|
|
1667
1981
|
VALUE rb_document, rb_node_cache, rb_node;
|
1668
1982
|
nokogiriTuplePtr node_has_a_document;
|
1669
1983
|
xmlDocPtr c_doc;
|
1670
|
-
void (*
|
1984
|
+
void (*f_mark)(xmlNodePtr) = NULL ;
|
1671
1985
|
|
1672
1986
|
assert(c_node);
|
1673
1987
|
|
@@ -1729,9 +2043,9 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
|
|
1729
2043
|
}
|
1730
2044
|
}
|
1731
2045
|
|
1732
|
-
|
2046
|
+
f_mark = node_has_a_document ? _xml_node_mark : NULL ;
|
1733
2047
|
|
1734
|
-
rb_node = Data_Wrap_Struct(rb_class,
|
2048
|
+
rb_node = Data_Wrap_Struct(rb_class, f_mark, _xml_node_dealloc, c_node) ;
|
1735
2049
|
c_node->_private = (void *)rb_node;
|
1736
2050
|
|
1737
2051
|
if (node_has_a_document) {
|
@@ -1772,61 +2086,59 @@ noko_init_xml_node()
|
|
1772
2086
|
|
1773
2087
|
rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1);
|
1774
2088
|
|
1775
|
-
rb_define_method(cNokogiriXmlNode, "add_namespace_definition",
|
2089
|
+
rb_define_method(cNokogiriXmlNode, "add_namespace_definition", rb_xml_node_add_namespace_definition, 2);
|
2090
|
+
rb_define_method(cNokogiriXmlNode, "attribute", rb_xml_node_attribute, 1);
|
2091
|
+
rb_define_method(cNokogiriXmlNode, "attribute_nodes", rb_xml_node_attribute_nodes, 0);
|
2092
|
+
rb_define_method(cNokogiriXmlNode, "attribute_with_ns", rb_xml_node_attribute_with_ns, 2);
|
2093
|
+
rb_define_method(cNokogiriXmlNode, "blank?", rb_xml_node_blank_eh, 0);
|
2094
|
+
rb_define_method(cNokogiriXmlNode, "child", rb_xml_node_child, 0);
|
2095
|
+
rb_define_method(cNokogiriXmlNode, "children", rb_xml_node_children, 0);
|
2096
|
+
rb_define_method(cNokogiriXmlNode, "content", rb_xml_node_content, 0);
|
2097
|
+
rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
|
2098
|
+
rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
|
2099
|
+
rb_define_method(cNokogiriXmlNode, "document", rb_xml_node_document, 0);
|
2100
|
+
rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
|
2101
|
+
rb_define_method(cNokogiriXmlNode, "element_children", rb_xml_node_element_children, 0);
|
2102
|
+
rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
|
2103
|
+
rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
|
2104
|
+
rb_define_method(cNokogiriXmlNode, "first_element_child", rb_xml_node_first_element_child, 0);
|
2105
|
+
rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
|
2106
|
+
rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
|
2107
|
+
rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
|
2108
|
+
rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
|
2109
|
+
rb_define_method(cNokogiriXmlNode, "last_element_child", rb_xml_node_last_element_child, 0);
|
2110
|
+
rb_define_method(cNokogiriXmlNode, "line", rb_xml_node_line, 0);
|
2111
|
+
rb_define_method(cNokogiriXmlNode, "line=", rb_xml_node_line_set, 1);
|
2112
|
+
rb_define_method(cNokogiriXmlNode, "namespace", rb_xml_node_namespace, 0);
|
2113
|
+
rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
|
2114
|
+
rb_define_method(cNokogiriXmlNode, "namespace_scopes", rb_xml_node_namespace_scopes, 0);
|
2115
|
+
rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
|
2116
|
+
rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
|
2117
|
+
rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0);
|
2118
|
+
rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
|
1776
2119
|
rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0);
|
1777
|
-
rb_define_method(cNokogiriXmlNode, "document", document, 0);
|
1778
2120
|
rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1);
|
2121
|
+
rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
|
1779
2122
|
rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0);
|
1780
|
-
rb_define_method(cNokogiriXmlNode, "
|
1781
|
-
rb_define_method(cNokogiriXmlNode, "
|
1782
|
-
rb_define_method(cNokogiriXmlNode, "last_element_child", last_element_child, 0);
|
1783
|
-
rb_define_method(cNokogiriXmlNode, "children", children, 0);
|
1784
|
-
rb_define_method(cNokogiriXmlNode, "element_children", element_children, 0);
|
1785
|
-
rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
|
1786
|
-
rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
|
1787
|
-
rb_define_method(cNokogiriXmlNode, "next_element", next_element, 0);
|
2123
|
+
rb_define_method(cNokogiriXmlNode, "path", rb_xml_node_path, 0);
|
2124
|
+
rb_define_method(cNokogiriXmlNode, "pointer_id", rb_xml_node_pointer_id, 0);
|
1788
2125
|
rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0);
|
1789
|
-
rb_define_method(cNokogiriXmlNode, "
|
1790
|
-
rb_define_method(cNokogiriXmlNode, "path", noko_xml_node_path, 0);
|
1791
|
-
rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
|
1792
|
-
rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
|
1793
|
-
rb_define_method(cNokogiriXmlNode, "blank?", blank_eh, 0);
|
1794
|
-
rb_define_method(cNokogiriXmlNode, "attribute_nodes", attribute_nodes, 0);
|
1795
|
-
rb_define_method(cNokogiriXmlNode, "attribute", attr, 1);
|
1796
|
-
rb_define_method(cNokogiriXmlNode, "attribute_with_ns", attribute_with_ns, 2);
|
1797
|
-
rb_define_method(cNokogiriXmlNode, "namespace", noko_xml_node_namespace, 0);
|
1798
|
-
rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
|
1799
|
-
rb_define_method(cNokogiriXmlNode, "namespace_scopes", namespace_scopes, 0);
|
1800
|
-
rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
|
1801
|
-
rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
|
2126
|
+
rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
|
1802
2127
|
rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
|
1803
|
-
rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
|
1804
|
-
rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
|
1805
|
-
rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
|
1806
|
-
rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
|
1807
|
-
rb_define_method(cNokogiriXmlNode, "pointer_id", pointer_id, 0);
|
1808
|
-
rb_define_method(cNokogiriXmlNode, "line", line, 0);
|
1809
|
-
rb_define_method(cNokogiriXmlNode, "line=", set_line, 1);
|
1810
|
-
rb_define_method(cNokogiriXmlNode, "content", get_native_content, 0);
|
1811
|
-
rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
|
1812
|
-
rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
|
1813
|
-
rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
|
1814
2128
|
|
1815
|
-
rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
|
1816
|
-
rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
|
1817
2129
|
rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
|
1818
|
-
rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
|
1819
2130
|
rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1);
|
1820
|
-
rb_define_private_method(cNokogiriXmlNode, "
|
2131
|
+
rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
|
2132
|
+
rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
|
1821
2133
|
rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0);
|
1822
|
-
rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
|
1823
2134
|
rb_define_private_method(cNokogiriXmlNode, "get", get, 1);
|
2135
|
+
rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
|
2136
|
+
rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
|
2137
|
+
rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
|
2138
|
+
rb_define_private_method(cNokogiriXmlNode, "replace_node", replace, 1);
|
1824
2139
|
rb_define_private_method(cNokogiriXmlNode, "set", set, 2);
|
1825
2140
|
rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1);
|
1826
|
-
rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
|
1827
2141
|
|
1828
2142
|
id_decorate = rb_intern("decorate");
|
1829
2143
|
id_decorate_bang = rb_intern("decorate!");
|
1830
2144
|
}
|
1831
|
-
|
1832
|
-
/* vim: set noet sw=4 sws=4 */
|