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 { + } +}