using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Szmedi.RevitToolkit.Approval.Assists; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text.RegularExpressions; using System.Windows.Markup; using Autodesk.Revit.DB.ExtensibleStorage; using Newtonsoft.Json; using Szmedi.RevitToolkit.Approval.Models; using static Dapper.SqlMapper; /// /// 用于保存从MVDLite文本中解析出的结构化数据的类。 /// public class MvdData { /// /// 文件头部的元数据。 /// 例如:# MVDLite_Version = '2.5.0.0' /// public Dictionary Metadata { get; set; } = []; /// /// 路径别名定义列表。 /// 例如: "hasAssignments as (IfcObjectDefinition)->HasAssignments->RelatedObjectsType" /// public List Aliases { get; set; } = new List(); /// /// 实体定义列表。 /// public List EntityDefinitions { get; set; } = []; } /// /// 代表一个规则定义 /// public class Alias { public string Name { get; set; } public string SourceType { get; set; } public string Path { get; set; } public override string ToString() => $"{Name} as ({SourceType}){Path}"; } /// /// 代表一个在 "定义" 块中定义的实体。 /// public class EntityDefinition { /// /// 继承那一行的名称 /// public string Name { get; set; } /// /// 定义后的第一行描述 /// public string Description { get; set; } /// /// 继承自的名称 /// public string InheritsFrom { get; set; } /// /// 新增:专门存放“类型标签”的值列表 /// public List TypeLabels { get; set; } = []; /// /// 类型判断 /// public List Conditions { get; set; } = []; /// /// 约束,每个约束就是一个属性条目 /// public List Constraints { get; set; } = []; public string IfcMap { get; set; } // 来自 "# IFC_MAP = 'IfcElement'" 这样的注释 public override string ToString() => $"Entity: {Name}" + (string.IsNullOrEmpty(InheritsFrom) ? "" : $" inherits {InheritsFrom}"); } /// /// 代表一个在 "约束" 块中定义的规则,即一个属性条目 /// public class Constraint { /// /// 描述约束规则,如:'预制剪力墙 的属性 \"编号\" 应满足值类型约束规则' /// public string Description { get; set; } /// /// 表达式,如:预制剪力墙->任意属性集->任意属性('编号')->属性值[Type]>='STRING' /// public string Expression { get; set; } /// ///用于解析注释中的额外信息,例如: # PropName = '型号规格',key:PropName,DefaultValue:型号规格,Key:Range,DefaultValue:>=0 /// 固定只有两个,一个是属性名,一个取值范围 /// public Dictionary PropertyDictionary { get; set; } = []; /// /// 参数值类型 /// public string ParameterType { get { if (ValueRange.Contains("实数值")) { return "Number"; } return "Text"; } } /// /// 参数的取值范围 /// public string[] Values { get { var range = ValueRange.Replace(" ", ""); if (range.Contains("实数值") || range.Contains(">=0")) { return ["0"]; } else if (range.Contains(">0")) { if (range.Contains("<=1")) { return ["1"]; } return ["100"]; } else if (range.Contains("字符串值")) { return [""]; } return [.. Regex.Matches(range, @"\\""([^""]*)\\""").OfType().Select(m => m.Groups[1].Value)]; } } /// /// 属性名 /// public string PropName => PropertyDictionary.ContainsKey("PropName") ? PropertyDictionary["PropName"] : string.Empty; /// /// 取值范围 /// public string ValueRange => PropertyDictionary.ContainsKey("Range") ? PropertyDictionary["Range"] : string.Empty; public override string ToString() => $"Constraint: {PropName} => {ValueRange}"; } /// /// 一个静态工具类,用于将MVDLite格式的文本数据解析为结构化的C#对象。 /// public class MvdLiteAssist { public static List GetSigns(Major major, string entityName, string inheritsFrom) { var archi = IOAssists.GetMvdLiteContent(major); var archiData = MvdLiteAssist.Parse(archi); var archiDefinition = MvdLiteAssist.GetDefinitionByName(archiData, entityName, inheritsFrom); var archiExpression = archiDefinition.Constraints.FirstOrDefault().Expression; var archiSigns = Regex.Matches(archiExpression, @"'([^']*)'").OfType().Select(m => m.Groups[1].Value); return [.. archiSigns]; } public static List GetSigns(string majorName, string entityName, string inheritsFrom) { var archi = IOAssists.GetMvdLiteContent(majorName); var archiData = MvdLiteAssist.Parse(archi); var archiDefinition = MvdLiteAssist.GetDefinitionByName(archiData, entityName, inheritsFrom); var archiExpression = archiDefinition.Constraints.FirstOrDefault().Expression; var archiSigns = Regex.Matches(archiExpression, @"'([^']*)'").OfType().Select(m => m.Groups[1].Value); return [.. archiSigns]; } private enum ParserState { Idle, // 用于解析元数据和别名 InDefinition, InConstraint } /// /// 获取所有直接包含属性的集合(不包含子类继承父类的属性) /// /// /// public static List GetProperties(MvdData mvdData) { List properties = []; List definitions = mvdData.EntityDefinitions; foreach (var entity in definitions) { var constraints = entity.Constraints; foreach (var cons in constraints) { if (string.IsNullOrEmpty(cons.PropName) || string.IsNullOrEmpty(cons.Description)) { continue; } var property = new AfcaArchiProperty { DefinitionName = entity.Name, Name = cons.PropName, ValueConstraints = cons.Values, ValueRange = cons.ValueRange, }; properties.Add(property); //sb.AppendLine($"Entity: {entity.Name}, Property: {cons.PropName}, DefaultValue: {cons.ValueRange}"); } } return properties; } /// /// 获取所有构件标识列表 /// /// /// public static HashSet GetElementSigns(MvdData mvdData, string ifcClass = "IfcElement") { HashSet signs = []; List definitions = mvdData.EntityDefinitions; foreach (var entity in definitions) { if (!string.IsNullOrEmpty(entity.Description) && entity.IfcMap == ifcClass) { foreach (var label in entity.TypeLabels) { signs.Add(label); } } } return signs; } /// /// 解析包含MVDLite数据的文本字符串。 /// /// 要解析的文本内容。 /// 一个包含所有解析后数据的 MvdData 对象。 public static MvdData Parse(string textContent) { var mvdData = new MvdData(); if (string.IsNullOrWhiteSpace(textContent)) return mvdData; var lines = textContent.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); ParserState state = ParserState.Idle; EntityDefinition currentEntity = null; Constraint currentConstraint = null; // 用于匹配不同类型行的正则表达式 var metaRegex = new Regex(@"^#\s*([^=]+?)\s*=\s*'(.*)'"); var aliasRegex = new Regex(@"^(\S+)\s+as\s+\((.*?)\)(.*)"); var entityInheritRegex = new Regex(@"^(\S+)\s+继承\s+(\S+)"); var descriptionCommentRegex = new Regex(@"^#\s*'(.*)'"); var ifcMapCommentRegex = new Regex(@"^#\s*IFC_MAP\s*=\s*'(.*)'"); var propCommentRegex = new Regex(@"^#\s*(\w+)\s*=\s*'(.*)'"); // 新增:专门用于匹配“类型标签”的正则表达式 var typeLabelRegex = new Regex(@"^(\S+)->类型标签\s*=\s*(.*)$"); foreach (var line in lines) { var trimmedLine = line.Trim(); if (trimmedLine.StartsWith("定义")) { state = ParserState.InDefinition; currentEntity = new EntityDefinition(); mvdData.EntityDefinitions.Add(currentEntity); continue; } if (trimmedLine.StartsWith("约束")) { state = ParserState.InConstraint; currentConstraint = null; continue; } if (trimmedLine.StartsWith("#BLOCK") || string.IsNullOrWhiteSpace(trimmedLine)) { if (state == ParserState.InConstraint && currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression)) { currentEntity.Constraints.Add(currentConstraint); } currentConstraint = null; if (string.IsNullOrWhiteSpace(trimmedLine)) continue; if (trimmedLine.StartsWith("#BLOCK")) { state = ParserState.Idle; currentEntity = null; continue; } } switch (state) { case ParserState.Idle: Match metaMatch = metaRegex.Match(trimmedLine); if (metaMatch.Success) { mvdData.Metadata[metaMatch.Groups[1].Value.Trim()] = metaMatch.Groups[2].Value; break; } Match aliasMatch = aliasRegex.Match(trimmedLine); if (aliasMatch.Success) { mvdData.Aliases.Add(new Alias { Name = aliasMatch.Groups[1].Value, SourceType = aliasMatch.Groups[2].Value, Path = aliasMatch.Groups[3].Value.Trim() }); } break; case ParserState.InDefinition: Match descMatch = descriptionCommentRegex.Match(trimmedLine); if (descMatch.Success) { currentEntity.Description = descMatch.Groups[1].Value; break; } Match ifcMapMatch = ifcMapCommentRegex.Match(trimmedLine); if (ifcMapMatch.Success) { currentEntity.IfcMap = ifcMapMatch.Groups[1].Value; break; } // --- 新增逻辑:优先处理类型标签 --- Match typeLabelMatch = typeLabelRegex.Match(trimmedLine); if (typeLabelMatch.Success) { string allLabelsRaw = typeLabelMatch.Groups[2].Value; // 使用正则表达式从长字符串中提取所有被单引号包裹的值 var labelMatches = Regex.Matches(allLabelsRaw, @"'([^']*)'"); var labels = labelMatches.Cast() .Select(m => m.Groups[1].Value) .ToList(); currentEntity.TypeLabels.AddRange(labels); break; // 处理完毕,跳过此行后续逻辑 } // --- 结束新增逻辑 --- Match entityInheritMatch = entityInheritRegex.Match(trimmedLine); if (entityInheritMatch.Success) { currentEntity.Name = entityInheritMatch.Groups[1].Value; currentEntity.InheritsFrom = entityInheritMatch.Groups[2].Value; } else if (!trimmedLine.StartsWith("#")) { // 其他非注释行、非类型标签行,被视为普通条件 currentEntity.Conditions.Add(trimmedLine); } break; case ParserState.InConstraint: if (trimmedLine.StartsWith("#")) { Match constraintDescMatch = descriptionCommentRegex.Match(trimmedLine); if (constraintDescMatch.Success) { if (currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression)) { currentEntity.Constraints.Add(currentConstraint); } currentConstraint = new Constraint { Description = constraintDescMatch.Groups[1].Value }; } else { Match propMatch = propCommentRegex.Match(trimmedLine); if (propMatch.Success) { if (currentConstraint == null) currentConstraint = new Constraint(); currentConstraint.PropertyDictionary[propMatch.Groups[1].Value] = propMatch.Groups[2].Value; } } } else { if (currentConstraint == null) { currentConstraint = new Constraint(); } currentConstraint.Expression = trimmedLine; if (currentEntity != null) { currentEntity.Constraints.Add(currentConstraint); } currentConstraint = null; } break; } } if (currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression)) { currentEntity.Constraints.Add(currentConstraint); } return mvdData; } /// /// 获取任意标识需要的所有属性 /// /// /// /// public static List GetConstraintsByLabel(MvdData data, string labelName) { var result = new List(); var definitions = FindDefinitionsByTypeLabel(data, labelName); foreach (var entity in definitions) { var constraints = entity.Constraints; foreach (var cons in constraints) { if (string.IsNullOrEmpty(cons.PropName) || string.IsNullOrEmpty(cons.Description)) { continue; } result.Add(cons); //sb.AppendLine($"Entity: {entity.Name}, Property: {cons.PropName}, DefaultValue: {cons.ValueRange}"); } } return result; } /// /// 按定义名称查找定义 /// /// /// /// public static EntityDefinition GetDefinitionByName(MvdData mvdData, string name) { if (mvdData == null || mvdData.EntityDefinitions == null || string.IsNullOrEmpty(name)) { return null; } return mvdData.EntityDefinitions.FirstOrDefault(def => def.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); } /// /// 按定义名称查找定义 /// /// /// /// public static EntityDefinition GetDefinitionByName(MvdData mvdData, string name, string inheritsFrom) { if (mvdData == null || mvdData.EntityDefinitions == null || string.IsNullOrEmpty(name)) { return null; } return mvdData.EntityDefinitions.FirstOrDefault(def => def.Name.Equals(name, StringComparison.OrdinalIgnoreCase) && def.InheritsFrom.ToLower() == inheritsFrom.ToLower()); } /// /// 查找所有在其类型标签列表中包含指定名称的实体定义。 /// /// 要搜索的数据源。 /// 要查找的类型标签名称。 /// 一个枚举值,指定比较字符串时是否区分大小写。默认为区分大小写。 /// 一个包含所有匹配的实体定义的列表。 public static List FindDefinitionsByTypeLabel( MvdData mvdData, string labelToFind, StringComparison comparisonType = StringComparison.Ordinal) { var allDefinitions = mvdData.EntityDefinitions; // 如果输入为空,则返回一个空列表 if (allDefinitions == null || string.IsNullOrEmpty(labelToFind) || mvdData.EntityDefinitions.Count == 0) { return []; } // 使用 LINQ 进行高效查询: // 遍历所有实体定义(def), // 并在每个实体的 TypeLabels 列表中查找(Any)是否存在一个标签(label) // 与要查找的标签(labelToFind)相等。 return [.. allDefinitions.Where( def => def.TypeLabels.Any(label => label.Equals(labelToFind, comparisonType)))]; } }