From 2d062b6456cf3a8578aa81634c38928d9d19e4fc Mon Sep 17 00:00:00 2001 From: lijiarao Date: Thu, 9 Nov 2023 10:28:15 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E6=96=87=E6=A1=A3=E6=8B=86=E5=88=86?= =?UTF-8?q?=E5=85=AC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../split/enums/SplitFilePragraTypeEnum.java | 5 +- .../split/service/impl/FileSpiltService.java | 207 ++++++++++++++++-- .../jero/modules/split/util/OmmlUtils.java | 42 ++++ .../util/ParagraphChildOrderManager.java | 87 ++++++++ 4 files changed, 321 insertions(+), 20 deletions(-) create mode 100644 laws-modules/src/main/java/com/jero/modules/split/util/OmmlUtils.java create mode 100644 laws-modules/src/main/java/com/jero/modules/split/util/ParagraphChildOrderManager.java diff --git a/laws-modules/src/main/java/com/jero/modules/split/enums/SplitFilePragraTypeEnum.java b/laws-modules/src/main/java/com/jero/modules/split/enums/SplitFilePragraTypeEnum.java index bc627224..5053c0c1 100644 --- a/laws-modules/src/main/java/com/jero/modules/split/enums/SplitFilePragraTypeEnum.java +++ b/laws-modules/src/main/java/com/jero/modules/split/enums/SplitFilePragraTypeEnum.java @@ -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; diff --git a/laws-modules/src/main/java/com/jero/modules/split/service/impl/FileSpiltService.java b/laws-modules/src/main/java/com/jero/modules/split/service/impl/FileSpiltService.java index 0fbd9b88..980c536c 100644 --- a/laws-modules/src/main/java/com/jero/modules/split/service/impl/FileSpiltService.java +++ b/laws-modules/src/main/java/com/jero/modules/split/service/impl/FileSpiltService.java @@ -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; * 日期: 2022-04-07
* 版权所有:版权归北京卡达克数据技术中心所有。
*/ +@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 queryWrapper = new LambdaQueryWrapper(); - queryWrapper.eq(OSSFile::getId, fileId); - queryWrapper.orderByDesc(OSSFile::getCreateTime); - List 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 queryWrapper = new LambdaQueryWrapper(); +// queryWrapper.eq(OSSFile::getId, fileId); +// queryWrapper.orderByDesc(OSSFile::getCreateTime); +// List 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 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 readMathInParagraph(XWPFParagraph paragraph) { + //图片索引List + List imageBundleList = new ArrayList(); + + //段落中所有XWPFRun + List 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 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 itemsValList, String p) { + message.getItemsCondi().add(p); + message.setItemContent(message.getItemContent() + "

" + p + "

"); + itemsValList.add(getSplitItemsValObject(message.getId(), SplitFilePragraTypeEnum.MATH.getValue(), p, message.getItemsCondi().size(), null)); + } + public static void addItermsConditionsOfTable(SarFileSplitItemsEO message, List itemsValList, XWPFTable table) throws IOException { StringBuilder tabaleStringNew = new StringBuilder(""); //将表格转为html字符串 diff --git a/laws-modules/src/main/java/com/jero/modules/split/util/OmmlUtils.java b/laws-modules/src/main/java/com/jero/modules/split/util/OmmlUtils.java new file mode 100644 index 00000000..8fbcbeaf --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/split/util/OmmlUtils.java @@ -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; + } +} diff --git a/laws-modules/src/main/java/com/jero/modules/split/util/ParagraphChildOrderManager.java b/laws-modules/src/main/java/com/jero/modules/split/util/ParagraphChildOrderManager.java new file mode 100644 index 00000000..b025fb4e --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/split/util/ParagraphChildOrderManager.java @@ -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开头的底层方式 + *

+ * 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 typeList = new ArrayList(); + 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 getChildList() { + List runsOrMathList = new ArrayList(); + List runs = p.getRuns(); + List oMathList = p.getCTP().getOMathList(); + +// Queue mathQueue = null; + if (oMathList != null && oMathList.size() > 0) { + Queue runsQueue = new LinkedList(runs); + Queue mathQueue = new LinkedList(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 oMathParaList = p.getCTP().getOMathParaList(); + Queue runsQueue = new LinkedList(runs); + Queue mathQueue = new LinkedList(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; + } + } +}