| 24 | |
| 25 | |
| 26 | class IFC4Extractor: |
| 27 | def __init__(self, xsd_file): |
| 28 | self.xsd_file = xsd_file |
| 29 | tree = ET.parse(self.xsd_file) |
| 30 | self.root = tree.getroot() |
| 31 | self.ns = {"xs": "http://www.w3.org/2001/XMLSchema"} |
| 32 | self.elements = {} |
| 33 | self.filters = [] |
| 34 | self.filtered_elements = {} |
| 35 | |
| 36 | def extract(self): |
| 37 | for element in self.root.findall("xs:element", self.ns): |
| 38 | print("Processing {}".format(element.attrib["name"])) |
| 39 | if not "substitutionGroup" in element.attrib or self.is_descendant_from_class(element, "uos"): |
| 40 | continue |
| 41 | data = { |
| 42 | "is_abstract": self.is_abstract(element), |
| 43 | "parent": element.attrib["substitutionGroup"].replace("ifc:", ""), |
| 44 | "attributes": self.get_attributes(element), |
| 45 | "complex_attributes": self.get_complex_attributes(element), |
| 46 | } |
| 47 | self.elements[element.attrib["name"]] = data |
| 48 | for filter in self.filters: |
| 49 | if self.is_descendant_from_class(element, filter) and not data["is_abstract"]: |
| 50 | self.filtered_elements.setdefault(filter, {})[element.attrib["name"]] = data |
| 51 | |
| 52 | def export(self, filename): |
| 53 | final = {} |
| 54 | for filter in self.filters: |
| 55 | final.update(self.filtered_elements[filter]) |
| 56 | with open(filename, "w") as file: |
| 57 | file.write(json.dumps(collections.OrderedDict(sorted(final.items())), indent=4)) |
| 58 | |
| 59 | def is_descendant_from_class(self, element, class_name): |
| 60 | if element is None or "substitutionGroup" not in element.attrib or "type" not in element.attrib: |
| 61 | return False |
| 62 | if element.attrib["substitutionGroup"] == "ifc:{}".format(class_name) or element.attrib[ |
| 63 | "type" |
| 64 | ] == "ifc:{}".format(class_name): |
| 65 | return True |
| 66 | return self.is_descendant_from_class(self.get_parent_element(element), class_name) |
| 67 | |
| 68 | def is_abstract(self, element): |
| 69 | return True if "abstract" in element.attrib else False |
| 70 | |
| 71 | def get_attributes(self, element, attributes=None): |
| 72 | if attributes is None: |
| 73 | attributes = [] |
| 74 | if element.attrib["substitutionGroup"] != self.get_ifcroot_parent_name(): |
| 75 | attributes = self.get_attributes(self.get_parent_element(element), attributes) |
| 76 | for attribute in self.root.findall(self.get_attribute_xpath(element), self.ns): |
| 77 | try: |
| 78 | attributes.append( |
| 79 | { |
| 80 | "name": attribute.attrib["name"], |
| 81 | "type": attribute.attrib["type"].replace("ifc:", ""), |
| 82 | "is_enum": self.is_enum(attribute), |
| 83 | "enum_values": self.get_enum_values(attribute), |