World Conquest Chronicles

World Conquest Chronicles

go-html-selector, v1.6

The library that implements collecting text, specified HTML tags, and their attributes from an HTML document.

Collecting text from an HTML document.

Change Log

  • collecting from an HTML document:
    • text (optional);
  • skipping whitespace-only text (optional);
  • representing a result:
    • built-in builders:
      • with collecting only text:
        • with support of merging with other builders.

Features

  • collecting from an HTML document:
    • HTML tags;
    • HTML attributes;
    • text (optional);
  • options:
    • filters:
      • filtering a result:
        • by specified HTML tags:
          • with support of the universal tag (*);
        • by specified HTML attributes;
      • friendly representation of filters:
        • for parsing from JSON;
        • for definition as a code literal;
    • skipping empty entities (separately optional):
      • tags without attributes;
      • attributes with an empty value;
      • whitespace-only text;
  • representing a result:
    • using the builder interface for building a result;
    • built-in builders:
      • with grouping HTML attributes by their tags;
      • with collecting only values of HTML attributes;
      • with collecting only text:
        • with support of merging with other builders;
  • optimizations:
    • of searching for a right filter among others:
      • with removing duplicate attribute filters, if there are the same filters for the universal tag;
    • of conversion from a byte slice to a string;
    • by the number:
      • of memory allocations;
      • of string copies.

Examples

htmlselector.SelectTags() with the text builder:

package main

import (
    "bytes"
    "fmt"
    "log"
    "strings"

    htmlselector "github.com/thewizardplusplus/go-html-selector"
    "github.com/thewizardplusplus/go-html-selector/builders"
)

func main() {
    reader := strings.NewReader(`
        <ul>
            <li>
                link #1: <a href="http://example.com/1">one</a>
                <video
                    src="http://example.com/1.1"
                    poster="http://example.com/1.2">
                    Unable to embed video #1.
                </video>
            </li>
            <li>
                link #2: <a href="http://example.com/2">two</a>
                <video
                    src="http://example.com/2.1"
                    poster="http://example.com/2.2">
                    Unable to embed video #2.
                </video>
            </li>
        </ul>
    `)

    filters := htmlselector.OptimizeFilters(htmlselector.FilterGroup{
        "a":     {"href"},
        "video": {"src", "poster"},
    })

    var builder builders.StructuralBuilder
    var textBuilder builders.TextBuilder
    err := htmlselector.SelectTags(
        reader,
        filters,
        htmlselector.MultiBuilder{Builder: &builder, TextBuilder: &textBuilder},
        htmlselector.SkipEmptyText(),
    )
    if err != nil {
        log.Fatal(err)
    }

    for _, tag := range builder.Tags() {
        fmt.Printf("<%s>:\n", tag.Name)
        for _, attribute := range tag.Attributes {
            fmt.Printf("  %s=%q\n", attribute.Name, attribute.Value)
        }
    }

    fmt.Println("text parts:")
    for _, textPart := range textBuilder.TextParts() {
        textPart = bytes.TrimSpace(textPart)
        fmt.Printf("  %q\n", textPart)
    }

    // Output:
    // <a>:
    //   href="http://example.com/1"
    // <video>:
    //   src="http://example.com/1.1"
    //   poster="http://example.com/1.2"
    // <a>:
    //   href="http://example.com/2"
    // <video>:
    //   src="http://example.com/2.1"
    //   poster="http://example.com/2.2"
    // text parts:
    //   "link #1:"
    //   "one"
    //   "Unable to embed video #1."
    //   "link #2:"
    //   "two"
    //   "Unable to embed video #2."
}

Benchmarks

With Structural & Text Builders

htmlselector.SelectTags() with a simple markup:

BenchmarkSelectTags/text_builder/simple_markup/10_tags/430B-8             122985         10339 ns/op         9466 B/op        45 allocs/op
BenchmarkSelectTags/text_builder/simple_markup/100_tags/4.4K-8             15040         78519 ns/op        48475 B/op       405 allocs/op
BenchmarkSelectTags/text_builder/simple_markup/1000_tags/45.7K-8            1990        813642 ns/op       510223 B/op      4005 allocs/op
BenchmarkSelectTags/text_builder/simple_markup/10000_tags/476.3K-8           160       6728975 ns/op      3817896 B/op     40005 allocs/op
BenchmarkSelectTags/text_builder/simple_markup/100000_tags/4.8M-8             19      75982499 ns/op     56745964 B/op    400005 allocs/op
BenchmarkSelectTags/text_builder/simple_markup/1000000_tags/50.3M-8            2     664071080 ns/op    290158432 B/op   4000005 allocs/op

htmlselector.SelectTags() with a complex markup:

BenchmarkSelectTags/text_builder/complex_markup/10_tags/1020B-8            68089         20964 ns/op        21599 B/op       116 allocs/op
BenchmarkSelectTags/text_builder/complex_markup/100_tags/10.4K-8            7014        167202 ns/op        41712 B/op      1106 allocs/op
BenchmarkSelectTags/text_builder/complex_markup/1000_tags/108.8K-8           717       1663950 ns/op       387312 B/op     11006 allocs/op
BenchmarkSelectTags/text_builder/complex_markup/10000_tags/1.1M-8             69      23245678 ns/op     27798263 B/op    110006 allocs/op
BenchmarkSelectTags/text_builder/complex_markup/100000_tags/11.6M-8            6     173781906 ns/op     38403312 B/op   1100006 allocs/op
BenchmarkSelectTags/text_builder/complex_markup/1000000_tags/120.6M-8          1    1740418254 ns/op    384003328 B/op  11000006 allocs/op

htmlselector.SelectTags() with the universal tag:

BenchmarkSelectTags/text_builder/universal_tag/10_tags/1020B-8             61375         19060 ns/op         8168 B/op       136 allocs/op
BenchmarkSelectTags/text_builder/universal_tag/100_tags/10.4K-8             6638        258572 ns/op       407046 B/op      1306 allocs/op
BenchmarkSelectTags/text_builder/universal_tag/1000_tags/108.8K-8            615       1775232 ns/op       387360 B/op     13006 allocs/op
BenchmarkSelectTags/text_builder/universal_tag/10000_tags/1.1M-8              57      27496277 ns/op     43162804 B/op    130006 allocs/op
BenchmarkSelectTags/text_builder/universal_tag/100000_tags/11.6M-8             6     187202961 ns/op     38403378 B/op   1300006 allocs/op
BenchmarkSelectTags/text_builder/universal_tag/1000000_tags/120.6M-8           1    1854043284 ns/op    384003408 B/op  13000006 allocs/op

Repository

Link: https://github.com/thewizardplusplus/go-html-selector/tree/v1.6.

Content: code.

License: MIT.