Search Shortcut cmd + k | ctrl + k
webbed

Comprehensive processing extension for web markup languages (XML and HTML) with SAX streaming for large files, intelligent schema inference, XPath-based data extraction, and HTML table parsing.

Maintainer(s): teaguesterling

Compatibility Matrix

This table covers all DuckDB releases that have not reached end-of-life, including LTS releases, and shows the 2 most recent patch releases of each. Older patch releases are not listed, but the extension may be available for them as well.

Platform 1.4.4 1.4.5 1.5.5 1.5.6 2.0.0
Linux AMD64
Linux ARM64
macOS AMD64
macOS ARM64
Windows AMD64
Windows ARM64
WebAssembly

Installing and Loading

INSTALL webbed FROM community;
LOAD webbed;

Example

-- Load the extension
LOAD webbed;

-- Read HTML files directly as structured document blocks
SELECT * FROM read_html_blocks('index.html');

-- Read XML files directly into tables
SELECT * FROM 'data.xml';
SELECT * FROM read_xml('config/*.xml');

-- Parse and extract from XML content using XPath
SELECT xml_extract_text('<book><title>Database Guide</title></book>', '//title');
-- Result: "Database Guide"

-- Parse and extract from HTML content
SELECT html_extract_text('<html><body><h1>Welcome</h1></body></html>', '//h1');
-- Result: "Welcome"

-- Extract HTML tables directly into DuckDB
SELECT * FROM html_extract_tables('<table><tr><th>Name</th><th>Age</th></tr><tr><td>John</td><td>25</td></tr></table>');

-- Extract links and images from HTML pages
SELECT html_extract_links('<a href="https://example.com">Click here</a>');
SELECT html_extract_images('<img src="photo.jpg" alt="Photo" width="800">');

-- Parse XML strings directly (without files)
SELECT * FROM parse_xml('<books><book><title>DuckDB</title><price>29.99</price></book></books>');

-- Convert between XML and JSON formats
SELECT xml_to_json('<person><name>John</name><age>30</age></person>');
SELECT json_to_xml('{"name":"John","age":"30"}');

-- Convert HTML to structured document blocks
SELECT html_to_duck_blocks('<h1>Title</h1><p>Paragraph with <strong>bold</strong> text.</p>');

About webbed

DuckDB XML is a comprehensive extension that brings powerful XML and HTML processing capabilities to DuckDB, enabling SQL-native analysis of structured documents. The extension provides four core areas of functionality:

XML Processing & Analysis: Parse, validate, and extract data from XML documents using full XPath 1.0 expressions. Functions include xml_extract_text(), xml_extract_elements(), xml_extract_attributes(), xml_valid(), and xml_stats() for comprehensive document analysis. The extension handles namespaces with intelligent 'auto' mode detection, comments, CDATA sections, and provides utilities like xml_pretty_print() and xml_minify().

HTML Processing & Web Scraping: Advanced HTML parsing capabilities with specialized functions for web data extraction. Extract text content with html_extract_text(), parse HTML tables into structured data with html_extract_tables(), extract links with metadata using html_extract_links(), and extract images with attributes using html_extract_images(). Perfect for web scraping and HTML document analysis workflows.

Document Block Processing: Convert HTML documents to and from structured block representations with read_html_blocks(), parse_html_blocks(), html_to_duck_blocks(), and duck_blocks_to_html(). Supports paragraphs, headings, code blocks, tables, lists, inline formatting (bold, italic, links, etc.), and frontmatter preservation. Integrates with the duck_block_utils extension for full Markdown support.

Smart Schema Inference & File Reading: Automatically flatten XML/HTML documents into relational tables with intelligent type detection for dates, numbers, booleans, and nested structures. Functions like read_xml() and read_html() provide direct file-to-table conversion with configurable options including datetime_format presets, nullstr for custom NULL values, and schema customization. SAX streaming (v2.0) automatically handles files over 16MB using a push parser that processes XML in 64KB chunks — peak memory stays proportional to a single record, not the file size.

Key XML Functions:

  • read_xml(pattern) - Read XML files with automatic schema inference
  • xml_extract_text(xml, xpath) - XPath-based text extraction
  • xml_extract_elements(xml, xpath) - Extract structured elements
  • xml_extract_attributes(xml, xpath) - Extract attributes as structs
  • xml_extract_text_each(xml, context_xpath, relative_xpath) - One entry per context node, NULL where the relative path matches nothing, so parallel calls over sibling paths stay aligned for unnest
  • xml_to_json(xml) / json_to_xml(json) - Format conversions
  • xml_stats(xml) - Document statistics and analysis
  • xml_validate_schema(xml, xsd) - XSD schema validation
  • xml_find_undefined_prefixes(xml, xpath) - Detect undeclared namespace prefixes
  • xml_add_namespace_declarations(xml, map) - Inject namespace declarations
  • parse_xml(content) - Parse XML strings with schema inference
  • parse_xml_objects(content) - Parse XML strings to raw XML type

Key HTML Functions:

  • read_html(pattern) - Read HTML files into tables
  • read_html_blocks(pattern) - Read HTML files directly into flattened duck_block rows
  • parse_html_blocks(content) - Parse HTML strings directly into flattened duck_block rows
  • html_extract_tables(html) - Extract HTML tables as structured data
  • html_extract_links(html) - Extract all links with metadata
  • html_extract_images(html) - Extract images with attributes
  • html_extract_text(html, xpath) - XPath-based HTML text extraction
  • parse_html(content) - Parse HTML strings with schema inference
  • parse_html_objects(content) - Parse HTML strings to raw HTML type
  • html_to_duck_blocks(html) - Convert HTML to structured document blocks
  • duck_blocks_to_html(blocks) - Convert document blocks back to HTML

See https://duckdb-webbed.readthedocs.io for comprehensive documentation and examples.

Built on libxml2 for robust, standards-compliant parsing with comprehensive error handling and memory-safe RAII implementation. 109 test suites with 4104 assertions, including DOM/SAX equivalence, adversarial/security, and multi-file parallelism testing. The extension supports mixed file systems, configurable schema inference, and efficient processing of large document collections.

Added Functions

function_name function_type description comment examples
duck_blocks_to_html scalar Convert a list of duck_block structures back into an HTML document string. NULL [duck_blocks_to_html(html_to_duck_blocks('<h1>Title</h1>'))]
html_escape scalar Escape special characters for HTML embedding. NULL [html_escape('<hello & world>')]
html_extract_images scalar Extract all image tags () from HTML as a list of structs. NULL [html_extract_images('Logo')]
html_extract_links scalar Extract all hyperlink tags () from HTML as a list of structs. NULL [html_extract_links('DuckDB')]
html_extract_table_rows scalar Extract rows and cells from all tables in HTML as a list of structs. NULL [html_extract_table_rows('<table><tr><td>A</td></tr></table>')]
html_extract_tables table Extract all HTML tables from an HTML string as structured rows. NULL [SELECT * FROM html_extract_tables('<table><tr><td>A</td></tr></table>')]
html_extract_tables_json scalar Extract all tables from HTML as JSON structures. NULL [html_extract_tables_json('<table><tr><th>H</th></tr><tr><td>V</td></tr></table>')]
html_extract_text scalar NULL NULL  
html_to_duck_blocks scalar Parse an HTML document into a list of duck_block structures. NULL [html_to_duck_blocks('<h1>Title</h1><p>Text</p>'), html_to_duck_blocks('<table>…</table>', capture_attributes := true)]
html_unescape scalar Decode HTML entities in a string. NULL [html_unescape('<hello&world>')]
json_to_xml scalar Convert a JSON string to XML. NULL [json_to_xml('{"root": {"item": "Hello"}}')]
parse_html scalar Parse an HTML string into an HTML type. NULL [parse_html('<div>Hello</div>')]
parse_html table Parse an HTML string with automatic schema inference and return tabular data. NULL [SELECT * FROM parse_html('<div><p>Paragraph</p></div>')]
parse_html_blocks table Parse an HTML string and return each element as a duck_block row. NULL [SELECT * FROM parse_html_blocks('<h1>Hello</h1><p>World</p>')]
parse_html_objects table Parse an HTML string and return raw HTML object content. NULL [SELECT * FROM parse_html_objects('<div>A</div>')]
parse_xml table Parse an XML string with automatic schema inference and return tabular data. NULL [SELECT * FROM parse_xml('A')]
parse_xml_objects table Parse an XML string and return raw XML object content. NULL [SELECT * FROM parse_xml_objects('1')]
read_html table Read an HTML file with automatic schema inference and return tabular data. NULL [SELECT * FROM read_html('page.html')]
read_html_blocks table Read an HTML file and return each element as a duck_block row. NULL [SELECT * FROM read_html_blocks('page.html')]
read_html_objects table Read an HTML file and return raw HTML object content. NULL [SELECT * FROM read_html_objects('page.html')]
read_xml table Read an XML file with automatic schema inference and return tabular data. NULL [SELECT * FROM read_xml('data.xml'), SELECT * FROM read_xml('data.xml', record_element := '//item')]
read_xml_objects table Read an XML file and return raw XML object content. NULL [SELECT * FROM read_xml_objects('data.xml')]
to_xml scalar NULL NULL  
xml scalar Cast or convert a string to XML. NULL [xml('value')]
xml_add_namespace_declarations scalar Inject xmlns namespace declarations into an XML document root element. NULL [xml_add_namespace_declarations('', map(['ns'], ['http://example.com']))]
xml_common_namespaces scalar Return a map of common, well-known namespace prefixes and their URIs. NULL [xml_common_namespaces()]
xml_detect_prefixes scalar Detect namespace prefixes used within an XPath expression. NULL [xml_detect_prefixes('//ns:item/other:tag')]
xml_extract_all_text scalar Extract all concatenated text content from an XML document or fragment. NULL [xml_extract_all_text('')]
xml_extract_attributes scalar Extract attributes from elements matching an XPath expression as a list of structs. NULL [xml_extract_attributes('', '//item')]
xml_extract_cdata scalar Extract CDATA sections from an XML document as a list of structs with content and line numbers. NULL [xml_extract_cdata('some raw content')]
xml_extract_comments scalar Extract comments from an XML document as a list of structs with content and line numbers. NULL [xml_extract_comments('')]
xml_extract_elements scalar Extract XML fragments matching an XPath expression as a list of XML fragments. NULL [xml_extract_elements('AB', '//item')]
xml_extract_elements_string scalar Extract XML elements matching an XPath expression as a single concatenated string. NULL [xml_extract_elements_string('A', '//item')]
xml_extract_text scalar Extract text content matching an XPath expression from XML as a list of strings. NULL [xml_extract_text('Hello', '//item'), xml_extract_text('A', '//ns:item', map(['ns'], ['uri']))]
xml_extract_text_each scalar Extract text relative to each node matched by context_xpath, as a list with one entry per context node and NULL where relative_xpath matches nothing. Use it when sibling elements are optional: two xml_extract_text calls return different-length lists that cannot be zipped. NULL [xml_extract_text_each('<p>C1</p><p>B</p>', '//n', 'p/a'), SELECT unnest(xml_extract_text_each(xml, '//note', 'pitch/step')) AS step, unnest(xml_extract_text_each(xml, '//note', 'pitch/alter')) AS alter FROM t]
xml_find_undefined_prefixes scalar Find namespace prefixes used in an XPath expression that are not declared in the XML document. NULL [xml_find_undefined_prefixes('', '//ns:item')]
xml_libxml2_version scalar Return the linked libxml2 version. NULL [xml_libxml2_version('test')]
xml_lookup_namespace scalar Lookup URI for a well-known namespace prefix. NULL [xml_lookup_namespace('soap')]
xml_minify scalar Minify an XML string by removing unnecessary whitespace. NULL [xml_minify('\n value\n')]
xml_mock_namespaces scalar Generate mock namespace URI mappings for a list of prefixes. NULL [xml_mock_namespaces(['ns', 'other'])]
xml_namespaces scalar Extract all declared namespace prefixes and URIs from an XML document as a MAP. NULL [xml_namespaces('')]
xml_oom_selftest scalar Internal regression self-test for libxml2 memory handling. NULL [xml_oom_selftest()]
xml_pretty_print scalar Format and indent an XML string. NULL [xml_pretty_print('value')]
xml_stats scalar Compute statistics (element count, attribute count, max depth, size, namespace count) for an XML document. NULL [xml_stats('')]
xml_to_json scalar Convert an XML string to JSON. NULL [xml_to_json('Hello'), xml_to_json('Hello', attr_mode := 'prefixed')]
xml_valid scalar Check if an XML string or document is well-formed. NULL [xml_valid(''), xml_valid('')]
xml_validate_schema scalar Validate an XML string against an XSD schema string. NULL [xml_validate_schema(xml_doc, xsd_schema)]
xml_well_formed scalar Check if an XML string or document is well-formed. NULL [xml_well_formed('')]
xml_wrap_fragment scalar Wrap XML fragment content in an enclosing root tag. NULL [xml_wrap_fragment('12', 'root')]

Overloaded Functions

This extension does not add any function overloads.

Added Types

type_name type_size logical_type type_category internal
HTML 16 VARCHAR STRING true
XML 16 VARCHAR STRING true
XMLFragment 16 VARCHAR STRING true

Added Settings

name description input_type scope aliases typed_value
temp_directory Set the directory to which temporary files are written. VARCHAR GLOBAL [] post.db.tmp