Class: Nokolexbor::Node
- Inherits:
-
Object
- Object
- Nokolexbor::Node
- Includes:
- Enumerable
- Defined in:
- lib/nokolexbor/node.rb,
ext/nokolexbor/nl_node.c
Direct Known Subclasses
Attribute, CharacterData, Document, DocumentFragment, Element, NodeSet, ProcessingInstruction
Constant Summary collapse
- ELEMENT_NODE =
1- ATTRIBUTE_NODE =
2- TEXT_NODE =
3- CDATA_SECTION_NODE =
4- ENTITY_REF_NODE =
5- ENTITY_NODE =
6- PI_NODE =
7- COMMENT_NODE =
8- DOCUMENT_NODE =
9- DOCUMENT_TYPE_NODE =
10- DOCUMENT_FRAG_NODE =
11- NOTATION_NODE =
12- LOOKS_LIKE_XPATH =
%r{^(\./|/|\.\.|\.$)}
Instance Attribute Summary collapse
-
#document ⇒ Document
readonly
The associated Document of this node.
Class Method Summary collapse
-
.new(name, document) {|Node| ... } ⇒ Node
Create a new node with
namethat belongs todocument.
Instance Method Summary collapse
-
#<<(node_or_tags) ⇒ Node
Add
node_or_tagsas a child of this Node. -
#==(other) ⇒ Boolean
True if this Node is equal to
other. -
#[](name) ⇒ String?
(also: #attr, #get_attribute)
Fetch an attribute from this node.
-
#[]=(name, value) ⇒ String?
(also: #set_attr, #set_attribute)
Update the attribute
nametovalue, or create the attribute if it does not exist. -
#add_child(new) ⇒ Node, NodeSet
Add
newas a child of this Node. -
#add_class(names) ⇒ Node
Ensure CSS classes are present on
self. -
#add_next_sibling(node_or_tags) ⇒ Node, NodeSet
(also: #next=)
Insert
node_or_tagsafter this Node (as a sibling). -
#add_previous_sibling(node_or_tags) ⇒ Node, NodeSet
(also: #previous=)
Insert
node_or_tagsbefore this Node (as a sibling). -
#add_sibling(next_or_previous, new) ⇒ Node, NodeSet
Insert
node_or_tagsbefore or after this Node (as a sibling). -
#after(node_or_tags) ⇒ Node
Insert
node_or_tagsafter this Node (as a sibling). -
#ancestors(selector = nil) ⇒ NodeSet
Get a list of ancestor Node of this Node.
-
#append_class(names) ⇒ Node
Add CSS classes to
self, regardless of duplication. -
#at(*args) ⇒ Node?
(also: #%)
Like #search, but returns the first match.
-
#at_css(*args) ⇒ Node?
Like #css, but returns the first match.
-
#at_css_impl(selector) ⇒ Object
Internal implementation of #at_css.
-
#at_xpath(*args) ⇒ Node?
Like #xpath, but returns the first match.
-
#attribute(name) ⇒ Attribute
The attribute belonging to this node with name
name. -
#attribute_nodes ⇒ Array<Attribute>
An array of Attribute belonging to this node.
-
#attributes ⇒ Hash{String => Attribute}
Fetch this node’s attributes.
-
#attrs ⇒ Hash{String => String}
Get a hash of attribute names and values of this Node.
-
#before(node_or_tags) ⇒ Node
Insert
node_or_tagsbefore this Node (as a sibling). -
#cdata? ⇒ Boolean
True if this is a CDATA.
-
#child ⇒ Node?
Get the first child of this node.
-
#children ⇒ NodeSet
Get the children of this node.
-
#children=(node) ⇒ Object
(also: #inner_html=)
Set the content of this Node.
-
#classes ⇒ Array
Fetch CSS class names of a Node.
-
#clone ⇒ Node
(also: #dup)
Copy this node.
-
#comment? ⇒ Boolean
True if this is a Comment.
-
#content ⇒ String
(also: #text, #inner_text, #to_str)
Contents of all the text nodes in this node’s subtree, concatenated together into a single String.
-
#content=(content) ⇒ String
Set the Node’s content to a Text node containing
content. -
#css(*args) ⇒ NodeSet
Search this object for CSS
rules. -
#css_impl(selector) ⇒ Object
Internal implementation of #css.
-
#destroy ⇒ nil
Remove this node from its current context and free its allocated memory.
-
#document? ⇒ Boolean
True if this is a Document.
-
#each {|String, String| ... } ⇒ Object
Iterate over each attribute name and value pair of this Node.
-
#element? ⇒ Boolean
True if this is an Element.
-
#first_element_child ⇒ Element
The first child Node that is an element.
-
#fragment(tags) ⇒ DocumentFragment
Create a DocumentFragment containing
tagsthat is relative to this context node. -
#fragment? ⇒ Boolean
True if this is a DocumentFragment.
-
#inner_html(*args) ⇒ String
Get the inner_html of this Node.
-
#key?(name) ⇒ Boolean
(also: #has_attribute?)
True if
nameis set. -
#keys ⇒ Array<String>
Get the attribute names of this Node.
-
#kwattr_add(attribute_name, keywords) ⇒ Node
Ensure that values are present in a keyword attribute.
-
#kwattr_append(attribute_name, keywords) ⇒ Node
Add keywords to a Node’s keyword attribute, regardless of duplication.
-
#kwattr_remove(attribute_name, keywords) ⇒ Node
Remove keywords from a keyword attribute.
-
#kwattr_values(attribute_name) ⇒ Array<String>
Fetch values from a keyword attribute of a Node.
-
#last_element_child ⇒ Element
The last child Node that is an element.
-
#matches?(selector) ⇒ Boolean
True if this Node matches
selector. -
#name ⇒ String
Get the name of this Node.
-
#next ⇒ Node?
(also: #next_sibling)
Get the next sibling node.
-
#next_element ⇒ Element?
Get the next sibling element.
-
#node_type ⇒ Integer
(also: #type)
Get the type of this Node.
-
#nokogiri_at_css(*args) ⇒ Node?
Like #nokogiri_css, but returns the first match.
-
#nokogiri_css(*args) ⇒ NodeSet
Search this object for CSS
rules. -
#outer_html(*args) ⇒ String
(also: #to_html, #serialize, #to_s)
Serialize this Node to HTML, also known as outer_html.
-
#parent ⇒ Node?
Get the parent node.
-
#parent=(parent_node) ⇒ Object
Set the parent Node of this Node.
-
#parse(html) ⇒ NodeSet
Parse
htmlas a document fragment within the context of this node. -
#prepend_child(node) ⇒ Node, NodeSet
Add
nodeas the first child of this Node. -
#previous ⇒ Node?
(also: #previous_sibling)
Get the previous sibling node.
-
#previous_element ⇒ Element?
Get the previous sibling element.
-
#processing_instruction? ⇒ Boolean
True if this is a ProcessingInstruction.
-
#remove ⇒ Node
(also: #unlink)
Remove this node from its current context.
-
#remove_attr(name) ⇒ Boolean
(also: #delete, #remove_attribute)
Remove the attribute named
name. -
#remove_class(names = nil) ⇒ Node
Remove CSS classes from this node.
-
#replace(node) ⇒ Node, NodeSet
Replace this Node with
node. -
#search(*args) ⇒ NodeSet
(also: #/)
Search this object for
paths. -
#swap(node) ⇒ Node
Swap this Node for
node. -
#text? ⇒ Boolean
True if this is a Text.
-
#traverse { ... } ⇒ Object
Traverse self and all children.
-
#values ⇒ Array<String>
Get the attribute values of this Node.
-
#wrap(node) ⇒ Node
Wrap this Node with another node.
-
#write_to(io, *options) ⇒ Object
(also: #write_html_to)
Serialize Node and write to
io. -
#xpath(*args) ⇒ NodeSet
Search this node for XPath
paths.
Instance Attribute Details
Class Method Details
.new(name, document) {|Node| ... } ⇒ Node
Create a new node with name that belongs to document.
If you intend to add a node to a document tree, it’s likely that you will prefer one of the Nokolexbor::Node methods like #add_child, #add_next_sibling, #replace, etc. which will both create an element (or subtree) and place it in the document tree.
Another alternative, if you are concerned about performance, is Document#create_element which accepts additional arguments for contents or attributes but (like this method) avoids parsing markup.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'ext/nokolexbor/nl_node.c', line 104 static VALUE nl_node_new(int argc, VALUE *argv, VALUE klass) { lxb_dom_document_t *document; VALUE rb_name; VALUE rb_document; VALUE rest; rb_scan_args(argc, argv, "2*", &rb_name, &rb_document, &rest); if (!rb_obj_is_kind_of(rb_document, cNokolexborDocument)) { rb_raise(rb_eArgError, "Document must be a Nokolexbor::Document"); } document = nl_rb_document_unwrap(rb_document); const char *c_name = StringValuePtr(rb_name); size_t name_len = RSTRING_LEN(rb_name); lxb_dom_element_t *element = lxb_dom_document_create_element(document, (const lxb_char_t *)c_name, name_len, NULL); if (element == NULL) { rb_raise(rb_eRuntimeError, "Error creating element"); } VALUE rb_node = nl_rb_node_create(&element->node, rb_document); if (rb_block_given_p()) { rb_yield(rb_node); } return rb_node; } |
Instance Method Details
#<<(node_or_tags) ⇒ Node
Add node_or_tags as a child of this Node.
200 201 202 203 |
# File 'lib/nokolexbor/node.rb', line 200 def <<() add_child() self end |
#==(other) ⇒ Boolean
Returns true if this Node is equal to other.
849 850 851 852 853 854 855 |
# File 'ext/nokolexbor/nl_node.c', line 849 static VALUE nl_node_equals(VALUE self, VALUE other) { lxb_dom_node_t *node1 = nl_rb_node_unwrap(self); lxb_dom_node_t *node2 = nl_rb_node_unwrap(other); return node1 == node2 ? Qtrue : Qfalse; } |
#[](name) ⇒ String? Also known as: attr, get_attribute
Fetch an attribute from this node.
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'ext/nokolexbor/nl_node.c', line 243 static VALUE nl_node_get_attr(VALUE self, VALUE rb_attr) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return Qnil; } VALUE rb_attr_s = rb_String(rb_attr); const char *attr_c = RSTRING_PTR(rb_attr_s); size_t attr_len = RSTRING_LEN(rb_attr_s); lxb_dom_element_t *element = lxb_dom_interface_element(node); if (!lxb_dom_element_has_attribute(element, (const lxb_char_t *)attr_c, attr_len)) { return Qnil; } size_t attr_value_len; const lxb_char_t *attr_value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)attr_c, attr_len, &attr_value_len); return rb_utf8_str_new((const char *)attr_value, attr_value_len); } |
#[]=(name, value) ⇒ String? Also known as: set_attr, set_attribute
Update the attribute name to value, or create the attribute if it does not exist.
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'ext/nokolexbor/nl_node.c', line 278 static VALUE nl_node_set_attr(VALUE self, VALUE rb_attr, VALUE rb_value) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return Qnil; } VALUE rb_attr_s = rb_String(rb_attr); VALUE rb_value_s = rb_String(rb_value); const char *attr_c = RSTRING_PTR(rb_attr_s); size_t attr_len = RSTRING_LEN(rb_attr_s); const char *value_c = RSTRING_PTR(rb_value_s); size_t value_len = RSTRING_LEN(rb_value_s); lxb_dom_element_t *element = lxb_dom_interface_element(node); lxb_dom_element_set_attribute(element, (const lxb_char_t *)attr_c, attr_len, (const lxb_char_t *)value_c, value_len); return rb_value; } |
#add_child(new) ⇒ Node, NodeSet
Add new as a child of this Node.
1010 1011 1012 1013 1014 |
# File 'ext/nokolexbor/nl_node.c', line 1010 static VALUE nl_node_add_child(VALUE self, VALUE new) { return nl_node_add_nodes(self, new, lxb_dom_node_insert_child, false); } |
#add_class(names) ⇒ Node
Ensure CSS classes are present on self. Any CSS classes in names that already exist in the “class” attribute are not added. Note that any existing duplicates in the “class” attribute are not removed. Compare with #append_class.
This is a convenience function and is equivalent to:
node.kwattr_add("class", names)
468 469 470 |
# File 'lib/nokolexbor/node.rb', line 468 def add_class(names) kwattr_add("class", names) end |
#add_next_sibling(node_or_tags) ⇒ Node, NodeSet Also known as: next=
Insert node_or_tags after this Node (as a sibling).
157 158 159 160 161 162 |
# File 'lib/nokolexbor/node.rb', line 157 def add_next_sibling() raise ArgumentError, "A document may not have multiple root nodes." if parent&.document? && !(.comment? || .processing_instruction?) add_sibling(:next, ) end |
#add_previous_sibling(node_or_tags) ⇒ Node, NodeSet Also known as: previous=
Insert node_or_tags before this Node (as a sibling).
143 144 145 146 147 148 |
# File 'lib/nokolexbor/node.rb', line 143 def add_previous_sibling() raise ArgumentError, "A document may not have multiple root nodes." if parent&.document? && !(.comment? || .processing_instruction?) add_sibling(:previous, ) end |
#add_sibling(next_or_previous, new) ⇒ Node, NodeSet
Insert node_or_tags before or after this Node (as a sibling).
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 |
# File 'ext/nokolexbor/nl_node.c', line 987 static VALUE nl_node_add_sibling(VALUE self, VALUE next_or_previous, VALUE new) { bool insert_after; if (rb_eql(rb_String(next_or_previous), rb_str_new_literal("next"))) { insert_after = true; } else if (rb_eql(rb_String(next_or_previous), rb_str_new_literal("previous"))) { insert_after = false; } else { rb_raise(rb_eArgError, "Unsupported inserting position"); } return insert_after ? nl_node_add_nodes(self, new, lxb_dom_node_insert_after, true) : nl_node_add_nodes(self, new, lxb_dom_node_insert_before, false); } |
#after(node_or_tags) ⇒ Node
Insert node_or_tags after this Node (as a sibling).
183 184 185 186 |
# File 'lib/nokolexbor/node.rb', line 183 def after() add_next_sibling() self end |
#ancestors(selector = nil) ⇒ NodeSet
Get a list of ancestor Node of this Node
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/nokolexbor/node.rb', line 65 def ancestors(selector = nil) return NodeSet.new(@document) unless respond_to?(:parent) return NodeSet.new(@document) unless parent parents = [parent] while parents.last.respond_to?(:parent) break unless (ctx_parent = parents.last.parent) parents << ctx_parent end return NodeSet.new(@document, parents) unless selector root = parents.last search_results = root.search(selector) NodeSet.new(@document, parents.find_all do |parent| search_results.include?(parent) end) end |
#append_class(names) ⇒ Node
Add CSS classes to self, regardless of duplication. Compare with #add_class.
This is a convenience function and is equivalent to:
node.kwattr_append("class", names)
484 485 486 |
# File 'lib/nokolexbor/node.rb', line 484 def append_class(names) kwattr_append("class", names) end |
#at(*args) ⇒ Node? Also known as: %
Like #search, but returns the first match.
409 410 411 412 413 414 415 416 417 |
# File 'lib/nokolexbor/node.rb', line 409 def at(*args) paths, handler, ns, binds = extract_params(args) if paths.size == 1 && !LOOKS_LIKE_XPATH.match?(paths.first) return at_css(paths.first) end at_xpath(*(paths + [ns, handler, binds].compact)) end |
#at_css(*args) ⇒ Node?
Like #css, but returns the first match.
This method uses Lexbor as the selector engine. Its performance is much higher than #at_xpath or #nokogiri_at_css.
333 334 335 |
# File 'lib/nokolexbor/node.rb', line 333 def at_css(*args) at_css_impl(args.join(', ')) end |
#at_css_impl(selector) ⇒ Object
Internal implementation of #at_css
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 |
# File 'ext/nokolexbor/nl_node.c', line 464 static VALUE nl_node_at_css(VALUE self, VALUE selector) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lexbor_array_t *array = lexbor_array_create(); lxb_status_t status = nl_node_find(self, selector, nl_node_at_css_callback, array); if (status != LXB_STATUS_OK) { lexbor_array_destroy(array, true); nl_raise_lexbor_error(status); } if (array->length == 0) { lexbor_array_destroy(array, true); return Qnil; } nl_sort_nodes_if_necessary(selector, node->owner_document, array); VALUE ret = nl_rb_node_create(array->list[0], nl_rb_document_get(self)); lexbor_array_destroy(array, true); return ret; } |
#at_xpath(*args) ⇒ Node?
Like #xpath, but returns the first match.
It works the same way as Nokogiri::Node#at_xpath.
385 386 387 |
# File 'lib/nokolexbor/node.rb', line 385 def at_xpath(*args) xpath(*args).first end |
#attribute(name) ⇒ Attribute
Returns The attribute belonging to this node with name name.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'ext/nokolexbor/nl_node.c', line 141 static VALUE nl_node_attribute(VALUE self, VALUE rb_name) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); const char *c_name = StringValuePtr(rb_name); size_t name_len = RSTRING_LEN(rb_name); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return Qnil; } lxb_dom_attr_t *attr = lxb_dom_element_attr_by_name(lxb_dom_interface_element(node), (const lxb_char_t *)c_name, name_len); if (attr == NULL) { return Qnil; } if (attr->owner == NULL) { attr->owner = lxb_dom_interface_element(node); } return nl_rb_node_create(attr, nl_rb_document_get(self)); } |
#attribute_nodes ⇒ Array<Attribute>
Returns An array of Attribute belonging to this node.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'ext/nokolexbor/nl_node.c', line 166 static VALUE nl_node_attribute_nodes(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); VALUE ary = rb_ary_new(); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return ary; } lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_dom_interface_element(node)); if (attr == NULL) { return ary; } VALUE rb_doc = nl_rb_document_get(self); while (attr != NULL) { if (attr->owner == NULL) { attr->owner = lxb_dom_interface_element(node); } rb_ary_push(ary, nl_rb_node_create(attr, rb_doc)); attr = attr->next; } return ary; } |
#attributes ⇒ Hash{String => Attribute}
Fetch this node’s attributes.
240 241 242 243 244 |
# File 'lib/nokolexbor/node.rb', line 240 def attributes attribute_nodes.each_with_object({}) do |node, hash| hash[node.name] = node end end |
#attrs ⇒ Hash{String => String}
Get a hash of attribute names and values of this Node.
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 |
# File 'ext/nokolexbor/nl_node.c', line 685 static VALUE nl_node_attrs(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); VALUE rb_hash = rb_hash_new(); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return rb_hash; } lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_dom_interface_element(node)); while (attr != NULL) { size_t tmp_len; const lxb_char_t *tmp = lxb_dom_attr_qualified_name(attr, &tmp_len); VALUE rb_key = rb_utf8_str_new((const char *)tmp, tmp_len); tmp = lxb_dom_attr_value(attr, &tmp_len); VALUE rb_value = tmp != NULL ? rb_utf8_str_new((const char *)tmp, tmp_len) : rb_str_new("", 0); rb_hash_aset(rb_hash, rb_key, rb_value); attr = lxb_dom_element_next_attribute(attr); } return rb_hash; } |
#before(node_or_tags) ⇒ Node
Insert node_or_tags before this Node (as a sibling).
171 172 173 174 |
# File 'lib/nokolexbor/node.rb', line 171 def before() add_previous_sibling() self end |
#cdata? ⇒ Boolean
Returns true if this is a CDATA.
31 32 33 |
# File 'lib/nokolexbor/node.rb', line 31 def cdata? type == CDATA_SECTION_NODE end |
#child ⇒ Node?
Get the first child of this node.
810 811 812 813 814 815 816 |
# File 'ext/nokolexbor/nl_node.c', line 810 static VALUE nl_node_child(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lxb_dom_node_t *child = node->first_child; return child ? nl_rb_node_create(child, nl_rb_document_get(self)) : Qnil; } |
#children ⇒ NodeSet
Get the children of this node.
790 791 792 793 794 795 796 797 798 799 800 801 802 803 |
# File 'ext/nokolexbor/nl_node.c', line 790 static VALUE nl_node_children(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lxb_dom_node_t *child = node->first_child; lexbor_array_t *array = lexbor_array_create(); while (child != NULL) { lexbor_array_push(array, child); child = child->next; } return nl_rb_node_set_create_with_data(array, nl_rb_document_get(self)); } |
#children=(node) ⇒ Object Also known as: inner_html=
Set the content of this Node.
276 277 278 279 |
# File 'lib/nokolexbor/node.rb', line 276 def children=(node) children.remove add_child(node) end |
#classes ⇒ Array
Fetch CSS class names of a Node.
This is a convenience function and is equivalent to:
node.kwattr_values("class")
438 439 440 |
# File 'lib/nokolexbor/node.rb', line 438 def classes kwattr_values("class") end |
#clone ⇒ Node Also known as: dup
Copy this node.
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 |
# File 'ext/nokolexbor/nl_node.c', line 1092 static VALUE nl_node_clone(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lxb_dom_node_t *clone; switch (node->type) { case LXB_DOM_NODE_TYPE_ATTRIBUTE: clone = (lxb_dom_node_t *)lxb_dom_attr_interface_clone(node->owner_document, lxb_dom_interface_attr(node)); case LXB_DOM_NODE_TYPE_CDATA_SECTION: clone = (lxb_dom_node_t *)lxb_dom_cdata_section_interface_clone(node->owner_document, lxb_dom_interface_cdata_section(node)); default: clone = lxb_dom_node_clone(node, true); break; } return nl_rb_node_create(clone, nl_rb_document_get(self)); } |
#comment? ⇒ Boolean
Returns true if this is a Comment.
26 27 28 |
# File 'lib/nokolexbor/node.rb', line 26 def comment? type == COMMENT_NODE end |
#content ⇒ String Also known as: text, inner_text, to_str
Returns Contents of all the text nodes in this node’s subtree, concatenated together into a single String.
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'ext/nokolexbor/nl_node.c', line 198 static VALUE nl_node_content(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); size_t str_len = 0; lxb_char_t *text = lxb_dom_node_text_content(node, &str_len); if (text == NULL) { return rb_str_new("", 0); } VALUE rb_str = rb_utf8_str_new((char *)text, str_len); lxb_dom_document_destroy_text(node->owner_document, text); return rb_str; } |
#content=(content) ⇒ String
Set the Node’s content to a Text node containing content. The string gets XML escaped, not interpreted as markup.
220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'ext/nokolexbor/nl_node.c', line 220 static VALUE nl_node_content_set(VALUE self, VALUE content) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); const char *c_content = StringValuePtr(content); size_t content_len = RSTRING_LEN(content); lxb_status_t status = lxb_dom_node_text_content_set(node, (const lxb_char_t *)c_content, content_len); if (status != LXB_STATUS_OK) { nl_raise_lexbor_error(status); } return content; } |
#css(*args) ⇒ NodeSet
Search this object for CSS rules. rules must be one or more CSS selectors.
This method uses Lexbor as the selector engine. Its performance is much higher than #xpath or #nokogiri_css.
321 322 323 |
# File 'lib/nokolexbor/node.rb', line 321 def css(*args) css_impl(args.join(', ')) end |
#css_impl(selector) ⇒ Object
Internal implementation of #css
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 |
# File 'ext/nokolexbor/nl_node.c', line 496 static VALUE nl_node_css(VALUE self, VALUE selector) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lexbor_array_t *array = lexbor_array_create(); lxb_status_t status = nl_node_find(self, selector, nl_node_css_callback, array); if (status != LXB_STATUS_OK) { lexbor_array_destroy(array, true); nl_raise_lexbor_error(status); } nl_sort_nodes_if_necessary(selector, node->owner_document, array); return nl_rb_node_set_create_with_data(array, nl_rb_document_get(self)); } |
#destroy ⇒ nil
Remove this node from its current context and free its allocated memory.
838 839 840 841 842 843 844 |
# File 'ext/nokolexbor/nl_node.c', line 838 static VALUE nl_node_destroy(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lxb_dom_node_destroy(node); return Qnil; } |
#document? ⇒ Boolean
Returns true if this is a Document.
56 57 58 |
# File 'lib/nokolexbor/node.rb', line 56 def document? is_a?(Nokolexbor::Document) end |
#each {|String, String| ... } ⇒ Object
Iterate over each attribute name and value pair of this Node.
291 292 293 294 295 |
# File 'lib/nokolexbor/node.rb', line 291 def each attributes.each do |name, node| yield [name, node.value] end end |
#element? ⇒ Boolean
Returns true if this is an Element.
51 52 53 |
# File 'lib/nokolexbor/node.rb', line 51 def element? type == ELEMENT_NODE end |
#first_element_child ⇒ Element
Returns The first child Node that is an element.
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 |
# File 'ext/nokolexbor/nl_node.c', line 1030 static VALUE nl_node_first_element_child(VALUE self) { lxb_dom_node_t *parent = nl_rb_node_unwrap(self); lxb_dom_node_t *cur; if (parent == NULL) { return Qnil; } switch (parent->type) { case LXB_DOM_NODE_TYPE_ELEMENT: case LXB_DOM_NODE_TYPE_ENTITY: case LXB_DOM_NODE_TYPE_DOCUMENT: cur = parent->first_child; break; default: return Qnil; } while (cur != NULL) { if (cur->type == LXB_DOM_NODE_TYPE_ELEMENT) { return nl_rb_node_create(cur, nl_rb_document_get(self)); } cur = cur->next; } return Qnil; } |
#fragment(tags) ⇒ DocumentFragment
Create a DocumentFragment containing tags that is relative to this context node.
301 302 303 |
# File 'lib/nokolexbor/node.rb', line 301 def fragment() Nokolexbor::DocumentFragment.new(document, , self) end |
#fragment? ⇒ Boolean
Returns true if this is a DocumentFragment.
46 47 48 |
# File 'lib/nokolexbor/node.rb', line 46 def fragment? type == DOCUMENT_FRAG_NODE end |
#inner_html(*args) ⇒ String
Get the inner_html of this Node.
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
# File 'ext/nokolexbor/nl_node.c', line 518 static VALUE nl_node_inner_html(int argc, VALUE *argv, VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lexbor_str_t str = {0}; VALUE ; lxb_status_t status; size_t indent = 0; rb_scan_args(argc, argv, "01", &); if (TYPE() == T_HASH) { VALUE rb_indent = rb_hash_aref(, ID2SYM(rb_intern("indent"))); if (!NIL_P(rb_indent)) { indent = NUM2INT(rb_indent); } } if (indent > 0) { status = lxb_html_serialize_pretty_deep_str(node, 0, 0, &str); } else { status = lxb_html_serialize_deep_str(node, &str); } if (status != LXB_STATUS_OK) { if (str.data != NULL) { lexbor_str_destroy(&str, node->owner_document->text, false); } nl_raise_lexbor_error(status); } if (str.data != NULL) { VALUE ret = rb_utf8_str_new((const char *)str.data, str.length); lexbor_str_destroy(&str, node->owner_document->text, false); return ret; } return Qnil; } |
#key?(name) ⇒ Boolean Also known as: has_attribute?
Returns true if name is set.
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 |
# File 'ext/nokolexbor/nl_node.c', line 602 static VALUE nl_node_has_key(VALUE self, VALUE rb_attr) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return Qfalse; } VALUE rb_attr_s = rb_String(rb_attr); const char *attr_c = RSTRING_PTR(rb_attr_s); size_t attr_len = RSTRING_LEN(rb_attr_s); lxb_dom_element_t *element = lxb_dom_interface_element(node); return lxb_dom_element_has_attribute(element, (const lxb_char_t *)attr_c, attr_len) ? Qtrue : Qfalse; } |
#keys ⇒ Array<String>
Get the attribute names of this Node.
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 |
# File 'ext/nokolexbor/nl_node.c', line 625 static VALUE nl_node_keys(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); VALUE ary_keys = rb_ary_new(); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return ary_keys; } lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_dom_interface_element(node)); while (attr != NULL) { size_t tmp_len; const lxb_char_t *tmp = lxb_dom_attr_qualified_name(attr, &tmp_len); rb_ary_push(ary_keys, rb_utf8_str_new((const char *)tmp, tmp_len)); attr = lxb_dom_element_next_attribute(attr); } return ary_keys; } |
#kwattr_add(attribute_name, keywords) ⇒ Node
Ensure that values are present in a keyword attribute.
Any values in keywords that already exist in the Node’s attribute values are not added. Note that any existing duplicates in the attribute values are not removed. Compare with #kwattr_append.
A “keyword attribute” is a node attribute that contains a set of space-delimited values. Perhaps the most familiar example of this is the HTML “class” attribute used to contain CSS classes. But other keyword attributes exist, for instance the “rel” attribute.
563 564 565 566 567 568 569 |
# File 'lib/nokolexbor/node.rb', line 563 def kwattr_add(attribute_name, keywords) keywords = keywordify(keywords) current_kws = kwattr_values(attribute_name) new_kws = (current_kws + (keywords - current_kws)).join(" ") set_attr(attribute_name, new_kws) self end |
#kwattr_append(attribute_name, keywords) ⇒ Node
Add keywords to a Node’s keyword attribute, regardless of duplication. Compare with #kwattr_add.
A “keyword attribute” is a node attribute that contains a set of space-delimited values. Perhaps the most familiar example of this is the HTML “class” attribute used to contain CSS classes. But other keyword attributes exist, for instance the “rel” attribute.
592 593 594 595 596 597 598 |
# File 'lib/nokolexbor/node.rb', line 592 def kwattr_append(attribute_name, keywords) keywords = keywordify(keywords) current_kws = kwattr_values(attribute_name) new_kws = (current_kws + keywords).join(" ") set_attr(attribute_name, new_kws) self end |
#kwattr_remove(attribute_name, keywords) ⇒ Node
Remove keywords from a keyword attribute. Any matching keywords that exist in the named attribute are removed, including any multiple entries.
If no keywords remain after this operation, or if keywords is nil, the attribute is deleted from the node.
A “keyword attribute” is a node attribute that contains a set of space-delimited values. Perhaps the most familiar example of this is the HTML “class” attribute used to contain CSS classes. But other keyword attributes exist, for instance the “rel” attribute.
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 |
# File 'lib/nokolexbor/node.rb', line 624 def kwattr_remove(attribute_name, keywords) if keywords.nil? remove_attr(attribute_name) return self end keywords = keywordify(keywords) current_kws = kwattr_values(attribute_name) new_kws = current_kws - keywords if new_kws.empty? remove_attr(attribute_name) else set_attr(attribute_name, new_kws.join(" ")) end self end |
#kwattr_values(attribute_name) ⇒ Array<String>
Fetch values from a keyword attribute of a Node.
A “keyword attribute” is a node attribute that contains a set of space-delimited values. Perhaps the most familiar example of this is the HTML “class” attribute used to contain CSS classes. But other keyword attributes exist, for instance the “rel” attribute.
@#kwattr_append @#kwattr_remove
535 536 537 |
# File 'lib/nokolexbor/node.rb', line 535 def kwattr_values(attribute_name) keywordify(attr(attribute_name) || []) end |
#last_element_child ⇒ Element
Returns The last child Node that is an element.
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 |
# File 'ext/nokolexbor/nl_node.c', line 1060 static VALUE nl_node_last_element_child(VALUE self) { lxb_dom_node_t *parent = nl_rb_node_unwrap(self); lxb_dom_node_t *cur; if (parent == NULL) { return Qnil; } switch (parent->type) { case LXB_DOM_NODE_TYPE_ELEMENT: case LXB_DOM_NODE_TYPE_ENTITY: case LXB_DOM_NODE_TYPE_DOCUMENT: cur = parent->last_child; break; default: return Qnil; } while (cur != NULL) { if (cur->type == LXB_DOM_NODE_TYPE_ELEMENT) { return nl_rb_node_create(cur, nl_rb_document_get(self)); } cur = cur->prev; } return Qnil; } |
#matches?(selector) ⇒ Boolean
Returns true if this Node matches selector.
233 234 235 |
# File 'lib/nokolexbor/node.rb', line 233 def matches?(selector) ancestors.last.css(selector).any? { |node| node == self } end |
#name ⇒ String
Get the name of this Node
872 873 874 875 876 877 878 879 |
# File 'ext/nokolexbor/nl_node.c', line 872 static VALUE nl_node_name(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); size_t len; const lxb_char_t *name = lxb_dom_node_name_qualified(node, &len); return rb_utf8_str_new((const char *)name, len); } |
#next ⇒ Node? Also known as: next_sibling
Get the next sibling node.
760 761 762 763 764 765 |
# File 'ext/nokolexbor/nl_node.c', line 760 static VALUE nl_node_next(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); return node->next ? nl_rb_node_create(node->next, nl_rb_document_get(self)) : Qnil; } |
#next_element ⇒ Element?
Get the next sibling element.
772 773 774 775 776 777 778 779 780 781 782 783 |
# File 'ext/nokolexbor/nl_node.c', line 772 static VALUE nl_node_next_element(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); while (node->next != NULL) { node = node->next; if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) { return nl_rb_node_create(node, nl_rb_document_get(self)); } } return Qnil; } |
#node_type ⇒ Integer Also known as: type
Get the type of this Node
1021 1022 1023 1024 1025 |
# File 'ext/nokolexbor/nl_node.c', line 1021 static VALUE nl_node_get_type(VALUE self) { return INT2NUM(nl_rb_node_unwrap(self)->type); } |
#nokogiri_at_css(*args) ⇒ Node?
Like #nokogiri_css, but returns the first match.
This method uses libxml2 as the selector engine. It works the same way as Nokogiri::Node#at_css.
359 360 361 |
# File 'lib/nokolexbor/node.rb', line 359 def nokogiri_at_css(*args) nokogiri_css(*args).first end |
#nokogiri_css(*args) ⇒ NodeSet
Search this object for CSS rules. rules must be one or more CSS selectors. It supports a mixed syntax of CSS selectors and XPath.
This method uses libxml2 as the selector engine. It works the same way as Nokogiri::Node#css.
345 346 347 348 349 |
# File 'lib/nokolexbor/node.rb', line 345 def nokogiri_css(*args) rules, handler, ns, _ = extract_params(args) nokogiri_css_internal(self, rules, handler, ns) end |
#outer_html(*args) ⇒ String Also known as: to_html, serialize, to_s
Serialize this Node to HTML, also known as outer_html.
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 |
# File 'ext/nokolexbor/nl_node.c', line 560 static VALUE nl_node_outer_html(int argc, VALUE *argv, VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lexbor_str_t str = {0}; VALUE ; lxb_status_t status; size_t indent = 0; rb_scan_args(argc, argv, "01", &); if (TYPE() == T_HASH) { VALUE rb_indent = rb_hash_aref(, ID2SYM(rb_intern("indent"))); if (!NIL_P(rb_indent)) { indent = NUM2INT(rb_indent); } } if (indent > 0) { status = lxb_html_serialize_pretty_tree_str(node, 0, 0, &str); } else { status = lxb_html_serialize_tree_str(node, &str); } if (status != LXB_STATUS_OK) { if (str.data != NULL) { lexbor_str_destroy(&str, node->owner_document->text, false); } nl_raise_lexbor_error(status); } if (str.data != NULL) { VALUE ret = rb_utf8_str_new((const char *)str.data, str.length); lexbor_str_destroy(&str, node->owner_document->text, false); return ret; } return Qnil; } |
#parent ⇒ Node?
Get the parent node.
718 719 720 721 722 723 |
# File 'ext/nokolexbor/nl_node.c', line 718 static VALUE nl_node_parent(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); return node->parent ? nl_rb_node_create(node->parent, nl_rb_document_get(self)) : Qnil; } |
#parent=(parent_node) ⇒ Object
Set the parent Node of this Node.
284 285 286 |
# File 'lib/nokolexbor/node.rb', line 284 def parent=(parent_node) parent_node.add_child(self) end |
#parse(html) ⇒ NodeSet
Parse html as a document fragment within the context of this node.
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
# File 'ext/nokolexbor/nl_node.c', line 910 static VALUE nl_node_parse(VALUE self, VALUE html) { Check_Type(html, T_STRING); lxb_dom_node_t *node = nl_rb_node_unwrap(self); lxb_dom_document_t *doc = node->owner_document; lxb_dom_node_t *frag_root = nl_node_parse_fragment(doc, lxb_dom_interface_element(node), (lxb_char_t *)RSTRING_PTR(html), RSTRING_LEN(html)); lexbor_array_t *array = lexbor_array_create(); while (frag_root->first_child != NULL) { lxb_dom_node_t *child = frag_root->first_child; lxb_dom_node_remove(child); lexbor_array_push(array, child); } lxb_dom_node_destroy(frag_root); return nl_rb_node_set_create_with_data(array, nl_rb_document_get(self)); } |
#prepend_child(node) ⇒ Node, NodeSet
Add node as the first child of this Node.
212 213 214 215 216 217 218 219 220 221 |
# File 'lib/nokolexbor/node.rb', line 212 def prepend_child(node) if (first = children.first) # Mimic the error add_child would raise. raise "Document already has a root node" if document? && !(node.comment? || node.processing_instruction?) first.add_sibling(:previous, node) else add_child(node) end end |
#previous ⇒ Node? Also known as: previous_sibling
Get the previous sibling node.
730 731 732 733 734 735 |
# File 'ext/nokolexbor/nl_node.c', line 730 static VALUE nl_node_previous(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); return node->prev ? nl_rb_node_create(node->prev, nl_rb_document_get(self)) : Qnil; } |
#previous_element ⇒ Element?
Get the previous sibling element.
742 743 744 745 746 747 748 749 750 751 752 753 |
# File 'ext/nokolexbor/nl_node.c', line 742 static VALUE nl_node_previous_element(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); while (node->prev != NULL) { node = node->prev; if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) { return nl_rb_node_create(node, nl_rb_document_get(self)); } } return Qnil; } |
#processing_instruction? ⇒ Boolean
Returns true if this is a ProcessingInstruction.
36 37 38 |
# File 'lib/nokolexbor/node.rb', line 36 def processing_instruction? type == PI_NODE end |
#remove ⇒ Node Also known as: unlink
Remove this node from its current context.
823 824 825 826 827 828 829 |
# File 'ext/nokolexbor/nl_node.c', line 823 static VALUE nl_node_remove(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); lxb_dom_node_remove(node); return self; } |
#remove_attr(name) ⇒ Boolean Also known as: delete, remove_attribute
Remove the attribute named name.
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'ext/nokolexbor/nl_node.c', line 311 static VALUE nl_node_remove_attr(VALUE self, VALUE rb_attr) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return Qfalse; } VALUE rb_attr_s = rb_String(rb_attr); const char *attr_c = RSTRING_PTR(rb_attr_s); size_t attr_len = RSTRING_LEN(rb_attr_s); lxb_dom_element_t *element = lxb_dom_interface_element(node); lxb_status_t status = lxb_dom_element_remove_attribute(element, (const lxb_char_t *)attr_c, attr_len); if (status != LXB_STATUS_OK) { nl_raise_lexbor_error(status); } return Qtrue; } |
#remove_class(names = nil) ⇒ Node
Remove CSS classes from this node. Any CSS class names in css_classes that exist in this node’s “class” attribute are removed, including any multiple entries.
If no CSS classes remain after this operation, or if css_classes is nil, the “class” attribute is deleted from the node.
This is a convenience function and is equivalent to:
node.kwattr_remove("class", css_classes)
514 515 516 |
# File 'lib/nokolexbor/node.rb', line 514 def remove_class(names = nil) kwattr_remove("class", names) end |
#replace(node) ⇒ Node, NodeSet
Replace this Node with node.
253 254 255 256 257 |
# File 'lib/nokolexbor/node.rb', line 253 def replace(node) ret = add_sibling(:previous, node) remove ret end |
#search(*args) ⇒ NodeSet Also known as: /
Search this object for paths. paths must be one or more XPath or CSS selectors.
392 393 394 395 396 397 398 399 400 |
# File 'lib/nokolexbor/node.rb', line 392 def search(*args) paths, handler, ns, binds = extract_params(args) if paths.size == 1 && !LOOKS_LIKE_XPATH.match?(paths.first) return css(paths.first) end xpath(*(paths + [ns, handler, binds].compact)) end |
#swap(node) ⇒ Node
Swap this Node for node.
266 267 268 269 |
# File 'lib/nokolexbor/node.rb', line 266 def swap(node) replace(node) self end |
#text? ⇒ Boolean
Returns true if this is a Text.
41 42 43 |
# File 'lib/nokolexbor/node.rb', line 41 def text? type == TEXT_NODE end |
#traverse { ... } ⇒ Object
Traverse self and all children.
225 226 227 228 |
# File 'lib/nokolexbor/node.rb', line 225 def traverse(&block) children.each { |j| j.traverse(&block) } yield(self) end |
#values ⇒ Array<String>
Get the attribute values of this Node.
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 |
# File 'ext/nokolexbor/nl_node.c', line 653 static VALUE nl_node_values(VALUE self) { lxb_dom_node_t *node = nl_rb_node_unwrap(self); VALUE ary_values = rb_ary_new(); if (node->type != LXB_DOM_NODE_TYPE_ELEMENT) { return ary_values; } lxb_dom_attr_t *attr = lxb_dom_element_first_attribute(lxb_dom_interface_element(node)); while (attr != NULL) { size_t tmp_len; const lxb_char_t *tmp = lxb_dom_attr_value(attr, &tmp_len); if (tmp != NULL) { rb_ary_push(ary_values, rb_utf8_str_new((const char *)tmp, tmp_len)); } else { rb_ary_push(ary_values, rb_str_new("", 0)); } attr = lxb_dom_element_next_attribute(attr); } return ary_values; } |
#wrap(node) ⇒ Node
Wrap this Node with another node.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/nokolexbor/node.rb', line 114 def wrap(node) case node when String new_parent = fragment(node).child when DocumentFragment new_parent = node.child when Node new_parent = node.dup else raise ArgumentError, "Requires a String or Node argument, and cannot accept a #{node.class}" end if parent add_sibling(:next, new_parent) else new_parent.remove end new_parent.add_child(self) self end |
#write_to(io, *options) ⇒ Object Also known as: write_html_to
Serialize Node and write to io.
642 643 644 |
# File 'lib/nokolexbor/node.rb', line 642 def write_to(io, *) io.write(to_html(*)) end |
#xpath(*args) ⇒ NodeSet
Search this node for XPath paths. paths must be one or more XPath queries.
It works the same way as Nokogiri::Node#xpath.
372 373 374 375 376 |
# File 'lib/nokolexbor/node.rb', line 372 def xpath(*args) paths, handler, ns, binds = extract_params(args) xpath_internal(self, paths, handler, ns, binds) end |