From ddadf26837a63b429d139f2991a9289635fc9460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E5=AE=87=20=E8=94=A1?= <2418394595@qq.com> Date: Wed, 6 May 2026 14:31:18 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(mms-mapping):=20test=E4=B8=AD=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0XML=E5=AD=97=E7=AC=A6=E4=B8=B2=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96JSON=E8=BD=ACXML?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在IcdToXmlGenerateResult和IcdToXmlResponse中新增mappingXml字段存储生成的XML字符串 - 修改IcdToXmlResponseConverter将XML内容从savedPath改为mappingXml字段 - 更新IcdToXmlTaskAppService将XML转换结果从保存路径改为直接返回XML内容 - 重构JsonToXmlConversionService移除临时文件创建,直接返回XML字符串 - 在JsonToXmlConversionService中添加性能监控日志输出 - 新增JsonToXmlDebugRunner用于本地调试JSON转XML功能 --- .../component/IcdToXmlResponseConverter.java | 2 +- .../component/JsonToXmlConversionService.java | 72 +++-- .../pojo/bo/IcdToXmlGenerateResult.java | 11 + .../icd/mapping/pojo/vo/IcdToXmlResponse.java | 10 + .../service/impl/IcdToXmlTaskAppService.java | 4 +- .../mapping/debug/JsonToXmlDebugRunner.java | 261 ++++++++++++++++++ 6 files changed, 341 insertions(+), 19 deletions(-) create mode 100644 tools/mms-mapping/src/test/java/com/njcn/gather/icd/mapping/debug/JsonToXmlDebugRunner.java diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/IcdToXmlResponseConverter.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/IcdToXmlResponseConverter.java index c0140b7..38dea81 100644 --- a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/IcdToXmlResponseConverter.java +++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/IcdToXmlResponseConverter.java @@ -20,7 +20,7 @@ public class IcdToXmlResponseConverter { response.setLdInst(result.getLdInst()); response.setSavedPath(result.getSavedPath()); response.getProblems().addAll(result.getProblems()); - + response.setMappingXml(result.getMappingXml()); if (result.getIndexAnalysis() != null && result.getIndexAnalysis().getCandidates() != null) { for (IndexCandidate candidate : result.getIndexAnalysis().getCandidates()) { IndexCandidateResponse candidateResponse = new IndexCandidateResponse(); diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/JsonToXmlConversionService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/JsonToXmlConversionService.java index 8395005..3dfccd0 100644 --- a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/JsonToXmlConversionService.java +++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/JsonToXmlConversionService.java @@ -55,37 +55,58 @@ public class JsonToXmlConversionService { List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - // 1. 反序列化JSON为MappingDocument对象 - MappingDocument mappingDocument = objectMapper.readValue(mappingJson, MappingDocument.class); + long startTime = System.currentTimeMillis(); + System.out.println("[JSON转XML] 开始转换..."); - // 2. 使用现有的规则引擎生成XML - // 注意:这里复用RuleBasedXmlMappingService的核心逻辑 - // 但数据来源从ICD直接解析改为从MappingDocument提取 - String xmlContent = buildXmlFromMapping(mappingDocument, templateStream, ruleStreams, indexMapping); - - // 3. 保存为临时文件 - Path tempPath = Files.createTempFile("converted_", ".xml"); - Files.write(tempPath, xmlContent.getBytes(StandardCharsets.UTF_8)); - - return tempPath.toString(); + try { + MappingDocument mappingDocument = objectMapper.readValue(mappingJson, MappingDocument.class); + + long parseTime = System.currentTimeMillis(); + System.out.println("[JSON转XML] JSON解析完成,耗时: " + (parseTime - startTime) + " ms"); + + String xmlContent = buildXmlFromMapping(mappingDocument, templateStream, ruleStreams, indexMapping); + + long totalTime = System.currentTimeMillis() - startTime; + System.out.println("[JSON转XML] 转换完成,总耗时: " + totalTime + " ms"); + + return xmlContent; + } catch (Exception e) { + long totalTime = System.currentTimeMillis() - startTime; + System.err.println("[JSON转XML] 转换失败,已耗时: " + totalTime + " ms,错误: " + e.getMessage()); + throw e; + } } - /** - * 从MappingDocument构建XML内容 - */ private String buildXmlFromMapping(MappingDocument mappingDocument, InputStream templateStream, List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { + long stepStart = System.currentTimeMillis(); + String templateContent = readInputStreamToString(templateStream); + long templateTime = System.currentTimeMillis(); + System.out.println(" [步骤1] 读取模板完成,耗时: " + (templateTime - stepStart) + " ms"); + String xmlContent = fillIedInfo(templateContent, mappingDocument); + long iedTime = System.currentTimeMillis(); + System.out.println(" [步骤2] 填充IED信息完成,耗时: " + (iedTime - templateTime) + " ms"); + xmlContent = fillReportControlsFromMapping(xmlContent, mappingDocument); + long reportTime = System.currentTimeMillis(); + System.out.println(" [步骤3] 填充ReportControl完成,耗时: " + (reportTime - iedTime) + " ms"); + xmlContent = applyRulesFromMapping(xmlContent, mappingDocument, ruleStreams, indexMapping); + long rulesTime = System.currentTimeMillis(); + System.out.println(" [步骤4] 应用规则完成,耗时: " + (rulesTime - reportTime) + " ms"); + + long totalStepTime = System.currentTimeMillis() - stepStart; + System.out.println(" [buildXmlFromMapping] 总计耗时: " + totalStepTime + " ms"); + return xmlContent; } @@ -219,21 +240,40 @@ public class JsonToXmlConversionService { List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { + long stepStart = System.currentTimeMillis(); + var mergedRules = mergeAllRulesDesc(ruleStreams, indexMapping); + long mergeTime = System.currentTimeMillis(); + System.out.println(" [规则合并] 耗时: " + (mergeTime - stepStart) + " ms,规则数: " + mergedRules.size()); + var mappingMetrics = extractMetricsFromMapping(mappingDocument); + long extractTime = System.currentTimeMillis(); + System.out.println(" [指标提取] 耗时: " + (extractTime - mergeTime) + " ms,指标数: " + mappingMetrics.size()); + System.out.println("========== 开始从JSON匹配规则 =========="); System.out.println("规则总数: " + mergedRules.size()); System.out.println("JSON中指标总数: " + mappingMetrics.size()); var applicableRules = findApplicableRulesDesc(mergedRules, mappingMetrics); + long matchTime = System.currentTimeMillis(); + System.out.println(" [规则匹配] 耗时: " + (matchTime - extractTime) + " ms"); + System.out.println("匹配成功: " + applicableRules.size() + " 条规则"); System.out.println("匹配失败: " + (mergedRules.size() - applicableRules.size()) + " 条规则"); + + String resultXml = applyRulesToXml(xmlContent, applicableRules); + + long applyTime = System.currentTimeMillis(); + System.out.println(" [规则应用] 耗时: " + (applyTime - matchTime) + " ms"); + + long totalApplyTime = System.currentTimeMillis() - stepStart; + System.out.println(" [applyRulesFromMapping] 总计耗时: " + totalApplyTime + " ms"); System.out.println("========== JSON规则匹配结束 ==========\n"); - return applyRulesToXml(xmlContent, applicableRules); + return resultXml; } /** diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/bo/IcdToXmlGenerateResult.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/bo/IcdToXmlGenerateResult.java index 43df5d9..e766e88 100644 --- a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/bo/IcdToXmlGenerateResult.java +++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/bo/IcdToXmlGenerateResult.java @@ -18,6 +18,17 @@ public class IcdToXmlGenerateResult { private MappingDocument mappingDocument; private String savedPath; private List problems = new ArrayList(); + /** 生成成功后的 Xml 字符串。 */ + private String mappingXml; + public String getMappingXml() { + return mappingXml; + } + + public void setMappingXml(String mappingXml) { + this.mappingXml = mappingXml; + } + + public GenerateStatus getStatus() { return status; } public void setStatus(GenerateStatus status) { this.status = status; } diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/vo/IcdToXmlResponse.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/vo/IcdToXmlResponse.java index 35579c2..add9ab2 100644 --- a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/vo/IcdToXmlResponse.java +++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/pojo/vo/IcdToXmlResponse.java @@ -16,6 +16,16 @@ public class IcdToXmlResponse { private MappingDocumentResponse mappingDocument; private List indexCandidates = new ArrayList(); private List problems = new ArrayList(); + /** 生成成功后的 Xml 字符串。 */ + private String mappingXml; + public String getMappingXml() { + return mappingXml; + } + + public void setMappingXml(String mappingXml) { + this.mappingXml = mappingXml; + } + public GenerateStatus getStatus() { return status; } public void setStatus(GenerateStatus status) { this.status = status; } public String getMessage() { return message; } diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/service/impl/IcdToXmlTaskAppService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/service/impl/IcdToXmlTaskAppService.java index 2349cb8..0a9014a 100644 --- a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/service/impl/IcdToXmlTaskAppService.java +++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/service/impl/IcdToXmlTaskAppService.java @@ -160,14 +160,14 @@ public class IcdToXmlTaskAppService { // 3. 从 JSON 转换为 XML - String xmlPath = jsonToXmlConversionService.convertFromJson( + String xmlContent = jsonToXmlConversionService.convertFromJson( mappingJson, templateStream, ruleStreams, icdToXmlMappingService.getIndexMapping() ); - result.setSavedPath(xmlPath); + result.setMappingXml(xmlContent); result.setStatus(GenerateStatus.SUCCESS); result.setMessage("XML 生成成功"); return result; diff --git a/tools/mms-mapping/src/test/java/com/njcn/gather/icd/mapping/debug/JsonToXmlDebugRunner.java b/tools/mms-mapping/src/test/java/com/njcn/gather/icd/mapping/debug/JsonToXmlDebugRunner.java new file mode 100644 index 0000000..b6c1b42 --- /dev/null +++ b/tools/mms-mapping/src/test/java/com/njcn/gather/icd/mapping/debug/JsonToXmlDebugRunner.java @@ -0,0 +1,261 @@ +package com.njcn.gather.icd.mapping.debug; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.njcn.gather.icd.mapping.component.IcdToXmlResponseConverter; +import com.njcn.gather.icd.mapping.pojo.bo.IcdToXmlGenerateResult; +import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus; +import com.njcn.gather.icd.mapping.service.impl.IcdToXmlTaskAppService; +import org.springframework.boot.Banner; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.ConfigurableApplicationContext; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * JSON 转 XML 本地调试入口。 + * + * 使用方式: + * 1. 先通过 GetIcdMmsJsonDebugRunner 获取 mappingJson,或使用已有的 JSON 文件。 + * 2. 修改 MMS_JSON_FILE_PATH 指向包含 mappingJson 的文件路径。 + * 3. 直接运行 main,查看生成的 XML 内容。 + * 4. 可选:设置 SAVE_XML_TO_DISK = true 将 XML 保存到磁盘。 + */ +public class JsonToXmlDebugRunner { + + /** + * 包含 mappingJson 的文件路径。 + * 文件格式:纯文本,内容为 getIcdMmsJson 接口返回的 mappingJson 字段值。 + * 或者完整的 MappingTaskResponse JSON(会自动提取 mappingJson 字段)。 + */ + private static final String MMS_JSON_FILE_PATH = "D:/temp/mms-output/mapping.json"; + + /** 是否输出格式化 XML,便于人工查看。 */ + private static final boolean PRETTY_XML = true; + + /** 是否把生成的 XML 写入磁盘。 */ + private static final boolean SAVE_XML_TO_DISK = true; + + /** saveXmlToDisk=true 时使用的输出文件路径。 */ + private static final String OUTPUT_XML_PATH = "D:/temp/mms-output/generated-config.xml"; + + /** 是否打印详细的转换过程日志。 */ + private static final boolean VERBOSE_LOG = true; + + public static void main(String[] args) { + try (ConfigurableApplicationContext context = new SpringApplicationBuilder(DebugApplication.class) + .web(WebApplicationType.NONE) + .bannerMode(Banner.Mode.OFF) + .logStartupInfo(false) + .run(args)) { + + IcdToXmlTaskAppService icdToXmlTaskAppService = context.getBean(IcdToXmlTaskAppService.class); + IcdToXmlResponseConverter responseConverter = context.getBean(IcdToXmlResponseConverter.class); + ObjectMapper objectMapper = createObjectMapper(); + + if (VERBOSE_LOG) { + System.out.println("========== JSON 转 XML 调试开始 =========="); + System.out.println("输入文件: " + MMS_JSON_FILE_PATH); + System.out.println("输出文件: " + (SAVE_XML_TO_DISK ? OUTPUT_XML_PATH : "(不保存)")); + System.out.println(); + } + + // 读取 JSON 文件 + String jsonContent = readJsonFile(); + if (VERBOSE_LOG) { + System.out.println("✓ JSON 文件读取成功,长度: " + jsonContent.length() + " 字符"); + } + + // 提取 mappingJson(可能是完整响应或纯 mappingJson) + String mappingJson = extractMappingJson(jsonContent, objectMapper); + if (VERBOSE_LOG) { + System.out.println("✓ MappingJSON 提取成功,长度: " + mappingJson.length() + " 字符"); + System.out.println(); + } + + // 调用服务生成 XML + if (VERBOSE_LOG) { + System.out.println("正在转换 JSON 为 XML..."); + } + IcdToXmlGenerateResult result = icdToXmlTaskAppService.generateXmlFromJson(mappingJson); + + // 输出结果 + printResult(result, objectMapper); + + // 保存 XML 到磁盘 + if (SAVE_XML_TO_DISK && result.getStatus() == GenerateStatus.SUCCESS) { + saveXmlToDisk(result.getMappingXml()); + } + + if (VERBOSE_LOG) { + System.out.println(); + System.out.println("========== JSON 转 XML 调试结束 =========="); + } + + } catch (Exception ex) { + throw new IllegalStateException("JSON 转 XML 调试失败:" + ex.getMessage(), ex); + } + } + + /** + * 读取 JSON 文件内容。 + */ + private static String readJsonFile() { + Path jsonPath = Paths.get(MMS_JSON_FILE_PATH); + if (!Files.exists(jsonPath)) { + throw new IllegalArgumentException("JSON 文件不存在:" + jsonPath.toAbsolutePath()); + } + + try { + byte[] bytes = Files.readAllBytes(jsonPath); + return new String(bytes, StandardCharsets.UTF_8); + } catch (Exception ex) { + throw new IllegalArgumentException("读取 JSON 文件失败:" + ex.getMessage(), ex); + } + } + + /** + * 从 JSON 内容中提取 mappingJson。 + * 支持两种格式: + * 1. 完整的 MappingTaskResponse JSON(包含 mappingJson 字段) + * 2. 纯 mappingJson 字符串 + */ + private static String extractMappingJson(String jsonContent, ObjectMapper objectMapper) { + try { + // 尝试解析为对象,看是否包含 mappingJson 字段 + if (jsonContent.trim().startsWith("{")) { + java.util.Map jsonMap = objectMapper.readValue( + jsonContent, + java.util.Map.class + ); + + if (jsonMap.containsKey("mappingJson")) { + Object mappingJsonObj = jsonMap.get("mappingJson"); + if (mappingJsonObj != null) { + return mappingJsonObj.toString(); + } + } + } + + // 如果不是对象或不包含 mappingJson,则假设整个内容就是 mappingJson + return jsonContent; + } catch (Exception ex) { + // 如果解析失败,也假设整个内容就是 mappingJson + return jsonContent; + } + } + + /** + * 打印转换结果。 + */ + private static void printResult(IcdToXmlGenerateResult result, ObjectMapper objectMapper) { + System.out.println(); + System.out.println("===== 转换结果 ====="); + System.out.println("状态: " + result.getStatus()); + System.out.println("消息: " + result.getMessage()); + + if (result.getProblems() != null && !result.getProblems().isEmpty()) { + System.out.println("问题列表:"); + for (String problem : result.getProblems()) { + System.out.println(" - " + problem); + } + } + + if (result.getStatus() == GenerateStatus.SUCCESS) { + System.out.println(); + System.out.println("----- 生成的 XML 内容 -----"); + String xmlContent = result.getMappingXml(); + + if (PRETTY_XML) { + // 简单格式化:每个标签独占一行 + xmlContent = formatXml(xmlContent); + } + + System.out.println(xmlContent); + System.out.println("--------------------------"); + System.out.println(); + System.out.println("XML 长度: " + result.getMappingXml().length() + " 字符"); + } + } + + /** + * 简单的 XML 格式化。 + */ + private static String formatXml(String xml) { + if (xml == null || xml.isEmpty()) { + return xml; + } + + // 在标签前后添加换行 + String formatted = xml.replaceAll(">", ">\n") + .replaceAll("<", "\n<") + .replaceAll("\n\n", "\n"); + + // 简单的缩进处理 + StringBuilder result = new StringBuilder(); + int indentLevel = 0; + String[] lines = formatted.split("\n"); + + for (String line : lines) { + line = line.trim(); + if (line.isEmpty()) { + continue; + } + + // 如果是闭合标签,减少缩进 + if (line.startsWith("")) { + indentLevel = Math.max(0, indentLevel - 1); + } + + // 添加缩进 + for (int i = 0; i < indentLevel; i++) { + result.append(" "); + } + result.append(line).append("\n"); + + // 如果是开始标签且不是自闭合,增加缩进 + if (line.startsWith("<") && !line.startsWith("") && !line.endsWith(">")) { + indentLevel++; + } + } + + return result.toString(); + } + + /** + * 保存 XML 到磁盘。 + */ + private static void saveXmlToDisk(String xmlContent) { + try { + Path outputPath = Paths.get(OUTPUT_XML_PATH); + + // 创建父目录 + if (outputPath.getParent() != null && !Files.exists(outputPath.getParent())) { + Files.createDirectories(outputPath.getParent()); + } + + Files.write(outputPath, xmlContent.getBytes(StandardCharsets.UTF_8)); + + System.out.println("✓ XML 已保存到: " + outputPath.toAbsolutePath()); + System.out.println(" 文件大小: " + Files.size(outputPath) + " 字节"); + } catch (Exception ex) { + throw new IllegalStateException("保存 XML 文件失败:" + ex.getMessage(), ex); + } + } + + private static ObjectMapper createObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + return objectMapper; + } + + @SpringBootApplication(scanBasePackages = "com.njcn.gather.icd.mapping") + public static class DebugApplication { + } +} From 8a92ff3be06249b8091065f508c199d5ae12936c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E5=AE=87=20=E8=94=A1?= <2418394595@qq.com> Date: Wed, 6 May 2026 15:43:19 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat(mapping):=20=E4=BC=98=E5=8C=96ICD?= =?UTF-8?q?=E5=88=B0XML=E8=BD=AC=E6=8D=A2=E6=9C=8D=E5=8A=A1=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=9C=AA=E5=8C=B9=E9=85=8D=E8=A7=84=E5=88=99=E8=AF=A6?= =?UTF-8?q?=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现convertFromJsonWithResult方法返回完整的转换结果 - 添加未匹配规则详细信息到生成结果的问题列表中 - 新增ConversionResult、RuleMatchingResult和UnmatchedRuleDetail数据结构 - 扩展应用规则逻辑以跟踪和报告未匹配的规则变体 - 重构buildXmlFromMapping方法以支持结果详情返回 - 更新控制台日志输出以显示规则匹配统计信息 --- .../component/JsonToXmlConversionService.java | 590 ++++++++++-------- .../service/impl/IcdToXmlTaskAppService.java | 68 +- 2 files changed, 377 insertions(+), 281 deletions(-) diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/JsonToXmlConversionService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/JsonToXmlConversionService.java index 3dfccd0..ec28fbe 100644 --- a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/JsonToXmlConversionService.java +++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/JsonToXmlConversionService.java @@ -22,7 +22,7 @@ import java.util.List; /** * JSON到XML转换服务。 - * + * * 职责: * 1. 接收JSON格式的MappingDocument * 2. 基于规则文件和模板,将JSON数据转换为XML格式 @@ -30,86 +30,128 @@ import java.util.List; */ @Component public class JsonToXmlConversionService { - + private final ObjectMapper objectMapper; private final RuleBasedXmlMappingService ruleBasedXmlMappingService; - + public JsonToXmlConversionService(RuleBasedXmlMappingService ruleBasedXmlMappingService) { this.ruleBasedXmlMappingService = ruleBasedXmlMappingService; this.objectMapper = new ObjectMapper(); this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } - + /** * 从JSON字符串转换为XML文件 - * - * @param mappingJson JSON格式的映射文档 - * @param templateStream XML模板流 - * @param ruleStreams 规则文件流列表 - * @param indexMapping 索引映射配置 - * @return 生成的XML文件路径 - * @throws Exception 转换异常 */ public String convertFromJson(String mappingJson, InputStream templateStream, List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - + long startTime = System.currentTimeMillis(); System.out.println("[JSON转XML] 开始转换..."); - + try { MappingDocument mappingDocument = objectMapper.readValue(mappingJson, MappingDocument.class); - + long parseTime = System.currentTimeMillis(); System.out.println("[JSON转XML] JSON解析完成,耗时: " + (parseTime - startTime) + " ms"); - - String xmlContent = buildXmlFromMapping(mappingDocument, templateStream, ruleStreams, indexMapping); - + + ConversionResult conversionResult = buildXmlFromMappingWithResult(mappingDocument, templateStream, ruleStreams, indexMapping); + long totalTime = System.currentTimeMillis() - startTime; System.out.println("[JSON转XML] 转换完成,总耗时: " + totalTime + " ms"); - - return xmlContent; + + if (conversionResult.getUnmatchedRuleDetails() != null && !conversionResult.getUnmatchedRuleDetails().isEmpty()) { + System.err.println("[JSON转XML] 警告: 有 " + conversionResult.getUnmatchedRuleDetails().size() + " 条规则未匹配到指标"); + } + + return conversionResult.getXmlContent(); } catch (Exception e) { long totalTime = System.currentTimeMillis() - startTime; System.err.println("[JSON转XML] 转换失败,已耗时: " + totalTime + " ms,错误: " + e.getMessage()); throw e; } } - + + /** + * 从JSON字符串转换为XML,并返回包含未匹配规则信息的完整结果。 + */ + public ConversionResult convertFromJsonWithResult(String mappingJson, + InputStream templateStream, + List ruleStreams, + IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { + + long startTime = System.currentTimeMillis(); + System.out.println("[JSON转XML] 开始转换(带结果)..."); + + try { + MappingDocument mappingDocument = objectMapper.readValue(mappingJson, MappingDocument.class); + + long parseTime = System.currentTimeMillis(); + System.out.println("[JSON转XML] JSON解析完成,耗时: " + (parseTime - startTime) + " ms"); + + ConversionResult conversionResult = buildXmlFromMappingWithResult(mappingDocument, templateStream, ruleStreams, indexMapping); + + long totalTime = System.currentTimeMillis() - startTime; + System.out.println("[JSON转XML] 转换完成,总耗时: " + totalTime + " ms"); + + if (conversionResult.getUnmatchedRuleDetails() != null && !conversionResult.getUnmatchedRuleDetails().isEmpty()) { + System.err.println("[JSON转XML] 警告: 有 " + conversionResult.getUnmatchedRuleDetails().size() + " 条规则未匹配到指标"); + } + + return conversionResult; + } catch (Exception e) { + long totalTime = System.currentTimeMillis() - startTime; + System.err.println("[JSON转XML] 转换失败,已耗时: " + totalTime + " ms,错误: " + e.getMessage()); + throw e; + } + } + private String buildXmlFromMapping(MappingDocument mappingDocument, InputStream templateStream, List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - + + return buildXmlFromMappingWithResult(mappingDocument, templateStream, ruleStreams, indexMapping).getXmlContent(); + } + + private ConversionResult buildXmlFromMappingWithResult(MappingDocument mappingDocument, + InputStream templateStream, + List ruleStreams, + IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { + long stepStart = System.currentTimeMillis(); - + String templateContent = readInputStreamToString(templateStream); - + long templateTime = System.currentTimeMillis(); System.out.println(" [步骤1] 读取模板完成,耗时: " + (templateTime - stepStart) + " ms"); - + String xmlContent = fillIedInfo(templateContent, mappingDocument); - + long iedTime = System.currentTimeMillis(); System.out.println(" [步骤2] 填充IED信息完成,耗时: " + (iedTime - templateTime) + " ms"); - + xmlContent = fillReportControlsFromMapping(xmlContent, mappingDocument); - + long reportTime = System.currentTimeMillis(); System.out.println(" [步骤3] 填充ReportControl完成,耗时: " + (reportTime - iedTime) + " ms"); - - xmlContent = applyRulesFromMapping(xmlContent, mappingDocument, ruleStreams, indexMapping); - + + RuleMatchingResult matchingResult = applyRulesFromMappingWithResult(xmlContent, mappingDocument, ruleStreams, indexMapping); + long rulesTime = System.currentTimeMillis(); System.out.println(" [步骤4] 应用规则完成,耗时: " + (rulesTime - reportTime) + " ms"); - + long totalStepTime = System.currentTimeMillis() - stepStart; System.out.println(" [buildXmlFromMapping] 总计耗时: " + totalStepTime + " ms"); - - return xmlContent; + + ConversionResult result = new ConversionResult(); + result.setXmlContent(matchingResult.getXmlContent()); + result.setUnmatchedRuleDetails(matchingResult.getUnmatchedRuleDetails()); + return result; } - + private String readInputStreamToString(InputStream inputStream) throws Exception { java.io.ByteArrayOutputStream result = new java.io.ByteArrayOutputStream(); byte[] buffer = new byte[1024]; @@ -119,10 +161,7 @@ public class JsonToXmlConversionService { } return result.toString(StandardCharsets.UTF_8.name()); } - - /** - * 填充IED信息 - */ + private String fillIedInfo(String xmlContent, MappingDocument mappingDocument) { if (mappingDocument == null) { return xmlContent; @@ -133,24 +172,21 @@ public class JsonToXmlConversionService { if (iedName != null && !iedName.isEmpty()) { xmlContent = xmlContent.replaceAll( - "\n"); + .append(escapeXml(reportControlStr)) + .append("\" />\n"); } } } @@ -184,21 +220,18 @@ public class JsonToXmlConversionService { reportStatBuilder.append("\t\t"); xmlContent = xmlContent.replaceAll( - "[\\s\\S]*?", - reportStatBuilder.toString().replace("$", "\\$").replace("[", "\\[").replace("]", "\\]") + "[\\s\\S]*?", + reportStatBuilder.toString().replace("$", "\\$").replace("[", "\\[").replace("]", "\\]") ); return xmlContent; } - - /** - * 构建ReportControl字符串 - */ + private String buildReportControlString(ReportMapItem rc) { StringBuilder sb = new StringBuilder(); sb.append("LLN0$").append(rc.getBuffered() != null && rc.getBuffered().equals("BR") ? "BR$" : "RP$").append(rc.getName()); - + if(rc.getName().contains("PLT") || rc.getName().contains("Flicker") || rc.getName().contains("PST") || rc.getName().contains("Fluc")){ sb.append(",600"); }else{ @@ -220,7 +253,7 @@ public class JsonToXmlConversionService { sb.append(",1"); sb.append(",1"); sb.append(",3"); - + if(rc.getName().contains("PLT") || rc.getName().contains("Flicker")){ sb.append(",1"); }else if(rc.getName().contains("PST") || rc.getName().contains("Fluc")){ @@ -231,60 +264,63 @@ public class JsonToXmlConversionService { return sb.toString(); } - - /** - * 从MappingDocument应用规则 - */ + private String applyRulesFromMapping(String xmlContent, MappingDocument mappingDocument, List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - + + return applyRulesFromMappingWithResult(xmlContent, mappingDocument, ruleStreams, indexMapping).getXmlContent(); + } + + private RuleMatchingResult applyRulesFromMappingWithResult(String xmlContent, + MappingDocument mappingDocument, + List ruleStreams, + IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { + long stepStart = System.currentTimeMillis(); - + var mergedRules = mergeAllRulesDesc(ruleStreams, indexMapping); - + long mergeTime = System.currentTimeMillis(); System.out.println(" [规则合并] 耗时: " + (mergeTime - stepStart) + " ms,规则数: " + mergedRules.size()); - + var mappingMetrics = extractMetricsFromMapping(mappingDocument); - + long extractTime = System.currentTimeMillis(); System.out.println(" [指标提取] 耗时: " + (extractTime - mergeTime) + " ms,指标数: " + mappingMetrics.size()); - + System.out.println("========== 开始从JSON匹配规则 =========="); System.out.println("规则总数: " + mergedRules.size()); System.out.println("JSON中指标总数: " + mappingMetrics.size()); - - var applicableRules = findApplicableRulesDesc(mergedRules, mappingMetrics); - + + RuleMatchingResult matchingResult = findApplicableRulesDescWithUnmatched(mergedRules, mappingMetrics); + long matchTime = System.currentTimeMillis(); System.out.println(" [规则匹配] 耗时: " + (matchTime - extractTime) + " ms"); - - System.out.println("匹配成功: " + applicableRules.size() + " 条规则"); - System.out.println("匹配失败: " + (mergedRules.size() - applicableRules.size()) + " 条规则"); - - String resultXml = applyRulesToXml(xmlContent, applicableRules); - + + System.out.println("匹配成功: " + matchingResult.getApplicableRules().size() + " 条规则"); + System.out.println("匹配失败: " + matchingResult.getUnmatchedRuleDetails().size() + " 条规则"); + + String resultXml = applyRulesToXml(xmlContent, matchingResult.getApplicableRules()); + long applyTime = System.currentTimeMillis(); System.out.println(" [规则应用] 耗时: " + (applyTime - matchTime) + " ms"); - + long totalApplyTime = System.currentTimeMillis() - stepStart; System.out.println(" [applyRulesFromMapping] 总计耗时: " + totalApplyTime + " ms"); System.out.println("========== JSON规则匹配结束 ==========\n"); - - return resultXml; + + matchingResult.setXmlContent(resultXml); + return matchingResult; } - - /** - * 合并所有规则文件 - */ + private java.util.Map> mergeAllRules( List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - + java.util.Map> mergedRules = new java.util.LinkedHashMap<>(); - + for (InputStream ruleStream : ruleStreams) { var rules = parseRuleFile(ruleStream, indexMapping); for (var entry : rules.entrySet()) { @@ -293,7 +329,7 @@ public class JsonToXmlConversionService { mergedRules.computeIfAbsent(key, k -> new ArrayList<>()).addAll(ruleList); } } - + return mergedRules; } @@ -314,40 +350,37 @@ public class JsonToXmlConversionService { return mergedRules; } - - /** - * 解析规则文件 - */ + private java.util.Map> parseRuleFile( InputStream ruleStream, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - + java.util.Map> rules = new java.util.HashMap<>(); - + java.io.BufferedReader reader = new java.io.BufferedReader( - new java.io.InputStreamReader(ruleStream, StandardCharsets.UTF_8) + new java.io.InputStreamReader(ruleStream, StandardCharsets.UTF_8) ); - + String line; String currentGroup = ""; - + java.util.regex.Pattern valueRulePattern = java.util.regex.Pattern.compile( - "", java.util.regex.Pattern.CASE_INSENSITIVE + "", java.util.regex.Pattern.CASE_INSENSITIVE ); - + while ((line = reader.readLine()) != null) { line = line.trim(); - + if (line.startsWith("