mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 15:08:51 +00:00
Fix #2745. You can now quote and escape complex pset names in the selector.
This commit is contained in:
@@ -35,9 +35,10 @@ class Selector:
|
|||||||
guid_selector: "#" /[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$]{22}/
|
guid_selector: "#" /[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$]{22}/
|
||||||
class_selector: "." WORD filter ?
|
class_selector: "." WORD filter ?
|
||||||
filter: "[" filter_key (comparison filter_value)? "]"
|
filter: "[" filter_key (comparison filter_value)? "]"
|
||||||
filter_key: WORD | pset_or_qto
|
filter_key: WORD | ESCAPED_STRING | keys_quoted | keys_simple
|
||||||
filter_value: ESCAPED_STRING | SIGNED_FLOAT | SIGNED_INT | BOOLEAN | NULL
|
filter_value: ESCAPED_STRING | SIGNED_FLOAT | SIGNED_INT | BOOLEAN | NULL
|
||||||
pset_or_qto: /[^\\W][^.=<>]*[^\\W]/ "." /[^\\W][^.=<>]*[^\\W]/
|
keys_quoted: ESCAPED_STRING "." ESCAPED_STRING
|
||||||
|
keys_simple: /[^\\W][^.=<>]*[^\\W]/ "." /[^\\W][^.=<>]*[^\\W]/
|
||||||
lfunction: and | or
|
lfunction: and | or
|
||||||
inverse_relationship: types | decomposed_by | bounded_by | grouped_by
|
inverse_relationship: types | decomposed_by | bounded_by | grouped_by
|
||||||
types: "*"
|
types: "*"
|
||||||
@@ -180,7 +181,13 @@ class Selector:
|
|||||||
results = []
|
results = []
|
||||||
key = filter_rule.children[0].children[0]
|
key = filter_rule.children[0].children[0]
|
||||||
if not isinstance(key, str):
|
if not isinstance(key, str):
|
||||||
key = key.children[0] + "." + key.children[1]
|
k0 = key.children[0]
|
||||||
|
if k0.type == "ESCAPED_STRING":
|
||||||
|
k0 = k0[1:-1].replace("\\\"", '"')
|
||||||
|
k1 = key.children[1]
|
||||||
|
if k1.type == "ESCAPED_STRING":
|
||||||
|
k1 = k1[1:-1].replace("\\\"", '"')
|
||||||
|
key = [k0, k1]
|
||||||
comparison = value = None
|
comparison = value = None
|
||||||
if len(filter_rule.children) > 1:
|
if len(filter_rule.children) > 1:
|
||||||
comparison = filter_rule.children[1].children[0].data
|
comparison = filter_rule.children[1].children[0].data
|
||||||
@@ -210,56 +217,29 @@ class Selector:
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_element_value(cls, element, key, value=None):
|
def get_element_value(cls, element, keys, value=None):
|
||||||
if "." in key and key.split(".")[0] == "type":
|
if not isinstance(keys, (tuple, list)):
|
||||||
try:
|
keys = [keys]
|
||||||
element = ifcopenshell.util.element.get_type(element)
|
value = element
|
||||||
if not element:
|
for key in keys:
|
||||||
return None
|
if key == "type":
|
||||||
except:
|
value = ifcopenshell.util.element.get_type(element)
|
||||||
return
|
elif key == "material":
|
||||||
key = ".".join(key.split(".")[1:])
|
value = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
|
||||||
elif "." in key and key.split(".")[0] == "material":
|
elif key == "container":
|
||||||
try:
|
value = ifcopenshell.util.element.get_container(element)
|
||||||
material_definition = ifcopenshell.util.element.get_material(
|
elif isinstance(value, ifcopenshell.entity_instance):
|
||||||
element, should_skip_usage=True
|
result = value.get_info().get(key, None)
|
||||||
)
|
if result is not None:
|
||||||
if not material_definition:
|
return result
|
||||||
return None
|
result = ifcopenshell.util.element.get_pset(value, key)
|
||||||
key = ".".join(key.split(".")[1:])
|
if result is None:
|
||||||
if value:
|
value = None
|
||||||
materials = [
|
else:
|
||||||
inst
|
value = result
|
||||||
for inst in cls.file.traverse(material_definition)
|
elif isinstance(value, dict): # Such as from the result of a prior get_pset
|
||||||
if inst.is_a("IfcMaterial")
|
return value.get(key, None)
|
||||||
]
|
return value
|
||||||
for material in materials or []:
|
|
||||||
info = material.get_info()
|
|
||||||
if key in info and info[key] == value:
|
|
||||||
element = material
|
|
||||||
element = material_definition
|
|
||||||
if not element:
|
|
||||||
return None
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
elif "." in key and key.split(".")[0] == "container":
|
|
||||||
try:
|
|
||||||
element = ifcopenshell.util.element.get_container(element)
|
|
||||||
if not element:
|
|
||||||
return None
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
key = ".".join(key.split(".")[1:])
|
|
||||||
info = element.get_info()
|
|
||||||
if key in info:
|
|
||||||
return info[key]
|
|
||||||
elif "." in key:
|
|
||||||
key_components = key.split(".")
|
|
||||||
pset_name = key_components[0]
|
|
||||||
prop = ".".join(key_components[1:])
|
|
||||||
psets = ifcopenshell.util.element.get_psets(element)
|
|
||||||
if pset_name in psets and prop in psets[pset_name]:
|
|
||||||
return psets[pset_name][prop]
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def filter_element(cls, element, element_value, comparison, value):
|
def filter_element(cls, element, element_value, comparison, value):
|
||||||
|
|||||||
@@ -145,6 +145,18 @@ class TestSelector(test.bootstrap.IFC4):
|
|||||||
self.file, '.IfcElement[a !%$§&/()?|*-+,€~#@µ^°a.a !%$§&/()?|*-+,€~#@µ^°a="Bar"]'
|
self.file, '.IfcElement[a !%$§&/()?|*-+,€~#@µ^°a.a !%$§&/()?|*-+,€~#@µ^°a="Bar"]'
|
||||||
) == [element]
|
) == [element]
|
||||||
|
|
||||||
|
def test_selecting_a_property_which_includes_a_dot(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
|
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="a.b")
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"c.d": "Bar"})
|
||||||
|
assert subject.Selector.parse(self.file, '.IfcElement["a.b"."c.d"="Bar"]') == [element]
|
||||||
|
|
||||||
|
def test_selecting_a_property_which_includes_an_escaped_quote(self):
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
|
pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name='"a.b"')
|
||||||
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={'"c.d"': "Bar"})
|
||||||
|
assert subject.Selector.parse(self.file, r'.IfcElement["\"a.b\""."\"c.d\""="Bar"]') == [element]
|
||||||
|
|
||||||
def test_comparing_if_value_is_in_a_list(self):
|
def test_comparing_if_value_is_in_a_list(self):
|
||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
element.Name = "Foobar"
|
element.Name = "Foobar"
|
||||||
|
|||||||
Reference in New Issue
Block a user