import ifcopenshell import xml.etree.ElementTree as ET from datetime import datetime def parse_ids(ids_file): """Parse the IDS file to extract properties and property sets.""" tree = ET.parse(ids_file) root = tree.getroot() ns = {'ids': 'http://standards.buildingsmart.org/IDS'} ids_data = { "properties": {}, # Entity: {PropertySet: [Properties]} } # Parse properties for property_elem in root.findall(".//ids:property", ns): property_set_elem = property_elem.find("ids:propertySet/ids:simpleValue", ns) property_name_elem = property_elem.find("ids:baseName/ids:simpleValue", ns) if property_set_elem is not None and property_name_elem is not None: property_set = property_set_elem.text.strip().lower() property_name = property_name_elem.text.strip().lower() for entity in root.findall(".//ids:entity", ns): entity_name_elem = entity.find("ids:name/ids:simpleValue", ns) if entity_name_elem is not None: entity_name = entity_name_elem.text.strip().lower() if entity_name not in ids_data["properties"]: ids_data["properties"][entity_name] = {} if property_set not in ids_data["properties"][entity_name]: ids_data["properties"][entity_name][property_set] = [] ids_data["properties"][entity_name][property_set].append(property_name) # Debugging: Print parsed IDS properties print("Parsed IDS Properties:", ids_data["properties"]) return ids_data def validate_ifc_properties(ifc_file, ids_data): """Validate the IFC file's properties and property sets against IDS definitions.""" non_compliant = { "undefined_properties": {} # {Entity: {PropertySet: [Invalid Properties]}} } # Load the IFC file ifc_model = ifcopenshell.open(ifc_file) for ifc_entity in ifc_model.by_type("IfcRoot"): entity_name = ifc_entity.is_a().lower() # Normalize to lowercase # Skip entities that are types (e.g., IfcBeamType, IfcWallType) if entity_name.endswith("type"): continue # Skip if the entity is not in IDS properties if entity_name not in ids_data["properties"]: continue for pset in getattr(ifc_entity, "IsDefinedBy", []): # Safely access IsDefinedBy if pset.is_a("IfcRelDefinesByProperties") and pset.RelatingPropertyDefinition.is_a("IfcPropertySet"): pset_name = pset.RelatingPropertyDefinition.Name.strip().lower() if pset_name in ids_data["properties"][entity_name]: for prop in pset.RelatingPropertyDefinition.HasProperties: if prop.is_a("IfcPropertySingleValue") and prop.Name: prop_name = prop.Name.strip().lower() if prop_name not in ids_data["properties"][entity_name][pset_name]: if entity_name not in non_compliant["undefined_properties"]: non_compliant["undefined_properties"][entity_name] = {} if pset_name not in non_compliant["undefined_properties"][entity_name]: non_compliant["undefined_properties"][entity_name][pset_name] = set() non_compliant["undefined_properties"][entity_name][pset_name].add(prop.Name) return non_compliant def save_debug_report(ids_properties, ifc_properties, output_path="debug_report.html"): """Save debugging information to an HTML file.""" with open(output_path, "w") as file: file.write("
Performed on: {current_time}
") # File Names file.write(f"IFC File: {ifc_file}
") file.write(f"IDS File: {ids_file}
") # Report Non-Compliant Properties if non_compliant["undefined_properties"]: file.write("