update 文档拆分公式
This commit is contained in:
+4
-1
@@ -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;
|
||||
|
||||
+188
-19
@@ -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;
|
||||
}
|
||||
}
|
||||
+87
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user