Office Math Markup Language (OMML, ECMA-376 part 1 §22.1) — typed model + builders.
Module ooxmlMath | Source packages/front/office/ooxml/src/math/math.js | Deps ooxmlErrors, xml | Worker-safe yes
OMML is cross-format: the same <m:…> markup appears in docx, pptx and (rarely) xlsx. The module types the structural constructs (fraction, superscript, radical, n-ary, delimiter, function, matrix, accent, bar, box); each "slot" is an array of mathElement, so composition is plain concatenation. Unknown elements are preserved as mathUnknown.
Resolve
const m = runtime.resolve('ooxmlMath');
// Returns: { parseOMath, renderOMath, parseOMathPara, renderOMathPara,
// parseMathElement, renderMathElement,
// r, frac, sup, sub, subSup, rad, nary, delim, func, matrix,
// oMath, oMathPara, M_NS }
API
| Method | Signature | Returns |
|---|---|---|
parseOMath |
(el: element) => oMathNode |
{ type:'oMath', children:[…] }. |
renderOMath |
(node) => element |
<m:oMath>. |
parseOMathPara / renderOMathPara |
symmetric | Block-level wrapper. |
parseMathElement / renderMathElement |
(el) / (node) |
Dispatch on the tag. |
r |
(text, sty?) => mathRun |
sty ∈ 'p'|'b'|'i'|'bi'. |
frac |
(num, den) => fracNode |
Numerator / denominator (each a slot or a single element). |
sup / sub |
(base, exp) => sSupNode | sSubNode |
Superscript / subscript. |
subSup |
(base, sub, sup) => sSubSupNode |
Both at once. |
rad |
(base, degree?) => radNode |
n-th root (empty degree → square root). |
nary |
(op, sub, sup, body) => naryNode |
Sum / integral / product. |
delim |
(content, opts?) => dNode |
Parens/brackets; opts: {open,close,sep}. |
func |
(name, body) => funcNode |
Function application f(x). |
matrix |
(rows: slot[][]) => mNode |
m×n matrix. |
oMath / oMathPara |
varargs builders | Top-level wrappers. |
M_NS |
string | The …/math namespace. |
Model (summary)
mathElement :=
| { type:'mathRun', text, rPr?:{sty} }
| { type:'frac', numerator:[me], denominator:[me] }
| { type:'sSup'|'sSub', base:[me], sup\|sub:[me] }
| { type:'sSubSup', base:[me], sub:[me], sup:[me] }
| { type:'rad', degree:[me], base:[me] }
| { type:'nary', op:string, sub:[me], sup:[me], body:[me] }
| { type:'d', open?, close?, sep?, children:[[me]] }
| { type:'func', name:[me], body:[me] }
| { type:'m', rows:[[[me]]] }
| { type:'acc'|'bar'|'box', ... }
| { type:'mathUnknown', node }
Examples
Build (a+b)² / 2
const m = runtime.resolve('ooxmlMath');
const expr = m.oMath(
m.frac(
m.sup(m.delim([m.r('a+b')]), m.r('2')),
m.r('2')
)
);
m.renderOMath(expr);
// → <m:oMath>…</m:oMath>
Sum of i² from 1 to n
m.oMath(
m.nary('∑', m.r('i=1'), m.r('n'), m.sup(m.r('i'), m.r('2')))
);
Round-trip
const node = m.parseOMath(xml.parse(omml));
m.renderOMath(node);
// Equivalent XML (except for `_extras`, which this module does not handle).
Notes
- Every builder accepts either a single element or an array —
r('x')or[r('x'), r('+'), r('y')]. delimdetects single-slot vs multi-slot automatically ([[…], […]]).mathRun.rPr.styfollows §22.1.2.114:'p'plain,'b'bold,'i'italic,'bi'both.- OMML elements that are not modelled (limits, advanced alignment) become
mathUnknownand are preserved in and out. - The
xml:space="preserve"attribute is set on<m:t>so significant whitespace survives the round-trip.
See also
- drawingml — also accepts math inside text bodies.
- docx-structure —
oMathParainside the docx body. - ooxmlErrors —
math/unknown-node-typeis raised by the renderer.