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