Doclingdocling 2.127.0 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
26 small wins to finish your pathNext lesson

The heading levels a PDF does not have

Every heading in the converted PDF came out at the same level. That is not a bug in your file, it is what the layout model can and cannot see.

Example
for item in document.texts:
    if item.label == "section_header":
        print(item.level, item.text)

Four headings, all level 1, although Returns is set in twenty point bold and the other three in fourteen. The layout model's job is to say this is a heading. It is not asked how deep the heading sits, so everything comes back flat.

Turning the levels on

Docling can work the depth out afterwards from three signals: the PDF's own bookmarks, numbering like 2.1 at the start of a heading, and the font each heading is set in. It is off by default because it is guesswork, and you ask for it with an options object.

Example
from docling.datamodel.pipeline_options import HeadingHierarchyOptions

options = PdfPipelineOptions()
options.heading_hierarchy_options = HeadingHierarchyOptions(enabled=True)
options.generate_parsed_pages = True
deep = DocumentConverter(
    format_options={InputFormat.PDF: PdfFormatOption(pipeline_options=options)})
nested = deep.convert("returns.pdf").document
for item in nested.texts:
    if item.label == "section_header":
        print(item.level, item.text)

Now Returns is level 1 and the three smaller headings are level 2, recovered from nothing but the point size. The second line matters as much as the first: generate_parsed_pages is what keeps the font information around, and without it the font signal has nothing to read.

What it changes downstream

Example
print(nested.export_to_markdown())

Three hashes where there were two. The bigger effect arrives in part 6: a chunk records the headings above it, and with a flat document every heading looks like a top level one, so a chunk from deep inside a report is labelled as if it were a chapter.

It is inference, not markup. A document whose headings are all the same size and carry no numbering gives the guess nothing to work with, and you get the flat list back. Check the result rather than assuming it worked.

Formats that never needed this

Markdown, HTML and Word files say the depth in the file, so their levels were right from lesson 6 without anyone asking. This option exists only because a PDF throws that information away.

Try it yourself
  • Set every heading in make_returns_pdf.py to the same point size and convert again.
  • Turn the option on but leave generate_parsed_pages off, and see what you get.
  • Export the nested document as DocTags and find the level in the tag names.

Little by little, you're building something great.