Skip to content

Expose OMML equation content (m:oMath) - equations are silently dropped from Paragraph.text #95

Closed

Description

@toxicphreAK

Word stores equations as OMML — m:oMath inline in a paragraph, or m:oMathPara as a block-level sibling of w:p. Neither is reachable from the API, and the m namespace (http://schemas.openxmlformats.org/officeDocument/2006/math) is not even in oxml/ns.py's nsmap.

This is silent data loss rather than a missing convenience. Equation text lives in m:t inside m:r, not in w:t inside w:r, so:

  • Paragraph.text drops every equation in the paragraph with no indication one was there
  • Paragraph.runs and iter_inner_content() skip them
  • replace_text() and isolate_run() offsets are computed over text that does not match what the document shows

A document like The result is <equation> for all n reads back as The result is for all n.

(Font.oMath already exists but is unrelated — that is w:rPr/w:oMath, the flag marking a run as part of an equation, not the equation content.)

Where the prior art is

VanOord/vo-python-docx, branches equation_support and update_package, adds docx/oxml/math.py with CT_OMath and CT_OMathPara, docx/text/math.py with an Equation proxy exposing .raw_xml, and Paragraph.equations returning [Equation(eq, self) for eq in self._p.oMathPara_lst].

That is the minimum viable version — find the equations, hand back their XML. It is a reasonable first target; a full OMML object model is a much larger job and probably not worth it.

Shape

  • m in nsmap, and the schema is already vendored at ref/xsd/shared-math.xsd
  • CT_OMath / CT_OMathPara registered in oxml/__init__.py
  • Math proxy in a new docx/math.py with at least .xml and .text (the concatenation of the m:t descendants)
  • Paragraph.math / Document.math, and inclusion in Paragraph.iter_inner_content()

Decide explicitly

Whether Paragraph.text should include equation text. Including it is more truthful about the document's content and keeps replace_text() offsets honest, but it is a behaviour change for anyone parsing documents with equations. Given 2.0.0 already redefined Paragraph.text for tracked changes and w:fldSimple, doing it here in the same release is the cheaper moment. Whatever is chosen needs a HISTORY.rst entry.

Activity

  1. toxicphreAK commented on Aug 5, 2026

    @toxicphreAK
    OwnerAuthor

    Landed in #139. Paragraph.math, BlockItemContainer.math and Document.math, each Math offering .text, .xml and .is_display.

    On the explicit decision the issue asked for: equation text is not included in Paragraph.text. Including it would describe the document more truthfully, but replace_text() and isolate_range() measure offsets against Paragraph.text and can only cut at run boundaries; equation text lives in m:t inside m:r and is unreachable to them, so including it would silently mis-target every replacement after the first equation in a paragraph. A wrong edit is worse than a missing character. In HISTORY.rst.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions