DOCX math: a delimiter with several arguments keeps only the last one
Los mantenedores suelen responder en 1 día
@drakeo338 ya está trabajando en esto.
Desde el 1/10/2026.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 86/100
Línea de trabajo
Comienza en packages/markitdown/src/markitdown/converter_utils/docx/math/omml.py, leyendo oMath2Latex.do_d, Pr, process_children_dict() y process_children_list(). Vuelve a ejecutar los ejemplos XML del issue y verifica después que todos los argumentos delimiter se conserven en orden y que los casos de sepChr explícito, omitido y sin valor produzcan los separadores esperados.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
When a Word equation contains a delimiter (<m:d>) with more than one argument, MarkItDown keeps only the last argument and drops the rest without any warning. The separator character (<m:sepChr>) is never read either.
Word writes this structure for the bracket templates "with separators" (Insert > Equation > Bracket), for example (a|b), {x|x>0} and bra-ket notation.
Repro
from xml.etree import ElementTree as ET
from markitdown.converter_utils.docx.math.omml import OMML_NS, oMath2Latex
M = f'xmlns:m="{OMML_NS[1:-1]}"'
def latex(xml):
return oMath2Latex(ET.fromstring(f"<m:oMath {M}>{xml}</m:oMath>")).latex
r = lambda t: f"<m:r><m:t>{t}</m:t></m:r>"
# Explicit separator
print(latex(r("f") + '<m:d><m:dPr><m:sepChr m:val=","/></m:dPr>'
f"<m:e>{r('x')}</m:e><m:e>{r('y')}</m:e></m:d>"))
# -> f\left(y\right)
# Set-builder braces, default separator (no sepChr)
print(latex('<m:d><m:dPr><m:begChr m:val="{"/><m:endChr m:val="}"/></m:dPr>'
f"<m:e>{r('x')}</m:e><m:e>{r('x>0')}</m:e></m:d>"))
# -> \left\{x>0\right\}
End to end, adding the first equation to a copy of tests/test_files/equations.docx makes MarkItDown().convert() emit $$f\left(y\right)$$.
Expected vs actual
| Input | Expected | Actual |
|---|---|---|
f + <m:d> with sepChr=",", args x, y |
f\left(x,y\right) |
f\left(y\right) |
<m:d> braces, no sepChr, args x, x>0 |
\left\{x|x>0\right\} |
\left\{x>0\right\} |
<m:d> with sepChr=";", args a, b, c |
\left(a;b;c\right) |
\left(c\right) |
In the OMML schema (ECMA-376 / ISO/IEC 29500-1, CT_D), <m:e> has maxOccurs="unbounded". The sepChr element "specifies the character that separates base arguments e in the delimiter object d". When the element is omitted, the separator is a vertical bar (U+2502). When it is present without m:val, there is no separator. See the Open XML SDK SeparatorChar reference, which reproduces the spec text. Dropping arguments silently loses document content.
Cause
In packages/markitdown/src/markitdown/converter_utils/docx/math/omml.py, oMath2Latex.do_d reads its children with process_children_dict(). That function returns a dict keyed by tag name, so each <m:e> overwrites the previous one and c_dict["e"] holds only the last argument. Separately, Pr.__val_tags (and Pr.tag2meth) do not include sepChr, so pr.sepChr is always None.
Suggested fix
In do_d, collect every <m:e> in order with process_children_list(elm, include=("e",)). Have Pr read sepChr, with an empty value when m:val is missing. Then join the arguments with the separator, falling back to | when sepChr is absent. A single-argument delimiter gives the same output as before.
Environment
- markitdown
mainat 1f9530a (0.1.8) - Python 3.13, macOS
AI assistance: drafted with an AI coding assistant (Claude). The reproduction above was run locally against the current default branch.
- Lenguaje dominante
- Python
- Estrellas
- 194k
- Forks
- 14.5k
- Merge medio
- 1 h 43 min
- PR fusionados (30 d)
- 8
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Incluye un Dockerfile o un archivo de Docker Compose
- Sin plantilla de pull request
- Sin guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de microsoft/markitdown
-
DOCX: math pre-processing re-parses every document.xml even without equations (32 s -> 17.5 s on a 12.5 MB document)Posiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 89/100
microsoft/markitdown#2834 ·
Los mantenedores suelen responder en 1 día
-
URL fetch sends default python-requests User-Agent, Wikipedia returns 403Posiblemente ocupada @sushan5140 la tomó hace 4 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
microsoft/markitdown#2820 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Valid Atom feeds with zero entries are rejected as an unknown feed typePosiblemente ocupada @pujitha24 la tomó hace 11 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
microsoft/markitdown#2781 ·
Los mantenedores suelen responder en 1 día
-
DOCX: footnote references and back-links point to anchors that don't exist in the MarkdownPosiblemente ocupada @sun04222 la tomó hace 15 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
microsoft/markitdown#2743 ·
Los mantenedores suelen responder en 1 día
-
DOCX: Heading 7-9 styles lose heading structure entirely (render as plain paragraphs)Posiblemente ocupada @stanleys12 la tomó hace 42 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
microsoft/markitdown#2530 ·
Los mantenedores suelen responder en 1 día
Todos los issues de microsoft/markitdown
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
huggingface/accelerate#4511 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
pylint-dev/pylint#11791 ·
Los mantenedores suelen responder en 1 día
-
Rasterio granule reads never retry, so one 503 (Service Unavailable) fails the whole requestPosiblemente ocupada @chuckwondo la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
developmentseed/titiler-cmr#305 ·
Los mantenedores suelen responder en 1 día
-
community enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día