1
- #------------------------------------------------------------------------------#
2
- # hsd-python: package for manipulating HSD-formatted data in Python #
3
- # Copyright (C) 2011 - 2021 DFTB+ developers group #
4
- # Licensed under the BSD 2-clause license. #
5
- #------------------------------------------------------------------------------#
1
+ #-------------------------------------------------------------------------------------------------- #
2
+ # hsd-python: package for manipulating HSD-formatted data in Python #
3
+ # Copyright (C) 2011 - 2021 DFTB+ developers group #
4
+ # Licensed under the BSD 2-clause license. #
5
+ #-------------------------------------------------------------------------------------------------- #
6
6
#
7
7
"""
8
8
Contains an event-driven builder for dictionary based (JSON-like) structure
9
9
"""
10
10
import re
11
11
from typing import List , Tuple , Union
12
- from hsd .common import np , ATTRIB_SUFFIX , HSD_ATTRIB_SUFFIX , HsdError ,\
12
+ from hsd .common import HSD_ATTRIB_NAME , np , ATTRIB_SUFFIX , HSD_ATTRIB_SUFFIX , HsdError ,\
13
13
QUOTING_CHARS , SPECIAL_CHARS
14
14
from hsd .eventhandler import HsdEventHandler , HsdEventPrinter
15
15
@@ -42,14 +42,16 @@ class HsdDictBuilder(HsdEventHandler):
42
42
43
43
Args:
44
44
flatten_data: Whether multiline data in the HSD input should be
45
- flattened into a single list. Othewise a list of lists is created,
46
- with one list for every line (default).
47
- include_hsd_attribs: Whether the HSD-attributes (processing related
48
- attributes, like original tag name, line information, etc.) should
49
- be stored.
45
+ flattened into a single list. Othewise a list of lists is created, with one list for
46
+ every line (default).
47
+ lower_tag_names: Whether tag names should be all converted to lower case (to ease case
48
+ insensitive processing). Default: False. If set and include_hsd_attribs is also set,
49
+ the original tag names can be retrieved from the "name" hsd attributes.
50
+ include_hsd_attribs: Whether the HSD-attributes (processing related attributes, like
51
+ original tag name, line information, etc.) should be stored (default: False).
50
52
"""
51
53
52
- def __init__ (self , flatten_data : bool = False ,
54
+ def __init__ (self , flatten_data : bool = False , lower_tag_names : bool = False ,
53
55
include_hsd_attribs : bool = False ):
54
56
super ().__init__ ()
55
57
self ._hsddict : dict = {}
@@ -58,6 +60,7 @@ def __init__(self, flatten_data: bool = False,
58
60
self ._data : Union [None , _DataType ] = None
59
61
self ._attribs : List [Tuple [str , dict ]] = []
60
62
self ._flatten_data : bool = flatten_data
63
+ self ._lower_tag_names : bool = lower_tag_names
61
64
self ._include_hsd_attribs : bool = include_hsd_attribs
62
65
63
66
@@ -79,35 +82,49 @@ def open_tag(self, tagname, attrib, hsdattrib):
79
82
def close_tag (self , tagname ):
80
83
attrib , hsdattrib = self ._attribs .pop (- 1 )
81
84
parentblock = self ._parentblocks .pop (- 1 )
85
+ key = tagname .lower () if self ._lower_tag_names else tagname
82
86
prevcont = parentblock .get (tagname )
83
- if prevcont is not None :
84
- if isinstance (prevcont , dict ) and self ._data is None :
85
- prevcont = [prevcont ]
86
- parentblock [tagname ] = prevcont
87
- elif not (isinstance (prevcont , list )
88
- and isinstance (prevcont [0 ], dict )):
89
- msg = f"Invalid duplicate occurance of node '{ tagname } '"
90
- raise HsdError (msg )
91
-
92
- if prevcont is None :
93
- content = self ._data if self ._data is not None else self ._curblock
94
- parentblock [tagname ] = content
95
- if attrib :
96
- parentblock [tagname + ATTRIB_SUFFIX ] = attrib
97
- if self ._include_hsd_attribs :
98
- parentblock [tagname + HSD_ATTRIB_SUFFIX ] = hsdattrib
87
+
88
+ if self ._data is not None :
89
+ if prevcont is None :
90
+ parentblock [key ] = self ._data
91
+ elif isinstance (prevcont , list ) and len (prevcont ) > 0 and isinstance (prevcont [0 ], dict ):
92
+ prevcont .append ({None : self ._data })
93
+ elif isinstance (prevcont , dict ):
94
+ parentblock [key ] = [prevcont , {None : self ._data }]
95
+ else :
96
+ parentblock [key ] = [{None : prevcont }, {None : self ._data }]
99
97
else :
100
- prevcont .append (self ._curblock )
101
- prevattrib = parentblock .get (tagname + ATTRIB_SUFFIX )
102
- if not (prevattrib is None and attrib is None ):
103
- msg = f"Duplicate node '{ tagname } ' should not carry attributes"
104
- if self ._include_hsd_attribs :
105
- prevhsdattrib = parentblock .get (tagname + HSD_ATTRIB_SUFFIX )
98
+ if prevcont is None :
99
+ parentblock [key ] = self ._curblock
100
+ elif isinstance (prevcont , list ) and len (prevcont ) > 0 and isinstance (prevcont [0 ], dict ):
101
+ prevcont .append (self ._curblock )
102
+ elif isinstance (prevcont , dict ):
103
+ parentblock [key ] = [prevcont , self ._curblock ]
104
+ else :
105
+ parentblock [key ] = [{None : prevcont }, self ._curblock ]
106
+
107
+ if attrib and prevcont is None :
108
+ parentblock [key + ATTRIB_SUFFIX ] = attrib
109
+ elif prevcont is not None :
110
+ prevattrib = parentblock .get (key + ATTRIB_SUFFIX )
111
+ if isinstance (prevattrib , list ):
112
+ prevattrib .append (attrib )
113
+ else :
114
+ parentblock [key + ATTRIB_SUFFIX ] = [prevattrib , attrib ]
115
+
116
+ if self ._include_hsd_attribs :
117
+ if self ._lower_tag_names :
118
+ hsdattrib = {} if hsdattrib is None else hsdattrib
119
+ hsdattrib [HSD_ATTRIB_NAME ] = tagname
120
+ if prevcont is None :
121
+ parentblock [key + HSD_ATTRIB_SUFFIX ] = hsdattrib
122
+ else :
123
+ prevhsdattrib = parentblock .get (key + HSD_ATTRIB_SUFFIX )
106
124
if isinstance (prevhsdattrib , list ):
107
125
prevhsdattrib .append (hsdattrib )
108
126
else :
109
- parentblock [tagname + HSD_ATTRIB_SUFFIX ] = [prevhsdattrib ,
110
- hsdattrib ]
127
+ parentblock [key + HSD_ATTRIB_SUFFIX ] = [prevhsdattrib , hsdattrib ]
111
128
self ._curblock = parentblock
112
129
self ._data = None
113
130
@@ -189,8 +206,12 @@ def walk(self, dictobj):
189
206
elif isinstance (value , list ) and value and isinstance (value [0 ], dict ):
190
207
for ind , item in enumerate (value ):
191
208
hsdattr = hsdattrib [ind ] if hsdattrib else None
192
- self ._eventhandler .open_tag (key , None , hsdattr )
193
- self .walk (item )
209
+ attr = attrib [ind ] if attrib else None
210
+ self ._eventhandler .open_tag (key , attr , hsdattr )
211
+ if None in item :
212
+ self ._eventhandler .add_text (_to_text (item [None ]))
213
+ else :
214
+ self .walk (item )
194
215
self ._eventhandler .close_tag (key )
195
216
196
217
else :
0 commit comments