【修改】完善wps考点

This commit is contained in:
huababa1
2025-09-15 18:04:43 +08:00
parent 247d0ab258
commit f3d30370e8
4 changed files with 716 additions and 128 deletions

View File

@@ -1,6 +1,7 @@
package com.example.exam.exam.service.wpsexcel.chart;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
@@ -11,10 +12,11 @@ import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGraphicalObjectFrame;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPivotTableDefinition;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -33,7 +35,9 @@ import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -144,35 +148,40 @@ public class ChartHandler {
if (ctChart == null || ctChart.getPlotArea() == null) return "无数据系列";
CTPlotArea plotArea = ctChart.getPlotArea();
StringBuilder sb = new StringBuilder();
// 使用 Set 去重
Set<String> generationSet = new LinkedHashSet<>();
// 遍历柱状图
for (CTBarChart barChart : plotArea.getBarChartList()) {
for (CTBarSer ser : barChart.getSerList()) {
String gen = getSeriesGeneration(ser.getTx());
sb.append(gen).append("; ");
generationSet.add(getSeriesGeneration(ser.getTx()));
}
}
// 遍历折线图
for (CTLineChart lineChart : plotArea.getLineChartList()) {
for (CTLineSer ser : lineChart.getSerList()) {
String gen = getSeriesGeneration(ser.getTx());
sb.append(gen).append("; ");
generationSet.add(getSeriesGeneration(ser.getTx()));
}
}
// 遍历饼图
for (CTPieChart pieChart : plotArea.getPieChartList()) {
for (CTPieSer ser : pieChart.getSerList()) {
String gen = getSeriesGeneration(ser.getTx());
sb.append(gen).append("; ");
generationSet.add(getSeriesGeneration(ser.getTx()));
}
}
return sb.length() > 0 ? sb.substring(0, sb.length() - 2) : "无数据系列";
if (generationSet.isEmpty()) {
return "无数据系列";
}
// 把 Set 转成字符串,输出唯一的产生方式
return String.join("; ", generationSet);
}
/** 图表-数据-数据系列 - 名称 */
public String getDataSeriesNames(XSSFChart chart, XSSFSheet sheet) {
if (chart == null) return "无图表";
@@ -329,96 +338,54 @@ public class ChartHandler {
return "未找到图表位置";
}
/** 图表-设计 - 图表样式*\
public String getChartStyle(XSSFChart chart, XSSFSheet sheet) {
if (chart == null) return "无图表";
/** 图表-设计 - 图表样式 */
public String getChartStyle(XSSFChart chart, XSSFSheet sheet) {
if (chart == null) return "无图表";
try {
Node chartNode = chart.getCTChartSpace().getDomNode();
}
// 先尝试取 c14:style
NodeList c14StyleNodes = ((Element) chartNode)
.getElementsByTagNameNS("http://schemas.microsoft.com/office/drawing/2007/8/2/chart", "style");
if (c14StyleNodes.getLength() > 0) {
String val = ((Element) c14StyleNodes.item(0)).getAttribute("val");
int styleId = Integer.parseInt(val);
// 映射 101114 → 114
if (styleId >= 101 && styleId <= 114) {
styleId -= 100;
}
return "样式" + styleId;
}
// 再尝试取 c:style
NodeList cStyleNodes = ((Element) chartNode)
.getElementsByTagNameNS("http://schemas.openxmlformats.org/drawingml/2006/chart", "style");
if (cStyleNodes.getLength() > 0) {
String val = ((Element) cStyleNodes.item(0)).getAttribute("val");
int styleId = Integer.parseInt(val);
return "样式" + styleId;
}
return "未定义样式";
} catch (Exception e) {
e.printStackTrace();
return "解析图表样式时出错: " + e.getMessage();
}
}
/**
/**
* 打印图表对应的 XML
*/
public static void printChartXml(XSSFChart chart) {
if (chart == null) {
System.out.println("无图表");
return;
}
try {
PackagePart part = chart.getPackagePart();
try (InputStream is = part.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
String xml = chart.getCTChartSpace().xmlText();
System.out.println(xml);
} catch (Exception e) {
e.printStackTrace();
System.out.println("读取图表XML失败: " + e.getMessage());
}
}
/** 获取图表高度,返回"磅(厘米)" */
public static String getChartHeight(XSSFChart chart, XSSFSheet sheet) {
if (chart == null || sheet == null) return "";
if (sheet == null) return "";
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFDrawing drawing = sheet.getDrawingPatriarch();
if (drawing == null) return "";
for (XSSFShape shape : drawing.getShapes()) {
if (!(shape instanceof XSSFGraphicFrame)) continue;
XSSFGraphicFrame frame = (XSSFGraphicFrame) shape;
CTGraphicalObjectFrame ctFrame = frame.getCTGraphicalObjectFrame();
CTGraphicalObjectData graphicData = ctFrame.getGraphic().getGraphicData();
if (graphicData.getUri().equals("http://schemas.openxmlformats.org/drawingml/2006/chart")) {
ClientAnchor anchor = frame.getAnchor();
double heightPt = 0;
for (int r = anchor.getRow1(); r < anchor.getRow2(); r++) {
Row row = sheet.getRow(r);
float rowHeightPt = row != null ? row.getHeightInPoints() : sheet.getDefaultRowHeightInPoints();
heightPt += rowHeightPt;
if (shape instanceof XSSFGraphicFrame) {
XSSFGraphicFrame frame = (XSSFGraphicFrame) shape;
if (frame.getCTGraphicalObjectFrame().getGraphic() != null &&
"http://schemas.openxmlformats.org/drawingml/2006/chart".equals(
frame.getCTGraphicalObjectFrame().getGraphic().getGraphicData().getUri()
)) {
CTTransform2D xfrm = frame.getCTGraphicalObjectFrame().getXfrm();
if (xfrm != null && xfrm.getExt() != null) {
long cy = xfrm.getExt().getCy();
double heightPt = emuToPoints(cy);
double heightCm = emuToCm(cy);
return String.format("%.2f磅(%.2f厘米)", heightPt, heightCm);
}
}
double heightCm = heightPt * 0.0352778;
return String.format("%.1f磅(%.2f厘米)", heightPt, heightCm);
}
}
return "";
}
/**
* 获取所有可用图表样式名称列表
*/
@@ -431,39 +398,117 @@ public class ChartHandler {
}
/** 获取图表宽度,返回"磅(厘米)" */
//todo
public static String getChartWidth(XSSFChart chart, XSSFSheet sheet) {
if (chart == null || sheet == null) return "";
if (sheet == null || chart == null) {
return "";
}
System.out.println("Sheet 名称:" + (sheet != null ? sheet.getSheetName() : "NULL"));
System.out.println("Chart 是否为空:" + (chart == null));
// XSSFDrawing drawing = sheet.createDrawingPatriarch();
// if (drawing == null) return "无";
//
// for (XSSFShape shape : drawing.getShapes()) {
// if (!(shape instanceof XSSFGraphicFrame)) continue;
// XSSFGraphicFrame frame = (XSSFGraphicFrame) shape;
// CTGraphicalObjectFrame ctFrame = frame.getCTGraphicalObjectFrame();
// CTGraphicalObjectData graphicData = ctFrame.getGraphic().getGraphicData();
//
// // 确保是 chart 类型
// if (!"http://schemas.openxmlformats.org/drawingml/2006/chart".equals(graphicData.getUri()))
// continue;
//
// // 判断是否是目标 chart
// List<XSSFChart> charts = drawing.getCharts();
// if (!charts.contains(chart)) continue;
//
// if (ctFrame.getXfrm() == null || ctFrame.getXfrm().getExt() == null) continue;
//
// long cxEmu = ctFrame.getXfrm().getExt().getCx(); // EMU
// double points = cxEmu * 72.0 / 914400.0; // EMU -> pt
// double cm = points * 2.54 / 72.0; // pt -> cm
//
// return String.format("%.1f磅(%.2f厘米)", points, cm);
// }
XSSFDrawing drawing = sheet.getDrawingPatriarch();
if (drawing != null) {
int i = 1;
for (XSSFShape shape : drawing.getShapes()) {
System.out.println("" + i + " 个 Shape 类型:" + shape.getClass().getName());
if (shape instanceof XSSFGraphicFrame) {
System.out.println(" -> 发现 GraphicFrame可能是图表");
XSSFGraphicFrame frame = (XSSFGraphicFrame) shape;
// 打印 XML
System.out.println(" Frame XML:");
System.out.println(frame.getCTGraphicalObjectFrame().xmlText());
// 检查锚点
ClientAnchor anchor = frame.getAnchor();
if (anchor != null) {
System.out.println(" Anchor 位置: col1=" + anchor.getCol1() + ", col2=" + anchor.getCol2() +
", row1=" + anchor.getRow1() + ", row2=" + anchor.getRow2());
} else {
System.out.println(" Anchor 为空(可能是浮动图表)");
}
}
i++;
}
}
if (sheet == null) return "";
if (drawing == null) return "";
for (XSSFShape shape : drawing.getShapes()) {
if (shape instanceof XSSFGraphicFrame) {
XSSFGraphicFrame frame = (XSSFGraphicFrame) shape;
if (frame.getCTGraphicalObjectFrame().getGraphic() != null &&
"http://schemas.openxmlformats.org/drawingml/2006/chart".equals(
frame.getCTGraphicalObjectFrame().getGraphic().getGraphicData().getUri()
)) {
// 找到图表
CTTransform2D xfrm = frame.getCTGraphicalObjectFrame().getXfrm();
if (xfrm != null && xfrm.getExt() != null) {
long cx = xfrm.getExt().getCx();
double widthPt = emuToPoints(cx);
double widthCm = emuToCm(cx);
return String.format("%.2f磅(%.2f厘米)", widthPt, widthCm);
}
}
}
}
return "";
}
// EMU 转磅
private static double emuToPoints(long emu) {
return emu / 12700.0;
}
// EMU 转厘米
private static double emuToCm(long emu) {
return emu / 360000.0;
}
/**
* 判断 frame 是否对应指定的 chart
*/
private static boolean isSameChart(XSSFGraphicFrame frame, XSSFChart targetChart) {
if (frame == null || targetChart == null) {
return false;
}
// 直接通过关系ID判断
String chartRelId = targetChart.getPackagePart().getPartName().getName();
String frameXml = frame.getCTGraphicalObjectFrame().xmlText();
return frameXml.contains(chartRelId);
}
/**
* 计算图表宽度(厘米)
* @param sheet 当前工作表
* @param anchor 图表的锚点信息
* @return 图表宽度cm
*/
private static double calculateChartWidth(XSSFSheet sheet, ClientAnchor anchor) {
int col1 = anchor.getCol1(); // 左上角所在列
int col2 = anchor.getCol2(); // 右下角所在列
int dx1 = anchor.getDx1(); // 左上角偏移量 (EMU)
int dx2 = anchor.getDx2(); // 右下角偏移量 (EMU)
// 1. 计算完整列宽
double totalWidthPixels = 0;
for (int c = col1; c < col2; c++) {
totalWidthPixels += sheet.getColumnWidthInPixels(c);
}
// 2. 偏移量修正 (1 英寸 = 914400 EMU, 1 英寸 = 96 像素)
double offsetStartPixels = dx1 / 9525.0; // EMU -> 像素
double offsetEndPixels = dx2 / 9525.0; // EMU -> 像素
double totalWidth = totalWidthPixels + offsetEndPixels - offsetStartPixels;
// 3. 像素 -> 磅 (1 像素 = 0.75 磅)
double widthPt = totalWidth * 0.75;
// 4. 磅 -> 厘米 (1 磅 = 0.0352778 厘米)
double widthCm = widthPt * 0.0352778;
return Math.round(widthCm * 100.0) / 100.0; // 保留两位小数
}
@@ -510,25 +555,199 @@ public class ChartHandler {
}
/** 图表标题 - 文本内容 */
public String getChartTitleText(XSSFChart chart,XSSFSheet sheet) {
public static String getChartTitleText(XSSFChart chart, XSSFSheet sheet) {
if (chart == null) return "无图表";
CTChart ctChart = chart.getCTChart();
if (ctChart == null || !ctChart.isSetTitle()) return "标题";
if (ctChart == null) return "图表";
// 标题文本一般在 rich 或 strRef
if (ctChart.getTitle().getTx() != null) {
if (ctChart.getTitle().getTx().isSetRich()) {
try {
return ctChart.getTitle().getTx().getRich().getPArray(0).getRArray(0).getT();
} catch (Exception e) {
return "标题解析异常";
// 1. 尝试读取标题
CTTitle title = ctChart.getTitle();
if (title != null) {
// 1.1 rich 文本
CTTx tx = title.getTx();
if (tx != null) {
CTTextBody rich = tx.getRich();
if (rich != null) {
for (CTTextParagraph p : rich.getPList()) {
for (CTRegularTextRun r : p.getRList()) {
String text = r.getT();
if (text != null && !text.trim().isEmpty()) {
return text.trim();
}
}
}
}
// 1.2 公式引用
CTStrRef strRef = (tx.getStrRef() != null) ? tx.getStrRef() : null;
if (strRef != null) {
try {
String formula = strRef.getF();
CellReference ref = new CellReference(formula);
Row row = sheet.getRow(ref.getRow());
if (row != null) {
Cell cell = row.getCell(ref.getCol());
if (cell != null) {
return cell.toString();
}
}
} catch (Exception e) {
// 出错继续尝试读取系列名称
}
}
}
// 1.3 txPr 占位符文本
CTTextBody txPr = title.getTxPr();
if (txPr != null) {
for (CTTextParagraph p : txPr.getPList()) {
for (CTRegularTextRun r : p.getRList()) {
String text = r.getT();
if (text != null && !text.trim().isEmpty()) {
return text.trim();
}
}
}
} else if (ctChart.getTitle().getTx().isSetStrRef()) {
return ctChart.getTitle().getTx().getStrRef().getF();
}
}
return "无标题文本";
// 2. 如果标题为空,则尝试读取第一个数据系列名称
CTPlotArea plotArea = ctChart.getPlotArea();
if (plotArea != null) {
// Pie3DChart
if (!plotArea.getPie3DChartList().isEmpty()) {
CTPie3DChart pie3DChart = plotArea.getPie3DChartArray(0);
if (!pie3DChart.getSerList().isEmpty()) {
CTPieSer ser = pie3DChart.getSerArray(0);
CTSerTx serTx = ser.getTx();
if (serTx != null) {
CTStrRef strRef = serTx.getStrRef();
if (strRef != null) {
try {
CellReference ref = new CellReference(strRef.getF());
Row row = sheet.getRow(ref.getRow());
if (row != null) {
Cell cell = row.getCell(ref.getCol());
if (cell != null) return cell.toString();
}
} catch (Exception e) {
return "系列名称引用解析异常";
}
} else if (serTx.getV() != null) {
return serTx.getV();
}
}
}
}
// PieChart
if (!plotArea.getPieChartList().isEmpty()) {
CTPieChart pieChart = plotArea.getPieChartArray(0);
if (!pieChart.getSerList().isEmpty()) {
CTPieSer ser = pieChart.getSerArray(0);
CTSerTx serTx = ser.getTx();
if (serTx != null) {
CTStrRef strRef = serTx.getStrRef();
if (strRef != null) {
try {
CellReference ref = new CellReference(strRef.getF());
Row row = sheet.getRow(ref.getRow());
if (row != null) {
Cell cell = row.getCell(ref.getCol());
if (cell != null) return cell.toString();
}
} catch (Exception e) {
return "系列名称引用解析异常";
}
} else if (serTx.getV() != null) {
return serTx.getV();
}
}
}
}
// BarChart
if (!plotArea.getBarChartList().isEmpty()) {
CTBarChart barChart = plotArea.getBarChartArray(0);
if (!barChart.getSerList().isEmpty()) {
CTBarSer ser = barChart.getSerArray(0);
CTSerTx serTx = ser.getTx();
if (serTx != null) {
CTStrRef strRef = serTx.getStrRef();
if (strRef != null) {
try {
CellReference ref = new CellReference(strRef.getF());
Row row = sheet.getRow(ref.getRow());
if (row != null) {
Cell cell = row.getCell(ref.getCol());
if (cell != null) return cell.toString();
}
} catch (Exception e) {
return "系列名称引用解析异常";
}
} else if (serTx.getV() != null) {
return serTx.getV();
}
}
}
}
// LineChart
if (!plotArea.getLineChartList().isEmpty()) {
CTLineChart lineChart = plotArea.getLineChartArray(0);
if (!lineChart.getSerList().isEmpty()) {
CTLineSer ser = lineChart.getSerArray(0);
CTSerTx serTx = ser.getTx();
if (serTx != null) {
CTStrRef strRef = serTx.getStrRef();
if (strRef != null) {
try {
CellReference ref = new CellReference(strRef.getF());
Row row = sheet.getRow(ref.getRow());
if (row != null) {
Cell cell = row.getCell(ref.getCol());
if (cell != null) return cell.toString();
}
} catch (Exception e) {
return "系列名称引用解析异常";
}
} else if (serTx.getV() != null) {
return serTx.getV();
}
}
}
}
// AreaChart
if (!plotArea.getAreaChartList().isEmpty()) {
CTAreaChart areaChart = plotArea.getAreaChartArray(0);
if (!areaChart.getSerList().isEmpty()) {
CTAreaSer ser = areaChart.getSerArray(0);
CTSerTx serTx = ser.getTx();
if (serTx != null) {
CTStrRef strRef = serTx.getStrRef();
if (strRef != null) {
try {
CellReference ref = new CellReference(strRef.getF());
Row row = sheet.getRow(ref.getRow());
if (row != null) {
Cell cell = row.getCell(ref.getCol());
if (cell != null) return cell.toString();
}
} catch (Exception e) {
return "系列名称引用解析异常";
}
} else if (serTx.getV() != null) {
return serTx.getV();
}
}
}
}
}
// 3. 如果都没有,返回占位符
return "标题为空或占位符";
}
/** 图表标题 - 位置 */
@@ -563,17 +782,225 @@ public class ChartHandler {
}
// 辅助方法根据CTSerTx判断产生方式
private String getSeriesGeneration(CTSerTx tx) {
if (tx != null) {
if (tx.getStrRef() != null) {
return "系列产生于列";
} else if (tx.getV() != null) {
return "手动输入";
}
if (tx == null) {
// 没有 tx 节点时,默认按“系列产生于列”处理
return "系列产生于列";
}
return "未知生成方式";
if (tx.isSetStrRef()) {
// isSetStrRef() 比直接判断 null 更语义化
return "系列产生于列";
}
if (tx.isSetV()) {
return "手动输入";
}
// 如果 tx 存在,但两个子节点都不存在
return "系列产生于列";
}
/**
* 获取图例显示状态
*
* @param chart XSSFChart对象
* @return "显示" 或 "隐藏"
*/
public static String getLegendVisible(XSSFChart chart, XSSFSheet sheet) {
if (chart == null) return "无图表";
CTChart ctChart = chart.getCTChart();
if (ctChart == null) return "无图表";
CTLegend legend = ctChart.getLegend();
if (legend == null) return "隐藏";
boolean visible = legend.getOverlay() == null || !legend.getOverlay().getVal();
return visible ? "显示" : "隐藏";
}
/**
* 获取图例位置(汉化)
*
* @param chart XSSFChart对象
* @return 中文位置,如 "上方", "下方", "左侧", "右侧",无图例返回 "无图例"
*/
public static String getLegendPosition(XSSFChart chart, XSSFSheet sheet) {
if (chart == null) return "无图表";
CTChart ctChart = chart.getCTChart();
if (ctChart == null) return "无图表";
CTLegend legend = ctChart.getLegend();
if (legend == null) return "无图例";
STLegendPos.Enum posEnum = legend.getLegendPos().getVal();
if (posEnum != null) {
switch (posEnum.intValue()) {
case STLegendPos.INT_T: return "上方";
case STLegendPos.INT_B: return "下方";
case STLegendPos.INT_L: return "左侧";
case STLegendPos.INT_R: return "右侧";
case STLegendPos.INT_TR: return "右上";
default: return "未知位置";
}
}
return "未知位置";
}
/**
* 获取第一个系列的数据标签是否显示
*/
public static String isDataLabelVisible(XSSFChart chart, XSSFSheet sheet) {
CTDLbls dLbls = getFirstSeriesDLbls(chart);
if (dLbls == null) return "隐藏";
// 只要任何一个显示属性不为空且为true就认为显示
boolean visible = (dLbls.getShowVal() != null && dLbls.getShowVal().getVal())
|| (dLbls.getShowCatName() != null && dLbls.getShowCatName().getVal())
|| (dLbls.getShowLegendKey() != null && dLbls.getShowLegendKey().getVal());
return visible ? "显示" : "隐藏";
}
/**
* 获取第一个系列的数据标签是否显示类别名称X
*/
public static String isDataLabelShowCategoryName(XSSFChart chart, XSSFSheet sheet) {
CTDLbls dLbls = getFirstSeriesDLbls(chart);
if (dLbls == null || dLbls.getShowCatName() == null) return "不显示";
return dLbls.getShowCatName().getVal() ? "显示" : "不显示";
}
/**
* 获取第一个系列的数据标签是否显示数值V
*/
public static String isDataLabelShowValue(XSSFChart chart, XSSFSheet sheet) {
CTDLbls dLbls = getFirstSeriesDLbls(chart);
if (dLbls == null || dLbls.getShowVal() == null) return "不显示";
return dLbls.getShowVal().getVal() ? "显示" : "不显示";
}
/**
* 获取第一个系列的数据标签位置(兼容旧版本 POI
* @param chart XSSFChart
* @param sheet XSSFSheet
* @return 位置字符串,例如 "上"、"下"、"居中"、"未设置"
*/
public static String getDataLabelPosition(XSSFChart chart, XSSFSheet sheet) {
if (chart == null) return "未设置";
CTPlotArea plotArea = chart.getCTChart().getPlotArea();
if (plotArea == null) return "未设置";
// 先尝试 PieChart
if (plotArea.getPieChartArray().length > 0) {
CTPieChart pieChart = plotArea.getPieChartArray(0);
if (pieChart.getSerArray().length > 0) {
CTPieSer ser = pieChart.getSerArray(0);
CTDLbls dLbls = ser.getDLbls();
return parseDLblPosFromXML(dLbls);
}
}
// 尝试 BarChart
if (plotArea.getBarChartArray().length > 0) {
CTBarChart barChart = plotArea.getBarChartArray(0);
if (barChart.getSerArray().length > 0) {
CTBarSer ser = barChart.getSerArray(0);
CTDLbls dLbls = ser.getDLbls();
return parseDLblPosFromXML(dLbls);
}
}
// 尝试 LineChart
if (plotArea.getLineChartArray().length > 0) {
CTLineChart lineChart = plotArea.getLineChartArray(0);
if (lineChart.getSerArray().length > 0) {
CTLineSer ser = lineChart.getSerArray(0);
CTDLbls dLbls = ser.getDLbls();
return parseDLblPosFromXML(dLbls);
}
}
// 其他图表类型可按需扩展
return "未设置";
}
/**
* 从 DLbls XML 获取位置并汉化
*/
private static String parseDLblPosFromXML(CTDLbls dLbls) {
if (dLbls == null) return "未设置";
// 通过底层 XML 解析 <dLblPos val="..."/>
if (dLbls.getDomNode() != null) {
org.w3c.dom.NodeList nodeList = dLbls.getDomNode().getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
org.w3c.dom.Node node = nodeList.item(i);
if ("dLblPos".equals(node.getLocalName())) {
org.w3c.dom.NamedNodeMap attrs = node.getAttributes();
org.w3c.dom.Node valNode = attrs.getNamedItem("val");
if (valNode != null) {
String val = valNode.getNodeValue();
return convertDLblPos(val);
}
}
}
}
return "未设置";
}
/**
* 将 OOXML 数据标签位置值汉化
*/
private static String convertDLblPos(String val) {
switch (val) {
case "bestFit": return "自动最佳";
case "b": return "";
case "ctr": return "居中";
case "inBase": return "内部底部";
case "inEnd": return "内部末端";
case "l": return "";
case "outEnd": return "外部末端";
case "r": return "";
case "t": return "";
default: return "其他";
}
}
// 获取第一个数据系列的 CTDLbls不使用 CTSer
private static CTDLbls getFirstSeriesDLbls(XSSFChart chart) {
if (chart == null) return null;
CTChart ctChart = chart.getCTChart();
if (ctChart == null) return null;
CTPlotArea plotArea = ctChart.getPlotArea();
if (plotArea == null) return null;
// Pie3DChart
if (!plotArea.getPie3DChartList().isEmpty()) {
CTPie3DChart chart0 = plotArea.getPie3DChartArray(0);
if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls();
}
// PieChart
if (!plotArea.getPieChartList().isEmpty()) {
CTPieChart chart0 = plotArea.getPieChartArray(0);
if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls();
}
// BarChart
if (!plotArea.getBarChartList().isEmpty()) {
CTBarChart chart0 = plotArea.getBarChartArray(0);
if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls();
}
// LineChart
if (!plotArea.getLineChartList().isEmpty()) {
CTLineChart chart0 = plotArea.getLineChartArray(0);
if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls();
}
// AreaChart
if (!plotArea.getAreaChartList().isEmpty()) {
CTAreaChart chart0 = plotArea.getAreaChartArray(0);
if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls();
}
return null;
}
// public void printChartXml(XSSFChart chart) {
// if (chart == null) {
// System.out.println("无图表");

View File

@@ -68,8 +68,6 @@ public class RangIng {
return cellValueBuilder.toString();
}
//范围 边框→样式
//范围 边框→颜色
/**
* 范围 边框 → 样式
*
@@ -593,7 +591,161 @@ public class RangIng {
return String.valueOf(row.getHeightInPoints());
}
/**
* 范围 -列 列宽
*/
public static String getColumnWidth(String cellRefRange, Workbook workbook, int sheetIndex) {
List<String> cellRefs = getCellRefsInRange(cellRefRange);
if (cellRefs.isEmpty()) return "";
// 取范围里的第一个单元格
String firstCellRef = cellRefs.get(0);
CellReference cr = new CellReference(firstCellRef);
int colIndex = cr.getCol();
Sheet sheet = workbook.getSheetAt(sheetIndex - 1);
if (sheet == null) return "";
// getColumnWidth 返回的是字符数*256单位1/256 个字符)
int width = sheet.getColumnWidth(colIndex);
int charWidth = width / 256; // 向下取整
return String.valueOf(charWidth);
}
/**
* 范围 -格式 -水平对齐
*/
public static String getCellHorizontalAlignment(String cellRefRange, Workbook workbook, int sheetIndex) {
List<String> cellRefs = getCellRefsInRange(cellRefRange);
if (cellRefs.isEmpty()) return "";
String firstCellRef = cellRefs.get(0);
CellReference cr = new CellReference(firstCellRef);
Sheet sheet = workbook.getSheetAt(sheetIndex - 1);
Row row = sheet.getRow(cr.getRow());
if (row == null) return "";
Cell cell = row.getCell(cr.getCol());
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "默认";
HorizontalAlignment ha = style.getAlignment();
if (ha == null) return "默认";
switch (ha) {
case LEFT: return "左对齐";
case CENTER: return "居中";
case RIGHT: return "右对齐";
case FILL: return "填充";
case JUSTIFY: return "两端对齐";
case CENTER_SELECTION: return "跨列居中";
default: return "其他";
}
}
/**
* 范围 -格式 -垂直对齐
*/
public static String getCellVerticalAlignment(String cellRefRange, Workbook workbook, int sheetIndex) {
List<String> cellRefs = getCellRefsInRange(cellRefRange);
if (cellRefs.isEmpty()) return "";
String firstCellRef = cellRefs.get(0);
CellReference cr = new CellReference(firstCellRef);
Sheet sheet = workbook.getSheetAt(sheetIndex - 1);
Row row = sheet.getRow(cr.getRow());
if (row == null) return "";
Cell cell = row.getCell(cr.getCol());
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "默认";
VerticalAlignment va = style.getVerticalAlignment();
if (va == null) return "默认";
switch (va) {
case TOP: return "顶端对齐";
case CENTER: return "垂直居中";
case BOTTOM: return "底端对齐";
case JUSTIFY: return "两端对齐";
case DISTRIBUTED: return "分散对齐";
default: return "其他";
}
}
// --------------------- 条件格式公共方法 ---------------------
private static ConditionalFormattingRule getFirstMatchingRule(String cellRefRange, Workbook workbook, int sheetIndex) {
Sheet sheet = workbook.getSheetAt(sheetIndex - 1);
List<String> cellRefs = getCellRefsInRange(cellRefRange);
if (cellRefs.isEmpty()) return null;
SheetConditionalFormatting cf = sheet.getSheetConditionalFormatting();
int numCF = cf.getNumConditionalFormattings();
if (numCF == 0) return null;
CellReference cr = new CellReference(cellRefs.get(0));
for (int i = 0; i < numCF; i++) {
ConditionalFormatting formatting = cf.getConditionalFormattingAt(i);
for (CellRangeAddress range : formatting.getFormattingRanges()) {
if (range.isInRange(cr.getRow(), cr.getCol())) {
if (formatting.getNumberOfRules() > 0) {
return formatting.getRule(0); // 返回第一个匹配规则
}
}
}
}
return null;
}
// 1. 数据标签显示
public static String isDataLabelVisible(String cellRefRange, Workbook workbook, int sheetIndex) {
ConditionalFormattingRule rule = getFirstMatchingRule(cellRefRange, workbook, sheetIndex);
return (rule != null) ? "显示" : "隐藏";
}
// 5. 数字格式(通过单元格样式读取)
public static String getConditionalFormatDataFormat(String cellRefRange, Workbook workbook, int sheetIndex) {
List<String> cellRefs = getCellRefsInRange(cellRefRange);
if (cellRefs.isEmpty()) return "";
Sheet sheet = workbook.getSheetAt(sheetIndex - 1);
CellReference cr = new CellReference(cellRefs.get(0));
Row row = sheet.getRow(cr.getRow());
if (row == null) return "";
Cell cell = row.getCell(cr.getCol());
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style != null) return style.getDataFormatString();
return "";
}
// 6. 数据条
public static String getConditionalFormatDataBar(String cellRefRange, Workbook workbook, int sheetIndex) {
ConditionalFormattingRule rule = getFirstMatchingRule(cellRefRange, workbook, sheetIndex);
if (rule != null && rule.getDataBarFormatting() != null) return "已应用";
return "未应用";
}
// 7. 色阶
public static String getConditionalFormatColorScale(String cellRefRange, Workbook workbook, int sheetIndex) {
ConditionalFormattingRule rule = getFirstMatchingRule(cellRefRange, workbook, sheetIndex);
if (rule != null && rule.getColorScaleFormatting() != null) return "已应用";
return "未应用";
}
// 8. 图标集
public static String getConditionalFormatIconSet(String cellRefRange, Workbook workbook, int sheetIndex) {
return "未应用";
}
// ---------- 辅助方法 ----------

View File

@@ -33,12 +33,14 @@ public class Style {
Sheet sheet = workbook.getSheetAt(sheetNum);
if (sheet instanceof XSSFSheet) {
XSSFColor color = ((XSSFSheet) sheet).getTabColor();
String hex=color.getARGBHex();
if (hex != null && hex.length() == 8) {
hex = hex.substring(2); // 去掉前两位 Alpha
}
if (hex != null) {
return ColorUtils.getChineseColorName(hex);
if (color != null) { // 非空判断
String hex=color.getARGBHex();
if (hex != null && hex.length() == 8) {
hex = hex.substring(2); // 去掉前两位 Alpha
}
if (hex != null && !hex.isEmpty()) {
return ColorUtils.getChineseColorName(hex);
}
}
}
return "";

View File

@@ -477,10 +477,17 @@ public class DocxMaster {
// 方法无法调用或内部异常,也跳过或打印日志
e.printStackTrace();
}
String processedValue = null;
if (value != null) {
if ("getTextValue".equals(function)){
// 对所有文字超过10个字的情况进行截断
if (value.length() > 13) {
processedValue = value.substring(0, 5) + "..." + value.substring(value.length() - 3);
}
}
judgementWordsVOS = setJudgementWord(judgementWordsVOS,
docxFunction + "@" + value,
firstName + examName + value);
firstName + examName + processedValue);
}
} else {
System.out.println("文本框中没有 Anchor 或 Inline 对象");