Good day.
I must generete docx or odt file with many math formulas inside.
i try to find solution in Apashe POI & ODFtoolkit but i am not was able.
google doesn't help. (
May be anybody can help me with solution in this task?
(any example?)
Thanks.
You could use the docx4j library. Here is the documentation for Getting started.
I recommend that you create a template file first, with all the formatting, and as much structure as you can. Then you should put in content-controls where you want your text to go. The content controls could contain other content, that you could use to repeat some common structure.
In Word, the Content Controls can be found in the Developer tab on the main ribbon. They are named Rich Text Content Control and Plain Text Content Control. You might need to enable the Developer Tab first though. In the options, under Customize ribbon, check Developer.
To change the tag of a Content Control, click its handle on the page to select it, and then press the Control Properties button on the ribbon. You will then get a dialog where you can set the title and the tag.
In Java, the content controls will be represented in the object model as SdtBlock
or SdtRun
. When you are processing the template, you should replace those with the content you want.
The org.docx4j.math
package contains the classes for creating math formulas.
Here is an example:
import java.*;
import java.io.*;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.namespace.*;
import org.docx4j.wml.*;
import org.docx4j.math.*;
import org.docx4j.openpackaging.packages.*;
import org.docx4j.openpackaging.parts.WordprocessingML.*;
public class Processor
{
public static void main(String[] args) throws Exception
{
File inFile = new File(args[0]);
File outFile = new File(args[1]);
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(inFile);
MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
Processor processor = new Processor();
processor.processContent(mdp.getContent());
wordMLPackage.save(outFile);
}
private Stack<String> tags = new Stack<String>();
private void pushTag(String tag)
{
tags.push(tag);
}
private String getTag()
{
return tags.peek();
}
private void popTag()
{
tags.pop();
}
private static final org.docx4j.wml.ObjectFactory wmlFactory = new org.docx4j.wml.ObjectFactory();
private static final org.docx4j.math.ObjectFactory mathFactory = new org.docx4j.math.ObjectFactory();
public void processContent(List<Object> content)
{
for (Object child : content)
{
if (child instanceof SdtBlock)
{
processBlock((SdtBlock) child);
}
else if (child instanceof P)
{
processP((P) child);
}
else if (child instanceof JAXBElement)
{
JAXBElement<?> elem = (JAXBElement<?>) child;
Class<?> elemType = elem.getDeclaredType();
if (elemType.equals(CTOMath.class))
{
processOMath((CTOMath) elem.getValue());
}
}
}
}
public void processP(P p)
{
processContent(p.getContent());
}
public void processBlock(SdtBlock block)
{
String tag = block.getSdtPr().getTag().getVal();
pushTag(tag);
processContent(block.getSdtContent().getContent());
popTag();
}
public void processOMath(CTOMath oMath)
{
String tag = getTag(); // tag of innermost <w:sdt>
if (getTag().equals("MyEquation"))
{
List<Object> content = oMath.getEGOMathElements();
content.clear();
content.add(makeRun("A=\u03c0"));
content.add(makeSSup(makeRun("r"), makeRun("2")));
}
}
private JAXBElement<CTR> makeRun(String text)
{
// <m:r>
CTR run = mathFactory.createCTR();
List<Object> content = run.getContent();
// <w:rPr><w:rFonts>
RPr pr = wmlFactory.createRPr();
RFonts rFonts = wmlFactory.createRFonts();
rFonts.setAscii("Cambria Math");
rFonts.setHAnsi("Cambria Math");
pr.setRFonts(rFonts);
content.add(wmlFactory.createSdtPrRPr(pr));
// <m:t>
CTText ctText = mathFactory.createCTText();
ctText.setValue(text);
content.add(mathFactory.createCTRTMath(ctText));
return mathFactory.createCTOMathArgR(run);
}
private JAXBElement<CTSSup> makeSSup(Object expr, Object exp)
{
// <m:ssup>
CTSSup ssup = mathFactory.createCTSSup();
// <m:e>
CTOMathArg eArg = mathFactory.createCTOMathArg();
eArg.getEGOMathElements().add(expr);
ssup.setE(eArg);
// <m:sup>
CTOMathArg supArg = mathFactory.createCTOMathArg();
supArg.getEGOMathElements().add(exp);
ssup.setSup(supArg);
return mathFactory.createCTOMathArgSSup(ssup);
}
}
It will look for block-level content-controls named "MyEquation", and replace the math-expressions in them with A=πr2
.
Specifically, it will look for
<w:sdt>
<w:sdtPr>
<w:tag w:val="MyEquation"/>
</w:sdtPr>
<w:sdtContent>
<w:p>
<m:oMath>
</m:oMath>
</w:p>
</w:sdtContent>
</w:sdt>
and replace it with
<w:p>
<m:oMath>
<m:r>
<w:rPr>
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
</w:rPr>
<m:t>A=π</m:t>
</m:r>
<m:sSup>
<m:sSupPr>
<m:ctrlPr>
<w:rPr>
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
</w:rPr>
</m:ctrlPr>
</m:sSupPr>
<m:e>
<m:r>
<w:rPr>
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
</w:rPr>
<m:t>r</m:t>
</m:r>
</m:e>
<m:sup>
<m:r>
<w:rPr>
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
</w:rPr>
<m:t>2</m:t>
</m:r>
</m:sup>
</m:sSup>
</m:oMath>
</w:p>
You can make the equation in Word, and look inside the docx-file. They are stored as zip-files, containing a lot of XML. Specifically, you want to look in the word/document.xml
file.
Also you can use Fmath library to generate OOXML code and then push it to docx files by doc4j library.
Here is some good examples.
http://www.fmath.info/java/latex-mathml-converter/