Home

Blocks

A block is one coherent semantic unit on a page — a single heading, a single paragraph, or a single table. It is the atomic unit DocSlicer extracts before any chunking happens: the document is first broken into blocks, then consecutive blocks are grouped into chunks sized for an embedding model.

A page generally holds several blocks — a heading, the paragraph beneath it, a table, the caption under it. Each is delimited from the next by whitespace and/or a change in formatting: a heading is bold and larger, the paragraph below it is not. DocSlicer reads those signals to decide where one block ends and the next begins.


Blocks and chunks

Blocks and chunks are two layers of the same pipeline:

  • A block is a single structural element on a single page — it never spans a heading or a page boundary.
  • A chunk is one or more consecutive blocks that fall under the same heading, merged together toward a target size.

So a chunk is always a whole number of blocks. The ~1,500-character Apple revenue chunk on the Chunking page, for instance, is five consecutive blocks — a heading, an intro paragraph, a table, and two closing paragraphs — joined into one chunk because they all sit under the same heading.

To work with the raw blocks before chunking, read result.blocks or pass chunking=False to skip chunk assembly entirely.

For Markdown output, work from blocks. When you only need a Markdown rendering of the document, pass chunking=False and call result.export_to_markdown(). This returns the full document as Markdown — headings, paragraphs, and tables — while skipping the chunking computation entirely.


What starts a new block

DocSlicer begins a new block whenever the document's structure shifts. The main triggers:

  • Role change — body text gives way to a heading, a table, or a list, and so on (a change in block.type).
  • Style change — within a run of body text, the font size, weight (bold), colour, or italic changes; the typographic cue that a new element has begun.
  • Layout, column, or page boundary — a block never spans two columns of a multi-column page, and never crosses a page break.
  • Indentation jump — in long single-style passages, a clear increase in left indent starts a new block, such as a nested sub-clause.

Consecutive lines that belong to the same heading are kept together even when their styling wobbles, so a heading and its wrapped continuation stay one unit.


Block types

Every block is exactly one of a fixed set of types, surfaced as block.type. Like OOXML's closed set of style definitions, the vocabulary is strict — there is no free-form or custom type. Most types are format-agnostic; a few appear only for specific input formats (PPTX charts, notes, and equations, DOCX headers and footers, HTML rules, images, and code, PDF rotated text and form fields).

block.typeDescription
paragraphDefault body text — the fallback when no other type matches.
headingA structural heading.
hybrid_heading_paragraphA heading that also carries body text inline on the same line.
suppressed_repeated_headingA heading suppressed because it repeats across pages.
tableTabular data, rendered per your chosen table representation.
tocA table-of-contents entry line.
toc_headingThe heading line of a TOC section (e.g. "Table of Contents").
exhibitsExhibit body content.
exhibit_headingThe heading line of an exhibit (e.g. "Exhibit A").
navigationRepeated header/footer navigation text.
page_labelA running page number or label (e.g. "Page 1", "A-6").
block_quoteA quoted or pulled-out passage, kept as its own block rather than merged into the surrounding body text (PDF, HTML).
headerPage header text in the top margin (DOCX); typically repeats across pages.
footerPage footer text in the bottom margin (DOCX); typically repeats across pages.
hrA horizontal rule / divider element (HTML).
imageAn image or figure block (HTML).
codeA code listing or preformatted block — <pre> / <code> (HTML).
vertical_textText with vertical orientation — rotated sidebar labels or spine text (PDF).
form_fieldAn interactive form field and its value — AcroForm widgets in fillable PDFs (PDF).
chartA chart object with its data points, axis labels, and legend (PPTX).
shapeA non-text shape with associated text content (PPTX).
mathAn equation / OMML math expression (PPTX).
speaker_notesSpeaker notes attached to a slide (PPTX).

Note that heading (a structural section title within the content) is distinct from header (the repeating text in a page's top margin) — the two are easily confused.

The format annotations say where a type is detected today, not where the content can occur. math is currently detected for PPTX only — DOCX equation support is planned — and code for HTML only. In a PDF, block_quote relies on the file's structure tree (a BlockQuote tag), so it only appears for tagged PDFs; in HTML it comes from a <blockquote> element.


Working with blocks

# All blocks, in reading order
result.blocks
 
# Blocks under a specific heading
node = result.find_heading("Risk Factors")[0]
result.blocks_under(node)
 
# Blocks on a given page — by number or by printed label
result.blocks_by_page(14)
result.blocks_by_page("F-3")
 
# Skip chunking entirely — faster, returns blocks only
result = docslicer.parse_document("report.pdf", chunking=False)

Each block carries the same section field as chunks — see Sections — alongside its type, text, page number, and (for PDFs) bounding box. For how blocks are assembled into chunks and the size parameters involved, see Chunking.

page_number is not page_label. page_number is the 1-based physical position in the file (1, 2, 3…), while page_label is the label printed on the page itself ("155", "A-1-5", "iv", "F-28"). They diverge whenever a document restarts or prefixes its numbering. blocks_by_page accepts either — pass an int to match the physical page, or a str to match the printed label.


Browsing SEC exhibits

The exhibits block type is purpose-built for SEC filings. An EDGAR filing's exhibit index lists each exhibit alongside a hyperlink to the document that holds it. Parse the filing URL, filter blocks to type == "exhibits", and read each block's link_url to get the full list of exhibit documents for the filing:

# Eli Lilly's tender offer to acquire Adverum Biotechnologies (Schedule TO)
result = docslicer.parse_document(
    "https://www.sec.gov/Archives/edgar/data/59478/000119312525272330/d67752dsctot.htm"
)
 
# Every exhibit reference in the filing, with the URL it points to
for block in result.blocks:
    if block.type == "exhibits":
        for url in block.link_url:
            print(block.text, "→", url)

The exhibit index resolves straight to the underlying documents — including the ones that matter most in an M&A deal:

ExhibitURL
(a)(1)(A) Offer to Purchase, dated November 7, 2025https://www.sec.gov/Archives/edgar/data/59478/000119312525272330/d67752dex99a1a.htm
(d)(1) Agreement and Plan of Merger, dated October 24, 2025https://www.sec.gov/Archives/edgar/data/1501756/000119312525249438/d70157dex21.htm
(d)(2) Form of Contingent Value Rights Agreementhttps://www.sec.gov/Archives/edgar/data/1501756/000119312525249438/d70157dex21.htm
(d)(3) Secured Promissory Note, dated October 24, 2025https://www.sec.gov/Archives/edgar/data/1501756/000119312525249438/d70157dex101.htm
(d)(4) Confidentiality Agreement, dated November 4, 2024https://www.sec.gov/Archives/edgar/data/59478/000119312525272330/d67752dex99d4.htm
(d)(5) First Amendment to Confidentiality Agreementhttps://www.sec.gov/Archives/edgar/data/59478/000119312525272330/d67752dex99d5.htm
107 Filing Fee Tablehttps://www.sec.gov/Archives/edgar/data/59478/000119312525272330/d67752dexfilingfees.htm

This turns a filing into a navigable index of its exhibits — pull the merger agreement, CVR agreement, or any other document directly, then parse those the same way. Handy if you work with EDGAR data, where the exhibits (material contracts, the merger agreement, certifications) are often the part you actually care about.