@@ -52,7 +52,7 @@ def token(value: mvdxml_expression.node | str) -> str:
5252}
5353
5454
55- def _rule (parent : ET .Element , value : rule ) -> None :
55+ def _rule (parent : ET .Element , value : rule , referenced : list [ tuple [ str , template ]] ) -> None :
5656 attributes : dict [str , str ] = {}
5757 if value .tag == "AttributeRule" :
5858 attributes = {"AttributeName" : str (value .attribute )}
@@ -67,12 +67,30 @@ def _rule(parent: ET.Element, value: rule) -> None:
6767
6868 element = _add (parent , value .tag , ** attributes )
6969 for tag , children in groupby (value .nodes , key = lambda child : child .tag ):
70+ if value .tag == "EntityRule" and tag == "EntityRule" :
71+ # Consecutive entity rules are an in-memory type restriction.
72+ # Write them as partial-template references in mvdXML.
73+ container = _add (element , "References" )
74+ for child in children :
75+ identifier = str (uuid .uuid4 ())
76+ _add (container , "Template" , ref = identifier )
77+ referenced .append (
78+ (identifier , template (child .attribute , None , child .nodes ))
79+ )
80+ continue
7081 container = _add (element , _CONTAINERS [tag ])
7182 for child in children :
72- _rule (container , child )
83+ _rule (container , child , referenced )
7384
7485
75- def _template (parent : ET .Element , value : template , identifier : str ) -> None :
86+ def _template (
87+ parent : ET .Element ,
88+ value : template ,
89+ identifier : str ,
90+ referenced : list [tuple [str , template ]],
91+ * ,
92+ partial : bool = False ,
93+ ) -> None :
7694 element = _add (
7795 parent ,
7896 "ConceptTemplate" ,
@@ -81,11 +99,12 @@ def _template(parent: ET.Element, value: template, identifier: str) -> None:
8199 status = "sample" ,
82100 applicableSchema = "IFC4" ,
83101 applicableEntity = value .entity ,
102+ isPartial = "true" if partial else None ,
84103 )
85104 if value .rules :
86105 rules = _add (element , "Rules" )
87106 for item in value .rules :
88- _rule (rules , item )
107+ _rule (rules , item , referenced )
89108
90109
91110def _key (value : template ) -> str | int :
@@ -138,8 +157,15 @@ def serialize(items: Iterable[mvd_item], destination: str | Path) -> None:
138157 {"uuid" : str (uuid .uuid4 ()), "name" : "" , "status" : "sample" },
139158 )
140159 template_elements = _add (document , "Templates" )
160+ referenced : list [tuple [str , template ]] = []
141161 for key , value in templates .items ():
142- _template (template_elements , value , template_ids [key ])
162+ _template (template_elements , value , template_ids [key ], referenced )
163+ # Serializing a partial template can discover further specializations.
164+ index = 0
165+ while index < len (referenced ):
166+ identifier , value = referenced [index ]
167+ _template (template_elements , value , identifier , referenced , partial = True )
168+ index += 1
143169
144170 roots = [item for item in parsed if isinstance (item , concept_root )]
145171 if roots :
0 commit comments