From 58ca8b0c236b6d20d19291b185cb804b239a1547 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, 27 May 2026 08:45:36 +0800 Subject: [PATCH] =?UTF-8?q?refactor(mms-mapping):=20=E9=87=8D=E6=9E=84ICD?= =?UTF-8?q?=E5=88=B0XML=E8=BD=AC=E6=8D=A2=E6=9C=8D=E5=8A=A1=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除IcdToXmlGenerateResult中未使用的iedName、ldInst、indexAnalysis、savedPath字段 - 注释掉相应的getter/setter方法减少代码冗余 - 重构IcdToXmlTaskAppService中generateFromIcd方法的业务逻辑 - 优化JsonToXmlConversionService的转换流程提高性能 - 添加详细的中文注释说明各个方法的功能和实现逻辑 - 调整规则匹配和XML生成的核心算法提升匹配准确性 - 修改未匹配规则的错误提示信息增加详细指标信息 --- .../component/IcdToXmlResponseConverter.java | 27 +- .../component/JsonToXmlConversionService.java | 329 ++++++++----- .../component/RuleBasedXmlMappingService.java | 461 +----------------- .../mapping/config/MappingModuleConfig.java | 8 + .../pojo/bo/IcdToXmlGenerateResult.java | 21 +- .../service/impl/IcdToXmlTaskAppService.java | 119 +---- .../mapping/debug/JsonToXmlDebugRunner.java | 30 +- 7 files changed, 280 insertions(+), 715 deletions(-) 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 38dea81..029a9e0 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 @@ -16,33 +16,10 @@ public class IcdToXmlResponseConverter { IcdToXmlResponse response = new IcdToXmlResponse(); response.setStatus(result.getStatus()); response.setMessage(result.getMessage()); - response.setIedName(result.getIedName()); - response.setLdInst(result.getLdInst()); - response.setSavedPath(result.getSavedPath()); + //response.setIedName(result.getIedName()); + //response.setLdInst(result.getLdInst()); 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(); - candidateResponse.setGroupKey(candidate.getGroupKey()); - candidateResponse.setGroupDesc(candidate.getGroupDesc()); - candidateResponse.setReportCount(candidate.getReportCount()); - candidateResponse.getTemplateLabels().addAll(candidate.getTemplateLabels()); - - if (candidate.getReports() != null) { - for (IndexCandidateReportItem item : candidate.getReports()) { - IndexCandidateReportItemResponse itemResponse = new IndexCandidateReportItemResponse(); - itemResponse.setReportName(item.getReportName()); - itemResponse.setDataSetName(item.getDataSetName()); - itemResponse.setReportDesc(item.getReportDesc()); - itemResponse.getAvailableLnInstValues().addAll(item.getAvailableLnInstValues()); - candidateResponse.getReports().add(itemResponse); - } - } - - response.getIndexCandidates().add(candidateResponse); - } - } if (result.getMappingDocument() != null) { MappingDocumentResponse doc = new MappingDocumentResponse(); 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 ec28fbe..7816135 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 @@ -30,128 +30,84 @@ 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(); + // 配置ObjectMapper忽略未知属性,避免反序列化时因字段不匹配而失败 this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } - /** - * 从JSON字符串转换为XML文件 - */ - 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"); - - 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.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; + public ConversionResult convertFromJsonWithResult(MappingDocument mappingDocument, + InputStream templateStream, + List ruleStreams, + IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { + + ConversionResult conversionResult = buildXmlFromMappingWithResult(mappingDocument, templateStream, ruleStreams, indexMapping); + + if (conversionResult.getUnmatchedRuleDetails() != null && !conversionResult.getUnmatchedRuleDetails().isEmpty()) { + System.out.println("[JSON转XML] 警告: 有 " + conversionResult.getUnmatchedRuleDetails().size() + " 条规则未匹配到指标"); } + + return conversionResult; } + /** + * 将JSON字符串解析为MappingDocument对象 + */ + public MappingDocument parseMappingJson(String mappingJson) throws Exception { + return objectMapper.readValue(mappingJson, MappingDocument.class); + } + + /** + * 基于映射文档构建XML内容(旧版方法,仅返回XML内容) + */ 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, + /** + * 基于映射文档构建XML内容并返回完整结果 + * 主要流程:读取模板 -> 填充IED信息 -> 填充报告控制块 -> 应用规则匹配 + */ + public ConversionResult buildXmlFromMappingWithResult(MappingDocument mappingDocument, InputStream templateStream, List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - - long stepStart = System.currentTimeMillis(); - + + // 读取XML模板内容为字符串 String templateContent = readInputStreamToString(templateStream); - - long templateTime = System.currentTimeMillis(); - System.out.println(" [步骤1] 读取模板完成,耗时: " + (templateTime - stepStart) + " ms"); - + + // 填充IED名称和LD前缀信息到模板中 String xmlContent = fillIedInfo(templateContent, mappingDocument); - long iedTime = System.currentTimeMillis(); - System.out.println(" [步骤2] 填充IED信息完成,耗时: " + (iedTime - templateTime) + " ms"); + // 填充报告控制块信息到XML中 xmlContent = fillReportControlsFromMapping(xmlContent, mappingDocument); - - long reportTime = System.currentTimeMillis(); - System.out.println(" [步骤3] 填充ReportControl完成,耗时: " + (reportTime - iedTime) + " ms"); - + + // 应用规则匹配,将JSON中的指标数据映射到XML节点 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"); - + + // 封装转换结果 ConversionResult result = new ConversionResult(); result.setXmlContent(matchingResult.getXmlContent()); result.setUnmatchedRuleDetails(matchingResult.getUnmatchedRuleDetails()); return result; } + /** + * 将输入流读取为UTF-8编码的字符串 + */ private String readInputStreamToString(InputStream inputStream) throws Exception { java.io.ByteArrayOutputStream result = new java.io.ByteArrayOutputStream(); byte[] buffer = new byte[1024]; @@ -162,6 +118,10 @@ public class JsonToXmlConversionService { return result.toString(StandardCharsets.UTF_8.name()); } + /** + * 填充IED名称和LD前缀信息到XML模板中 + * 通过正则表达式替换模板中的占位符 + */ private String fillIedInfo(String xmlContent, MappingDocument mappingDocument) { if (mappingDocument == null) { return xmlContent; @@ -170,6 +130,7 @@ public class JsonToXmlConversionService { String iedName = mappingDocument.getIed(); String ldPrefix = mappingDocument.getLd(); + // 替换IED名称 if (iedName != null && !iedName.isEmpty()) { xmlContent = xmlContent.replaceAll( "\n"); + // 遍历报告映射项,构建报告控制块字符串 for (var reportItem : mappingDocument.getReportMap()) { if (reportItem.getName() != null && !reportItem.getName().isEmpty()) { String name = reportItem.getName(); + // 只处理特定类型的报告控制块 if (name.contains("brcbFluc") || name.contains("brcbStHarm") || name.contains("brcbStIHarm") || @@ -219,6 +187,7 @@ public class JsonToXmlConversionService { reportStatBuilder.append("\t\t"); + // 使用正则表达式替换XML中的ReportStat节点 xmlContent = xmlContent.replaceAll( "[\\s\\S]*?", reportStatBuilder.toString().replace("$", "\\$").replace("[", "\\[").replace("]", "\\]") @@ -227,25 +196,32 @@ public class JsonToXmlConversionService { return xmlContent; } + /** + * 构建报告控制块字符串 + * 格式:LLN0$BR/RP$名称,超时时间,重传次数等参数 + */ private String buildReportControlString(ReportMapItem rc) { StringBuilder sb = new StringBuilder(); + // 构建报告控制块的基本路径:LLN0$缓冲类型$名称 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"); + sb.append(",600"); // 闪变相关报告超时时间为600秒 }else{ - sb.append(",60"); + sb.append(",60"); // 其他报告超时时间为60秒 } - sb.append(",1"); - sb.append(",0"); - sb.append(",0"); - sb.append(",0"); - sb.append(",0"); - sb.append(",yes"); - sb.append(",1"); - sb.append(",1"); - sb.append(",1"); + // 设置其他固定参数ReportControl:ID,RCBName,intgPd,dchg,qchg,dupd,period,gi,issuffixed,seqNum,timeStamp,reasonCode,dataSet,dataRef,bufOvfl,entryID,configRef,segmentation,FlickerFlag + sb.append(",1");// intgPd: 完整性周期(启用) + sb.append(",0"); // dchg: 数据变化触发(禁用) + sb.append(",0");// qchg: 品质变化触发(禁用) + sb.append(",0");// dupd: 数据更新触发(禁用) + sb.append(",0");// period: 周期性触发(禁用) + sb.append(",yes");// gi: 总召唤支持(启用) + sb.append(",1"); // issuffixed: 使用后缀命名(启用) + sb.append(",1");// seqNum: 包含序列号(启用) + sb.append(",1"); // timeStamp: 包含时间戳(启用) sb.append(",1"); sb.append(",1"); sb.append(",0"); @@ -254,6 +230,7 @@ public class JsonToXmlConversionService { 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")){ @@ -265,56 +242,54 @@ public class JsonToXmlConversionService { return sb.toString(); } + /** + * 从映射文档应用规则到XML(旧版方法) + */ private String applyRulesFromMapping(String xmlContent, MappingDocument mappingDocument, List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - + return applyRulesFromMappingWithResult(xmlContent, mappingDocument, ruleStreams, indexMapping).getXmlContent(); } - + + /** + * 从映射文档应用规则到XML并返回匹配结果 + * 核心流程:合并规则 -> 提取指标 -> 匹配规则 -> 应用规则到XML + */ 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()); - + + // 执行规则匹配,获取匹配结果和未匹配规则详情 RuleMatchingResult matchingResult = findApplicableRulesDescWithUnmatched(mergedRules, mappingMetrics); - - long matchTime = System.currentTimeMillis(); - System.out.println(" [规则匹配] 耗时: " + (matchTime - extractTime) + " ms"); - + System.out.println("匹配成功: " + matchingResult.getApplicableRules().size() + " 条规则"); System.out.println("匹配失败: " + matchingResult.getUnmatchedRuleDetails().size() + " 条规则"); - + + // 将匹配成功的规则应用到XML内容中 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"); - + matchingResult.setXmlContent(resultXml); return matchingResult; } + /** + * 合并所有规则文件中的规则(按name+desc作为key) + */ private java.util.Map> mergeAllRules( List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { @@ -333,6 +308,9 @@ public class JsonToXmlConversionService { return mergedRules; } + /** + * 合并所有规则文件中的规则(仅按desc作为key) + */ private java.util.Map> mergeAllRulesDesc( List ruleStreams, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { @@ -351,6 +329,9 @@ public class JsonToXmlConversionService { return mergedRules; } + /** + * 解析单个规则文件,按name+desc组合作为key + */ private java.util.Map> parseRuleFile( InputStream ruleStream, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { @@ -364,6 +345,7 @@ public class JsonToXmlConversionService { String line; String currentGroup = ""; + // 定义Value标签的正则表达式模式,用于解析规则文件中的节点 java.util.regex.Pattern valueRulePattern = java.util.regex.Pattern.compile( " new ArrayList<>()).add(rule); @@ -435,6 +421,9 @@ public class JsonToXmlConversionService { return rules; } + /** + * 解析单个规则文件,仅按desc作为key(用于描述匹配) + */ private java.util.Map> parseRuleFileDesc( InputStream ruleStream, IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { @@ -448,6 +437,7 @@ public class JsonToXmlConversionService { String line; String currentGroup = ""; + // 定义Value标签的正则表达式模式,用于解析规则文件中的节点 java.util.regex.Pattern valueRulePattern = java.util.regex.Pattern.compile( " new ArrayList<>()).add(rule); @@ -519,6 +513,10 @@ public class JsonToXmlConversionService { return rules; } + /** + * 应用索引映射,将规则中的DO路径索引转换为实际使用的索引 + * 例如:将MMXU1转换为MMXU2(根据用户选择的统计类型) + */ private String applyIndexMapping(String doPath, String currentGroup, IcdToXmlMappingService.IndexMappingConfig indexMapping, String name, String desc) { @@ -526,7 +524,9 @@ public class JsonToXmlConversionService { return doPath; } + // 匹配带索引的逻辑节点名称,如MMXU1、MHAI2等 java.util.regex.Pattern doIndexPattern = java.util.regex.Pattern.compile("(MMXU|MHAI|MSQI|MFLK|QVVR)(\\d+)"); + // 匹配不带索引但以$结尾的逻辑节点名称 java.util.regex.Pattern doNoIndexPattern = java.util.regex.Pattern.compile("(MMXU|MHAI|MSQI|MFLK|QVVR)\\$"); java.util.regex.Matcher matcherWithIndex = doIndexPattern.matcher(doPath); @@ -534,6 +534,7 @@ public class JsonToXmlConversionService { String lnClass = matcherWithIndex.group(1); int originalIndex = Integer.parseInt(matcherWithIndex.group(2)); + // 根据统计类型(平均值、最大值、最小值、95值)确定新的索引 int newIndex = determineNewIndex(currentGroup, lnClass, originalIndex, indexMapping, name, desc); if (newIndex >= 0) { @@ -557,6 +558,10 @@ public class JsonToXmlConversionService { return doPath; } + /** + * 根据统计类型确定新的索引值 + * 统计类型包括:平均值(avg)、最大值(max)、最小值(min)、95百分位值(g_) + */ private int determineNewIndex(String currentGroup, String lnClass, int originalIndex, IcdToXmlMappingService.IndexMappingConfig indexMapping, String name, String desc) { @@ -567,13 +572,15 @@ public class JsonToXmlConversionService { String lowerName = (name != null ? name : "").toLowerCase(); String lowerDesc = (desc != null ? desc : "").toLowerCase(); + // 判断统计类型 boolean isAverage = lowerName.contains("avg") || lowerDesc.contains("平均值"); boolean isMaximum = lowerName.startsWith("max_") || lowerDesc.contains("最大值"); boolean isMinimum = lowerName.startsWith("min_") || lowerDesc.contains("最小值"); - boolean is95Percentile = lowerName.startsWith("g_") || lowerDesc.contains("95值"); + boolean is95Percentile = lowerName.startsWith("g_") || lowerDesc.contains("95값"); boolean isInterHarmonic = lowerDesc.contains("间谐波"); + // 根据不同的数据组和统计类型,从索引映射配置中获取对应的索引值 if ("MMXU".equals(currentGroup) || "MMXU".equals(lnClass)) { IcdToXmlMappingService.IndexMappingConfig.StatIndex mmxu = indexMapping.getMmxu(); if (mmxu != null) { @@ -635,6 +642,9 @@ public class JsonToXmlConversionService { return originalIndex; } + /** + * 构建规则key,优先使用name,如果name为空则使用desc + */ private String buildRuleKey(String name, String desc) { if (name != null && !name.isEmpty()) { return name; @@ -642,11 +652,19 @@ public class JsonToXmlConversionService { return desc != null ? desc : ""; } + /** + * 检查规则是否有有效的DO或DA路径 + */ private boolean hasValidDoOrDa(RuleBasedXmlMappingService.ValueRule rule) { return (rule.getDoPath() != null && !rule.getDoPath().isEmpty()) || (rule.getDaPath() != null && !rule.getDaPath().isEmpty()); } + /** + * 从映射文档中提取所有指标信息 + * 遍历DataSetList -> InstList -> DoiList -> SdiList -> TypeList层级结构 + * 构建以desc组合为key的指标映射表 + */ private java.util.Map extractMetricsFromMapping(MappingDocument mappingDocument) { java.util.Map metrics = new java.util.HashMap<>(); @@ -654,19 +672,24 @@ public class JsonToXmlConversionService { return metrics; } + // 遍历数据集列表 for (var dataSetGroup : mappingDocument.getDataSetList()) { if (dataSetGroup.getInstList() == null) continue; + // 遍历实例列表 for (var instItem : dataSetGroup.getInstList()) { if (instItem.getDoiList() == null) continue; + // 遍历DOI列表 for (var doiItem : instItem.getDoiList()) { String doPath = buildDoPath(dataSetGroup.getLnClass(), instItem.getInst(), doiItem.getName()); + // 遍历SDI列表和Type列表,构建完整的指标信息 if (doiItem.getSdiList() != null) { for (var sdiItem : doiItem.getSdiList()) { if (sdiItem.getTypeList() != null) { for (var typeItem : sdiItem.getTypeList()) { + // 构建指标的唯一key(基于desc组合) String fullKey = doiItem.getDesc() + instItem.getDesc()+typeItem.getDesc(); if(fullKey.contains("正序")){ fullKey = doiItem.getDesc() + instItem.getDesc()+sdiItem.getDesc()+typeItem.getDesc(); @@ -697,6 +720,9 @@ public class JsonToXmlConversionService { return metrics; } + /** + * 构建DO路径,格式:LN类名+LN实例+$MX+$DO名称 + */ private String buildDoPath(String lnClass, String lnInst, String doName) { StringBuilder sb = new StringBuilder(); if (lnClass != null) { @@ -716,22 +742,28 @@ public class JsonToXmlConversionService { return sb.toString(); } + /** + * 构建DA路径,处理相位名称标准化和谐波索引 + */ private String buildDaPath(String sdiName, String typeName, DoiItem doiItem) { StringBuilder sb = new StringBuilder(); if (sdiName != null && !sdiName.isEmpty()) { String normalizedSdi = normalizePhaseName(sdiName); sb.append(normalizedSdi); + // 处理谐波数据的特殊索引格式 if (sdiName.endsWith("Har") && doiItem != null) { int baseflag = doiItem.getBaseflag(); int start = doiItem.getStart(); if (baseflag == 1) { + // 间谐波使用特殊格式:[%-i] boolean isInterHarmonic = isInterHarmonicMetric(doiItem); int m = isInterHarmonic ? 0 : 2; int i = m - start; sb.append("[%-").append(i).append("]"); } else { + // 普通谐波使用格式:[start] sb.append("[").append(start).append("]"); } } @@ -745,6 +777,9 @@ public class JsonToXmlConversionService { return sb.toString(); } + /** + * 标准化相位名称,将phsa、phsb、phsc统一为phs* + */ private String normalizePhaseName(String name) { if (name == null || name.isEmpty()) { return name; @@ -761,6 +796,9 @@ public class JsonToXmlConversionService { return name; } + /** + * 判断指标是否为间谐波类型 + */ private boolean isInterHarmonicMetric(DoiItem doiItem) { if (doiItem == null || doiItem.getDesc() == null) { return false; @@ -768,6 +806,9 @@ public class JsonToXmlConversionService { return doiItem.getDesc().toLowerCase().contains("间谐波"); } + /** + * 查找适用的规则(旧版方法) + */ private java.util.Map findApplicableRulesDesc( java.util.Map> allRules, java.util.Map mappingMetrics) { @@ -775,6 +816,10 @@ public class JsonToXmlConversionService { return findApplicableRulesDescWithUnmatched(allRules, mappingMetrics).getApplicableRules(); } + /** + * 查找适用的规则并返回未匹配规则详情 + * 核心匹配逻辑:遍历所有规则,在指标映射表中查找匹配的指标 + */ private RuleMatchingResult findApplicableRulesDescWithUnmatched( java.util.Map> allRules, java.util.Map mappingMetrics) { @@ -782,19 +827,23 @@ public class JsonToXmlConversionService { java.util.Map applicable = new java.util.HashMap<>(); List failedRuleDetails = new ArrayList<>(); + // 遍历所有规则 for (var entry : allRules.entrySet()) { String ruleKey = entry.getKey(); List ruleVariants = entry.getValue(); boolean matched = false; + // 尝试匹配规则的任意一个候选变体 for (RuleBasedXmlMappingService.ValueRule rule : ruleVariants) { if (rule.getName() == null || rule.getDoPath().isEmpty()) { continue; } + // 直接通过name在指标映射表中查找 if(mappingMetrics.containsKey(rule.getName())){ MetricInfo metric = mappingMetrics.get(rule.getName()); + // 将匹配到的指标的DO和DA路径赋值给规则 rule.setDoPath(metric.getDoPath()); rule.setDaPath(metric.getDaPath()); applicable.put(ruleKey, rule); @@ -807,6 +856,7 @@ public class JsonToXmlConversionService { } } + // 如果所有候选都未匹配,记录未匹配规则详情 if (!matched) { UnmatchedRuleDetail detail = new UnmatchedRuleDetail(); detail.setRuleKey(ruleKey); @@ -856,6 +906,9 @@ public class JsonToXmlConversionService { return result; } + /** + * 查找适用的规则(旧版方法,使用路径匹配) + */ private java.util.Map findApplicableRules( java.util.Map> allRules, java.util.Map mappingMetrics) { @@ -877,6 +930,7 @@ public class JsonToXmlConversionService { String ruleDo = normalizePath(rule.getDoPath()); String ruleDa = normalizePath(rule.getDaPath()); + // 遍历所有指标,尝试通过路径模式匹配 for (var metricEntry : mappingMetrics.entrySet()) { MetricInfo metric = metricEntry.getValue(); @@ -919,16 +973,24 @@ public class JsonToXmlConversionService { return applicable; } + /** + * 标准化路径字符串,转为小写并去除首尾空格 + */ private String normalizePath(String path) { if (path == null) return ""; return path.trim().toLowerCase(); } + /** + * 判断路径是否匹配模式 + * 支持通配符匹配,忽略数组索引部分 + */ private boolean matchesPattern(String pattern, String actual) { if (pattern == null || actual == null) { return pattern == null && actual == null; } + // 移除数组索引部分(如[1]、[%-0]等)后再比较 String normalizedPattern = pattern.replaceAll("\\[[^\\]]*\\]", ""); if (normalizedPattern.isEmpty() || actual.isEmpty()) { @@ -938,9 +1000,14 @@ public class JsonToXmlConversionService { return actual.equals(normalizedPattern); } + /** + * 将匹配的规则应用到XML内容中 + * 通过正则表达式查找XML中的节点,并用匹配的规则替换 + */ private String applyRulesToXml(String xmlContent, java.util.Map applicableRules) { + // 定义XML Value标签的正则表达式模式 java.util.regex.Pattern xmlValuePattern = java.util.regex.Pattern.compile( " applicableRules; private List unmatchedRuleDetails; @@ -1090,6 +1169,9 @@ public class JsonToXmlConversionService { } } + /** + * 转换结果类,包含生成的XML内容和未匹配的规则详情 + */ public static class ConversionResult { private String xmlContent; private List unmatchedRuleDetails; @@ -1111,6 +1193,9 @@ public class JsonToXmlConversionService { } } + /** + * 未匹配规则详情类,记录匹配失败的规则信息 + */ public static class UnmatchedRuleDetail { private String ruleKey; private String ruleVariants; diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/RuleBasedXmlMappingService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/RuleBasedXmlMappingService.java index 79e3270..9029d5b 100644 --- a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/RuleBasedXmlMappingService.java +++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/component/RuleBasedXmlMappingService.java @@ -1,30 +1,25 @@ package com.njcn.gather.icd.mapping.component; - +import com.njcn.gather.icd.mapping.config.MappingModuleConfig; import com.njcn.gather.icd.mapping.pojo.bo.icd.*; -import com.njcn.gather.icd.mapping.utils.XmlTemplateParser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.njcn.gather.icd.mapping.pojo.dto.*; -import com.njcn.gather.icd.mapping.pojo.bo.*; -import com.njcn.gather.icd.mapping.pojo.param.*; -import com.njcn.gather.icd.mapping.pojo.vo.*; -import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus; + @Component public class RuleBasedXmlMappingService { @Autowired private IcdParserService icdParserService; + + @Autowired + private MappingModuleConfig mappingModuleConfig; private static final Pattern VALUE_RULE_PATTERN = Pattern.compile( " loadDefaultRuleFile( ) throws Exception { + /** + * 加载JSON转XML使用的默认规则文件 + * 路径通过MappingModuleConfig配置,默认为template/默认规则.txt + */ + public List loadDefaultRuleFile() throws Exception { - ClassPathResource ruleResource = new ClassPathResource("template/默认规则.txt"); - if ( !ruleResource.exists()) { + ClassPathResource ruleResource = new ClassPathResource(mappingModuleConfig.getJsonToXmlRulePath()); + if (!ruleResource.exists()) { return null; } @@ -80,117 +82,6 @@ public class RuleBasedXmlMappingService { ruleStreams.add(ruleStream); return ruleStreams; } - - - - - public String generateWithRuleFiles(IcdDocument icdDocument, - InputStream templateStream, - List ruleStreams, - IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - - Map> mergedRules = mergeAllRules(ruleStreams, indexMapping); - - Map icdMetrics = extractIcdMetrics(icdDocument); - - Map applicableRules = findApplicableRules(mergedRules, icdMetrics); - - XmlTemplateParser.ParseResult parseResult = new XmlTemplateParser().parse(templateStream); - String xmlContent = parseResult.getTemplateContent(); - - xmlContent = fillIedInfo(xmlContent, icdDocument); - - xmlContent = fillReportControls(xmlContent, icdDocument); - - xmlContent = applyRulesToXml(xmlContent, applicableRules); - - Path tempPath = Files.createTempFile("rule_mapped_", ".xml"); - Files.write(tempPath, xmlContent.getBytes(StandardCharsets.UTF_8)); - return tempPath.toString(); - } - - - private Map> mergeAllRules(List ruleStreams, - IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - Map> mergedRules = new LinkedHashMap<>(); - - for (InputStream ruleStream : ruleStreams) { - Map> rules = parseRuleFile(ruleStream, indexMapping); - for (Map.Entry> entry : rules.entrySet()) { - String key = entry.getKey(); - List ruleList = entry.getValue(); - mergedRules.computeIfAbsent(key, k -> new ArrayList<>()).addAll(ruleList); - } - } - - return mergedRules; - } - - - private Map> parseRuleFile(InputStream ruleStream, - IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { - Map> rules = new HashMap<>(); - - BufferedReader reader = new BufferedReader(new InputStreamReader(ruleStream, StandardCharsets.UTF_8)); - String line; - String currentGroup = ""; - - while ((line = reader.readLine()) != null) { - line = line.trim(); - - if (line.startsWith("