update 文档拆分公式

This commit is contained in:
lijiarao
2023-11-09 10:28:33 +08:00
parent 7300adf1da
commit 2d062b6456
4 changed files with 321 additions and 20 deletions
@@ -7,7 +7,10 @@ package com.jero.modules.split.enums;
*/
public enum SplitFilePragraTypeEnum {
TEXT("TEXT","文字"),IMG("IMG","图片"),TABLE("TABLE","表格");
TEXT("TEXT","文字"),
IMG("IMG","图片"),
TABLE("TABLE","表格"),
MATH("MATH","公式");
private String value;
private String lable;
@@ -13,12 +13,12 @@ import com.jero.modules.split.enums.SplitFileTypeTypeEnum;
import com.jero.modules.split.mapper.SarFileSplitMenuEOMapper;
import com.jero.modules.split.service.IFileSplitItemsEOService;
import com.jero.modules.split.service.ISarFileSplitItemsValEOService;
import com.jero.modules.split.util.AsposeUtil;
import com.jero.modules.split.util.FileSplitUtils;
import com.jero.modules.split.util.ReadWordTable;
import com.jero.modules.split.util.*;
import com.jero.modules.split.vo.TitleNumberVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.shiro.SecurityUtils;
@@ -28,6 +28,9 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMath;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMathArg;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMathPara;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLevelText;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
@@ -36,6 +39,9 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.FileInputStream;
import java.io.IOException;
@@ -52,6 +58,7 @@ import java.util.regex.Pattern;
* <b>日期:</b> 2022-04-07 <br>
* <b>版权所有:<b>版权归北京卡达克数据技术中心所有。<br>
*/
@Slf4j
@Service
@Transactional(value = "transactionManager", readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public class FileSpiltService {
@@ -121,22 +128,22 @@ public class FileSpiltService {
// nowStart.add(String.valueOf(sarFileSplitInfoEO.getStartNumber()));
// }
// 获取文件地址
String fileId = sarFileSplitInfoEO.getFileId();
LambdaQueryWrapper<OSSFile> queryWrapper = new LambdaQueryWrapper();
queryWrapper.eq(OSSFile::getId, fileId);
queryWrapper.orderByDesc(OSSFile::getCreateTime);
List<OSSFile> ossFileList = iossFileService.list(queryWrapper);
if (CollectionUtils.isEmpty(ossFileList)) {
throw new JeroBootException("当前文件未找到,请重新选择!");
}
OSSFile ossFile = ossFileList.get(0);
String readFilePath = ossFile.getUrl();
if (StringUtils.isEmpty(readFilePath) || !MinioUtil.doesObjectExist(readFilePath)) {
throw new JeroBootException("当前文件未找到,请重新选择!");
}
try (InputStream is = MinioUtil.download(readFilePath);InputStream is1 = MinioUtil.download(readFilePath)) {
//String readFilePath = "E:\\Data\\Downloads\\wordtest\\GB7258标准修订test - 表格测试 - 副本.docx";
//try (InputStream is = new FileInputStream(readFilePath); InputStream is1 = new FileInputStream(readFilePath)) {//需要将文件路更改为word文档所在路径。
// String fileId = sarFileSplitInfoEO.getFileId();
// LambdaQueryWrapper<OSSFile> queryWrapper = new LambdaQueryWrapper();
// queryWrapper.eq(OSSFile::getId, fileId);
// queryWrapper.orderByDesc(OSSFile::getCreateTime);
// List<OSSFile> ossFileList = iossFileService.list(queryWrapper);
// if (CollectionUtils.isEmpty(ossFileList)) {
// throw new JeroBootException("当前文件未找到,请重新选择!");
// }
// OSSFile ossFile = ossFileList.get(0);
// String readFilePath = ossFile.getUrl();
// if (StringUtils.isEmpty(readFilePath) || !MinioUtil.doesObjectExist(readFilePath)) {
// throw new JeroBootException("当前文件未找到,请重新选择!");
// }
// try (InputStream is = MinioUtil.download(readFilePath);InputStream is1 = MinioUtil.download(readFilePath)) {
String readFilePath = "E:\\Data\\Downloads\\wordtest\\GB7258标准修订test - 表格测试 - 副本.docx";
try (InputStream is = new FileInputStream(readFilePath); InputStream is1 = new FileInputStream(readFilePath)) {//需要将文件路更改为word文档所在路径。
ZipSecureFile.setMinInflateRatio(-1.0d);
XWPFDocument doc = new XWPFDocument(is);
@@ -165,6 +172,30 @@ public class FileSpiltService {
if (element instanceof XWPFParagraph) {
XWPFParagraph p = (XWPFParagraph) element;
StringBuilder stringBuilder = new StringBuilder();
ParagraphChildOrderManager runOrMaths = new ParagraphChildOrderManager(p);
List<Object> childList = runOrMaths.getChildList();
for (Object child : childList) {
//if (child instanceof XWPFRun) {
// //处理段落中的文本以及图片
// handleParagraphRun(content, (XWPFRun) child, imageParser);
//} else
if (child instanceof CTOMath) {
// 处理word中存在的公式成mathML格式
handleParagraphOMath(stringBuilder, (CTOMath) child);
if (messageList.size() > 0) {
addItermsConditionsMath(messageList.get(messageList.size() - 1), itemValList, stringBuilder.toString());
}
} else if (child instanceof CTOMathPara) {
//处理word中存在的公式
handleParagraphOMath(stringBuilder, (CTOMathPara) child);
if (messageList.size() > 0) {
addItermsConditionsMath(messageList.get(messageList.size() - 1), itemValList, stringBuilder.toString());
}
}
}
for (XWPFRun xwrun : p.getRuns()) {
VerticalAlign subscript = xwrun.getSubscript();
String smalltext = xwrun.getText(0);
@@ -426,7 +457,31 @@ public class FileSpiltService {
return "";
}
/**
* 处理公式
*
* @param content
* @param child
*/
private static void handleParagraphOMath(StringBuilder content, CTOMath child) {
log.info(">> 开始解析段落中的CTOMath公式");
//将word中的omml格式转换成mathML
String mathMLFromNode = OmmlUtils.getMathMLFromNode(child.xmlText());
content.append(mathMLFromNode);
}
/**
* 处理公式(将word中的omML格式的公式转换成mathML格式的工单)
*
* @param content
* @param child
*/
private static void handleParagraphOMath(StringBuilder content, CTOMathPara child) {
log.info(">> 开始解析段落中的CTOMathPara公式");
//将word中的omml格式转换成mathML
String mathMLFromNode = OmmlUtils.getMathMLFromNode(child.xmlText());
content.append(mathMLFromNode);
}
/**
* 通过传递过来的编号,得出下次可能出现的编号
@@ -863,6 +918,113 @@ public class FileSpiltService {
return imageBundleList;
}
private List<String> readMathInParagraph(XWPFParagraph paragraph) {
//图片索引List
List<String> imageBundleList = new ArrayList<String>();
//段落中所有XWPFRun
List<XWPFRun> runList = paragraph.getRuns();
StringBuffer text = new StringBuffer();
for (XWPFRun run : runList) {
Node runNode = run.getCTR().getDomNode();
text.append(getText(runNode));
String math = getMath(run, runNode);
text.append(math);
}
System.out.println("段落内容:".concat(text.toString()));
return imageBundleList;
}
/**
* 获取字符串
*
* @param runNode
* @return
*/
private String getText(Node runNode) {
Node textNode = getChildNode(runNode, "w:t");
if (textNode == null) {
return "";
}
return textNode.getFirstChild().getNodeValue();
}
private String getMath(XWPFRun run, Node runNode) {
Node objectNode = getChildNode(runNode, "m:oMathPara");
if (objectNode == null) {
return "";
}
Node shapeNode = getChildNode(objectNode, "v:shape");
if (shapeNode == null) {
return "";
}
Node imageNode = getChildNode(shapeNode, "v:imagedata");
if (imageNode == null) {
return "";
}
Node binNode = getChildNode(objectNode, "o:OLEObject");
if (binNode == null) {
return "";
}
XWPFDocument word = run.getDocument();
NamedNodeMap shapeAttrs = shapeNode.getAttributes();
// 图片在Word中显示的宽高
String style = shapeAttrs.getNamedItem("style").getNodeValue();
System.out.println("图片宽高:".concat(style));
System.out.println("--------------");
NamedNodeMap imageAttrs = imageNode.getAttributes();
// 图片在Word中的ID
String imageRid = imageAttrs.getNamedItem("r:id").getNodeValue();
// 获取图片信息
PackagePart imgPart = word.getPartById(imageRid);
System.out.println("图片名称".concat(imgPart.getPartName().getName()));
try {
System.out.println(imgPart.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("--------------");
NamedNodeMap binAttrs = binNode.getAttributes();
// 公式二进制文件在Word中的ID
String binRid = binAttrs.getNamedItem("r:id").getNodeValue();
// 获取二进制文件
PackagePart binPart = word.getPartById(binRid);
System.out.println("二进制文件名称:".concat(binPart.getPartName().getName()));
try {
System.out.println(binPart.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("--------------");
return "{公式#}";
}
private Node getChildNode(Node node, String nodeName) {
if (!node.hasChildNodes()) {
return null;
}
NodeList childNodes = node.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
if (nodeName.equals(childNode.getNodeName())) {
return childNode;
}
childNode = getChildNode(childNode, nodeName);
if (childNode != null) {
return childNode;
}
}
return null;
}
// 像每个条款中依次插入每一段的内容
public static void addItermsConditionsText(SarFileSplitItemsEO message, List<SarFileSplitItemsValEO> itemsValList, String p) {
message.getItemsCondi().add(p);
@@ -870,6 +1032,13 @@ public class FileSpiltService {
itemsValList.add(getSplitItemsValObject(message.getId(), SplitFilePragraTypeEnum.TEXT.getValue(), p, message.getItemsCondi().size(), null));
}
// 像每个条款中依次插入每一段的内容
public static void addItermsConditionsMath(SarFileSplitItemsEO message, List<SarFileSplitItemsValEO> itemsValList, String p) {
message.getItemsCondi().add(p);
message.setItemContent(message.getItemContent() + "<p>" + p + "</p>");
itemsValList.add(getSplitItemsValObject(message.getId(), SplitFilePragraTypeEnum.MATH.getValue(), p, message.getItemsCondi().size(), null));
}
public static void addItermsConditionsOfTable(SarFileSplitItemsEO message, List<SarFileSplitItemsValEO> itemsValList, XWPFTable table) throws IOException {
StringBuilder tabaleStringNew = new StringBuilder("");
//将表格转为html字符串
@@ -0,0 +1,42 @@
package com.jero.modules.split.util;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
/**
* @author liJiaRao
* @date 2023-11-09 9:51
*/
public class OmmlUtils {
/**
* 将word文档中公式格式为omML转换为mathMl
* @param omML
* @return
*/
public static String getMathMLFromNode(String omML) {
//通过word中的xsl转成器解析omml公式格式
//StreamSource xslSource = new StreamSource(new File("src/main/resources/OMML2MML.XSL"));
StringWriter writer = new StringWriter();
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
Source sources = new StreamSource(new StringReader(omML));
StreamResult result = new StreamResult(writer);
t.transform(sources, result);
} catch (TransformerException e) {
e.printStackTrace();
}
String mathML = writer.getBuffer().toString();
mathML = mathML.replaceAll("xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"", "");
mathML = mathML.replaceAll("xmlns:mml", "xmlns");
mathML = mathML.replaceAll("mml:", "");
return mathML;
}
}
@@ -0,0 +1,87 @@
package com.jero.modules.split.util;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMath;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMathPara;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* 可以把公式和XWPFRun按顺序遍历,用到了以CTP开头的底层方式
* <p>
* XWPFParagraph中主有两个方法可以分别提出XWPFRun和CTOMath,但是不知道位置
* ParagraphChildOrderManager这个类是专门解决这个问题的
* @author liJiaRao
* @date 2023-11-09 9:24
*/
public class ParagraphChildOrderManager {
public static int TYPE_RUN = 1;
public static int TYPE_OMATH = 2;
List<Integer> typeList = new ArrayList<Integer>();
XWPFParagraph p;
public ParagraphChildOrderManager(XWPFParagraph paragraph) {
this.p = paragraph;
//using a cursor to go through the paragraph from top to down
XmlCursor xmlcursor = paragraph.getCTP().newCursor();
while (xmlcursor.hasNextToken()) {
XmlCursor.TokenType tokenType = xmlcursor.toNextToken();
if (tokenType.isStart()) {
if (xmlcursor.getName().getPrefix().equalsIgnoreCase("w") && xmlcursor.getName().getLocalPart().equalsIgnoreCase("r")) {
typeList.add(TYPE_RUN);
} else if (xmlcursor.getName().getLocalPart().equalsIgnoreCase("oMath")) {
typeList.add(TYPE_OMATH);
}
} else if (tokenType.isEnd()) {
xmlcursor.push();
xmlcursor.toParent();
if (xmlcursor.getName().getLocalPart().equalsIgnoreCase("p")) {
break;
}
xmlcursor.pop();
}
}
}
public List<Object> getChildList() {
List<Object> runsOrMathList = new ArrayList<Object>();
List<XWPFRun> runs = p.getRuns();
List<CTOMath> oMathList = p.getCTP().getOMathList();
// Queue<Object> mathQueue = null;
if (oMathList != null && oMathList.size() > 0) {
Queue<XWPFRun> runsQueue = new LinkedList<XWPFRun>(runs);
Queue<CTOMath> mathQueue = new LinkedList<CTOMath>(oMathList);
for (int i = 0; i < typeList.size(); i++) {
Integer type = typeList.get(i);
if (type.equals(TYPE_RUN) && runs.size() > 0) {
runsOrMathList.add(runsQueue.poll());
} else if (type.equals(TYPE_OMATH) && mathQueue.size() > 0) {
runsOrMathList.add(mathQueue.poll());
}
}
return runsOrMathList;
} else {
List<CTOMathPara> oMathParaList = p.getCTP().getOMathParaList();
Queue<XWPFRun> runsQueue = new LinkedList<XWPFRun>(runs);
Queue<CTOMathPara> mathQueue = new LinkedList<CTOMathPara>(oMathParaList);
for (int i = 0; i < typeList.size(); i++) {
Integer type = typeList.get(i);
if (type.equals(TYPE_RUN) && runs.size() > 0) {
runsOrMathList.add(runsQueue.poll());
} else if (type.equals(TYPE_OMATH) && mathQueue.size() > 0) {
runsOrMathList.add(mathQueue.poll());
}
}
return runsOrMathList;
}
}
}