Mammoth

repository·master·Indexed 22 days ago

https://github.com/mwilliamson/python-mammoth

A tool for converting .docx documents into clean, semantic HTML. Mammoth prioritizes semantic structure over visual styling, converting document elements like headings, lists, tables, and images into maintainable HTML. It includes a CLI for file conversion, a Python API with functions like convert_to_html and extract_raw_text, and a customizable style mapping system to define how Word styles map to specific HTML elements or classes.

Tokens
3.6K
Snippets
13
Records
19
Agent score
28%

What's inside python-mammoth

  1. What is Mammoth and how does it work?

    master

    Mammoth is a converter designed to transform .docx documents (from Microsoft Word, Google Docs, LibreOffice, etc.) into clean, semantic HTML.

    Unlike converters that attempt to replicate exact visual styling (fonts, colors, sizes), Mammoth focuses on the semantic structure of the document. For example, a paragraph styled as Heading 1 in Word is converted to an <h1> element in HTML. This approach produces much cleaner and more maintainable HTML code.

    Best Practices: Mammoth works best when you use styles to semantically mark up your document rather than relying on manual formatting.

  2. Use the :fresh modifier to prevent element reuse

    master

    By default, Mammoth reuses HTML elements if they are not explicitly closed. For example, if multiple consecutive paragraphs match p[style-name='Heading 1'] => h1, Mammoth will append the text of subsequent paragraphs into the same h1 element.

    To force Mammoth to create a new element for every match, use the :fresh modifier on the HTML path side.

    Example: Creating separate headings p[style-name='Heading 1'] => h1:fresh

    p[style-name='Heading 1'] => h1:fresh
  3. Customize styles using a Style Map

    master

    Mammoth uses a style_map to decide how Word styles (like Heading 1) map to HTML elements (like <h1>). You can pass this as a string to convert_to_html.

    Common mapping patterns:

    • Paragraph styles: p[style-name='Style Name'] => element:modifier (e.g., p[style-name='Aside Heading'] => div.aside > h2:fresh)
    • Inline styles: b => em (changes bold from <strong> to <em>), i => strong, u => em, strike => del.
    • Comments: comment-reference => sup (appends comments to the end of the document).

    User-defined mappings take precedence over defaults. To use only your mappings, set include_default_style_map=False.

    import mammoth
    
    # Map specific Word styles to HTML elements
    style_map = """
        p[style-name='Section Title'] => h1:fresh
        p[style-name='Subsection Title'] => h2:fresh
    """
    
    with open("document.docx", "rb") as docx_file:
        result = mammoth.convert_to_html(docx_file, style_map=style_map)
  4. Use Document Transforms (Unstable API)

    master

    Mammoth allows you to modify the document structure before it is converted to HTML using the transform_document argument.

    Warning: This API is considered unstable and may change between versions.

    Available Transform Helpers:

    • mammoth.transforms.paragraph(transform_func): Applies transform_func to every paragraph. The function should return the modified (or original) paragraph.
    • mammoth.transforms.run(transform_func): Applies transform_func to every run (inline text segment).
    • mammoth.transforms.get_descendants(element): Returns all descendants of an element.
    • mammoth.transforms.get_descendants_of_type(element, type): Returns descendants of a specific type (e.g., mammoth.documents.Run).
    import mammoth.transforms
    import mammoth.documents
    
    # Example: Transform center-aligned paragraphs into Heading 2
    def transform_paragraph(element):
        if element.alignment == "center" and not element.style_id:
            return element.copy(style_id="Heading2")
        else:
            return element
    
    transform_document = mammoth.transforms.paragraph(transform_paragraph)
    
    mammoth.convert_to_html(docx_file, transform_document=transform_document)
  5. How writing style maps work

    master

    Style maps allow you to control how .docx elements are converted to HTML. A style map consists of mappings separated by new lines. Blank lines and lines starting with # are ignored.

    Each mapping has two parts:

    1. Document element matcher (left side): Matches the .docx element.
    2. HTML path (right side): Defines the resulting HTML structure.

    When converting a paragraph, Mammoth finds the first mapping where the matcher matches the current paragraph and then ensures the HTML path is satisfied.

    p[style-name='Heading 1'] => h1
  6. Match styles by name, prefix, or ID

    master

    You can target specific styles using the following syntax:

    • By Name: Use the exact name displayed in Word/LibreOffice. p[style-name='Heading 1']
    • By Prefix: Use ^= to match styles starting with a string. p[style-name^='Heading']
    • By Style ID: Use a dot followed by the internal .docx style ID. p.Heading1
    p[style-name='Heading 1']
    p[style-name^='Heading']
    p.Heading1
  7. Security considerations for Mammoth

    master

    Mammoth performs no sanitization of the source document. When using it with untrusted user input, be aware of the following risks:

    1. XSS (Cross-Site Scripting): Source documents can contain links with javascript: targets. If you embed the resulting HTML directly into a website, these links can execute arbitrary code.
    2. File Exfiltration: Documents can reference external files. By default, access to these is disabled. Do not set external_file_access=True unless you trust the source.
    3. Denial of Service (DoS): Specially crafted documents can cause high CPU or memory usage. Consider running Mammoth in an isolated process or thread with a timeout to mitigate this.
  8. Use :separator to handle collapsed elements

    master

    When elements are reused (not marked :fresh), Mammoth collapses their contents. To prevent content from running together on a single line, use the :separator modifier to insert a string (like a newline) between them.

    Example: Mapping code block paragraphs to <pre> with newlines p[style-name='Code Block'] => pre:separator('\n')

    p[style-name='Code Block'] => pre:separator('\n')
  9. Extract raw text with `extract_raw_text`

    master

    Extracts the plain text from a .docx file, ignoring all formatting. Each paragraph is followed by two newlines.

    Returns: A result object containing:

    • value: The raw text string.
    • messages: A list of message objects.
    import mammoth
    
    with open("document.docx", "rb") as docx_file:
        result = mammoth.extract_raw_text(docx_file)
        text = result.value
        messages = result.messages
  10. Convert .docx to HTML with `convert_to_html`

    master

    Converts a .docx file (provided as a binary file-like object) to an HTML fragment.

    Returns: A result object containing:

    • value: The generated HTML string.
    • messages: A list of message objects (e.g., warnings).

    Key Arguments:

    • fileobj: The source file opened in binary mode.
    • style_map: A string defining how Word styles map to HTML elements.
    • include_default_style_map: (bool) If False, only your style_map is used.
    • include_embedded_style_map: (bool) If False, ignores style maps embedded in the document.
    • external_file_access: (bool) Set to True to allow access to files referenced outside the document (use only with trusted input).
    • convert_image: An image converter function to override default inline behavior.
    • ignore_empty_paragraphs: (bool) If False, preserves empty paragraphs.
    • id_prefix: (str) A prefix for generated IDs (bookmarks, footnotes, etc.).
    • transform_document: A function to modify the document structure before conversion (unstable API).
    import mammoth
    
    with open("document.docx", "rb") as docx_file:
        result = mammoth.convert_to_html(docx_file)
        html = result.value
        messages = result.messages
  11. Implement custom image handlers

    master

    By default, images are converted to inline Base64-encoded <img> elements. To change this (e.g., to save files to disk or use a different format), provide a custom converter to the convert_image argument via mammoth.images.img_element(func).

    Your function func receives an image object with:

    • open(): Returns a file-like object of the image bytes.
    • content_type: The MIME type (e.g., image/png).

    func must return a dict of attributes for the <img> tag, including a src key.

    import mammoth
    import base64
    
    def convert_image(image):
        with image.open() as image_bytes:
            encoded_src = base64.b64encode(image_bytes.read()).decode("ascii")
    
        return {
            "src": "data:{0};base64,{1}".format(image.content_type, encoded_src)
        }
    
    # Use the converter
    with open("document.docx", "rb") as docx_file:
        result = mammoth.convert_to_html(
            docx_file, 
            convert_image=mammoth.images.img_element(convert_image)
        )