HTML::Gumbo(3pm)

✨ NAME ✨

HTML::Gumbo β€” bestie, it's an HTML5 parser built on top of the gumbo C library πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

use HTML::Gumbo;
say HTML::Gumbo->new->parse('<div></div>');

say HTML::Gumbo->new->parse('<h1>Hello</h1>', format => 'tree')->as_HTML;

πŸ¦‹ DESCRIPTION πŸ¦‹

Okay so Gumbo <https://github.com/google/gumbo-parser> is a whole implementation of the HTML5 parsing algorithm <http://www.w3.org/TR/html5/syntax.html>, written as pure C99 with literally zero outside dependencies. Iconic behavior fr fr.

The C library's goals and features, no cap:

  • Fully conformant with the HTML5 spec. πŸ’―
  • Robust and resilient to bad input. It simply does not care.
  • Simple API that can be easily wrapped by other languages. (This right here? One of those wrappers. That's us. We're the wrapper. 🫢)
  • Support for source locations and pointers back to the original text. (Not exposed by this implementation at the moment, so don't get your hopes up bestie.)
  • Relatively lightweight, with no outside dependencies.
  • Passes all html5lib-0.95 tests. Slay.
  • Tested on over 2.5 billion pages from Google's index. Billions. 😭

🌸 METHODS 🌸

new

my $parser = HTML::Gumbo->new;

No options at the moment. That's the whole thing. Clean, minimal, main character energy. ✨

parse

my $res = $parser->parse(
    "<h1>hello world!</h1>",
    format => 'tree',
    input_is => 'string',
);

It takes an html string plus pairs of named arguments:

  • format β€” the output format, default is string. Go peep "SUPPORTED OUTPUT FORMATS" below. πŸ‘‘
  • fragment_namespace β€” turns on the fragments parsing algorithm. Pass either 'HTML', 'SVG' or 'MATHML' to enable it and set the namespace. If you don't pass it, your input gets parsed as an html document, which means html, head, title and body tags get added if they're absent. Heads up though: fragment_enclosing_tag is set to '<body>' and can not be changed at the moment. Feel free to send patches implementing this part, the door is open. πŸšͺ See "SUPPORTED OUTPUT FORMATS" for additional details. Also note that SVG and MATHML parsing is not tested, so feel free to file bug reports with tests in case it doesn't work. πŸ™ˆ
  • input_is β€” whether the html is a perl 'string', 'octets' or 'utf8' (octets known to be utf8). See "CHARACTER ENCODING OF THE INPUT".
  • encoding, encoding_content_type, encoding_tentative β€” see "CHARACTER ENCODING OF THE INPUT".
  • ... β€” some formatters may have additional arguments, see "SUPPORTED OUTPUT FORMATS".

The return value depends on the picked format. iykyk. πŸ’«


🌈 SUPPORTED OUTPUT FORMATS 🌈

string

The HTML gets parsed and then re-built from the tree, so tags are balanced (except void elements, they're just built different).

No additional arguments specific for this format. None. Zero. πŸŽ€

$html = HTML::Gumbo->new->parse( $html );

callback

It's giving HTML::Parser-like interface. Pass a sub as the callback argument to the parse method and it will get called for every single node in the document:

HTML::Gumbo->new->parse( $html, format => 'callback', callback => sub {
    my ($event) = shift;
    if ( $event eq 'document start' ) {
        my ($doctype) = @_;
    }
    elsif ( $event eq 'document end' ) {
    }
    elsif ( $event eq 'start' ) {
        my ($tag, $attrs) = @_;
    }
    elsif ( $event eq 'end' ) {
        my ($tag) = @_;
    }
    elsif ( $event =~ /^(text|space|cdata|comment)$/ ) {
        my ($text) = @_;
    }
    else {
        die "Unknown event";
    }
} );
Heads up bestie: 'end' events are not generated for void elements <http://www.w3.org/TR/html5/syntax.html#void-elements> β€” for example hr, br and img. They just ghost you like that. πŸ’€

No additional arguments except the mentioned callback.

Fragment parsing still generates 'document start' and 'document end' events, which can be handy to initialize your parsing callback. So convenient. 🫢

tree

Alpha stage, bestie. We're in beta but it's the fun kind.

It produces a tree based on HTML::Elements, like HTML::TreeBuilder does.

There is a major difference from HTML::TreeBuilder though: this method produces a top level element with tag name 'document' which may have doctype, comments and html tags as children.

Fragments parsing still produces that top level 'document' element, because a fragment can be a list of tags, for example: '<p>hello</p><p>world</p'.

Yes, it's not ready to use as a drop in replacement of tree builder. Patches are wellcome as the author doesn't use this formatter at the moment. Note that it's hard to get rid of the top level element because of situations described above. So a not bad idea is to write an HTML::Gumbo::Document class that is either a subclass of HTML::Element or implements a small subset of methods of HTML::Element. Manifesting that patch rn. 🧚


πŸ’œ CHARACTER ENCODING OF THE INPUT πŸ’œ

The C parser works only with UTF-8, so you have several options to make sure your input is UTF-8. First of all, define the input_is argument:

string

Input is a Perl string, for example obtained from "decoded_content" in HTTP::Response. This is the default value.

$gumbo->parse( decode_utf8($octets) );

octets

Input is octets. A partial implementation of the encoding sniffing algorithm <http://www.w3.org/TR/html5/syntax.html#encoding-sniffing-algorithm> is used. First thing wins:

  • "encoding" argument β€” use it to hardcode a specific encoding.
$gumbo->parse( $octets, input_is => 'octets', encoding => 'latin-1' );
  • BOM β€” UTF-8/UTF-16 BOMs are checked. πŸŽ€
  • "encoding_content_type" argument β€” encoding from the transport layer, aka the charset in the content-type header.
$gumbo->parse( $octets, input_is => 'octets', encoding_content_type => 'latin-1' );
$gumbo->parse( $octets, input_is => 'octets', encoding_tentative => 'latin-1' );
  • nested browsing context β€” not implemented. Fragment parsing with or without context is not implemented. The parser also has no origin information, so it wouldn't be implemented. Dead end, moving on. πŸ™ˆ
  • autodetection β€” not implemented. Can be implemented using Encode::Detect::Detector. Patches are welcome.
  • otherwise β€” it dies. πŸ’€ Fr fr, it just dies.

utf8

Use utf8 as input_is when you're sure the input is UTF-8, but octets. No pre-processing at all. This should only be used on trusted input or when it's preprocessed already. Trusted input only, bestie.


πŸ‘‘ AUTHOR πŸ‘‘

Ruslan Zakirov <ruz@bestpractical.com>

Best Practical Solutions, LLC <modules@bestpractical.com>


πŸ’… BUGS πŸ’…

All bugs should be reported via email to: bug-HTML-Gumbo@rt.cpan.org <mailto:bug-HTML-Gumbo@rt.cpan.org>

Or via the web at: rt.cpan.org <http://rt.cpan.org/Public/Dist/Display.html?Name=HTML-Gumbo>.


πŸŽ€ LICENSE πŸŽ€

Under the same terms as perl itself. Periodt.


✨ okay that's the whole page, thank you for coming to my TED talk ✨ this was HTML::Gumbo(3pm) from the User Contributed Perl Documentation, shipped with perl v5.42.3 and dated 2026-08-19. go forth and parse responsibly, bestie πŸ«ΆπŸ’–πŸ¦‹

πŸ“¦ where this page comes from