1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

net.html: add get_tags_by_class_name (#17024)

This commit is contained in:
Minsoo 2023-01-19 02:00:46 +09:00 committed by GitHub
parent 6688c0f3d7
commit d850d3caba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 0 deletions

View File

@ -185,3 +185,8 @@ pub fn (dom DocumentObjectModel) get_root() &Tag {
pub fn (dom DocumentObjectModel) get_tags() []&Tag { pub fn (dom DocumentObjectModel) get_tags() []&Tag {
return dom.all_tags return dom.all_tags
} }
// get_tags_by_class_name retrieves all the tags recursively in the document that has the given class name(s).
pub fn (dom DocumentObjectModel) get_tags_by_class_name(names ...string) []&Tag {
return dom.root.get_tags_by_class_name(...names)
}

View File

@ -54,3 +54,33 @@ fn test_access_tag_fields() {
assert id_tags[0].name == 'div' assert id_tags[0].name == 'div'
assert id_tags[1].attributes['class'] == 'several-1' assert id_tags[1].attributes['class'] == 'several-1'
} }
fn generate_temp_html_with_classes() string {
mut temp_html := strings.new_builder(400)
temp_html.write_string('<!doctype html><html><head><title>Giant String</title></head><body>')
temp_html.write_string("<div class='single'>Single</div>")
for counter := 0; counter < 4; counter++ {
temp_html.write_string("<div id='name_${counter}' ")
temp_html.write_string("class='common'>Common No. ${counter}</div>")
}
temp_html.write_string("<div class='complex-0 complex-1 complex-2'>Complex</div>")
temp_html.write_string("<div class='complex-0 complex-2'>Partial</div>")
temp_html.write_string('</body></html>')
return temp_html.str()
}
fn test_search_by_class() {
dom := parse(generate_temp_html_with_classes())
single_class_tags := dom.get_tags_by_class_name('single')
common_class_tags := dom.get_tags_by_class_name('common')
complex_class_tags := dom.get_tags_by_class_name('complex-0', 'complex-1', 'complex-2')
partial_class_tags := dom.get_tags_by_class_name('complex-0', 'complex-2')
shuffled_class_tags := dom.get_tags_by_class_name('complex-2', 'complex-0', 'complex-1')
assert single_class_tags.len == 1
assert common_class_tags.len == 4
assert complex_class_tags.len == 1
assert complex_class_tags[0].attributes['class'] == 'complex-0 complex-1 complex-2'
assert partial_class_tags.len == 2
assert shuffled_class_tags.len == 1
assert shuffled_class_tags[0].attributes['class'] == 'complex-0 complex-1 complex-2'
}

View File

@ -151,6 +151,13 @@ pub fn (mut parser Parser) split_parse(data string) {
nval := temp_lexeme.substr(1, temp_lexeme.len - 1) nval := temp_lexeme.substr(1, temp_lexeme.len - 1)
// parser.print_debug(lattr + " = " + temp_lexeme) // parser.print_debug(lattr + " = " + temp_lexeme)
parser.lexical_attributes.current_tag.attributes[lattr] = nval parser.lexical_attributes.current_tag.attributes[lattr] = nval
if lattr == 'class' {
for class_name in nval.split_any('\t\r\n \x0D') {
if class_name != '' {
parser.lexical_attributes.current_tag.class_set.add(class_name)
}
}
}
parser.lexical_attributes.current_tag.last_attribute = '' parser.lexical_attributes.current_tag.last_attribute = ''
} else { } else {
parser.lexical_attributes.current_tag.attributes[temp_lexeme.to_lower()] = '' parser.lexical_attributes.current_tag.attributes[temp_lexeme.to_lower()] = ''

View File

@ -1,6 +1,7 @@
module html module html
import strings import strings
import datatypes
enum CloseTagType { enum CloseTagType {
in_name in_name
@ -16,6 +17,7 @@ pub mut:
children []&Tag children []&Tag
attributes map[string]string // attributes will be like map[name]value attributes map[string]string // attributes will be like map[name]value
last_attribute string last_attribute string
class_set datatypes.Set[string]
parent &Tag = unsafe { nil } parent &Tag = unsafe { nil }
position_in_parent int position_in_parent int
closed bool closed bool
@ -102,3 +104,22 @@ pub fn (tag &Tag) get_tags_by_attribute_value(name string, value string) []&Tag
} }
return res return res
} }
// get_tags_by_class_name retrieves all the child tags recursively in the tag that has the given class name(s).
pub fn (tag &Tag) get_tags_by_class_name(names ...string) []&Tag {
mut res := []&Tag{}
for child in tag.children {
mut matched := true
for name in names {
matched = child.class_set.exists(name)
if !matched {
break
}
}
if matched {
res << child
}
res << child.get_tags_by_class_name(...names)
}
return res
}

View File

@ -1,5 +1,7 @@
module html module html
import strings
const ( const (
html = '<!doctype html> html = '<!doctype html>
<html> <html>
@ -34,4 +36,36 @@ fn test_search_by_tag_type() {
assert tag.get_tags('div').len == 5 assert tag.get_tags('div').len == 5
assert tag.get_tags_by_attribute('href')[2].content == 'vpm' assert tag.get_tags_by_attribute('href')[2].content == 'vpm'
assert tag.get_tags_by_attribute_value('class', 'bar').len == 3 assert tag.get_tags_by_attribute_value('class', 'bar').len == 3
assert tag.get_tags_by_class_name('bar').len == 3
}
fn generate_temp_html_with_classes() string {
mut temp_html := strings.new_builder(400)
temp_html.write_string('<!doctype html><html><head><title>Giant String</title></head><body>')
temp_html.write_string("<div class='single'>Single</div>")
for counter := 0; counter < 4; counter++ {
temp_html.write_string("<div id='name_${counter}' ")
temp_html.write_string("class='common'>Common No. ${counter}</div>")
}
temp_html.write_string("<div class='complex-0 complex-1 complex-2'>Complex</div>")
temp_html.write_string("<div class='complex-0 complex-2'>Partial</div>")
temp_html.write_string('</body></html>')
return temp_html.str()
}
fn test_search_by_class() {
mut dom := parse(generate_temp_html_with_classes())
tag := dom.get_tag('body')[0]
single_class_tags := tag.get_tags_by_class_name('single')
common_class_tags := tag.get_tags_by_class_name('common')
complex_class_tags := tag.get_tags_by_class_name('complex-0', 'complex-1', 'complex-2')
partial_class_tags := tag.get_tags_by_class_name('complex-0', 'complex-2')
shuffled_class_tags := tag.get_tags_by_class_name('complex-2', 'complex-0', 'complex-1')
assert single_class_tags.len == 1
assert common_class_tags.len == 4
assert complex_class_tags.len == 1
assert complex_class_tags[0].attributes['class'] == 'complex-0 complex-1 complex-2'
assert partial_class_tags.len == 2
assert shuffled_class_tags.len == 1
assert shuffled_class_tags[0].attributes['class'] == 'complex-0 complex-1 complex-2'
} }