Skip to content

Commit 81b2b55

Browse files
committed
mvd.validate_data() function to apply template rules to extracted data
1 parent ddd31f5 commit 81b2b55

File tree

2 files changed

+75
-5
lines changed

2 files changed

+75
-5
lines changed

__init__.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def __init__(self, tag, attribute, nodes, bind=None, optional=False):
1313

1414
def to_string(self, indent=0):
1515
# return "%s%s%s[%s](%s%s)%s" % ("\n" if indent else "", " "*indent, self.tag, self.attribute, "".join(n.to_string(indent+2) for n in self.nodes), ("\n" + " "*indent) if len(self.nodes) else "", (" -> %s" % self.bind) if self.bind else "")
16-
return "<Rule %s %s>" % (self.tag, self.attribute)
16+
return "<%s %s%s>" % (self.tag, f"{self.bind}=" if self.bind else "", self.attribute)
1717

1818
def __repr__(self):
1919
return self.to_string()
@@ -23,8 +23,8 @@ class template(object):
2323
Representation of an mvdXML template
2424
"""
2525

26-
def __init__(self, concept, root, constraints=None, rules=None):
27-
self.concept, self.root, self.constraints = concept, root, (constraints or [])
26+
def __init__(self, concept, root, constraints=None, rules=None, parent=None):
27+
self.concept, self.root, self.constraints, self.parent = concept, root, (constraints or []), parent
2828
self.rules = rules or []
2929
self.entity = str(root.attributes['applicableEntity'].value)
3030
try:
@@ -58,7 +58,7 @@ def visit(n, p=root, ps=[root]):
5858
visit(r)
5959

6060
def parse_rule(self, root, visited=None):
61-
def visit(node, prefix="", visited=None):
61+
def visit(node, prefix="", visited=None, parent=None):
6262
r = None
6363
n = node
6464
nm = None
@@ -112,7 +112,10 @@ def _(n):
112112
for x in visit(subnode, p, visited=visited): yield x
113113

114114
if r:
115-
yield rule(node.localName, r, list(_(n)), (p + nm) if nm else nm, optional=optional)
115+
R = rule(node.localName, r, list(_(n)), (p + nm) if nm else nm, optional=optional)
116+
for rr in R.nodes:
117+
rr.parent = R
118+
yield R
116119
else:
117120
for subnode in n.childNodes:
118121
if not isinstance(subnode, Element): continue

mvd.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,5 +418,72 @@ def visualize(file, not_respecting_entities):
418418
ifcopenshell.geom.utils.main_loop()
419419

420420

421+
def validate_data(concept, data):
422+
import io
423+
import ast
424+
import operator
425+
from functools import reduce, partial
426+
427+
rules = [x[0] for x in concept.rules() if not isinstance(x, str)]
428+
429+
def transform_data(d):
430+
"""
431+
Transform dictionary keys from tree nodes to rule ids
432+
"""
433+
434+
return {(k.parent if k.bind is None and k.parent.bind is not None else k).bind: v for k, v in d.items()}
435+
436+
437+
def parse_mvdxml_token(v):
438+
# @todo make more permissive and tolerant
439+
return ast.literal_eval(v)
440+
441+
442+
data = list(map(transform_data, data))
443+
444+
output = io.StringIO()
445+
446+
# https://stackoverflow.com/a/70227259
447+
def operation_reduce(x, y):
448+
"""
449+
Takes alternating value and function as input and
450+
reduces while applying function
451+
"""
452+
453+
if callable(x):
454+
return x(y)
455+
else:
456+
return partial(y, x)
457+
458+
459+
def apply_rules():
460+
461+
for r in rules:
462+
463+
def apply_data():
464+
465+
for d in data:
466+
467+
def translate(v):
468+
if isinstance(v, str):
469+
return getattr(operator, v.lower() + "_")
470+
else:
471+
if v.b == "Value":
472+
return d[v.a] == parse_mvdxml_token(v.c)
473+
elif v.b == "Type":
474+
return d[v.a].is_a(parse_mvdxml_token(v.c))
475+
476+
r2 = list(map(translate, r))
477+
yield reduce(operation_reduce, r2)
478+
479+
v = any(list(apply_data()))
480+
print(("Met:" if v else "Not met:"), r, file=output)
481+
yield v
482+
483+
484+
valid = all(list(apply_rules()))
485+
return valid, output.getvalue()
486+
487+
421488
if __name__ == '__main__':
422489
print('functions to parse MVD rules and extract IFC data/filter IFC entities from them')

0 commit comments

Comments
 (0)