Update to IDS 0.5.8

This commit is contained in:
ArturTomczak
2022-02-23 00:24:40 +01:00
committed by Thomas Krijnen
parent ad135f70f1
commit 320bb7a086
3 changed files with 506 additions and 195 deletions
+191 -85
View File
@@ -22,7 +22,7 @@ import logging
import operator import operator
import os import os
import numpy as np import numpy as np
from datetime import date import datetime
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.placement import ifcopenshell.util.placement
@@ -36,7 +36,7 @@ from xmlschema.validators import identities
cwd = os.path.dirname(os.path.realpath(__file__)) cwd = os.path.dirname(os.path.realpath(__file__))
ids_schema = XMLSchema(os.path.join(cwd, "ids.xsd")) # source: "http://standards.buildingsmart.org/IDS/ids_04.xsd" ids_schema = XMLSchema(os.path.join(cwd, "ids.xsd")) # source: "http://standards.buildingsmart.org/IDS/ids_05.xsd"
def error(msg): def error(msg):
@@ -48,29 +48,29 @@ class ids:
def __init__( def __init__(
self, self,
ifcversion=None, title="Name",
description=None,
author=None,
copyright=None, copyright=None,
version=None, version=None,
creation_date=None, description=None,
author=None,
date=None,
purpose=None, purpose=None,
milestone=None, milestone=None,
): ):
"""Create an IDS object. """Create an IDS object.
:param ifcversion: IFC schema version. If None, then schema independent. Options: '2.3.0.1'|'4.0.2.1'|'4.3.0.0'|None, defaults to None :param title: Name of the IDS file, defaults to None
:type ifcversion: str, optional :type title: str, required
:param description:, defaults to None
:type description: str, optional
:param author: Email of the IDS author, defaults to None
:type author: str, optional
:param copyright:, defaults to None :param copyright:, defaults to None
:type copyright: str, optional :type copyright: str, optional
:param version: IDS file version, defaults to None :param version: IDS file version, defaults to None
:type version: float, optional :type version: float, optional
:param creation_date: Date in 'yyyy-mm-dd' format, defaults to current date :param description:, defaults to None
:type creation_date: str, optional :type description: str, optional
:param author: Email of the IDS author, defaults to None
:type author: str, optional
:param date: Date in 'yyyy-mm-dd' format, defaults to current date
:type date: str, optional
:param purpose:, defaults to None :param purpose:, defaults to None
:type purpose: str, optional :type purpose: str, optional
:param milestone:, defaults to None :param milestone:, defaults to None
@@ -78,23 +78,22 @@ class ids:
""" """
self.specifications = [] self.specifications = []
self.info = {} self.info = {}
if ifcversion: if title:
if ifcversion in ["2.3.0.1", "4.0.2.1", "4.3.0.0"]: self.info["title"] = title
self.info["ifcversion"] = ifcversion
if author:
if "@" in author:
self.info["author"] = author
if description:
self.info["description"] = description
if copyright: if copyright:
self.info["copyright"] = copyright self.info["copyright"] = copyright
if version: if version:
self.info["version"] = version self.info["version"] = version
if creation_date: if description:
if re.match(r"\d\d\d\d-\d\d-\d\d", creation_date): self.info["description"] = description
self.info["date"] = creation_date # date.fromisoformat(creation_date).isoformat() if author:
if "@" in author:
self.info["author"] = author
if date:
if re.match(r"\d\d\d\d-\d\d-\d\d", date):
self.info["date"] = date # date.fromisoformat(creation_date).isoformat()
if "date" not in self.info: if "date" not in self.info:
self.info["date"] = date.today().isoformat() self.info["date"] = datetime.date.today().isoformat()
if purpose: if purpose:
self.info["purpose"] = purpose self.info["purpose"] = purpose
if milestone: if milestone:
@@ -110,12 +109,12 @@ class ids:
"@xmlns": "http://standards.buildingsmart.org/IDS", "@xmlns": "http://standards.buildingsmart.org/IDS",
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema", "@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS/ids_04.xsd", "@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS/ids_05.xsd",
"specification": [],
"info": self.info, "info": self.info,
"specifications": [],
} }
for spec in self.specifications: for spec in self.specifications:
ids_dict["specification"].append(spec.asdict()) ids_dict["specifications"].append({"specification": spec.asdict()}) #TEST!
return ids_dict return ids_dict
def to_xml(self, filepath="./", ids_schema=ids_schema): def to_xml(self, filepath="./", ids_schema=ids_schema):
@@ -142,7 +141,7 @@ class ids:
"": "http://standards.buildingsmart.org/IDS", "": "http://standards.buildingsmart.org/IDS",
"xs": "http://www.w3.org/2001/XMLSchema", "xs": "http://www.w3.org/2001/XMLSchema",
"xsi": "http://www.w3.org/2001/XMLSchema-instance", "xsi": "http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation": "http://standards.buildingsmart.org/IDS/ids_04.xsd", "xsi:schemaLocation": "http://standards.buildingsmart.org/IDS/ids_05.xsd",
}, },
) # validation='skip', ) # validation='skip',
@@ -152,7 +151,7 @@ class ids:
"": "http://standards.buildingsmart.org/IDS", "": "http://standards.buildingsmart.org/IDS",
# 'xs': 'http://www.w3.org/2001/XMLSchema', # 'xs': 'http://www.w3.org/2001/XMLSchema',
# 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', # 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
# 'xsi:schemaLocation': "http://standards.buildingsmart.org/IDS/ids_04.xsd" # 'xsi:schemaLocation': "http://standards.buildingsmart.org/IDS/ids_05.xsd"
}, },
) )
@@ -181,7 +180,7 @@ class ids:
filepath, strip_namespaces=True, namespaces={"": "http://standards.buildingsmart.org/IDS"} filepath, strip_namespaces=True, namespaces={"": "http://standards.buildingsmart.org/IDS"}
) )
ids_file = ids() ids_file = ids()
ids_file.specifications = [specification.parse(s) for s in ids_content["specification"]] ids_file.specifications = [specification.parse(s) for s in ids_content["specifications"]["specification"]]
return ids_file return ids_file
def validate(self, ifc_file, logger=None): def validate(self, ifc_file, logger=None):
@@ -197,19 +196,19 @@ class ids:
logging.basicConfig(level=logging.INFO, format="%(message)s") logging.basicConfig(level=logging.INFO, format="%(message)s")
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
if "ifcversion" in self.info.keys(): # if "ifcversion" in self.info.keys():
if self.info["ifcversion"] in ["2.3.0.1", "4.0.2.1", "4.3.0.0"]: # if self.info["ifcversion"] in ["2.3.0.1", "4.0.2.1", "4.3.0.0"]:
if self.info["ifcversion"][0:3] == "2.3": # if self.info["ifcversion"][0:3] == "2.3":
if not ifc_file.schema.startswith("IFC2x3"): # if not ifc_file.schema.startswith("IFC2x3"):
logger.error("IFC file is of %s not of %s schema." % (ifc_file.schema, self.info["ifcversion"])) # logger.error("IFC file is of %s not of %s schema." % (ifc_file.schema, self.info["ifcversion"]))
elif self.info["ifcversion"][0:3] == "4.0": # elif self.info["ifcversion"][0:3] == "4.0":
if not ifc_file.schema == "IFC4": # if not ifc_file.schema == "IFC4":
logger.error("IFC file is of %s not of %s schema." % (ifc_file.schema, self.info["ifcversion"])) # logger.error("IFC file is of %s not of %s schema." % (ifc_file.schema, self.info["ifcversion"]))
elif self.info["ifcversion"][0:3] == "4.3": # elif self.info["ifcversion"][0:3] == "4.3":
if not ifc_file.schema.startswith("IFC4x3"): # if not ifc_file.schema.startswith("IFC4x3"):
logger.error("IFC file is of %s not of %s schema." % (ifc_file.schema, self.info["ifcversion"])) # logger.error("IFC file is of %s not of %s schema." % (ifc_file.schema, self.info["ifcversion"]))
else: # else:
logger.error("IFC version not recognized") # logger.error("IFC version not recognized")
# Consider other way around: for elem, for spec so we can see if an element pass all IDSes? # Consider other way around: for elem, for spec so we can see if an element pass all IDSes?
for spec in self.specifications: for spec in self.specifications:
@@ -222,7 +221,7 @@ class ids:
if comply: if comply:
self.ifc_passed += 1 self.ifc_passed += 1
if self.ifc_applicable == 0: if self.ifc_applicable == 0:
if spec.necessity == "required": if spec.use == "required":
logger.error("No applicable elements found. Minimum 1 applicable element required.") logger.error("No applicable elements found. Minimum 1 applicable element required.")
else: else:
logger.debug("No applicable elements found. None required.") logger.debug("No applicable elements found. None required.")
@@ -248,18 +247,19 @@ class ids:
class specification: class specification:
"""Represents the XML <specification> node and its two children <applicability> and <requirements>""" """Represents the XML <specification> node and its two children <applicability> and <requirements>"""
def __init__(self, name="Specification", necessity="required"): def __init__(self, name="Specification", use="required", ifcVersion="IFC2X3"):
"""Create a specification to be added in ids. """Create a specification to be added in ids.
:param name:, defaults to "Specification" :param name:, defaults to "Specification"
:type name: str, optional :type name: str, optional
:param necessity: 'required'|'optional', defaults to "required" :param use: 'required'|'optional', defaults to "required"
:type necessity: str, optional :type use: str, optional
""" """
self.name = name self.name = name
self.applicability = None self.applicability = None
self.requirements = None self.requirements = None
self.necessity = necessity self.ifcVersion = ifcVersion
self.use = use
def asdict(self): def asdict(self):
"""Converts object to a dictionary, adding required attributes. """Converts object to a dictionary, adding required attributes.
@@ -270,7 +270,8 @@ class specification:
# if older python collections.OrderedDict() # if older python collections.OrderedDict()
spec_dict = { spec_dict = {
"@name": self.name, "@name": self.name,
"@necessity": self.necessity, "@use": self.use,
"@ifcVersion": self.ifcVersion,
"applicability": {}, "applicability": {},
"requirements": {}, "requirements": {},
} }
@@ -299,8 +300,12 @@ class specification:
return facets return facets
spec = specification() spec = specification()
spec.name = ids_dict["@name"] try:
spec.necessity = ids_dict["@necessity"] spec.name = ids_dict["@name"]
except KeyError:
spec.name = ""
spec.use = ids_dict["@use"]
spec.ifcVersion = ids_dict["@ifcVersion"]
spec.applicability = boolean_and(parse_rules(ids_dict["applicability"])) spec.applicability = boolean_and(parse_rules(ids_dict["applicability"]))
spec.requirements = boolean_and(parse_rules(ids_dict["requirements"])) spec.requirements = boolean_and(parse_rules(ids_dict["requirements"]))
return spec return spec
@@ -315,7 +320,7 @@ class specification:
i = ids.ids() i = ids.ids()
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
e = ids.entity.create(name="Test_Name", predefinedtype="Test_PredefinedType") e = ids.entity.create(name="Test_Name", predefinedType="Test_PredefinedType")
i.specifications[0].add_applicability(e) i.specifications[0].add_applicability(e)
""" """
if self.applicability: if self.applicability:
@@ -481,23 +486,23 @@ class facet(metaclass=meta_facet):
class entity(facet): class entity(facet):
"""The IDS entity facet currently *with* inheritance""" """The IDS entity facet currently *with* inheritance"""
parameters = ["name", "predefinedtype"] parameters = ["name", "predefinedType"]
@staticmethod @staticmethod
def create(name=None, predefinedtype=None): def create(name=None, predefinedType=None):
"""Create an entity facet that can be added to applicability or requirements of IDS specification. """Create an entity facet that can be added to applicability or requirements of IDS specification.
:param name: IFC entity name that is required. e.g. IfcWall, defaults to None :param name: IFC entity name that is required. e.g. IfcWall, defaults to None
:type name: str, optional :type name: str, optional
:param predefinedtype: name of the predefined type, defaults to None :param predefinedType: name of the predefined type, defaults to None
:type predefinedtype: str, optional :type predefinedType: str, optional
:return: entity object :return: entity object
:rtype: entity :rtype: entity
""" """
inst = entity() inst = entity()
inst.name = name inst.name = name
inst.predefinedtype = predefinedtype inst.predefinedType = predefinedType
return inst return inst
def asdict(self): def asdict(self):
@@ -507,11 +512,11 @@ class entity(facet):
:rtype: dict :rtype: dict
""" """
fac_dict = {"name": parameter_asdict(self.name)} fac_dict = {"name": parameter_asdict(self.name)}
if "predefinedtype" in self: if "predefinedType" in self:
if self.predefinedtype: if self.predefinedType:
fac_dict["predefinedtype"] = parameter_asdict(self.predefinedtype) fac_dict["predefinedType"] = parameter_asdict(self.predefinedType)
# try: # try:
# fac_dict["predefinedtype"] = parameter_asdict(self.predefinedtype) # fac_dict["predefinedType"] = parameter_asdict(self.predefinedType)
# except (RecursionError, UnboundLocalError) as e: # except (RecursionError, UnboundLocalError) as e:
# print(e) # print(e)
return fac_dict return fac_dict
@@ -528,11 +533,11 @@ class entity(facet):
""" """
# @nb with inheritance # @nb with inheritance
if self.predefinedtype and hasattr(inst, "PredefinedType"): if self.predefinedType and hasattr(inst, "PredefinedType"):
self.message = "an entity name '%(name)s' of predefined type '%(predefinedtype)s'" self.message = "an entity name '%(name)s' of predefined type '%(predefinedType)s'"
return facet_evaluation( return facet_evaluation(
inst.is_a(self.name) and inst.PredefinedType == self.predefinedtype, inst.is_a(self.name) and inst.PredefinedType == self.predefinedType,
self.message % {"name": inst.is_a(), "predefinedtype": inst.PredefinedType}, self.message % {"name": inst.is_a(), "predefinedType": inst.PredefinedType},
) )
else: else:
self.message = "an entity name '%(name)s'" self.message = "an entity name '%(name)s'"
@@ -632,22 +637,114 @@ class classification(facet):
return facet_evaluation(False, "does not have %sclassification reference" % self.location_msg) return facet_evaluation(False, "does not have %sclassification reference" % self.location_msg)
class partOf(facet):
"""
The IDS partOf facet by traversing the _______ inverse attribute
"""
parameters = ["entity"]
message = "relation as part of %(entity)s"
#TODO temp default
entity = "IfcElementAssembly"
@staticmethod
#TODO should not assume IfcElementAssembly
# def create(entity=None):
def create(entity="IfcElementAssembly"):
"""Create a partOf facet that can be added to applicability or requirements of IDS specification.
:param entity: Entity that should contain this object. Could be alphanumeric or restriction object, defaults to None
:type entity: restriction|alphanumeric, optional
:return: partOf object
:rtype: partOf
"""
inst = partOf()
inst.entity = entity
return inst
def asdict(self):
"""Converts object to a dictionary, adding required attributes.
:return: Xmlschema compliant dictionary.
:rtype: dict
"""
fac_dict = {
"@entity": parameter_asdict(self.entity),
# "instructions": "SAMPLE_INSTRUCTIONS",
}
return fac_dict
def __call__(self, inst, logger):
"""Validate an ifc instance against that partOf facet.
:param inst: IFC entity element
:type inst: IFC entity
:param logger: Logging object
:type logger: logging
:return: result of the validation as bool and message
:rtype: facet_evaluation(bool, str)
"""
#TODO handle partOf facet
# instance_classiciations = inst.HasAssociations
# if ifcopenshell.util.element.get_type(inst):
# type_classifications = ifcopenshell.util.element.get_type(inst).HasAssociations
# else:
# type_classifications = ()
# if self.location == "instance" and instance_classiciations:
# associations = instance_classiciations
# elif self.location == "type" and type_classifications:
# associations = type_classifications
# elif self.location == "any" and (instance_classiciations or type_classifications):
# associations = instance_classiciations + type_classifications
# else:
# associations = ()
refs = []
# for association in associations:
# if association.is_a("IfcRelAssociatesClassification"):
# cref = association.RelatingClassification
# if hasattr(cref, "ItemReference"): # IFC2x3
# refs.append((cref.ReferencedSource.Name, cref.ItemReference))
# elif hasattr(cref, "Identification"): # IFC4
# refs.append((cref.ReferencedSource.Name, cref.Identification))
# self.location_msg = location[self.location]
if refs:
pass
# return facet_evaluation(
# (self.system, self.value) in refs,
# self.message
# % {
# "system": refs[0][0],
# "value": "'" + refs[0][1] + "'",
# "location": self.location_msg,
# }, # what if not first item of refs?
# )
else:
return facet_evaluation(False, "is not a part of %s" % self.node['@entity'])
class property(facet): class property(facet):
""" """
The IDS property facet implemented using `ifcopenshell.util.element` The IDS property facet implemented using `ifcopenshell.util.element`
""" """
parameters = ["name", "propertyset", "value", "location"] parameters = ["name", "propertySet", "value", "location"]
message = "%(location)sproperty '%(name)s' in '%(propertyset)s' with a value %(value)s" message = "%(location)sproperty '%(name)s' in '%(propertySet)s' with a value %(value)s"
@staticmethod @staticmethod
def create(location="any", propertyset=None, name=None, value=None): def create(location="any", propertySet=None, name=None, value=None):
"""Create a property facet that can be added to applicability or requirements of IDS specification. """Create a property facet that can be added to applicability or requirements of IDS specification.
:param location: Define where to check for the parameter. One of "any"|"instance"|"type", defaults to "any" :param location: Define where to check for the parameter. One of "any"|"instance"|"type", defaults to "any"
:type location: str, optional :type location: str, optional
:param propertyset: Propertyset that is required. Could be alphanumeric or restriction object, defaults to None :param propertySet: Propertyset that is required. Could be alphanumeric or restriction object, defaults to None
:type propertyset: restriction|alphanumeric, optional :type propertySet: restriction|alphanumeric, optional
:param name: Name that is required. Could be alphanumeric or restriction object, defaults to None :param name: Name that is required. Could be alphanumeric or restriction object, defaults to None
:type name: restriction|alphanumeric, optional :type name: restriction|alphanumeric, optional
:param value: Value that is required. Could be alphanumeric or restriction object, defaults to None :param value: Value that is required. Could be alphanumeric or restriction object, defaults to None
@@ -657,7 +754,7 @@ class property(facet):
""" """
inst = property() inst = property()
inst.location = location inst.location = location
inst.propertyset = propertyset inst.propertySet = propertySet
inst.name = name inst.name = name
inst.value = value inst.value = value
# cls.attributes = {'@location': location} # 'type', 'instance', 'any' # cls.attributes = {'@location': location} # 'type', 'instance', 'any'
@@ -673,7 +770,7 @@ class property(facet):
""" """
fac_dict = { fac_dict = {
"@location": self.location, "@location": self.location,
"propertyset": parameter_asdict(self.propertyset), "propertySet": parameter_asdict(self.propertySet),
"name": parameter_asdict(self.name), "name": parameter_asdict(self.name),
"value": parameter_asdict(self.value), "value": parameter_asdict(self.value),
# "instructions": "SAMPLE_INSTRUCTIONS", # "instructions": "SAMPLE_INSTRUCTIONS",
@@ -694,8 +791,8 @@ class property(facet):
# self.location = self.node["@location"] # self.location = self.node["@location"]
#TODO add documentation that attributes should have "attribute" as propertysets #TODO add documentation that attributes should have "attribute" as propertySets
if self.propertyset == "attribute": if self.propertySet == "attribute":
val = {k.lower(): v for k, v in inst.get_info().items()}.get(self.name, None) val = {k.lower(): v for k, v in inst.get_info().items()}.get(self.name, None)
else: else:
# TODO sometimes AttributeError: 'str' object has no attribute 'wrappedValue' # TODO sometimes AttributeError: 'str' object has no attribute 'wrappedValue'
@@ -722,19 +819,19 @@ class property(facet):
else: else:
props = {} props = {}
pset = props.get(self.propertyset) pset = props.get(self.propertySet)
val = pset.get(self.name) if pset else None val = pset.get(self.name) if pset else None
self.location_msg = location[self.location] self.location_msg = location[self.location]
di = {"name": self.name, "propertyset": self.propertyset, "value": "'%s'" % val, "location": self.location_msg} di = {"name": self.name, "propertySet": self.propertySet, "value": "'%s'" % val, "location": self.location_msg}
if val is not None: if val is not None:
msg = self.message % di msg = self.message % di
else: else:
if pset: if pset:
msg = "does not have %(location)sproperty '%(name)s' in a set '%(propertyset)s'" % di msg = "does not have %(location)sproperty '%(name)s' in a set '%(propertySet)s'" % di
else: else:
msg = "does not have %(location)sset '%(propertyset)s'" % di msg = "does not have %(location)sset '%(propertySet)s'" % di
# TODO implement data type comparison # TODO implement data type comparison
# xs:string # xs:string
@@ -826,8 +923,8 @@ class material(facet):
for rel in material_relations: for rel in material_relations:
if rel.RelatingMaterial.is_a() == "IfcMaterial": if rel.RelatingMaterial.is_a() == "IfcMaterial":
materials.append(rel.RelatingMaterial.Name) materials.append(rel.RelatingMaterial.Name)
elif rel.RelatingMaterial.is_a() == "IfcMaterialMaterialList": # DEPRECATED in IFC4 elif rel.RelatingMaterial.is_a() == "IfcMaterialList": # DEPRECATED in IFC4
[materials.append(mat.Name) for mat in rel.RelatingMaterial] [materials.append(mat.Name) for mat in rel.RelatingMaterial.Materials]
elif rel.RelatingMaterial.is_a() == "IfcMaterialConstituentSet": elif rel.RelatingMaterial.is_a() == "IfcMaterialConstituentSet":
[materials.append(mat.Material.Name) for mat in rel.RelatingMaterial.MaterialConstituents] [materials.append(mat.Material.Name) for mat in rel.RelatingMaterial.MaterialConstituents]
elif rel.RelatingMaterial.is_a() == "IfcMaterialLayerSet": elif rel.RelatingMaterial.is_a() == "IfcMaterialLayerSet":
@@ -911,14 +1008,19 @@ class restriction:
@staticmethod @staticmethod
def parse(ids_dict): def parse(ids_dict):
"""Parse xml restriction to python object. """Parse xml restriction to python object.
:param ids_dict: :param ids_dict:
:type ids_dict: dict :type ids_dict: dict
""" """
r = restriction() r = restriction()
if ids_dict: if ids_dict:
# TODO 'base' missing in some IDS?! # TODO 'base' missing in some IDS?!
r.base = ids_dict["@base"][3:]
try:
r.base = ids_dict["@base"][3:]
except KeyError:
r.base = "String"
for n in ids_dict: for n in ids_dict:
if n == "enumeration": if n == "enumeration":
r.type = "enumeration" r.type = "enumeration"
@@ -1038,7 +1140,11 @@ class restriction:
if eval(str(len(other)) + op): # TODO eval not safe? if eval(str(len(other)) + op): # TODO eval not safe?
result = True result = True
elif self.type == "pattern": elif self.type == "pattern":
translated_pattern = identities.translate_pattern(self.options) if isinstance(self.options, list):
#TODO handle case with multiple pattern options
translated_pattern = identities.translate_pattern(self.options[0])
else:
translated_pattern = identities.translate_pattern(self.options)
regex_pattern = re.compile(translated_pattern) regex_pattern = re.compile(translated_pattern)
if regex_pattern.fullmatch(other) is not None: if regex_pattern.fullmatch(other) is not None:
result = True result = True
+281 -76
View File
@@ -1,52 +1,46 @@
<!-- edited with XMLSpy v2021 rel. 3 (x64) --> <!-- edited with XMLSpy v2022 (x64) (http://www.altova.com) by Leon van Berlo (Overleaf Investments B.V.) -->
<!-- Version 0.4.1- July 26, 2021 - DRAFT --> <!-- February 8, 2022 - DRAFT -->
<!-- Most recent version available at: http://standards.buildingsmart.org/IDS --> <xs:schema xmlns:ids="http://standards.buildingsmart.org/IDS" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" targetNamespace="http://standards.buildingsmart.org/IDS" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.5.8">
<xs:schema xmlns:ids="http://standards.buildingsmart.org/IDS" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://www.w3.org/2001/XMLSchema-instance" targetNamespace="http://standards.buildingsmart.org/IDS" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.4.1">
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/> <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
<xs:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="https://www.w3.org/2001/XMLSchema.xsd"/> <xs:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="https://www.w3.org/2001/XMLSchema.xsd"/>
<xs:import namespace="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="http://www.w3.org/2001/XMLSchema-instance"/> <xs:import namespace="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="http://www.w3.org/2001/XMLSchema-instance"/>
<xs:element name="ids"> <xs:element name="ids">
<xs:complexType> <xs:complexType>
<xs:complexContent> <xs:sequence>
<xs:extension base="ids:idsType"> <xs:element name="info">
<xs:sequence> <xs:complexType>
<xs:element name="info"> <xs:sequence>
<xs:complexType> <xs:element name="title" type="xs:string"/>
<xs:choice maxOccurs="unbounded"> <xs:element name="copyright" type="xs:string" minOccurs="0"/>
<xs:element name="ifcversion"> <xs:element name="version" type="xs:string" minOccurs="0"/>
<xs:simpleType> <xs:element name="description" type="xs:string" minOccurs="0"/>
<xs:restriction base="xs:string"> <xs:element name="author" minOccurs="0">
<xs:enumeration value="2.3.0.1"/> <xs:simpleType>
<xs:enumeration value="4.0.2.1"/> <xs:restriction base="xs:string">
<xs:enumeration value="4.3.0.0"/> <xs:pattern value="[^@]+@[^\.]+\..+"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:element> </xs:element>
<xs:element name="description" type="xs:string" minOccurs="0"/> <xs:element name="date" type="xs:date" minOccurs="0"/>
<xs:element name="author" minOccurs="0"> <xs:element name="purpose" type="xs:string" minOccurs="0"/>
<xs:simpleType> <xs:element name="milestone" type="xs:string" minOccurs="0"/>
<xs:restriction base="xs:string"> </xs:sequence>
<xs:pattern value="[^@]+@[^\.]+\..+"/> </xs:complexType>
</xs:restriction> </xs:element>
</xs:simpleType> <xs:element name="specifications">
</xs:element> <xs:complexType>
<xs:element name="copyright" type="xs:string"/> <xs:complexContent>
<xs:element name="version" type="xs:decimal"/> <xs:extension base="ids:specificationsType"/>
<xs:element name="date" type="xs:date"/> </xs:complexContent>
<xs:element name="purpose" type="xs:string" minOccurs="0"/> </xs:complexType>
<xs:element name="milestone" type="xs:string" minOccurs="0"/> </xs:element>
</xs:choice> </xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:complexType name="entityType"> <xs:complexType name="entityType">
<xs:sequence> <xs:sequence>
<xs:element name="name" type="ids:idsValue"/> <xs:element name="name" type="ids:idsValue"/>
<xs:element name="predefinedtype" type="ids:idsValue" minOccurs="0"/> <xs:element name="predefinedType" type="ids:idsValue" minOccurs="0"/>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
<xs:complexType name="idsValue"> <xs:complexType name="idsValue">
@@ -57,8 +51,8 @@
</xs:choice> </xs:choice>
</xs:complexType> </xs:complexType>
<xs:complexType name="classificationType"> <xs:complexType name="classificationType">
<xs:sequence maxOccurs="2"> <xs:sequence>
<xs:element name="value" type="ids:idsValue"/> <xs:element name="value" type="ids:idsValue" minOccurs="0"/>
<xs:element name="system" type="ids:idsValue" minOccurs="0"/> <xs:element name="system" type="ids:idsValue" minOccurs="0"/>
</xs:sequence> </xs:sequence>
<xs:attribute name="location" use="required"> <xs:attribute name="location" use="required">
@@ -73,12 +67,77 @@
</xs:complexType> </xs:complexType>
<xs:complexType name="applicabilityType"> <xs:complexType name="applicabilityType">
<xs:sequence> <xs:sequence>
<xs:element name="entity" type="ids:entityType"/> <xs:element name="entity" type="ids:entityType" minOccurs="0"/>
<xs:element name="classification" type="ids:classificationType" minOccurs="0"/> <xs:element name="classification" type="ids:classificationType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="attribute" type="ids:attributeType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="property" minOccurs="0" maxOccurs="unbounded"> <xs:element name="property" minOccurs="0" maxOccurs="unbounded">
<xs:complexType> <xs:complexType>
<xs:complexContent> <xs:complexContent>
<xs:extension base="ids:propertyType"/> <xs:extension base="ids:propertyType">
<xs:attribute name="measure">
<xs:annotation>
<xs:documentation>See the documentation and default units of these measures on https://github.com/buildingSMART/IDS/wiki/Physical-Quantities-and-Units</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="String"/>
<xs:enumeration value="Number"/>
<xs:enumeration value="AmountOfSubstance"/>
<xs:enumeration value="AreaDensity"/>
<xs:enumeration value="Area"/>
<xs:enumeration value="DynamicViscosity"/>
<xs:enumeration value="ElectricCapacitance"/>
<xs:enumeration value="ElectricCharge"/>
<xs:enumeration value="ElectricConductance"/>
<xs:enumeration value="ElectricCurrent"/>
<xs:enumeration value="ElectricResistance"/>
<xs:enumeration value="ElectricVoltage"/>
<xs:enumeration value="Energy"/>
<xs:enumeration value="Force"/>
<xs:enumeration value="Frequency"/>
<xs:enumeration value="HeatFluxDensity"/>
<xs:enumeration value="Heating"/>
<xs:enumeration value="Illuminance"/>
<xs:enumeration value="IonConcentration"/>
<xs:enumeration value="IsoThermalMoistureCapacity"/>
<xs:enumeration value="Length"/>
<xs:enumeration value="Speed"/>
<xs:enumeration value="LuminousFlux"/>
<xs:enumeration value="LuminousIntensity"/>
<xs:enumeration value="MassDensity"/>
<xs:enumeration value="MassFlowRate"/>
<xs:enumeration value="Mass"/>
<xs:enumeration value="MassPerLength"/>
<xs:enumeration value="ModulusOfElasticity"/>
<xs:enumeration value="MoistureDiffusivity"/>
<xs:enumeration value="MolecularWeight"/>
<xs:enumeration value="MomentOfInertia"/>
<xs:enumeration value="PH"/>
<xs:enumeration value="PlanarForce"/>
<xs:enumeration value="Angle"/>
<xs:enumeration value="PlaneAngle"/>
<xs:enumeration value="Power"/>
<xs:enumeration value="Pressure"/>
<xs:enumeration value="RadioActivity"/>
<xs:enumeration value="Ratio"/>
<xs:enumeration value="RotationalFrequency"/>
<xs:enumeration value="SectionModulus"/>
<xs:enumeration value="SoundPower"/>
<xs:enumeration value="SoundPressure"/>
<xs:enumeration value="SpecificHeatCapacity"/>
<xs:enumeration value="TemperatureRateOfChange"/>
<xs:enumeration value="ThermalConductivity"/>
<xs:enumeration value="Temperature"/>
<xs:enumeration value="Time"/>
<xs:enumeration value="Torque"/>
<xs:enumeration value="VaporPermeability"/>
<xs:enumeration value="Volume"/>
<xs:enumeration value="VolumetricFlowRate"/>
<!-- kind of number defined in base of restriction -->
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
@@ -100,9 +159,24 @@
</xs:complexType> </xs:complexType>
<xs:complexType name="propertyType"> <xs:complexType name="propertyType">
<xs:sequence> <xs:sequence>
<xs:element name="propertyset" type="ids:idsValue"/> <xs:element name="propertySet" type="ids:idsValue"/>
<xs:element name="name" type="ids:idsValue"/> <xs:element name="name" type="ids:idsValue"/>
<xs:element name="value" type="ids:idsValue"/> <xs:element name="value" type="ids:idsValue" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="location" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="type"/>
<xs:enumeration value="instance"/>
<xs:enumeration value="any"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
<xs:complexType name="attributeType">
<xs:sequence>
<xs:element name="name" type="ids:idsValue"/>
<xs:element name="value" type="ids:idsValue" minOccurs="0"/>
</xs:sequence> </xs:sequence>
<xs:attribute name="location" use="required"> <xs:attribute name="location" use="required">
<xs:simpleType> <xs:simpleType>
@@ -116,7 +190,7 @@
</xs:complexType> </xs:complexType>
<xs:complexType name="materialType"> <xs:complexType name="materialType">
<xs:sequence> <xs:sequence>
<xs:element name="value" type="ids:idsValue"/> <xs:element name="value" type="ids:idsValue" minOccurs="0"/>
</xs:sequence> </xs:sequence>
<xs:attribute name="location" use="required"> <xs:attribute name="location" use="required">
<xs:simpleType> <xs:simpleType>
@@ -130,31 +204,76 @@
</xs:complexType> </xs:complexType>
<xs:complexType name="requirementsType"> <xs:complexType name="requirementsType">
<xs:sequence maxOccurs="unbounded"> <xs:sequence maxOccurs="unbounded">
<xs:element name="entity" type="ids:entityType" minOccurs="0"> <xs:element name="entity" minOccurs="0">
<xs:annotation> <xs:annotation>
<xs:documentation>Make sure 'Name' value of requirements entity is the same as the 'applicability' node, or a wildcard (inclusive pattern).</xs:documentation> <xs:documentation>Make sure 'Name' value of requirements entity is the same as the 'applicability' node, or a wildcard (inclusive pattern).</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType>
<xs:complexContent>
<xs:extension base="ids:entityType">
<xs:attribute name="instructions">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element> </xs:element>
<xs:element name="classification" minOccurs="0"> <xs:element name="partOf" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="entity" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="IfcElementAssembly"/>
<xs:enumeration value="IfcGroup"/>
<xs:enumeration value="IfcSystem"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="classification" minOccurs="0" maxOccurs="unbounded">
<xs:complexType> <xs:complexType>
<xs:complexContent> <xs:complexContent>
<xs:extension base="ids:classificationType"> <xs:extension base="ids:classificationType">
<xs:sequence>
<xs:element name="instructions" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="uri" type="xs:anyURI" use="optional"/> <xs:attribute name="uri" type="xs:anyURI" use="optional"/>
<xs:attribute name="use" use="optional"> <xs:attribute name="use" use="optional">
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:enumeration value="required"/>
<xs:enumeration value="optional"/> <xs:enumeration value="optional"/>
<xs:enumeration value="prohibited"/>
<xs:enumeration value="required"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
<xs:attribute name="instructions">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="attribute" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:complexContent>
<xs:extension base="ids:attributeType">
<xs:attribute name="use" use="optional">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="optional"/>
<xs:enumeration value="prohibited"/>
<xs:enumeration value="required"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="instructions">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension> </xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
@@ -163,22 +282,84 @@
<xs:complexType> <xs:complexType>
<xs:complexContent> <xs:complexContent>
<xs:extension base="ids:propertyType"> <xs:extension base="ids:propertyType">
<xs:sequence>
<xs:element name="instructions" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="uri" type="xs:anyURI" use="optional"/> <xs:attribute name="uri" type="xs:anyURI" use="optional"/>
<xs:attribute name="use" use="optional"> <xs:attribute name="use" use="optional">
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:enumeration value="required"/>
<xs:enumeration value="optional"/> <xs:enumeration value="optional"/>
<xs:enumeration value="prohibited"/>
<xs:enumeration value="required"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
<xs:attribute name="measure">
<xs:annotation>
<xs:documentation>See the documentation and default units of these measures on https://github.com/buildingSMART/IDS/wiki/Physical-Quantities-and-Units</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="String"/>
<xs:enumeration value="Number"/>
<xs:enumeration value="AmountOfSubstance"/>
<xs:enumeration value="AreaDensity"/>
<xs:enumeration value="Area"/>
<xs:enumeration value="DynamicViscosity"/>
<xs:enumeration value="ElectricCapacitance"/>
<xs:enumeration value="ElectricCharge"/>
<xs:enumeration value="ElectricConductance"/>
<xs:enumeration value="ElectricCurrent"/>
<xs:enumeration value="ElectricResistance"/>
<xs:enumeration value="ElectricVoltage"/>
<xs:enumeration value="Energy"/>
<xs:enumeration value="Force"/>
<xs:enumeration value="Frequency"/>
<xs:enumeration value="HeatFluxDensity"/>
<xs:enumeration value="Heating"/>
<xs:enumeration value="Illuminance"/>
<xs:enumeration value="IonConcentration"/>
<xs:enumeration value="IsoThermalMoistureCapacity"/>
<xs:enumeration value="Length"/>
<xs:enumeration value="Speed"/>
<xs:enumeration value="LuminousFlux"/>
<xs:enumeration value="LuminousIntensity"/>
<xs:enumeration value="MassDensity"/>
<xs:enumeration value="MassFlowRate"/>
<xs:enumeration value="Mass"/>
<xs:enumeration value="MassPerLength"/>
<xs:enumeration value="ModulusOfElasticity"/>
<xs:enumeration value="MoistureDiffusivity"/>
<xs:enumeration value="MolecularWeight"/>
<xs:enumeration value="MomentOfInertia"/>
<xs:enumeration value="PH"/>
<xs:enumeration value="PlanarForce"/>
<xs:enumeration value="Angle"/>
<xs:enumeration value="PlaneAngle"/>
<xs:enumeration value="Power"/>
<xs:enumeration value="Pressure"/>
<xs:enumeration value="RadioActivity"/>
<xs:enumeration value="Ratio"/>
<xs:enumeration value="RotationalFrequency"/>
<xs:enumeration value="SectionModulus"/>
<xs:enumeration value="SoundPower"/>
<xs:enumeration value="SoundPressure"/>
<xs:enumeration value="SpecificHeatCapacity"/>
<xs:enumeration value="TemperatureRateOfChange"/>
<xs:enumeration value="ThermalConductivity"/>
<xs:enumeration value="Temperature"/>
<xs:enumeration value="Time"/>
<xs:enumeration value="Torque"/>
<xs:enumeration value="VaporPermeability"/>
<xs:enumeration value="Volume"/>
<xs:enumeration value="VolumetricFlowRate"/>
<!-- kind of number defined in base of restriction -->
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="instructions">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension> </xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
@@ -187,22 +368,21 @@
<xs:complexType> <xs:complexType>
<xs:complexContent> <xs:complexContent>
<xs:extension base="ids:materialType"> <xs:extension base="ids:materialType">
<xs:sequence>
<xs:element name="instructions" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="uri" type="xs:anyURI" use="optional"/> <xs:attribute name="uri" type="xs:anyURI" use="optional"/>
<xs:attribute name="use" use="optional"> <xs:attribute name="use" use="optional">
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:enumeration value="required"/>
<xs:enumeration value="optional"/> <xs:enumeration value="optional"/>
<xs:enumeration value="prohibited"/>
<xs:enumeration value="required"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
<xs:attribute name="instructions">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension> </xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
@@ -215,16 +395,41 @@
<xs:element name="requirements" type="ids:requirementsType"/> <xs:element name="requirements" type="ids:requirementsType"/>
</xs:sequence> </xs:sequence>
<xs:attribute name="name" type="xs:string" use="optional"/> <xs:attribute name="name" type="xs:string" use="optional"/>
<xs:attribute name="necessity" use="required"> <xs:attribute name="use" use="required">
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:enumeration value="required"/>
<xs:enumeration value="optional"/> <xs:enumeration value="optional"/>
<xs:enumeration value="prohibited"/>
<xs:enumeration value="required"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
<xs:attribute name="ifcVersion" use="required">
<xs:simpleType>
<xs:list>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="IFC2X3"/>
<xs:enumeration value="IFC4"/>
<xs:enumeration value="IFC4_3"/>
</xs:restriction>
</xs:simpleType>
</xs:list>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="identifier">
<xs:annotation>
<xs:documentation>Author of the IDS can provide an identifier to the IDS. Beware: this cannot be enforced/assumed as (global) unique.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="description" type="xs:string" use="optional"/>
<xs:attribute name="instructions">
<xs:annotation>
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType> </xs:complexType>
<xs:complexType name="idsType"> <xs:complexType name="specificationsType">
<xs:sequence> <xs:sequence>
<xs:element name="specification" type="ids:specificationType" minOccurs="1" maxOccurs="unbounded"/> <xs:element name="specification" type="ids:specificationType" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence> </xs:sequence>
+34 -34
View File
@@ -54,20 +54,20 @@ class TestIdsParsing(unittest.TestCase):
ids_file = ids.ids.open(IDS_URL) ids_file = ids.ids.open(IDS_URL)
self.assertEqual(ids_file.specifications[0].requirements.terms[0].node["name"]["simpleValue"], "IfcWall") self.assertEqual(ids_file.specifications[0].requirements.terms[0].node["name"]["simpleValue"], "IfcWall")
def test_parse_predefinedtype_facet(self): def test_parse_predefinedType_facet(self):
IDS_URL = ( IDS_URL = (
os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "IDS_Wall_needs_predefinedtype.xml") os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "IDS_Wall_needs_predefinedType.xml")
) )
ids_file = ids.ids.open(IDS_URL) ids_file = ids.ids.open(IDS_URL)
self.assertEqual( self.assertEqual(
ids_file.specifications[0].requirements.terms[0].node["predefinedtype"]["simpleValue"], "CLADDING" ids_file.specifications[0].requirements.terms[0].node["predefinedType"]["simpleValue"], "CLADDING"
) )
def test_parse_property_facet(self): def test_parse_property_facet(self):
IDS_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "IDS_Wall_needs_property.xml") IDS_URL = os.path.join(os.path.dirname(__file__), "Sample-BIM-Files/IDS/", "IDS_Wall_needs_property.xml")
ids_file = ids.ids.open(IDS_URL) ids_file = ids.ids.open(IDS_URL)
self.assertEqual( self.assertEqual(
ids_file.specifications[0].requirements.terms[0].node["propertyset"]["simpleValue"], "Test_PropertySet" ids_file.specifications[0].requirements.terms[0].node["propertySet"]["simpleValue"], "Test_PropertySet"
) )
self.assertEqual(ids_file.specifications[0].requirements.terms[0].node["name"]["simpleValue"], "Test_Parameter") self.assertEqual(ids_file.specifications[0].requirements.terms[0].node["name"]["simpleValue"], "Test_Parameter")
self.assertEqual(ids_file.specifications[0].requirements.terms[0].node["value"]["simpleValue"], "Test_Value") self.assertEqual(ids_file.specifications[0].requirements.terms[0].node["value"]["simpleValue"], "Test_Value")
@@ -141,9 +141,9 @@ class TestIdsAuthoring(unittest.TestCase):
"""Creating basic IDS""" """Creating basic IDS"""
def test_entity_create(self): def test_entity_create(self):
e = ids.entity.create(name="Test_Name", predefinedtype="Test_PredefinedType") e = ids.entity.create(name="Test_Name", predefinedType="Test_PredefinedType")
self.assertEqual(e.name, "Test_Name") self.assertEqual(e.name, "Test_Name")
self.assertEqual(e.predefinedtype, "Test_PredefinedType") self.assertEqual(e.predefinedType, "Test_PredefinedType")
def test_classification_create(self): def test_classification_create(self):
c = ids.classification.create(location="any", value="Test_Value", system="Test_System") c = ids.classification.create(location="any", value="Test_Value", system="Test_System")
@@ -153,10 +153,10 @@ class TestIdsAuthoring(unittest.TestCase):
def test_property_create(self): def test_property_create(self):
p = ids.property.create( p = ids.property.create(
location="any", propertyset="Test_PropertySet", name="Test_Parameter", value="Test_Value" location="any", propertySet="Test_PropertySet", name="Test_Parameter", value="Test_Value"
) )
self.assertEqual(p.location, "any") self.assertEqual(p.location, "any")
self.assertEqual(p.propertyset, "Test_PropertySet") self.assertEqual(p.propertySet, "Test_PropertySet")
self.assertEqual(p.name, "Test_Parameter") self.assertEqual(p.name, "Test_Parameter")
self.assertEqual(p.value, "Test_Value") self.assertEqual(p.value, "Test_Value")
@@ -170,7 +170,7 @@ class TestIdsAuthoring(unittest.TestCase):
self.assertEqual(s.name, "Test_Specification") self.assertEqual(s.name, "Test_Specification")
def test_ids_add_content(self): def test_ids_add_content(self):
i = ids.ids() i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
self.assertEqual(i.specifications[0].name, "Test_Specification") self.assertEqual(i.specifications[0].name, "Test_Specification")
m = ids.material.create(location="any", value="Test_Value") m = ids.material.create(location="any", value="Test_Value")
@@ -186,7 +186,7 @@ class TestIdsAuthoring(unittest.TestCase):
""" Creating IDS with restrictions """ """ Creating IDS with restrictions """
def test_create_restrictions_enumeration(self): def test_create_restrictions_enumeration(self):
i = ids.ids() i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
i.specifications[0].add_applicability(ids.entity.create(name="Test_Name")) i.specifications[0].add_applicability(ids.entity.create(name="Test_Name"))
r = ids.restriction.create(options=["testA", "testB"], type="enumeration", base="string") r = ids.restriction.create(options=["testA", "testB"], type="enumeration", base="string")
@@ -197,11 +197,11 @@ class TestIdsAuthoring(unittest.TestCase):
self.assertNotEqual(i.specifications[0].requirements.terms[0].value, "testC") self.assertNotEqual(i.specifications[0].requirements.terms[0].value, "testC")
def test_create_restrictions_bounds(self): def test_create_restrictions_bounds(self):
i = ids.ids() i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
i.specifications[0].add_applicability(ids.entity.create(name="Test_Name")) i.specifications[0].add_applicability(ids.entity.create(name="Test_Name"))
r = ids.restriction.create(options={"minInclusive": 0, "maxExclusive": 10}, type="bounds", base="integer") r = ids.restriction.create(options={"minInclusive": 0, "maxExclusive": 10}, type="bounds", base="integer")
p = ids.property.create(location="any", propertyset="Test", name="Test", value=r) p = ids.property.create(location="any", propertySet="Test", name="Test", value=r)
i.specifications[0].add_requirement(p) i.specifications[0].add_requirement(p)
self.assertEqual(i.specifications[0].requirements.terms[0].value, 0) self.assertEqual(i.specifications[0].requirements.terms[0].value, 0)
self.assertEqual(i.specifications[0].requirements.terms[0].value, 5) self.assertEqual(i.specifications[0].requirements.terms[0].value, 5)
@@ -209,11 +209,11 @@ class TestIdsAuthoring(unittest.TestCase):
self.assertNotEqual(i.specifications[0].requirements.terms[0].value, 10) self.assertNotEqual(i.specifications[0].requirements.terms[0].value, 10)
def test_create_restrictions_pattern_simple(self): def test_create_restrictions_pattern_simple(self):
i = ids.ids() i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
i.specifications[0].add_applicability(ids.entity.create(name="Test_Name")) i.specifications[0].add_applicability(ids.entity.create(name="Test_Name"))
r = ids.restriction.create(options="[A-Z]{2,4}", type="pattern", base="string") r = ids.restriction.create(options="[A-Z]{2,4}", type="pattern", base="string")
p = ids.property.create(location="any", propertyset="Test", name="Test", value=r) p = ids.property.create(location="any", propertySet="Test", name="Test", value=r)
i.specifications[0].add_requirement(p) i.specifications[0].add_requirement(p)
self.assertEqual(i.specifications[0].requirements.terms[0].value, "XYZ") self.assertEqual(i.specifications[0].requirements.terms[0].value, "XYZ")
self.assertNotEqual(i.specifications[0].requirements.terms[0].value, "abc") self.assertNotEqual(i.specifications[0].requirements.terms[0].value, "abc")
@@ -221,43 +221,43 @@ class TestIdsAuthoring(unittest.TestCase):
self.assertNotEqual(i.specifications[0].requirements.terms[0].value, "A") self.assertNotEqual(i.specifications[0].requirements.terms[0].value, "A")
def test_create_restrictions_pattern_advanced(self): def test_create_restrictions_pattern_advanced(self):
i = ids.ids() i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
i.specifications[0].add_applicability(ids.entity.create(name="Test_Name")) i.specifications[0].add_applicability(ids.entity.create(name="Test_Name"))
r = ids.restriction.create(options="(Wanddurchbruch|Deckendurchbruch).*", type="pattern", base="string") r = ids.restriction.create(options="(Wanddurchbruch|Deckendurchbruch).*", type="pattern", base="string")
p = ids.property.create(location="any", propertyset="Test", name="Test", value=r) p = ids.property.create(location="any", propertySet="Test", name="Test", value=r)
i.specifications[0].add_requirement(p) i.specifications[0].add_requirement(p)
self.assertEqual(i.specifications[0].requirements.terms[0].value, "Wanddurchbruch") self.assertEqual(i.specifications[0].requirements.terms[0].value, "Wanddurchbruch")
self.assertEqual(i.specifications[0].requirements.terms[0].value, "Deckendurchbruch") self.assertEqual(i.specifications[0].requirements.terms[0].value, "Deckendurchbruch")
self.assertNotEqual(i.specifications[0].requirements.terms[0].value, "Deeckendurchbruch") self.assertNotEqual(i.specifications[0].requirements.terms[0].value, "Deeckendurchbruch")
def test_create_restrictions_pattern_utf(self): def test_create_restrictions_pattern_utf(self):
i = ids.ids() i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
i.specifications[0].add_applicability(ids.entity.create(name="Test_Name")) i.specifications[0].add_applicability(ids.entity.create(name="Test_Name"))
r = ids.restriction.create(options="èêóòâôæøåążźćęóʑʒʓʔʕʗʘʙʚʛʜʝʞ", type="pattern", base="string") r = ids.restriction.create(options="èêóòâôæøåążźćęóʑʒʓʔʕʗʘʙʚʛʜʝʞ", type="pattern", base="string")
p = ids.property.create(location="any", propertyset="Test", name="Test", value=r) p = ids.property.create(location="any", propertySet="Test", name="Test", value=r)
i.specifications[0].add_requirement(p) i.specifications[0].add_requirement(p)
self.assertEqual(i.specifications[0].requirements.terms[0].value, "èêóòâôæøåążźćęóʑʒʓʔʕʗʘʙʚʛʜʝʞ") self.assertEqual(i.specifications[0].requirements.terms[0].value, "èêóòâôæøåążźćęóʑʒʓʔʕʗʘʙʚʛʜʝʞ")
""" Saving created IDS to IDS.xml """ """ Saving created IDS to IDS.xml """
def test_created_ids_to_xml(self): def test_created_ids_to_xml(self):
i = ids.ids() i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
e = ids.entity.create(name="Test_Name", predefinedtype="Test_PredefinedType") e = ids.entity.create(name="Test_Name", predefinedType="Test_PredefinedType")
c = ids.classification.create(location="any", value="Test_Value", system="Test_System") c = ids.classification.create(location="any", value="Test_Value", system="Test_System")
m = ids.material.create(location="any", value="Test_Value") m = ids.material.create(location="any", value="Test_Value")
re = ids.restriction.create(options=["testA", "testB"], type="enumeration", base="string") re = ids.restriction.create(options=["testA", "testB"], type="enumeration", base="string")
rb = ids.restriction.create(options={"minInclusive": 0, "maxExclusive": 10}, type="bounds", base="integer") rb = ids.restriction.create(options={"minInclusive": 0, "maxExclusive": 10}, type="bounds", base="integer")
rp1 = ids.restriction.create(options="[A-Z]{2,4}", type="pattern", base="string") rp1 = ids.restriction.create(options="[A-Z]{2,4}", type="pattern", base="string")
rp2 = ids.restriction.create(options="èêóòâôæøåążźćęóʑʒʓʔʕʗʘʙʚʛʜʝʞ", type="pattern", base="string") rp2 = ids.restriction.create(options="èêóòâôæøåążźćęóʑʒʓʔʕʗʘʙʚʛʜʝʞ", type="pattern", base="string")
p1 = ids.property.create(location="any", propertyset="Test_PropertySet", name="Test_Parameter", value=re) p1 = ids.property.create(location="any", propertySet="Test_PropertySet", name="Test_Parameter", value=re)
p2 = ids.property.create(location="any", propertyset="Test_PropertySet", name="Test_Parameter", value=rb) p2 = ids.property.create(location="any", propertySet="Test_PropertySet", name="Test_Parameter", value=rb)
p3 = ids.property.create(location="any", propertyset="Test_PropertySet", name="Test_Parameter", value=rp1) p3 = ids.property.create(location="any", propertySet="Test_PropertySet", name="Test_Parameter", value=rp1)
p4 = ids.property.create(location="any", propertyset="Test_PropertySet", name="Test_Parameter", value=rp2) p4 = ids.property.create(location="any", propertySet="Test_PropertySet", name="Test_Parameter", value=rp2)
p5 = ids.property.create( p5 = ids.property.create(
location="any", propertyset="Test_PropertySet", name="Test_Parameter", value=[re, rb, rp1] location="any", propertySet="Test_PropertySet", name="Test_Parameter", value=[re, rb, rp1]
) )
i.specifications[0].add_applicability(e) i.specifications[0].add_applicability(e)
i.specifications[0].add_applicability(m) i.specifications[0].add_applicability(m)
@@ -276,12 +276,12 @@ class TestIdsAuthoring(unittest.TestCase):
def test_create_full_information(self): def test_create_full_information(self):
i = ids.ids( i = ids.ids(
ifcversion="2.3.0.1", title="Test IDS",
description="test", description="test",
author="test@test.com", author="test@test.com",
copyright="test", copyright="test",
version=1.23, version=1.23,
creation_date="2021-01-01", date="2021-01-01",
purpose="test", purpose="test",
milestone="test", milestone="test",
) )
@@ -302,15 +302,15 @@ class TestIfcValidation(unittest.TestCase):
def test_validate_all_facets(self): def test_validate_all_facets(self):
#Those are true: #Those are true:
e = ids.entity.create(name="IfcWall") e = ids.entity.create(name="IfcWall")
p1 = ids.property.create(location="any", propertyset="MySet", name="Param1", value="banan") p1 = ids.property.create(location="any", propertySet="MySet", name="Param1", value="banan")
p2 = ids.property.create(location="any", propertyset="MySet", name="Param2", value=120.0) p2 = ids.property.create(location="any", propertySet="MySet", name="Param2", value=120.0)
p3 = ids.property.create(location="any", propertyset="Pset_WallCommon", name="LoadBearing", value=False) p3 = ids.property.create(location="any", propertySet="Pset_WallCommon", name="LoadBearing", value=False)
#Those are false: #Those are false:
p4 = ids.property.create(location="any", propertyset="MySet", name="Param1", value="orange") p4 = ids.property.create(location="any", propertySet="MySet", name="Param1", value="orange")
p5 = ids.property.create(location="any", propertyset="MySet", name="Param2", value=123.4) p5 = ids.property.create(location="any", propertySet="MySet", name="Param2", value=123.4)
p6 = ids.property.create(location="any", propertyset="Pset_WallCommon", name="LoadBearing", value=True) p6 = ids.property.create(location="any", propertySet="Pset_WallCommon", name="LoadBearing", value=True)
i = ids.ids() i = ids.ids(title="My IDS")
i.specifications.append(ids.specification(name="Test_Specification")) i.specifications.append(ids.specification(name="Test_Specification"))
i.specifications[0].add_applicability(e) i.specifications[0].add_applicability(e)
i.specifications[0].add_requirement(p1) i.specifications[0].add_requirement(p1)