Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docling/backend/html_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -928,7 +928,11 @@ def convert(self) -> DoclingDocument:
binary_hash=self.document_hash,
)
doc = DoclingDocument(name=self.file.stem or "file", origin=origin)
self.convert_into(doc)
return doc

def convert_into(self, doc: DoclingDocument) -> None:
"""Append the converted content to the body of `doc`."""
if cast(HTMLBackendOptions, self.options).render_page:
self._render_with_browser()
if self._rendered_html:
Expand Down Expand Up @@ -1011,7 +1015,6 @@ def convert(self) -> DoclingDocument:
self.ctx = _Context()
self._render_visibility_cache.clear()
self._walk(content, doc)
return doc

@staticmethod
def _is_header_in_cell_or_item(header: Tag) -> bool:
Expand Down Expand Up @@ -3333,7 +3336,7 @@ def _get_list_style_marker(li: Tag) -> str:

Docling's HTML export writes the original marker of a list item this way,
so reading it back keeps markers such as `3.` when the HTML is converted
again (the Markdown backend does this for files with HTML blocks).
again.
"""
style = li.get("style")
if not isinstance(style, str):
Expand Down
108 changes: 35 additions & 73 deletions docling/backend/md_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@
from docling.backend.abstract_backend import (
DeclarativeDocumentBackend,
)
from docling.backend.html_backend import HTMLDocumentBackend
from docling.backend.utils.image_resource_loader import ImageResourceLoader
from docling.backend.utils.markdown_html import (
MarkdownHTMLDocumentBackend,
serialize_markdown_for_html,
)
from docling.datamodel.backend_options import (
HTMLBackendOptions,
MarkdownBackendOptions,
Expand Down Expand Up @@ -108,10 +105,6 @@ class _GfmStrikethrough(marko.inline.InlineElement):
"Install it with `pip install 'docling-slim[format-markdown]'`."
)

_MARKER_BODY = "DOCLING_DOC_MD_HTML_EXPORT"
_START_MARKER = f"#_#_{_MARKER_BODY}_START_#_#"
_STOP_MARKER = f"#_#_{_MARKER_BODY}_STOP_#_#"


class _PendingCreationType(str, Enum):
"""CoordOrigin."""
Expand Down Expand Up @@ -268,7 +261,6 @@ def __init__(

self._pending_hard_line_break = False
self._pending_soft_line_break = False
self._html_blocks: int = 0
self._image_loader: ImageResourceLoader | None = None

# A leading BOM is dropped. Kept, it prefixes the first line, so a
Expand Down Expand Up @@ -998,21 +990,9 @@ def _iterate_elements( # noqa: C901
self._pending_hard_line_break = True

elif isinstance(element, marko.block.HTMLBlock):
self._html_blocks += 1
_log.debug("HTML Block: %s", element)
if (
len(element.body) > 0
): # If Marko doesn't return any content for HTML block, skip it
html_block = element.body.strip()

# wrap in markers to enable post-processing in convert()
text_to_add = f"{_START_MARKER}{html_block}{_STOP_MARKER}"
doc.add_code(
parent=parent_item,
text=text_to_add,
formatting=formatting,
hyperlink=hyperlink,
)
if html_block := element.body.strip():
self._add_html_block(doc, parent_item, html_block)

elif isinstance(element, _gfm_el.Table):
_log.debug(" - GFM Table")
Expand Down Expand Up @@ -1137,6 +1117,38 @@ def _load_image_ref(self, dest: str) -> ImageRef | None:
warnings.warn(f"Could not process an image from {dest}: {exc}")
return None

def _add_html_block(
self, doc: DoclingDocument, parent_item: NodeItem | None, html_block: str
) -> None:
"""Convert one HTML block with the HTML backend into `parent_item`."""
md_options = cast(MarkdownBackendOptions, self.options)
html_options = HTMLBackendOptions(
enable_local_fetch=md_options.enable_local_fetch,
enable_remote_fetch=md_options.enable_remote_fetch,
fetch_images=md_options.fetch_images,
source_uri=md_options.source_uri,
infer_furniture=False,
add_title=False,
)
stream = BytesIO(html_block.encode("utf-8"))
in_doc = InputDocument(
path_or_stream=stream,
format=InputFormat.HTML,
backend=HTMLDocumentBackend,
filename=self.file.name,
backend_options=html_options,
)
first_new = len(doc.body.children)
HTMLDocumentBackend(
in_doc=in_doc, path_or_stream=stream, options=html_options
).convert_into(doc)
if parent_item is not None:
new_refs = doc.body.children[first_new:]
del doc.body.children[first_new:]
for ref in new_refs:
ref.resolve(doc).parent = parent_item.get_ref()
parent_item.children.extend(new_refs)

def is_valid(self) -> bool:
return self.valid

Expand Down Expand Up @@ -1181,56 +1193,6 @@ def convert(self) -> DoclingDocument:
list_item_counter_by_ref={},
list_last_item_by_ref={},
)

if self._html_blocks > 0:
html_backend_cls = MarkdownHTMLDocumentBackend
html_payload = serialize_markdown_for_html(
doc, source_hash=self.document_hash
)
html_str = html_payload.text

# Restore only the marked HTML blocks. The HTML serializer
# escapes code content, so decode each block before parsing it.
pattern = (
rf"<pre>\s*<code>\s*{re.escape(_START_MARKER)}"
rf"(.*?){re.escape(_STOP_MARKER)}\s*</code>\s*</pre>"
)
html_str, count = re.subn(
pattern,
lambda match: unescape(match.group(1)),
html_str,
flags=re.DOTALL,
)
if count != self._html_blocks:
raise RuntimeError(
"An internal error has occurred during Markdown conversion."
)
self._html_blocks = 0
# delegate to HTML backend
stream = BytesIO(bytes(html_str, encoding="utf-8"))
md_options = cast(MarkdownBackendOptions, self.options)
html_options = HTMLBackendOptions(
enable_local_fetch=md_options.enable_local_fetch,
enable_remote_fetch=md_options.enable_remote_fetch,
fetch_images=md_options.fetch_images,
source_uri=md_options.source_uri,
infer_furniture=False,
add_title=False,
)
in_doc = InputDocument(
path_or_stream=stream,
format=InputFormat.HTML,
backend=html_backend_cls,
filename=self.file.name,
backend_options=html_options,
)
html_backend_obj = html_backend_cls(
in_doc=in_doc,
path_or_stream=stream,
options=html_options,
picture_refs=html_payload.picture_refs,
)
doc = html_backend_obj.convert()
else:
raise RuntimeError(
f"Cannot convert md with {self.document_hash} because the backend failed to init."
Expand Down
101 changes: 0 additions & 101 deletions docling/backend/utils/markdown_html.py

This file was deleted.

Loading
Loading