Extract definitions and descriptions for use in plugin

This commit is contained in:
Dion Moult
2019-10-04 17:24:49 +10:00
parent 00aad53181
commit 75f254d162
+104
View File
@@ -0,0 +1,104 @@
import xml.sax, json, copy, pathlib
from bs4 import BeautifulSoup
import sys
sys.setrecursionlimit(100)
class IfcElementHandler(xml.sax.ContentHandler):
def __init__(self):
self.elements = {}
self.current_element_name = None
self.enums = {}
self.current_enum_name = None
self.attribute_stack = []
def startElement(self, name, attrs):
if name == 'xs:element' and 'substitutionGroup' in attrs:
self.elements[attrs['name']] = {
'description': self.get_description(attrs['name']),
'is_abstract': True if 'abstract' in attrs else False,
'parent': attrs['substitutionGroup'][len('ifc:'):],
'attributes': []
}
self.current_element_name = attrs['name']
elif name == 'xs:simpleType' \
and 'name' in attrs \
and 'Enum' in attrs['name']:
self.current_enum_name = attrs['name']
self.enums[self.current_enum_name] = []
elif name == 'xs:enumeration' and self.current_enum_name:
self.enums[self.current_enum_name].append(attrs['value'].upper())
elif name == 'xs:attribute' \
and self.current_element_name \
and 'name' in attrs \
and 'type' in attrs:
self.elements[self.current_element_name]['attributes'].append({
'name': attrs['name'],
'type': attrs['type'].replace('ifc:', ''),
})
def endDocument(self):
elements = {}
for name, data in self.elements.items():
for index, attribute in enumerate(data['attributes']):
data['attributes'][index] = self.resolve_enums(attribute)
for name, data in self.elements.items():
if data['is_abstract']:
continue
if self.is_an_ifcproduct(data):
self.attribute_stack = []
self.get_parent_attributes(data)
elements[name] = copy.deepcopy(data)
elements[name]['attributes'] = copy.deepcopy(self.attribute_stack)
self.elements = elements
def get_description(self, name):
try:
filenames = pathlib.Path(
'io_export_ifc/schema/ifc4-add2-tc1/ifc4-add2-tc1/html/schema/').glob(
'**/{}.htm'.format(name.lower()))
for filename in filenames:
with open(filename, 'r') as file:
soup = BeautifulSoup(file, 'html.parser')
for detail in soup.find_all('details'):
if detail.summary.string == 'Entity definition' \
and detail.p:
return str(detail.p.text.replace('\n', ' '))
return None
except:
return None
#print('Failed to get description for {}'.format(name))
return None
def resolve_enums(self, attribute):
if attribute['type'] in self.enums:
attribute['is_enum'] = True
attribute['enum_values'] = self.enums[attribute['type']]
return attribute
attribute['is_enum'] = False
attribute['enum_values'] = []
return attribute
def get_parent_attributes(self, data):
self.attribute_stack.extend(data['attributes'])
if data['parent'] != 'IfcProduct': # For now, we treat attributes above IfcProduct in a special way
self.get_parent_attributes(self.elements[data['parent']])
def is_an_ifcproduct(self, data):
if data['parent'] == 'IfcProduct':
return True
else:
for name, parent_data in self.elements.items():
if name == data['parent']:
return self.is_an_ifcproduct(parent_data)
return False
xsd_path = 'io_export_ifc/schema/IFC4.xsd'
handler = IfcElementHandler()
parser = xml.sax.make_parser()
parser.setContentHandler(handler)
parser.parse(xsd_path)
print(json.dumps(handler.elements, indent=4))