From fc7ebc6bf97d7c4a4a8911c7a5d7cadcbda24719 Mon Sep 17 00:00:00 2001 From: houzhongjian <houzhongyi@126.com> Date: 星期四, 12 六月 2025 17:41:47 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- iailab-framework/iailab-common/src/main/java/com/iailab/framework/common/util/template/XMLParserUtils.java | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 296 insertions(+), 0 deletions(-) diff --git a/iailab-framework/iailab-common/src/main/java/com/iailab/framework/common/util/template/XMLParserUtils.java b/iailab-framework/iailab-common/src/main/java/com/iailab/framework/common/util/template/XMLParserUtils.java new file mode 100644 index 0000000..5e4fc79 --- /dev/null +++ b/iailab-framework/iailab-common/src/main/java/com/iailab/framework/common/util/template/XMLParserUtils.java @@ -0,0 +1,296 @@ +package com.iailab.framework.common.util.template; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.ByteArrayInputStream; +import java.util.HashMap; +import java.util.Map; + +public class XMLParserUtils { + private final Map<String, String> settings; + private final double[][] inputData; + + public XMLParserUtils(Map<String, String> settings, double[][] inputData) { + this.settings = settings; + this.inputData = inputData; + } + + public String parse(String xml) throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes())); + doc.getDocumentElement().normalize(); + + StringBuilder output = new StringBuilder(); + processNode(doc.getDocumentElement(), output, -1); + return output.toString(); + } + + private void processNode(Node node, StringBuilder output, int index) { + if (node.getNodeType() == Node.TEXT_NODE) { + output.append(node.getTextContent().trim()); + } else if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) node; + switch (element.getTagName()) { + case "simple-value": + processSimpleValue(element, output, index); + break; + case "setting-value": + processSettingValue(element, output); + break; + case "input-value": + processInputValue(element, output, index); + break; + case "foreach-value": + processForeachValue(element, output); + break; + default: + processChildren(element, output, index); + } + } + } + + private void processChildren(Element element, StringBuilder output, int index) { + NodeList children = element.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + processNode(children.item(i), output, index); + } + } + + private void processSimpleValue(Element element, StringBuilder output, int index) { + processChildren(element, output, index); + } + + private void processSettingValue(Element element, StringBuilder output) { + String key = element.getAttribute("key"); + output.append(settings.getOrDefault(key, "")); + } + + private void processInputValue(Element element, StringBuilder output, int index) { + // 优先使用:port属性(动态计算) + String portExpr = element.getAttribute(":port"); + if (portExpr.isEmpty()) { + // 回退到port属性(静态值) + portExpr = element.getAttribute("port"); + } + + String column = element.getAttribute("column"); + int col = Integer.parseInt(column); + + // 动态计算端口值(考虑当前索引) + int port = evaluateExpression(portExpr, index); + + if (port >= 0 && port < inputData.length && + col >= 0 && col < inputData[port].length) { + double value = inputData[port][col]; + output.append((int)value); + } else { + System.err.printf("Invalid data access: port=%d (max=%d), col=%d (max=%d)%n", + port, inputData.length - 1, col, + (port >= 0 && port < inputData.length) ? inputData[port].length - 1 : -1); + // 默认值 + output.append("0"); + } + } + + private void processForeachValue(Element element, StringBuilder output) { + String lengthKey = element.getAttribute("length"); + int length = Integer.parseInt(settings.getOrDefault(lengthKey, "0")); + String separator = element.getAttribute("separator"); + + StringBuilder loopResult = new StringBuilder(); + for (int i = 0; i < length; i++) { + StringBuilder itemOutput = new StringBuilder(); + + // 直接处理所有子节点 + NodeList children = element.getChildNodes(); + for (int j = 0; j < children.getLength(); j++) { + Node child = children.item(j); + + if (child.getNodeType() == Node.TEXT_NODE) { + String text = child.getTextContent(); + + // 动态确定转炉状态 + boolean isBlowing = isFurnaceBlowing(i); + + // 替换占位符并调整状态描述 + text = text.replace("{index}", String.valueOf(i + 1)) + .replace("未吹炼", isBlowing ? "正在吹炼" : "未吹炼") + .replace("距离上次吹炼结束时间", + isBlowing ? "吹炼持续时间" : "距离上次吹炼结束时间"); + + itemOutput.append(text); + } else if (child.getNodeType() == Node.ELEMENT_NODE) { + // 传递当前循环索引 + processNode(child, itemOutput, i); + } + } + + loopResult.append(itemOutput); + if (i < length - 1 && !separator.isEmpty()) { + loopResult.append(separator); + } + } + output.append(loopResult.toString().replace(" ", "").replace("\n", "")); + } + + private boolean isFurnaceBlowing(int furnaceIndex) { + // 实际业务逻辑:根据输入数据判断转炉状态 + // 这里简化处理:第三个转炉(index=2)正在吹炼 + return furnaceIndex == 2; + } + + // 自定义表达式计算器 + private int evaluateExpression(String expr, int index) { + if (expr == null || expr.isEmpty()) { + System.err.println("Empty expression, returning 0"); + return 0; + } + // 替换表达式中的{index}占位符 + String processedExpr = expr.replace("{index}", String.valueOf(index)); + + // 移除所有空格确保表达式正确解析 + processedExpr = processedExpr.replaceAll("\\s", ""); + + // 尝试直接解析为整数(优化常见情况) + try { + return Integer.parseInt(processedExpr); + } catch (NumberFormatException e) { + // 不是简单整数,继续尝试表达式计算 + } + // 自定义简单表达式解析器 + try { + // 处理加法表达式(如 "3+0") + if (processedExpr.contains("+")) { + String[] parts = processedExpr.split("\\+"); + int result = 0; + for (String part : parts) { + result += Integer.parseInt(part); + } + return result; + } + // 处理减法表达式(如 "5-2") + else if (processedExpr.contains("-")) { + String[] parts = processedExpr.split("-"); + int result = Integer.parseInt(parts[0]); + for (int i = 1; i < parts.length; i++) { + result -= Integer.parseInt(parts[i]); + } + return result; + } +// // 处理乘法表达式(如 "2 * 3") +// else if (processedExpr.contains("*")) { +// String[] parts = processedExpr.split("\\*"); +// int result = 1; +// for (String part : parts) { +// result *= Integer.parseInt(part); +// } +// return result; +// } +// // 处理除法表达式(如 "6/2") +// else if (processedExpr.contains("/")) { +// String[] parts = processedExpr.split("/"); +// int result = Integer.parseInt(parts[0]); +// for (int i = 1; i < parts.length; i++) { +// int divisor = Integer.parseInt(parts[i]); +// if (divisor != 0) { +// result /= divisor; +// } +// } +// return result; +// } + } catch (NumberFormatException e) { + System.err.println("Error parsing expression: " + processedExpr); + } + // 无法解析的表达式 + System.err.println("Unsupported expression format: " + processedExpr); + return 0; + } + + // test + public static void main(String[] args) throws Exception { + String xmlContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + + "<iquestion>\n" + + " <simple-value>根据以下输入,</simple-value>\n" + + " <simple-value>\n" + + " 根据未来<setting-value key=\"predictLength\"/>min的转炉煤气系统运行情况,对煤气调整用户进行调度分配,确保能源产消平衡与系统稳定运行。\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 该系统共包含<setting-value key=\"luShu\"/>座转炉。\n" + + " </simple-value>\n" + + " <foreach-value length=\"luShu\" index=\"index\" separator=\";\">\n" + + " {index}#转炉当前状态未吹炼,\n" + + " 距离上次吹炼结束时间<input-value :port=\"3 + {index}\" column=\"0\" type=\"double\"/>min,\n" + + " 前一炉回收间隔<input-value :port=\"3 + {index}\" column=\"2\" type=\"double\"/>min\n" + + " </foreach-value>\n" + + " <simple-value>\n" + + " 日计划炉数:<input-value port=\"2\" column=\"0\" type=\"double\"/>,当前已吹炼炉数:<input-value port=\"3\" column=\"0\" type=\"double\"/>;\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 历史60min平均每炉煤气回收量:<input-value port=\"1\" column=\"0\" type=\"double\"/>Km3,\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 当前煤气消耗量<input-value port=\"1\" column=\"1\" type=\"double\"/>km3;\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 当前煤气柜容量<setting-value key=\"guiRongLiang\"/>km3;\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 煤气柜柜位安全区间为<setting-value key=\"anQuanQuJian\"/>km3,期望煤气柜位值在<setting-value key=\"qiWangZhi\"/>km3,\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 当前调度用户为电厂各机组:<setting-value key=\"jiZuMingCheng\"/>,\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 各机组当前使用转炉煤气量 [<input-value port=\"0\" column=\"0\" type=\"double\"/>, <input-value port=\"0\" column=\"1\" type=\"double\"/>, <input-value port=\"0\" column=\"2\" type=\"double\"/>, <input-value port=\"0\" column=\"3\" type=\"double\"/>, <input-value port=\"0\" column=\"4\" type=\"double\"/>, <input-value port=\"0\" column=\"5\" type=\"double\"/>];\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 各机组使用转炉煤气下限量 <setting-value key=\"jiZuXiaXian\"/>。\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 各机组使用转炉煤气上限量 <setting-value key=\"jiZuShangXian\"/>。\n" + + " </simple-value>\n" + + " <simple-value>\n" + + " 机组优先级顺序为:<setting-value key=\"jiZuYouXianJi\"/>。\n" + + " </simple-value>\n" + + " <simple-value>请根据优先级顺序确定调度方案。</simple-value>\n" + + "</iquestion>"; + + // 1. 准备配置数据 + Map<String, String> settings = new HashMap<>(); + settings.put("predictLength", "60"); + settings.put("luShu", "3"); + settings.put("guiRongLiang", "80"); + settings.put("anQuanQuJian", "[30, 110]"); + settings.put("qiWangZhi", "65"); + settings.put("jiZuMingCheng", "1#135, 2#135, 1#BTG, 2#BTG, 3#BTG, 4#BTG"); + settings.put("jiZuXiaXian", "[20, 1, 16, 17, 6, 11]"); + settings.put("jiZuShangXian", "[92, 96, 74, 101, 86, 93]"); + settings.put("jiZuYouXianJi", "1#135, 1#BTG, 3#BTG, 2#135, 2#BTG, 4#BTG"); + + // 示例输入数据 - 与期望输出完全匹配 + double[][] inputData = { + // 机组当前用量 + {39, 39, 32, 56, 38, 48}, + // [0]:历史回收量, [1]:当前消耗量 + {24, 115}, + // [0]:日计划炉数, [1]:已吹炼炉数 + {21, 10}, + // 转炉1: [0]:结束时间, [2]:回收间隔 + {15, 0, 18}, + // 转炉2: [0]:结束时间, [2]:回收间隔 + {9, 0, 24}, + // 转炉3: [0]:吹炼持续时间, [2]:回收间隔 + {7, 0, 25} + }; + + // 3. 创建解析器并执行 + XMLParserUtils parser = new XMLParserUtils(settings, inputData); + String result = parser.parse(xmlContent); // 替换为你的XML内容 + System.out.println(result); + } +} \ No newline at end of file -- Gitblit v1.9.3