@@ -191,25 +191,19 @@ def __str__(self) -> str:
191
191
192
192
def json (self , ** kwargs ) -> dict :
193
193
if isinstance (self .context , TimeFrameContext ):
194
- start_date = self .context .start_date
195
- end_date = self .context .end_date
194
+ period : str = f"{ self .context .start_date } /{ self .context .end_date } "
196
195
elif isinstance (self .context , InstantContext ):
197
- start_date = self .context .instant_date
198
- end_date = self .context .instant_date
196
+ period : str = str (self .context .instant_date )
199
197
else :
200
- start_date = '' ,
201
- end_date = ''
198
+ period : str = '' # Forever context not specified in REC-2021-10-13
202
199
203
200
kwargs ['value' ] = self .value
204
- kwargs ['start_date' ] = str (start_date )
205
- kwargs ['end_date' ] = str (end_date )
206
- kwargs ["taxonomy" ] = self .concept .schema_url
207
- kwargs ['concept' ] = self .concept .name
208
- kwargs ["entity" ] = self .context .entity
209
- if len (self .context .segments ) != 0 :
210
- kwargs ['dimensions' ] = []
211
- for segment in self .context .segments :
212
- kwargs ['dimensions' ].append ({"axis" : segment .dimension .name , "member" : segment .member .name })
201
+ if 'dimensions' not in kwargs : kwargs ['dimensions' ] = {}
202
+ kwargs ['dimensions' ]['concept' ] = self .concept .name
203
+ kwargs ['dimensions' ]['entity' ] = self .context .entity
204
+ kwargs ['dimensions' ]['period' ] = period
205
+ for segment in self .context .segments :
206
+ kwargs ['dimensions' ][segment .dimension .name ] = segment .member .name
213
207
return kwargs
214
208
215
209
@@ -236,7 +230,7 @@ def __init__(self, concept: Concept, context: AbstractContext, value: float or N
236
230
self .decimals : int or None = decimals
237
231
238
232
def json (self ) -> dict :
239
- return super ().json (unit = str (self .unit ))
233
+ return super ().json (dimensions = { "unit" : str (self .unit )}, decimals = self . decimals )
240
234
241
235
242
236
class TextFact (AbstractFact ):
@@ -292,26 +286,26 @@ def __str__(self) -> str:
292
286
file_name : str = self .instance_url .split ('/' )[- 1 ]
293
287
return "{} with {} facts" .format (file_name , len (self .facts ))
294
288
295
- def json (self , file_path : str = None ) -> str or None :
289
+ def json (self , file_path : str = None , override_fact_ids : bool = True ) -> str or None :
296
290
"""
297
291
Converts the instance document into json format
298
292
:param file_path: if a path is given the function will store the json there
293
+ :param override_fact_ids:
299
294
:return: string (serialized json) or None (if file_path was given)
300
295
301
- https://www.xbrl.org/Specification/xbrl-json/CR-2017-05-02/xbrl-json-CR-2017-05-02.html
302
- https://www.xbrl.org/Specification/xbrl-json/CR-2021-07-07/xbrl-json-CR-2021-07-07.html
303
- These two xbrl-json specification drafts are very different.
304
- The latter uses fact_id as keys in the fact dictionary. However many older reports have no fact id's.
305
- Additionally fact ids of iXBRL documents can be really really ugly (Hashes concatenated with UUIDs).
306
- Therefore i will design my own JSON structure until the Specification is finalized by XBRL International.
296
+ https://www.xbrl.org/Specification/xbrl-json/REC-2021-10-13/xbrl-json-REC-2021-10-13.html
307
297
"""
308
298
json_dict : dict = {
309
- "instance_url" : self .instance_url ,
310
- "taxonomy_urls" : self .taxonomy .get_schema_urls (),
311
- "facts" : []
299
+ "facts" : {},
300
+ "documentInfo" : {
301
+ "documentType" : "https://xbrl.org/2021/xbrl-json" ,
302
+ "taxonomy" : self .taxonomy .get_schema_urls (),
303
+ "baseUrl" : self .instance_url
304
+ }
312
305
}
313
- for fact in self .facts :
314
- json_dict ['facts' ].append (fact .json ())
306
+ for i , fact in enumerate (self .facts ):
307
+ fact_id = fact .xml_id if fact .xml_id and not override_fact_ids else f'f{ i } '
308
+ json_dict ['facts' ][fact_id ] = fact .json ()
315
309
if file_path :
316
310
with open ('data.json' , 'w' ) as f :
317
311
return json .dump (json_dict , f )
0 commit comments