python-docx-template icon indicating copy to clipboard operation
python-docx-template copied to clipboard

Generating Word equation

Open Mill7 opened this issue 4 years ago • 5 comments

Hi folks,

I am trying to generate a Word equation using MathML. Basically, I inject some MathML code in a variable then creating an alias to this variable in my template. However, this does not show up as a Word equation, instead we see the MathML code. The MathML seems to be copied as "Unformatted Unicode Text". Would you have an idea how I could deal with that please ?

Many thanks !

Mill7 avatar Jan 04 '22 10:01 Mill7

Modifying mathematical expression is not and will not be supported, see #334

elapouya avatar Jan 22 '22 09:01 elapouya

I continue to believe that dealing with Word equations would make docxtpl users happier.

Mill7 avatar Jan 25 '22 11:01 Mill7

May be I was a little too quick, I just found this post :

https://stackoverflow.com/questions/60997398/is-there-a-complete-example-to-write-a-mathematical-expression-in-sympy-to-a-mic

This could be a way. I re-open the issue and mark it as request for enhancement

elapouya avatar Jan 25 '22 11:01 elapouya

I tried to use MathMl manually i.e. by putting some MathMl code in a Python variable that I then send to my Word template in an Equation zone. The issue is that what appears is the MathMl code, not the equation, it is needed to enter in the Equation field then press Enter to make the equation appear.

Mill7 avatar Feb 18 '22 12:02 Mill7

It works already using the method from the link above, albeit with some nasty hacks. Create a separate document with the equation and include that document as a subdocument in a template:

from docxtpl import DocxTemplate
from lxml import etree

doc = DocxTemplate('calcexport.docx')

mathml = '<math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mrow><msub><mi>I</mi><mrow><mi>Н</mi><mi>Б</mi></mrow></msub><mo>&#x0003D;</mo><mo stretchy="false">&#x00028;</mo><mo stretchy="false">&#x00028;</mo><msub><mi>K</mi><mrow><mi>r</mi></mrow></msub><mi>&#x000B7;</mi><msub><mi>&#x003F5;</mi><mrow><mi>m</mi><mi>a</mi><mi>x</mi></mrow></msub><mo>&#x0002B;</mo><mi>&#x00394;</mi><msub><mi>U</mi><mrow><mn>2</mn></mrow></msub><mi>&#x000B7;</mi><mi>&#x00394;</mi><mi>f</mi><mo stretchy="false">&#x00029;</mo><mo>&#x0002F;</mo><mn>100</mn><mo stretchy="false">&#x00029;</mo><mo>&#x0003D;</mo><mn>0</mn><mo>&#x0002C;</mo><mn>3102</mn></mrow></math>'
tree = etree.fromstring('<math xmlns="http://www.w3.org/1998/Math/MathML">' + mathml + '</math>')
# convert to MS Office structure
xslt = etree.parse('MML2OMML.XSL')
transform = etree.XSLT(xslt)
new_dom = transform(tree)
# write to docx
equation_document = doc.new_subdoc()
p = equation_document.add_paragraph()
p._element.append(new_dom.getroot())

# monkey patch namespace because when adding the subdoc to the template the 'm' namespace gets lost
old_get_xml = equation_document._get_xml
def new_get_xml():
    xml = old_get_xml()
    return xml.replace('<m:oMath xmlns:mml="http://www.w3.org/1998/Math/MathML">', '<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">')

equation_document._get_xml = new_get_xml

doc.render({"equation_document": equation_document})
doc.save("document_with_equation.docx")

With calcexport.docx a simple template containing {{p equation_document }} and MML2OMML.XSL from the following source: https://github.com/python-openxml/python-docx/issues/320#issuecomment-342798909

It would definitely be nice if this was officially supported and didn't require such ugly hacks :)

RemcoTukker avatar Jun 11 '22 21:06 RemcoTukker