feat(mapping): 优化ICD到XML转换服务支持未匹配规则详情

- 实现convertFromJsonWithResult方法返回完整的转换结果
- 添加未匹配规则详细信息到生成结果的问题列表中
- 新增ConversionResult、RuleMatchingResult和UnmatchedRuleDetail数据结构
- 扩展应用规则逻辑以跟踪和报告未匹配的规则变体
- 重构buildXmlFromMapping方法以支持结果详情返回
- 更新控制台日志输出以显示规则匹配统计信息
This commit is contained in:
周宇 蔡
2026-05-06 15:43:19 +08:00
parent ddadf26837
commit 8a92ff3be0
2 changed files with 377 additions and 281 deletions

View File

@@ -42,13 +42,6 @@ public class JsonToXmlConversionService {
/** /**
* 从JSON字符串转换为XML文件 * 从JSON字符串转换为XML文件
*
* @param mappingJson JSON格式的映射文档
* @param templateStream XML模板流
* @param ruleStreams 规则文件流列表
* @param indexMapping 索引映射配置
* @return 生成的XML文件路径
* @throws Exception 转换异常
*/ */
public String convertFromJson(String mappingJson, public String convertFromJson(String mappingJson,
InputStream templateStream, InputStream templateStream,
@@ -64,12 +57,50 @@ public class JsonToXmlConversionService {
long parseTime = System.currentTimeMillis(); long parseTime = System.currentTimeMillis();
System.out.println("[JSON转XML] JSON解析完成耗时: " + (parseTime - startTime) + " ms"); 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; long totalTime = System.currentTimeMillis() - startTime;
System.out.println("[JSON转XML] 转换完成,总耗时: " + totalTime + " ms"); 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<InputStream> 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) { } catch (Exception e) {
long totalTime = System.currentTimeMillis() - startTime; long totalTime = System.currentTimeMillis() - startTime;
System.err.println("[JSON转XML] 转换失败,已耗时: " + totalTime + " ms错误: " + e.getMessage()); System.err.println("[JSON转XML] 转换失败,已耗时: " + totalTime + " ms错误: " + e.getMessage());
@@ -82,6 +113,14 @@ public class JsonToXmlConversionService {
List<InputStream> ruleStreams, List<InputStream> ruleStreams,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
return buildXmlFromMappingWithResult(mappingDocument, templateStream, ruleStreams, indexMapping).getXmlContent();
}
private ConversionResult buildXmlFromMappingWithResult(MappingDocument mappingDocument,
InputStream templateStream,
List<InputStream> ruleStreams,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
long stepStart = System.currentTimeMillis(); long stepStart = System.currentTimeMillis();
String templateContent = readInputStreamToString(templateStream); String templateContent = readInputStreamToString(templateStream);
@@ -99,7 +138,7 @@ public class JsonToXmlConversionService {
long reportTime = System.currentTimeMillis(); long reportTime = System.currentTimeMillis();
System.out.println(" [步骤3] 填充ReportControl完成耗时: " + (reportTime - iedTime) + " ms"); 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(); long rulesTime = System.currentTimeMillis();
System.out.println(" [步骤4] 应用规则完成,耗时: " + (rulesTime - reportTime) + " ms"); System.out.println(" [步骤4] 应用规则完成,耗时: " + (rulesTime - reportTime) + " ms");
@@ -107,7 +146,10 @@ public class JsonToXmlConversionService {
long totalStepTime = System.currentTimeMillis() - stepStart; long totalStepTime = System.currentTimeMillis() - stepStart;
System.out.println(" [buildXmlFromMapping] 总计耗时: " + totalStepTime + " ms"); 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 { private String readInputStreamToString(InputStream inputStream) throws Exception {
@@ -120,9 +162,6 @@ public class JsonToXmlConversionService {
return result.toString(StandardCharsets.UTF_8.name()); return result.toString(StandardCharsets.UTF_8.name());
} }
/**
* 填充IED信息
*/
private String fillIedInfo(String xmlContent, MappingDocument mappingDocument) { private String fillIedInfo(String xmlContent, MappingDocument mappingDocument) {
if (mappingDocument == null) { if (mappingDocument == null) {
return xmlContent; return xmlContent;
@@ -133,24 +172,21 @@ public class JsonToXmlConversionService {
if (iedName != null && !iedName.isEmpty()) { if (iedName != null && !iedName.isEmpty()) {
xmlContent = xmlContent.replaceAll( xmlContent = xmlContent.replaceAll(
"<IED\\s+name=\"[^\"]*\"", "<IED\\s+name=\"[^\"]*\"",
"<IED name=\"" + escapeXml(iedName) + "\"" "<IED name=\"" + escapeXml(iedName) + "\""
); );
} }
if (ldPrefix != null && !ldPrefix.isEmpty()) { if (ldPrefix != null && !ldPrefix.isEmpty()) {
xmlContent = xmlContent.replaceAll( xmlContent = xmlContent.replaceAll(
"<LDevice\\s+Prefix=\"[^\"]*\"", "<LDevice\\s+Prefix=\"[^\"]*\"",
"<LDevice Prefix=\"" + escapeXml(ldPrefix) + "\"" "<LDevice Prefix=\"" + escapeXml(ldPrefix) + "\""
); );
} }
return xmlContent; return xmlContent;
} }
/**
* 从MappingDocument填充ReportControl信息
*/
private String fillReportControlsFromMapping(String xmlContent, MappingDocument mappingDocument) { private String fillReportControlsFromMapping(String xmlContent, MappingDocument mappingDocument) {
if (mappingDocument == null || mappingDocument.getReportMap() == null || mappingDocument.getReportMap().isEmpty()) { if (mappingDocument == null || mappingDocument.getReportMap() == null || mappingDocument.getReportMap().isEmpty()) {
return xmlContent; return xmlContent;
@@ -164,19 +200,19 @@ public class JsonToXmlConversionService {
String name = reportItem.getName(); String name = reportItem.getName();
if (name.contains("brcbFluc") || if (name.contains("brcbFluc") ||
name.contains("brcbStHarm") || name.contains("brcbStHarm") ||
name.contains("brcbStIHarm") || name.contains("brcbStIHarm") ||
name.contains("brcbStMMXU") || name.contains("brcbStMMXU") ||
name.contains("brcbStMSQI") || name.contains("brcbStMSQI") ||
name.contains("brcbPLT") || name.contains("brcbPLT") ||
name.contains("brcbPST") || name.contains("brcbPST") ||
name.contains("brcbFlicker") || name.contains("brcbFlicker") ||
name.contains("brcbStatistic")) { name.contains("brcbStatistic")) {
String reportControlStr = buildReportControlString(reportItem); String reportControlStr = buildReportControlString(reportItem);
reportStatBuilder.append("\t\t\t<Report ReportControl=\"") reportStatBuilder.append("\t\t\t<Report ReportControl=\"")
.append(escapeXml(reportControlStr)) .append(escapeXml(reportControlStr))
.append("\" />\n"); .append("\" />\n");
} }
} }
} }
@@ -184,16 +220,13 @@ public class JsonToXmlConversionService {
reportStatBuilder.append("\t\t</ReportStat>"); reportStatBuilder.append("\t\t</ReportStat>");
xmlContent = xmlContent.replaceAll( xmlContent = xmlContent.replaceAll(
"<ReportStat>[\\s\\S]*?</ReportStat>", "<ReportStat>[\\s\\S]*?</ReportStat>",
reportStatBuilder.toString().replace("$", "\\$").replace("[", "\\[").replace("]", "\\]") reportStatBuilder.toString().replace("$", "\\$").replace("[", "\\[").replace("]", "\\]")
); );
return xmlContent; return xmlContent;
} }
/**
* 构建ReportControl字符串
*/
private String buildReportControlString(ReportMapItem rc) { private String buildReportControlString(ReportMapItem rc) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -232,14 +265,19 @@ public class JsonToXmlConversionService {
return sb.toString(); return sb.toString();
} }
/**
* 从MappingDocument应用规则
*/
private String applyRulesFromMapping(String xmlContent, private String applyRulesFromMapping(String xmlContent,
MappingDocument mappingDocument, MappingDocument mappingDocument,
List<InputStream> ruleStreams, List<InputStream> ruleStreams,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
return applyRulesFromMappingWithResult(xmlContent, mappingDocument, ruleStreams, indexMapping).getXmlContent();
}
private RuleMatchingResult applyRulesFromMappingWithResult(String xmlContent,
MappingDocument mappingDocument,
List<InputStream> ruleStreams,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
long stepStart = System.currentTimeMillis(); long stepStart = System.currentTimeMillis();
var mergedRules = mergeAllRulesDesc(ruleStreams, indexMapping); var mergedRules = mergeAllRulesDesc(ruleStreams, indexMapping);
@@ -256,15 +294,15 @@ public class JsonToXmlConversionService {
System.out.println("规则总数: " + mergedRules.size()); System.out.println("规则总数: " + mergedRules.size());
System.out.println("JSON中指标总数: " + mappingMetrics.size()); System.out.println("JSON中指标总数: " + mappingMetrics.size());
var applicableRules = findApplicableRulesDesc(mergedRules, mappingMetrics); RuleMatchingResult matchingResult = findApplicableRulesDescWithUnmatched(mergedRules, mappingMetrics);
long matchTime = System.currentTimeMillis(); long matchTime = System.currentTimeMillis();
System.out.println(" [规则匹配] 耗时: " + (matchTime - extractTime) + " ms"); System.out.println(" [规则匹配] 耗时: " + (matchTime - extractTime) + " ms");
System.out.println("匹配成功: " + applicableRules.size() + " 条规则"); System.out.println("匹配成功: " + matchingResult.getApplicableRules().size() + " 条规则");
System.out.println("匹配失败: " + (mergedRules.size() - applicableRules.size()) + " 条规则"); System.out.println("匹配失败: " + matchingResult.getUnmatchedRuleDetails().size() + " 条规则");
String resultXml = applyRulesToXml(xmlContent, applicableRules); String resultXml = applyRulesToXml(xmlContent, matchingResult.getApplicableRules());
long applyTime = System.currentTimeMillis(); long applyTime = System.currentTimeMillis();
System.out.println(" [规则应用] 耗时: " + (applyTime - matchTime) + " ms"); System.out.println(" [规则应用] 耗时: " + (applyTime - matchTime) + " ms");
@@ -273,12 +311,10 @@ public class JsonToXmlConversionService {
System.out.println(" [applyRulesFromMapping] 总计耗时: " + totalApplyTime + " ms"); System.out.println(" [applyRulesFromMapping] 总计耗时: " + totalApplyTime + " ms");
System.out.println("========== JSON规则匹配结束 ==========\n"); System.out.println("========== JSON规则匹配结束 ==========\n");
return resultXml; matchingResult.setXmlContent(resultXml);
return matchingResult;
} }
/**
* 合并所有规则文件
*/
private java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> mergeAllRules( private java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> mergeAllRules(
List<InputStream> ruleStreams, List<InputStream> ruleStreams,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
@@ -315,9 +351,6 @@ public class JsonToXmlConversionService {
return mergedRules; return mergedRules;
} }
/**
* 解析规则文件
*/
private java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> parseRuleFile( private java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> parseRuleFile(
InputStream ruleStream, InputStream ruleStream,
IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception { IcdToXmlMappingService.IndexMappingConfig indexMapping) throws Exception {
@@ -325,24 +358,24 @@ public class JsonToXmlConversionService {
java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> rules = new java.util.HashMap<>(); java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> rules = new java.util.HashMap<>();
java.io.BufferedReader reader = new java.io.BufferedReader( 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 line;
String currentGroup = ""; String currentGroup = "";
java.util.regex.Pattern valueRulePattern = java.util.regex.Pattern.compile( java.util.regex.Pattern valueRulePattern = java.util.regex.Pattern.compile(
"<Value\\s+" + "<Value\\s+" +
"name=\"([^\"]+)\"\\s+" + "name=\"([^\"]+)\"\\s+" +
"desc=\"([^\"]+)\"\\s+" + "desc=\"([^\"]+)\"\\s+" +
"type=\"([^\"]+)\"\\s+" + "type=\"([^\"]+)\"\\s+" +
"(?:DO=\"([^\"]*)\")?\\s*" + "(?:DO=\"([^\"]*)\")?\\s*" +
"(?:DA=\"([^\"]*)\")?\\s*" + "(?:DA=\"([^\"]*)\")?\\s*" +
"(?:BaseFlag=\"([^\"]*)\")?\\s*" + "(?:BaseFlag=\"([^\"]*)\")?\\s*" +
"(?:LimitUp=\"([^\"]*)\")?\\s*" + "(?:LimitUp=\"([^\"]*)\")?\\s*" +
"(?:LimitDown=\"([^\"]*)\")?\\s*" + "(?:LimitDown=\"([^\"]*)\")?\\s*" +
"(?:Coefficient=\"([^\"]*)\")?\\s*" + "(?:Coefficient=\"([^\"]*)\")?\\s*" +
"/>", java.util.regex.Pattern.CASE_INSENSITIVE "/>", java.util.regex.Pattern.CASE_INSENSITIVE
); );
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
@@ -486,11 +519,6 @@ public class JsonToXmlConversionService {
return rules; return rules;
} }
/**
* 应用索引映射
*/
private String applyIndexMapping(String doPath, String currentGroup, private String applyIndexMapping(String doPath, String currentGroup,
IcdToXmlMappingService.IndexMappingConfig indexMapping, IcdToXmlMappingService.IndexMappingConfig indexMapping,
String name, String desc) { String name, String desc) {
@@ -529,9 +557,6 @@ public class JsonToXmlConversionService {
return doPath; return doPath;
} }
/**
* 确定新索引
*/
private int determineNewIndex(String currentGroup, String lnClass, int originalIndex, private int determineNewIndex(String currentGroup, String lnClass, int originalIndex,
IcdToXmlMappingService.IndexMappingConfig indexMapping, IcdToXmlMappingService.IndexMappingConfig indexMapping,
String name, String desc) { String name, String desc) {
@@ -610,9 +635,6 @@ public class JsonToXmlConversionService {
return originalIndex; return originalIndex;
} }
/**
* 构建规则键
*/
private String buildRuleKey(String name, String desc) { private String buildRuleKey(String name, String desc) {
if (name != null && !name.isEmpty()) { if (name != null && !name.isEmpty()) {
return name; return name;
@@ -620,17 +642,11 @@ public class JsonToXmlConversionService {
return desc != null ? desc : ""; return desc != null ? desc : "";
} }
/**
* 检查是否有有效的DO或DA
*/
private boolean hasValidDoOrDa(RuleBasedXmlMappingService.ValueRule rule) { private boolean hasValidDoOrDa(RuleBasedXmlMappingService.ValueRule rule) {
return (rule.getDoPath() != null && !rule.getDoPath().isEmpty()) || return (rule.getDoPath() != null && !rule.getDoPath().isEmpty()) ||
(rule.getDaPath() != null && !rule.getDaPath().isEmpty()); (rule.getDaPath() != null && !rule.getDaPath().isEmpty());
} }
/**
* 从MappingDocument提取指标信息
*/
private java.util.Map<String, MetricInfo> extractMetricsFromMapping(MappingDocument mappingDocument) { private java.util.Map<String, MetricInfo> extractMetricsFromMapping(MappingDocument mappingDocument) {
java.util.Map<String, MetricInfo> metrics = new java.util.HashMap<>(); java.util.Map<String, MetricInfo> metrics = new java.util.HashMap<>();
@@ -681,9 +697,6 @@ public class JsonToXmlConversionService {
return metrics; return metrics;
} }
/**
* 构建DO路径
*/
private String buildDoPath(String lnClass, String lnInst, String doName) { private String buildDoPath(String lnClass, String lnInst, String doName) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (lnClass != null) { if (lnClass != null) {
@@ -703,9 +716,6 @@ public class JsonToXmlConversionService {
return sb.toString(); return sb.toString();
} }
/**
* 构建DA路径
*/
private String buildDaPath(String sdiName, String typeName, DoiItem doiItem) { private String buildDaPath(String sdiName, String typeName, DoiItem doiItem) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (sdiName != null && !sdiName.isEmpty()) { if (sdiName != null && !sdiName.isEmpty()) {
@@ -735,11 +745,6 @@ public class JsonToXmlConversionService {
return sb.toString(); return sb.toString();
} }
/**
* 标准化相别名称,将具体相别转换为通配符格式
* - phsA, phsB, phsC, phsAB, phsBC, phsCA -> phs*
* - phsAHar, phsBHar, phsCHar, phsABHar, phsBCHar, phsCAHar -> phs*Har
*/
private String normalizePhaseName(String name) { private String normalizePhaseName(String name) {
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {
return name; return name;
@@ -756,9 +761,6 @@ public class JsonToXmlConversionService {
return name; return name;
} }
/**
* 判断是否为间谐波指标
*/
private boolean isInterHarmonicMetric(DoiItem doiItem) { private boolean isInterHarmonicMetric(DoiItem doiItem) {
if (doiItem == null || doiItem.getDesc() == null) { if (doiItem == null || doiItem.getDesc() == null) {
return false; return false;
@@ -766,15 +768,19 @@ public class JsonToXmlConversionService {
return doiItem.getDesc().toLowerCase().contains("间谐波"); return doiItem.getDesc().toLowerCase().contains("间谐波");
} }
/**
* 查找适用的规则
*/
private java.util.Map<String, RuleBasedXmlMappingService.ValueRule> findApplicableRulesDesc( private java.util.Map<String, RuleBasedXmlMappingService.ValueRule> findApplicableRulesDesc(
java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> allRules, java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> allRules,
java.util.Map<String, MetricInfo> mappingMetrics) { java.util.Map<String, MetricInfo> mappingMetrics) {
return findApplicableRulesDescWithUnmatched(allRules, mappingMetrics).getApplicableRules();
}
private RuleMatchingResult findApplicableRulesDescWithUnmatched(
java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> allRules,
java.util.Map<String, MetricInfo> mappingMetrics) {
java.util.Map<String, RuleBasedXmlMappingService.ValueRule> applicable = new java.util.HashMap<>(); java.util.Map<String, RuleBasedXmlMappingService.ValueRule> applicable = new java.util.HashMap<>();
List<String> failedRules = new ArrayList<>(); List<UnmatchedRuleDetail> failedRuleDetails = new ArrayList<>();
for (var entry : allRules.entrySet()) { for (var entry : allRules.entrySet()) {
String ruleKey = entry.getKey(); String ruleKey = entry.getKey();
@@ -794,20 +800,41 @@ public class JsonToXmlConversionService {
applicable.put(ruleKey, rule); applicable.put(ruleKey, rule);
matched = true; matched = true;
System.out.println("✓ 规则匹配成功: " + ruleKey + " -> DO=" + rule.getDoPath() + ", DA=" + rule.getDaPath()); System.out.println("✓ 规则匹配成功: " + ruleKey + " -> DO=" + rule.getDoPath() + ", DA=" + rule.getDaPath());
} }
if (matched) { if (matched) {
break; break;
} }
} }
if (!matched) { if (!matched) {
failedRules.add(ruleKey); UnmatchedRuleDetail detail = new UnmatchedRuleDetail();
detail.setRuleKey(ruleKey);
StringBuilder ruleInfo = new StringBuilder();
for (int i = 0; i < ruleVariants.size(); i++) {
RuleBasedXmlMappingService.ValueRule rule = ruleVariants.get(i);
if (i > 0) {
ruleInfo.append("; ");
}
ruleInfo.append("候选").append(i + 1).append(": ");
if (rule.getDoPath() != null && !rule.getDoPath().isEmpty()) {
ruleInfo.append("DO=").append(rule.getDoPath());
}
if (rule.getDaPath() != null && !rule.getDaPath().isEmpty()) {
if (rule.getDoPath() != null && !rule.getDoPath().isEmpty()) {
ruleInfo.append(", ");
}
ruleInfo.append("DA=").append(rule.getDaPath());
}
}
detail.setRuleVariants(ruleInfo.toString());
failedRuleDetails.add(detail);
System.out.println("✗ 规则匹配失败: " + ruleKey + " (共" + ruleVariants.size() + "个候选)"); System.out.println("✗ 规则匹配失败: " + ruleKey + " (共" + ruleVariants.size() + "个候选)");
for (RuleBasedXmlMappingService.ValueRule rule : ruleVariants) { for (RuleBasedXmlMappingService.ValueRule rule : ruleVariants) {
System.out.println(" 候选指标名: " + rule.getName()); System.out.println(" 候选: DO=" + rule.getDoPath() + ", DA=" + rule.getDaPath());
} }
} }
} }
@@ -818,16 +845,17 @@ public class JsonToXmlConversionService {
System.out.println(" - " + key); System.out.println(" - " + key);
} }
System.out.println("\n失败匹配的规则 (" + failedRules.size() + " 条):"); System.out.println("\n失败匹配的规则 (" + failedRuleDetails.size() + " 条):");
for (String key : failedRules) { for (UnmatchedRuleDetail detail : failedRuleDetails) {
System.out.println(" - " + key); System.out.println(" - " + detail.getRuleKey() + " [" + detail.getRuleVariants() + "]");
} }
return applicable; RuleMatchingResult result = new RuleMatchingResult();
result.setApplicableRules(applicable);
result.setUnmatchedRuleDetails(failedRuleDetails);
return result;
} }
private java.util.Map<String, RuleBasedXmlMappingService.ValueRule> findApplicableRules( private java.util.Map<String, RuleBasedXmlMappingService.ValueRule> findApplicableRules(
java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> allRules, java.util.Map<String, List<RuleBasedXmlMappingService.ValueRule>> allRules,
java.util.Map<String, MetricInfo> mappingMetrics) { java.util.Map<String, MetricInfo> mappingMetrics) {
@@ -891,17 +919,11 @@ public class JsonToXmlConversionService {
return applicable; return applicable;
} }
/**
* 标准化路径
*/
private String normalizePath(String path) { private String normalizePath(String path) {
if (path == null) return ""; if (path == null) return "";
return path.trim().toLowerCase(); return path.trim().toLowerCase();
} }
/**
* 匹配模式
*/
private boolean matchesPattern(String pattern, String actual) { private boolean matchesPattern(String pattern, String actual) {
if (pattern == null || actual == null) { if (pattern == null || actual == null) {
return pattern == null && actual == null; return pattern == null && actual == null;
@@ -916,24 +938,21 @@ public class JsonToXmlConversionService {
return actual.equals(normalizedPattern); return actual.equals(normalizedPattern);
} }
/**
* 应用规则到XML
*/
private String applyRulesToXml(String xmlContent, private String applyRulesToXml(String xmlContent,
java.util.Map<String, RuleBasedXmlMappingService.ValueRule> applicableRules) { java.util.Map<String, RuleBasedXmlMappingService.ValueRule> applicableRules) {
java.util.regex.Pattern xmlValuePattern = java.util.regex.Pattern.compile( java.util.regex.Pattern xmlValuePattern = java.util.regex.Pattern.compile(
"<Value\\s+" + "<Value\\s+" +
"name=\"([^\"]+)\"\\s+" + "name=\"([^\"]+)\"\\s+" +
"desc=\"([^\"]+)\"\\s+" + "desc=\"([^\"]+)\"\\s+" +
"type=\"([^\"]+)\"\\s+" + "type=\"([^\"]+)\"\\s+" +
"(?:DO=\"([^\"]*)\")?\\s*" + "(?:DO=\"([^\"]*)\")?\\s*" +
"(?:DA=\"([^\"]*)\")?\\s*" + "(?:DA=\"([^\"]*)\")?\\s*" +
"(?:BaseFlag=\"([^\"]*)\")?\\s*" + "(?:BaseFlag=\"([^\"]*)\")?\\s*" +
"(?:LimitUp=\"([^\"]*)\")?\\s*" + "(?:LimitUp=\"([^\"]*)\")?\\s*" +
"(?:LimitDown=\"([^\"]*)\")?\\s*" + "(?:LimitDown=\"([^\"]*)\")?\\s*" +
"(?:Coefficient=\"([^\"]*)\")?\\s*" + "(?:Coefficient=\"([^\"]*)\")?\\s*" +
"/>", java.util.regex.Pattern.CASE_INSENSITIVE "/>", java.util.regex.Pattern.CASE_INSENSITIVE
); );
java.util.regex.Matcher matcher = xmlValuePattern.matcher(xmlContent); java.util.regex.Matcher matcher = xmlValuePattern.matcher(xmlContent);
@@ -944,8 +963,6 @@ public class JsonToXmlConversionService {
String desc = matcher.group(2); String desc = matcher.group(2);
String type = matcher.group(3); String type = matcher.group(3);
// String key = buildRuleKey(name, desc);
//RuleBasedXmlMappingService.ValueRule matchedRule = applicableRules.get(key.toLowerCase());
RuleBasedXmlMappingService.ValueRule matchedRule = applicableRules.get(desc); RuleBasedXmlMappingService.ValueRule matchedRule = applicableRules.get(desc);
if (matchedRule != null) { if (matchedRule != null) {
StringBuilder valueNode = new StringBuilder("<Value "); StringBuilder valueNode = new StringBuilder("<Value ");
@@ -981,21 +998,15 @@ public class JsonToXmlConversionService {
return result.toString(); return result.toString();
} }
/**
* XML转义
*/
private String escapeXml(String text) { private String escapeXml(String text) {
if (text == null) return ""; if (text == null) return "";
return text.replace("&", "&amp;") return text.replace("&", "&amp;")
.replace("<", "&lt;") .replace("<", "&lt;")
.replace(">", "&gt;") .replace(">", "&gt;")
.replace("\"", "&quot;") .replace("\"", "&quot;")
.replace("'", "&apos;"); .replace("'", "&apos;");
} }
/**
* 指标信息内部类
*/
static class MetricInfo { static class MetricInfo {
private String lnClass; private String lnClass;
private String lnInst; private String lnInst;
@@ -1048,5 +1059,76 @@ public class JsonToXmlConversionService {
this.baseFlag = baseFlag; this.baseFlag = baseFlag;
} }
} }
}
public static class RuleMatchingResult {
private java.util.Map<String, RuleBasedXmlMappingService.ValueRule> applicableRules;
private List<UnmatchedRuleDetail> unmatchedRuleDetails;
private String xmlContent;
public java.util.Map<String, RuleBasedXmlMappingService.ValueRule> getApplicableRules() {
return applicableRules;
}
public void setApplicableRules(java.util.Map<String, RuleBasedXmlMappingService.ValueRule> applicableRules) {
this.applicableRules = applicableRules;
}
public List<UnmatchedRuleDetail> getUnmatchedRuleDetails() {
return unmatchedRuleDetails;
}
public void setUnmatchedRuleDetails(List<UnmatchedRuleDetail> unmatchedRuleDetails) {
this.unmatchedRuleDetails = unmatchedRuleDetails;
}
public String getXmlContent() {
return xmlContent;
}
public void setXmlContent(String xmlContent) {
this.xmlContent = xmlContent;
}
}
public static class ConversionResult {
private String xmlContent;
private List<UnmatchedRuleDetail> unmatchedRuleDetails;
public String getXmlContent() {
return xmlContent;
}
public void setXmlContent(String xmlContent) {
this.xmlContent = xmlContent;
}
public List<UnmatchedRuleDetail> getUnmatchedRuleDetails() {
return unmatchedRuleDetails;
}
public void setUnmatchedRuleDetails(List<UnmatchedRuleDetail> unmatchedRuleDetails) {
this.unmatchedRuleDetails = unmatchedRuleDetails;
}
}
public static class UnmatchedRuleDetail {
private String ruleKey;
private String ruleVariants;
public String getRuleKey() {
return ruleKey;
}
public void setRuleKey(String ruleKey) {
this.ruleKey = ruleKey;
}
public String getRuleVariants() {
return ruleVariants;
}
public void setRuleVariants(String ruleVariants) {
this.ruleVariants = ruleVariants;
}
}
}

View File

@@ -61,7 +61,6 @@ public class IcdToXmlTaskAppService {
result.setLdInst(icdDocument.getLdInst()); result.setLdInst(icdDocument.getLdInst());
// 2. 加载 DefaultCfg.txt和默认配置 // 2. 加载 DefaultCfg.txt和默认配置
//DefaultTemplate template = defaultTemplateLoader.loadDefaultTemplateToXml();
DefaultTemplate template = defaultTemplateLoader.load(); DefaultTemplate template = defaultTemplateLoader.load();
result.getProblems().addAll(template.verify()); result.getProblems().addAll(template.verify());
@@ -112,14 +111,23 @@ public class IcdToXmlTaskAppService {
IcdToXmlMappingService.IndexMappingConfig mappingConfig = icdToXmlMappingService.buildIndexMappingFromSelection(command.getIndexSelection()); IcdToXmlMappingService.IndexMappingConfig mappingConfig = icdToXmlMappingService.buildIndexMappingFromSelection(command.getIndexSelection());
icdToXmlMappingService.setIndexMapping(mappingConfig); icdToXmlMappingService.setIndexMapping(mappingConfig);
// 9. 从JSON转换为XML // 9. 从JSON转换为XML(带未匹配规则信息)
String xmlPath = jsonToXmlConversionService.convertFromJson( JsonToXmlConversionService.ConversionResult conversionResult =
mappingJson, jsonToXmlConversionService.convertFromJsonWithResult(
templateStream, mappingJson,
ruleStreams, templateStream,
icdToXmlMappingService.getIndexMapping() ruleStreams,
); icdToXmlMappingService.getIndexMapping()
result.setSavedPath(xmlPath); );
result.setSavedPath(conversionResult.getXmlContent());
// 10. 将未匹配的规则详细信息添加到 problems 中
if (conversionResult.getUnmatchedRuleDetails() != null && !conversionResult.getUnmatchedRuleDetails().isEmpty()) {
for (JsonToXmlConversionService.UnmatchedRuleDetail detail : conversionResult.getUnmatchedRuleDetails()) {
String problemMsg = "规则匹配失败: " + detail.getRuleKey() + " [" + detail.getRuleVariants() + "]";
result.getProblems().add(problemMsg);
}
}
result.setStatus(GenerateStatus.SUCCESS); result.setStatus(GenerateStatus.SUCCESS);
result.setMessage("映射生成成功"); result.setMessage("映射生成成功");
@@ -134,9 +142,6 @@ public class IcdToXmlTaskAppService {
/** /**
* 直接从 JSON 字符串生成 XML 文件。 * 直接从 JSON 字符串生成 XML 文件。
*
* @param mappingJson MMS 映射 JSON 字符串(由 getIcdMmsJson 接口返回)
* @return XML 生成结果
*/ */
public IcdToXmlGenerateResult generateXmlFromJson(String mappingJson){ public IcdToXmlGenerateResult generateXmlFromJson(String mappingJson){
IcdToXmlGenerateResult result = new IcdToXmlGenerateResult(); IcdToXmlGenerateResult result = new IcdToXmlGenerateResult();
@@ -158,16 +163,25 @@ public class IcdToXmlTaskAppService {
return result; return result;
} }
// 2. 从 JSON 转换为 XML带未匹配规则信息
JsonToXmlConversionService.ConversionResult conversionResult =
jsonToXmlConversionService.convertFromJsonWithResult(
mappingJson,
templateStream,
ruleStreams,
icdToXmlMappingService.getIndexMapping()
);
// 3. 从 JSON 转换为 XML result.setMappingXml(conversionResult.getXmlContent());
String xmlContent = jsonToXmlConversionService.convertFromJson(
mappingJson, // 3. 将未匹配的规则详细信息添加到 problems 中
templateStream, if (conversionResult.getUnmatchedRuleDetails() != null && !conversionResult.getUnmatchedRuleDetails().isEmpty()) {
ruleStreams, for (JsonToXmlConversionService.UnmatchedRuleDetail detail : conversionResult.getUnmatchedRuleDetails()) {
icdToXmlMappingService.getIndexMapping() String problemMsg = "规则匹配失败: " + detail.getRuleKey() + " [" + detail.getRuleVariants() + "]";
); result.getProblems().add(problemMsg);
}
}
result.setMappingXml(xmlContent);
result.setStatus(GenerateStatus.SUCCESS); result.setStatus(GenerateStatus.SUCCESS);
result.setMessage("XML 生成成功"); result.setMessage("XML 生成成功");
return result; return result;