nokogiri 1.12.5-x86_64-darwin → 1.13.0-x86_64-darwin
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 +2 -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/include/libxml2/libxml/xmlerror.h +1 -0
- data/ext/nokogiri/include/libxslt/xsltconfig.h +1 -1
- 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 +638 -333
- data/ext/nokogiri/xml_reader.c +37 -11
- data/ext/nokogiri/xml_xpath_context.c +72 -49
- data/lib/nokogiri/2.6/nokogiri.bundle +0 -0
- data/lib/nokogiri/2.7/nokogiri.bundle +0 -0
- data/lib/nokogiri/3.0/nokogiri.bundle +0 -0
- data/lib/nokogiri/{2.5 → 3.1}/nokogiri.bundle +0 -0
- data/lib/nokogiri/class_resolver.rb +67 -0
- data/lib/nokogiri/css/node.rb +9 -8
- data/lib/nokogiri/css/parser.rb +11 -3
- data/lib/nokogiri/css/parser.y +10 -2
- data/lib/nokogiri/css/parser_extras.rb +20 -20
- data/lib/nokogiri/css/syntax_error.rb +1 -0
- data/lib/nokogiri/css/tokenizer.rb +2 -1
- data/lib/nokogiri/css/tokenizer.rex +2 -1
- data/lib/nokogiri/css/xpath_visitor.rb +174 -75
- 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 +32 -32
- data/lib/nokogiri/xml/cdata.rb +2 -1
- data/lib/nokogiri/xml/character_data.rb +1 -0
- data/lib/nokogiri/xml/document.rb +139 -103
- 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 +6 -3
- 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 +42 -22
- 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 +3 -2
- data/lib/nokogiri.rb +19 -16
- data/lib/xsd/xmlparser/nokogiri.rb +25 -24
- metadata +124 -52
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
|
{
|
@@ -143,7 +145,9 @@ relink_namespace(xmlNodePtr reparented)
|
|
143
145
|
}
|
144
146
|
}
|
145
147
|
|
146
|
-
|
148
|
+
|
149
|
+
/* internal function meant to wrap xmlReplaceNode
|
150
|
+
and fix some issues we have with libxml2 merging nodes */
|
147
151
|
static xmlNodePtr
|
148
152
|
xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
|
149
153
|
{
|
@@ -168,7 +172,18 @@ xmlReplaceNodeWrapper(xmlNodePtr pivot, xmlNodePtr new_node)
|
|
168
172
|
return retval ;
|
169
173
|
}
|
170
174
|
|
171
|
-
|
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
|
+
|
172
187
|
static VALUE
|
173
188
|
reparent_node_with(VALUE pivot_obj, VALUE reparentee_obj, pivot_reparentee_func prf)
|
174
189
|
{
|
@@ -357,25 +372,397 @@ ok:
|
|
357
372
|
* adjacent text nodes.
|
358
373
|
*/
|
359
374
|
DATA_PTR(reparentee_obj) = reparented ;
|
360
|
-
|
361
|
-
relink_namespace(reparented);
|
362
|
-
|
363
375
|
reparented_obj = noko_xml_node_wrap(Qnil, reparented);
|
364
376
|
|
365
377
|
rb_funcall(reparented_obj, id_decorate_bang, 0);
|
366
378
|
|
379
|
+
/* if we've created a cycle, raise an exception */
|
380
|
+
raise_if_ancestor_of_self(reparented);
|
381
|
+
|
382
|
+
relink_namespace(reparented);
|
383
|
+
|
367
384
|
return reparented_obj ;
|
368
385
|
}
|
369
386
|
|
387
|
+
// :startdoc:
|
370
388
|
|
371
389
|
/*
|
372
|
-
* call-seq:
|
373
|
-
*
|
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"
|
374
433
|
*
|
375
|
-
* Get the document for this Node
|
376
434
|
*/
|
377
435
|
static VALUE
|
378
|
-
|
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
|
579
|
+
*
|
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
|
656
|
+
*/
|
657
|
+
static VALUE
|
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)
|
379
766
|
{
|
380
767
|
xmlNodePtr node;
|
381
768
|
Data_Get_Struct(self, xmlNode, node);
|
@@ -383,13 +770,14 @@ document(VALUE self)
|
|
383
770
|
}
|
384
771
|
|
385
772
|
/*
|
386
|
-
* call-seq:
|
387
|
-
* pointer_id
|
773
|
+
* :call-seq: pointer_id() → Integer
|
388
774
|
*
|
389
|
-
*
|
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.
|
390
778
|
*/
|
391
779
|
static VALUE
|
392
|
-
|
780
|
+
rb_xml_node_pointer_id(VALUE self)
|
393
781
|
{
|
394
782
|
xmlNodePtr node;
|
395
783
|
Data_Get_Struct(self, xmlNode, node);
|
@@ -398,8 +786,7 @@ pointer_id(VALUE self)
|
|
398
786
|
}
|
399
787
|
|
400
788
|
/*
|
401
|
-
* call-seq:
|
402
|
-
* encode_special_chars(string)
|
789
|
+
* :call-seq: encode_special_chars(string) → String
|
403
790
|
*
|
404
791
|
* Encode any special characters in +string+
|
405
792
|
*/
|
@@ -423,8 +810,8 @@ encode_special_chars(VALUE self, VALUE string)
|
|
423
810
|
}
|
424
811
|
|
425
812
|
/*
|
426
|
-
* call-seq:
|
427
|
-
*
|
813
|
+
* :call-seq:
|
814
|
+
* create_internal_subset(name, external_id, system_id)
|
428
815
|
*
|
429
816
|
* Create the internal subset of a document.
|
430
817
|
*
|
@@ -462,8 +849,8 @@ create_internal_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_i
|
|
462
849
|
}
|
463
850
|
|
464
851
|
/*
|
465
|
-
* call-seq:
|
466
|
-
*
|
852
|
+
* :call-seq:
|
853
|
+
* create_external_subset(name, external_id, system_id)
|
467
854
|
*
|
468
855
|
* Create an external subset
|
469
856
|
*/
|
@@ -495,8 +882,8 @@ create_external_subset(VALUE self, VALUE name, VALUE external_id, VALUE system_i
|
|
495
882
|
}
|
496
883
|
|
497
884
|
/*
|
498
|
-
* call-seq:
|
499
|
-
*
|
885
|
+
* :call-seq:
|
886
|
+
* external_subset()
|
500
887
|
*
|
501
888
|
* Get the external subset
|
502
889
|
*/
|
@@ -520,8 +907,8 @@ external_subset(VALUE self)
|
|
520
907
|
}
|
521
908
|
|
522
909
|
/*
|
523
|
-
* call-seq:
|
524
|
-
*
|
910
|
+
* :call-seq:
|
911
|
+
* internal_subset()
|
525
912
|
*
|
526
913
|
* Get the internal subset
|
527
914
|
*/
|
@@ -545,16 +932,19 @@ internal_subset(VALUE self)
|
|
545
932
|
}
|
546
933
|
|
547
934
|
/*
|
548
|
-
* call-seq:
|
549
|
-
*
|
550
|
-
*
|
551
|
-
*
|
935
|
+
* :call-seq:
|
936
|
+
* dup → Nokogiri::XML::Node
|
937
|
+
* dup(depth) → Nokogiri::XML::Node
|
938
|
+
* dup(depth, new_parent_doc) → Nokogiri::XML::Node
|
552
939
|
*
|
553
940
|
* Copy this node.
|
554
|
-
*
|
555
|
-
*
|
556
|
-
*
|
557
|
-
*
|
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
|
558
948
|
*/
|
559
949
|
static VALUE
|
560
950
|
duplicate_node(int argc, VALUE *argv, VALUE self)
|
@@ -589,8 +979,8 @@ duplicate_node(int argc, VALUE *argv, VALUE self)
|
|
589
979
|
}
|
590
980
|
|
591
981
|
/*
|
592
|
-
* call-seq:
|
593
|
-
*
|
982
|
+
* :call-seq:
|
983
|
+
* unlink() → self
|
594
984
|
*
|
595
985
|
* Unlink this node from its current context.
|
596
986
|
*/
|
@@ -604,19 +994,6 @@ unlink_node(VALUE self)
|
|
604
994
|
return self;
|
605
995
|
}
|
606
996
|
|
607
|
-
/*
|
608
|
-
* call-seq:
|
609
|
-
* blank?
|
610
|
-
*
|
611
|
-
* Is this node blank?
|
612
|
-
*/
|
613
|
-
static VALUE
|
614
|
-
blank_eh(VALUE self)
|
615
|
-
{
|
616
|
-
xmlNodePtr node;
|
617
|
-
Data_Get_Struct(self, xmlNode, node);
|
618
|
-
return (1 == xmlIsBlankNode(node)) ? Qtrue : Qfalse ;
|
619
|
-
}
|
620
997
|
|
621
998
|
/*
|
622
999
|
* call-seq:
|
@@ -711,53 +1088,27 @@ replace(VALUE self, VALUE new_node)
|
|
711
1088
|
}
|
712
1089
|
|
713
1090
|
/*
|
714
|
-
* call-seq:
|
715
|
-
*
|
1091
|
+
* :call-seq:
|
1092
|
+
* element_children() → NodeSet
|
1093
|
+
* elements() → NodeSet
|
716
1094
|
*
|
717
|
-
*
|
718
|
-
|
719
|
-
|
720
|
-
children(VALUE self)
|
721
|
-
{
|
722
|
-
xmlNodePtr node;
|
723
|
-
xmlNodePtr child;
|
724
|
-
xmlNodeSetPtr set;
|
725
|
-
VALUE document;
|
726
|
-
VALUE node_set;
|
727
|
-
|
728
|
-
Data_Get_Struct(self, xmlNode, node);
|
729
|
-
|
730
|
-
child = node->children;
|
731
|
-
set = xmlXPathNodeSetCreate(child);
|
732
|
-
|
733
|
-
document = DOC_RUBY_OBJECT(node->doc);
|
734
|
-
|
735
|
-
if (!child) { return noko_xml_node_set_wrap(set, document); }
|
736
|
-
|
737
|
-
child = child->next;
|
738
|
-
while (NULL != child) {
|
739
|
-
xmlXPathNodeSetAddUnique(set, child);
|
740
|
-
child = child->next;
|
741
|
-
}
|
742
|
-
|
743
|
-
node_set = noko_xml_node_set_wrap(set, document);
|
744
|
-
|
745
|
-
return node_set;
|
746
|
-
}
|
747
|
-
|
748
|
-
/*
|
749
|
-
* call-seq:
|
750
|
-
* 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.
|
751
1098
|
*
|
752
|
-
*
|
753
|
-
* element nodes.
|
1099
|
+
* *Example:*
|
754
1100
|
*
|
755
|
-
*
|
1101
|
+
* Note that #children returns the Text node "hello" while #element_children does not.
|
756
1102
|
*
|
757
|
-
*
|
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">]>]
|
758
1109
|
*/
|
759
1110
|
static VALUE
|
760
|
-
|
1111
|
+
rb_xml_node_element_children(VALUE self)
|
761
1112
|
{
|
762
1113
|
xmlNodePtr node;
|
763
1114
|
xmlNodePtr child;
|
@@ -786,35 +1137,22 @@ element_children(VALUE self)
|
|
786
1137
|
}
|
787
1138
|
|
788
1139
|
/*
|
789
|
-
* call-seq:
|
790
|
-
*
|
1140
|
+
* :call-seq:
|
1141
|
+
* first_element_child() → Node
|
791
1142
|
*
|
792
|
-
* Returns
|
793
|
-
*/
|
794
|
-
static VALUE
|
795
|
-
child(VALUE self)
|
796
|
-
{
|
797
|
-
xmlNodePtr node, child;
|
798
|
-
Data_Get_Struct(self, xmlNode, node);
|
799
|
-
|
800
|
-
child = node->children;
|
801
|
-
if (!child) { return Qnil; }
|
802
|
-
|
803
|
-
return noko_xml_node_wrap(Qnil, child);
|
804
|
-
}
|
805
|
-
|
806
|
-
/*
|
807
|
-
* call-seq:
|
808
|
-
* first_element_child
|
1143
|
+
* [Returns] The first child Node that is an element.
|
809
1144
|
*
|
810
|
-
*
|
1145
|
+
* *Example:*
|
811
1146
|
*
|
812
|
-
*
|
1147
|
+
* Note that the "hello" child, which is a Text node, is skipped and the <tt><span></tt> element is
|
1148
|
+
* returned.
|
813
1149
|
*
|
814
|
-
*
|
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")] })
|
815
1153
|
*/
|
816
1154
|
static VALUE
|
817
|
-
|
1155
|
+
rb_xml_node_first_element_child(VALUE self)
|
818
1156
|
{
|
819
1157
|
xmlNodePtr node, child;
|
820
1158
|
Data_Get_Struct(self, xmlNode, node);
|
@@ -826,17 +1164,22 @@ first_element_child(VALUE self)
|
|
826
1164
|
}
|
827
1165
|
|
828
1166
|
/*
|
829
|
-
* call-seq:
|
830
|
-
*
|
1167
|
+
* :call-seq:
|
1168
|
+
* last_element_child() → Node
|
831
1169
|
*
|
832
|
-
* Returns
|
1170
|
+
* [Returns] The last child Node that is an element.
|
833
1171
|
*
|
834
|
-
* Example
|
1172
|
+
* *Example:*
|
835
1173
|
*
|
836
|
-
*
|
1174
|
+
* Note that the "hello" child, which is a Text node, is skipped and the <tt><span>yes</span></tt>
|
1175
|
+
* element is returned.
|
1176
|
+
*
|
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")] })
|
837
1180
|
*/
|
838
1181
|
static VALUE
|
839
|
-
|
1182
|
+
rb_xml_node_last_element_child(VALUE self)
|
840
1183
|
{
|
841
1184
|
xmlNodePtr node, child;
|
842
1185
|
Data_Get_Struct(self, xmlNode, node);
|
@@ -992,67 +1335,29 @@ set_namespace(VALUE self, VALUE namespace)
|
|
992
1335
|
}
|
993
1336
|
|
994
1337
|
/*
|
995
|
-
* call-seq:
|
996
|
-
*
|
1338
|
+
* :call-seq:
|
1339
|
+
* namespace() → Namespace
|
997
1340
|
*
|
998
|
-
*
|
999
|
-
*/
|
1000
|
-
static VALUE
|
1001
|
-
attr(VALUE self, VALUE name)
|
1002
|
-
{
|
1003
|
-
xmlNodePtr node;
|
1004
|
-
xmlAttrPtr prop;
|
1005
|
-
Data_Get_Struct(self, xmlNode, node);
|
1006
|
-
prop = xmlHasProp(node, (xmlChar *)StringValueCStr(name));
|
1007
|
-
|
1008
|
-
if (! prop) { return Qnil; }
|
1009
|
-
return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
|
1010
|
-
}
|
1011
|
-
|
1012
|
-
/*
|
1013
|
-
* call-seq:
|
1014
|
-
* attribute_with_ns(name, namespace)
|
1341
|
+
* [Returns] The Namespace of the element or attribute node, or +nil+ if there is no namespace.
|
1015
1342
|
*
|
1016
|
-
*
|
1017
|
-
*/
|
1018
|
-
static VALUE
|
1019
|
-
attribute_with_ns(VALUE self, VALUE name, VALUE namespace)
|
1020
|
-
{
|
1021
|
-
xmlNodePtr node;
|
1022
|
-
xmlAttrPtr prop;
|
1023
|
-
Data_Get_Struct(self, xmlNode, node);
|
1024
|
-
prop = xmlHasNsProp(node, (xmlChar *)StringValueCStr(name),
|
1025
|
-
NIL_P(namespace) ? NULL : (xmlChar *)StringValueCStr(namespace));
|
1026
|
-
|
1027
|
-
if (! prop) { return Qnil; }
|
1028
|
-
return noko_xml_node_wrap(Qnil, (xmlNodePtr)prop);
|
1029
|
-
}
|
1030
|
-
|
1031
|
-
/*
|
1032
|
-
* @overload attribute_nodes()
|
1033
|
-
* Get the attributes for a Node
|
1034
|
-
* @return [Array<Nokogiri::XML::Attr>] containing the Node's attributes.
|
1035
|
-
*/
|
1036
|
-
static VALUE
|
1037
|
-
attribute_nodes(VALUE rb_node)
|
1038
|
-
{
|
1039
|
-
xmlNodePtr c_node;
|
1040
|
-
|
1041
|
-
Data_Get_Struct(rb_node, xmlNode, c_node);
|
1042
|
-
|
1043
|
-
return noko_xml_node_attrs(c_node);
|
1044
|
-
}
|
1045
|
-
|
1046
|
-
|
1047
|
-
/*
|
1048
|
-
* call-seq:
|
1049
|
-
* namespace()
|
1343
|
+
* *Example:*
|
1050
1344
|
*
|
1051
|
-
*
|
1052
|
-
*
|
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" })
|
1053
1358
|
*/
|
1054
1359
|
static VALUE
|
1055
|
-
|
1360
|
+
rb_xml_node_namespace(VALUE rb_node)
|
1056
1361
|
{
|
1057
1362
|
xmlNodePtr c_node ;
|
1058
1363
|
Data_Get_Struct(rb_node, xmlNode, c_node);
|
@@ -1065,10 +1370,32 @@ noko_xml_node_namespace(VALUE rb_node)
|
|
1065
1370
|
}
|
1066
1371
|
|
1067
1372
|
/*
|
1068
|
-
*
|
1069
|
-
*
|
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.
|
1379
|
+
*
|
1380
|
+
* *Example:*
|
1070
1381
|
*
|
1071
|
-
*
|
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" })]
|
1072
1399
|
*/
|
1073
1400
|
static VALUE
|
1074
1401
|
namespace_definitions(VALUE rb_node)
|
@@ -1094,16 +1421,35 @@ namespace_definitions(VALUE rb_node)
|
|
1094
1421
|
}
|
1095
1422
|
|
1096
1423
|
/*
|
1097
|
-
*
|
1098
|
-
*
|
1424
|
+
* :call-seq:
|
1425
|
+
* namespace_scopes() → Array<Nokogiri::XML::Namespace>
|
1099
1426
|
*
|
1100
|
-
*
|
1101
|
-
*
|
1102
|
-
*
|
1103
|
-
*
|
1427
|
+
* [Returns] Array of all the Namespaces on this node and its ancestors.
|
1428
|
+
*
|
1429
|
+
* See also #namespaces
|
1430
|
+
*
|
1431
|
+
* *Example:*
|
1432
|
+
*
|
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" })]
|
1104
1450
|
*/
|
1105
1451
|
static VALUE
|
1106
|
-
|
1452
|
+
rb_xml_node_namespace_scopes(VALUE rb_node)
|
1107
1453
|
{
|
1108
1454
|
xmlNodePtr c_node ;
|
1109
1455
|
xmlNsPtr *namespaces;
|
@@ -1163,30 +1509,6 @@ set_native_content(VALUE self, VALUE content)
|
|
1163
1509
|
return content;
|
1164
1510
|
}
|
1165
1511
|
|
1166
|
-
/*
|
1167
|
-
* call-seq:
|
1168
|
-
* content
|
1169
|
-
*
|
1170
|
-
* Returns the plaintext content for this Node. Note that entities will always
|
1171
|
-
* be expanded in the returned string.
|
1172
|
-
*/
|
1173
|
-
static VALUE
|
1174
|
-
get_native_content(VALUE self)
|
1175
|
-
{
|
1176
|
-
xmlNodePtr node;
|
1177
|
-
xmlChar *content;
|
1178
|
-
|
1179
|
-
Data_Get_Struct(self, xmlNode, node);
|
1180
|
-
|
1181
|
-
content = xmlNodeGetContent(node);
|
1182
|
-
if (content) {
|
1183
|
-
VALUE rval = NOKOGIRI_STR_NEW2(content);
|
1184
|
-
xmlFree(content);
|
1185
|
-
return rval;
|
1186
|
-
}
|
1187
|
-
return Qnil;
|
1188
|
-
}
|
1189
|
-
|
1190
1512
|
/*
|
1191
1513
|
* call-seq:
|
1192
1514
|
* lang=
|
@@ -1297,7 +1619,7 @@ get_name(VALUE self)
|
|
1297
1619
|
* Returns the path associated with this Node
|
1298
1620
|
*/
|
1299
1621
|
static VALUE
|
1300
|
-
|
1622
|
+
rb_xml_node_path(VALUE rb_node)
|
1301
1623
|
{
|
1302
1624
|
xmlNodePtr c_node;
|
1303
1625
|
xmlChar *c_path ;
|
@@ -1376,18 +1698,39 @@ native_write_to(
|
|
1376
1698
|
}
|
1377
1699
|
|
1378
1700
|
/*
|
1379
|
-
* call-seq:
|
1380
|
-
*
|
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
|
1714
|
+
*
|
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)
|
1381
1720
|
*
|
1382
|
-
*
|
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
|
1383
1726
|
*/
|
1384
1727
|
static VALUE
|
1385
|
-
|
1728
|
+
rb_xml_node_line(VALUE rb_node)
|
1386
1729
|
{
|
1387
|
-
xmlNodePtr
|
1388
|
-
Data_Get_Struct(
|
1730
|
+
xmlNodePtr c_node;
|
1731
|
+
Data_Get_Struct(rb_node, xmlNode, c_node);
|
1389
1732
|
|
1390
|
-
return INT2NUM(xmlGetLineNo(
|
1733
|
+
return INT2NUM(xmlGetLineNo(c_node));
|
1391
1734
|
}
|
1392
1735
|
|
1393
1736
|
/*
|
@@ -1397,90 +1740,56 @@ line(VALUE self)
|
|
1397
1740
|
* Sets the line for this Node. num must be less than 65535.
|
1398
1741
|
*/
|
1399
1742
|
static VALUE
|
1400
|
-
|
1743
|
+
rb_xml_node_line_set(VALUE rb_node, VALUE rb_line_number)
|
1401
1744
|
{
|
1402
|
-
xmlNodePtr
|
1403
|
-
int
|
1404
|
-
|
1405
|
-
Data_Get_Struct(self, xmlNode, node);
|
1406
|
-
if (value < 65535) {
|
1407
|
-
node->line = value;
|
1408
|
-
}
|
1409
|
-
|
1410
|
-
return num;
|
1411
|
-
}
|
1412
|
-
|
1413
|
-
/*
|
1414
|
-
* call-seq:
|
1415
|
-
* add_namespace_definition(prefix, href)
|
1416
|
-
*
|
1417
|
-
* Adds a namespace definition with +prefix+ using +href+ value. The result is
|
1418
|
-
* as if parsed XML for this node had included an attribute
|
1419
|
-
* 'xmlns:prefix=value'. A default namespace for this node ("xmlns=") can be
|
1420
|
-
* added by passing 'nil' for prefix. Namespaces added this way will not
|
1421
|
-
* show up in #attributes, but they will be included as an xmlns attribute
|
1422
|
-
* when the node is serialized to XML.
|
1423
|
-
*/
|
1424
|
-
static VALUE
|
1425
|
-
add_namespace_definition(VALUE rb_node, VALUE rb_prefix, VALUE rb_href)
|
1426
|
-
{
|
1427
|
-
xmlNodePtr c_node, element;
|
1428
|
-
xmlNsPtr c_namespace;
|
1429
|
-
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);
|
1430
1747
|
|
1431
1748
|
Data_Get_Struct(rb_node, xmlNode, c_node);
|
1432
|
-
element = c_node ;
|
1433
1749
|
|
1434
|
-
|
1435
|
-
|
1436
|
-
if (
|
1437
|
-
|
1438
|
-
|
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;
|
1439
1758
|
}
|
1440
|
-
c_namespace = xmlNewNs(element, (const xmlChar *)StringValueCStr(rb_href), c_prefix);
|
1441
|
-
}
|
1442
|
-
|
1443
|
-
if (!c_namespace) {
|
1444
|
-
return Qnil ;
|
1445
|
-
}
|
1446
|
-
|
1447
|
-
if (NIL_P(rb_prefix) || c_node != element) {
|
1448
|
-
xmlSetNs(c_node, c_namespace);
|
1449
1759
|
}
|
1450
1760
|
|
1451
|
-
return
|
1761
|
+
return rb_line_number;
|
1452
1762
|
}
|
1453
1763
|
|
1454
|
-
/*
|
1455
|
-
* @overload new(name, document)
|
1456
|
-
* Create a new node with +name+ sharing GC lifecycle with +document+.
|
1457
|
-
* @param name [String]
|
1458
|
-
* @param document [Nokogiri::XML::Document]
|
1459
|
-
* @yieldparam node [Nokogiri::XML::Node]
|
1460
|
-
* @return [Nokogiri::XML::Node]
|
1461
|
-
* @see Nokogiri::XML::Node#initialize
|
1462
|
-
*/
|
1764
|
+
/* :nodoc: documented in lib/nokogiri/xml/node.rb */
|
1463
1765
|
static VALUE
|
1464
1766
|
rb_xml_node_new(int argc, VALUE *argv, VALUE klass)
|
1465
1767
|
{
|
1466
|
-
|
1467
|
-
xmlNodePtr
|
1468
|
-
VALUE
|
1469
|
-
VALUE
|
1768
|
+
xmlNodePtr c_document_node;
|
1769
|
+
xmlNodePtr c_node;
|
1770
|
+
VALUE rb_name;
|
1771
|
+
VALUE rb_document_node;
|
1470
1772
|
VALUE rest;
|
1471
1773
|
VALUE rb_node;
|
1472
1774
|
|
1473
|
-
rb_scan_args(argc, argv, "2*", &
|
1775
|
+
rb_scan_args(argc, argv, "2*", &rb_name, &rb_document_node, &rest);
|
1474
1776
|
|
1475
|
-
|
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);
|
1476
1785
|
|
1477
|
-
|
1478
|
-
|
1479
|
-
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);
|
1480
1789
|
|
1481
1790
|
rb_node = noko_xml_node_wrap(
|
1482
1791
|
klass == cNokogiriXmlNode ? (VALUE)NULL : klass,
|
1483
|
-
|
1792
|
+
c_node
|
1484
1793
|
);
|
1485
1794
|
rb_obj_call_init(rb_node, argc, argv);
|
1486
1795
|
|
@@ -1614,9 +1923,7 @@ in_context(VALUE self, VALUE _str, VALUE _options)
|
|
1614
1923
|
*/
|
1615
1924
|
child_iter = node->doc->children ;
|
1616
1925
|
while (child_iter) {
|
1617
|
-
|
1618
|
-
child_iter->parent = (xmlNodePtr)node->doc;
|
1619
|
-
}
|
1926
|
+
child_iter->parent = (xmlNodePtr)node->doc;
|
1620
1927
|
child_iter = child_iter->next;
|
1621
1928
|
}
|
1622
1929
|
|
@@ -1674,7 +1981,7 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
|
|
1674
1981
|
VALUE rb_document, rb_node_cache, rb_node;
|
1675
1982
|
nokogiriTuplePtr node_has_a_document;
|
1676
1983
|
xmlDocPtr c_doc;
|
1677
|
-
void (*
|
1984
|
+
void (*f_mark)(xmlNodePtr) = NULL ;
|
1678
1985
|
|
1679
1986
|
assert(c_node);
|
1680
1987
|
|
@@ -1736,9 +2043,9 @@ noko_xml_node_wrap(VALUE rb_class, xmlNodePtr c_node)
|
|
1736
2043
|
}
|
1737
2044
|
}
|
1738
2045
|
|
1739
|
-
|
2046
|
+
f_mark = node_has_a_document ? _xml_node_mark : NULL ;
|
1740
2047
|
|
1741
|
-
rb_node = Data_Wrap_Struct(rb_class,
|
2048
|
+
rb_node = Data_Wrap_Struct(rb_class, f_mark, _xml_node_dealloc, c_node) ;
|
1742
2049
|
c_node->_private = (void *)rb_node;
|
1743
2050
|
|
1744
2051
|
if (node_has_a_document) {
|
@@ -1779,61 +2086,59 @@ noko_init_xml_node()
|
|
1779
2086
|
|
1780
2087
|
rb_define_singleton_method(cNokogiriXmlNode, "new", rb_xml_node_new, -1);
|
1781
2088
|
|
1782
|
-
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);
|
1783
2119
|
rb_define_method(cNokogiriXmlNode, "node_name", get_name, 0);
|
1784
|
-
rb_define_method(cNokogiriXmlNode, "document", document, 0);
|
1785
2120
|
rb_define_method(cNokogiriXmlNode, "node_name=", set_name, 1);
|
2121
|
+
rb_define_method(cNokogiriXmlNode, "node_type", node_type, 0);
|
1786
2122
|
rb_define_method(cNokogiriXmlNode, "parent", get_parent, 0);
|
1787
|
-
rb_define_method(cNokogiriXmlNode, "
|
1788
|
-
rb_define_method(cNokogiriXmlNode, "
|
1789
|
-
rb_define_method(cNokogiriXmlNode, "last_element_child", last_element_child, 0);
|
1790
|
-
rb_define_method(cNokogiriXmlNode, "children", children, 0);
|
1791
|
-
rb_define_method(cNokogiriXmlNode, "element_children", element_children, 0);
|
1792
|
-
rb_define_method(cNokogiriXmlNode, "next_sibling", next_sibling, 0);
|
1793
|
-
rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
|
1794
|
-
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);
|
1795
2125
|
rb_define_method(cNokogiriXmlNode, "previous_element", previous_element, 0);
|
1796
|
-
rb_define_method(cNokogiriXmlNode, "
|
1797
|
-
rb_define_method(cNokogiriXmlNode, "path", noko_xml_node_path, 0);
|
1798
|
-
rb_define_method(cNokogiriXmlNode, "key?", key_eh, 1);
|
1799
|
-
rb_define_method(cNokogiriXmlNode, "namespaced_key?", namespaced_key_eh, 2);
|
1800
|
-
rb_define_method(cNokogiriXmlNode, "blank?", blank_eh, 0);
|
1801
|
-
rb_define_method(cNokogiriXmlNode, "attribute_nodes", attribute_nodes, 0);
|
1802
|
-
rb_define_method(cNokogiriXmlNode, "attribute", attr, 1);
|
1803
|
-
rb_define_method(cNokogiriXmlNode, "attribute_with_ns", attribute_with_ns, 2);
|
1804
|
-
rb_define_method(cNokogiriXmlNode, "namespace", noko_xml_node_namespace, 0);
|
1805
|
-
rb_define_method(cNokogiriXmlNode, "namespace_definitions", namespace_definitions, 0);
|
1806
|
-
rb_define_method(cNokogiriXmlNode, "namespace_scopes", namespace_scopes, 0);
|
1807
|
-
rb_define_method(cNokogiriXmlNode, "encode_special_chars", encode_special_chars, 1);
|
1808
|
-
rb_define_method(cNokogiriXmlNode, "dup", duplicate_node, -1);
|
2126
|
+
rb_define_method(cNokogiriXmlNode, "previous_sibling", previous_sibling, 0);
|
1809
2127
|
rb_define_method(cNokogiriXmlNode, "unlink", unlink_node, 0);
|
1810
|
-
rb_define_method(cNokogiriXmlNode, "internal_subset", internal_subset, 0);
|
1811
|
-
rb_define_method(cNokogiriXmlNode, "external_subset", external_subset, 0);
|
1812
|
-
rb_define_method(cNokogiriXmlNode, "create_internal_subset", create_internal_subset, 3);
|
1813
|
-
rb_define_method(cNokogiriXmlNode, "create_external_subset", create_external_subset, 3);
|
1814
|
-
rb_define_method(cNokogiriXmlNode, "pointer_id", pointer_id, 0);
|
1815
|
-
rb_define_method(cNokogiriXmlNode, "line", line, 0);
|
1816
|
-
rb_define_method(cNokogiriXmlNode, "line=", set_line, 1);
|
1817
|
-
rb_define_method(cNokogiriXmlNode, "content", get_native_content, 0);
|
1818
|
-
rb_define_method(cNokogiriXmlNode, "native_content=", set_native_content, 1);
|
1819
|
-
rb_define_method(cNokogiriXmlNode, "lang", get_lang, 0);
|
1820
|
-
rb_define_method(cNokogiriXmlNode, "lang=", set_lang, 1);
|
1821
2128
|
|
1822
|
-
rb_define_private_method(cNokogiriXmlNode, "process_xincludes", process_xincludes, 1);
|
1823
|
-
rb_define_private_method(cNokogiriXmlNode, "in_context", in_context, 2);
|
1824
2129
|
rb_define_private_method(cNokogiriXmlNode, "add_child_node", add_child, 1);
|
1825
|
-
rb_define_private_method(cNokogiriXmlNode, "add_previous_sibling_node", add_previous_sibling, 1);
|
1826
2130
|
rb_define_private_method(cNokogiriXmlNode, "add_next_sibling_node", add_next_sibling, 1);
|
1827
|
-
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);
|
1828
2133
|
rb_define_private_method(cNokogiriXmlNode, "dump_html", dump_html, 0);
|
1829
|
-
rb_define_private_method(cNokogiriXmlNode, "native_write_to", native_write_to, 4);
|
1830
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);
|
1831
2139
|
rb_define_private_method(cNokogiriXmlNode, "set", set, 2);
|
1832
2140
|
rb_define_private_method(cNokogiriXmlNode, "set_namespace", set_namespace, 1);
|
1833
|
-
rb_define_private_method(cNokogiriXmlNode, "compare", compare, 1);
|
1834
2141
|
|
1835
2142
|
id_decorate = rb_intern("decorate");
|
1836
2143
|
id_decorate_bang = rb_intern("decorate!");
|
1837
2144
|
}
|
1838
|
-
|
1839
|
-
/* vim: set noet sw=4 sws=4 */
|