diff --git a/JsonPreprocessor/CJsonPreprocessor.py b/JsonPreprocessor/CJsonPreprocessor.py index e3b2c33c..4d0583bd 100644 --- a/JsonPreprocessor/CJsonPreprocessor.py +++ b/JsonPreprocessor/CJsonPreprocessor.py @@ -48,31 +48,32 @@ import os import json import re +import sys +import platform class CSyntaxType(): python = "python" json = "json" -NUMBER_RE = re.compile( +class CPythonJSONDecoder(json.JSONDecoder): + """ +**Method: PythonJSONDecoder** + Add python data types and syntax to json. ``True``, ``False`` and ``None`` will be a accepted as json syntax elements. + +**Args:** + **json.JSONDecoder** (*object*) + Decoder object provided by ``json.loads`` + """ + + NUMBER_RE = re.compile( r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?', (re.VERBOSE | re.MULTILINE | re.DOTALL)) -class CPythonJSONDecoder(json.JSONDecoder): - """ Add below python values when scanning json data - - +---------------+-------------------+ - | True | True | - +---------------+-------------------+ - | False | False | - +---------------+-------------------+ - | None | None | - +---------------+-------------------+ - """ - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.scan_once = self.custom_scan_once + self.scan_once = self.custom_scan_once - def _custom_scan_once(self, string, idx): + def _custom_scan_once(self, string :str, idx: int) -> any: try: nextchar = string[idx] except IndexError: @@ -98,7 +99,7 @@ def _custom_scan_once(self, string, idx): elif nextchar == 'F' and string[idx:idx + 5] == 'False': return False, idx + 5 - m = NUMBER_RE.match(string, idx) + m = CPythonJSONDecoder.NUMBER_RE.match(string, idx) if m is not None: integer, frac, exp = m.groups() if frac or exp: @@ -115,105 +116,212 @@ def _custom_scan_once(self, string, idx): else: raise StopIteration(idx) - def custom_scan_once(self, string, idx): + def custom_scan_once(self, string : str, idx : int) -> any: try: return self._custom_scan_once(string, idx) finally: self.memo.clear() class CJsonPreprocessor(): - ''' - CJsonPreprocessor helps to handle configuration file as json format: - - Allow comment within json file - - Allow import json file within json file - ''' - def __init__(self, syntax=CSyntaxType.json, currentCfg={}): + """ +CJsonPreprocessor extends the syntax of json. + +Features are + +- Allow c/c++-style comments within json files. + + // single line or part of single line and /\* \*/ multline comments are possible + +- Allow to import json files into json files + + ``"[import]" : "relative/absolute path"``, imports another json file to exactly this location. + + ``%envariable%`` and ``${envariable}`` can be used, too. + +- Allow use of variables within json files + + In any place the syntax ``${basenode.subnode. ... nodename}`` allows to reference an already existing variable. + + Example: + + .. code:: json + + { + "basenode" : { + subnode : { + "myparam" : 5 + }, + + }, + + "myVar" : "${basenode.subnode.myparam}" + } + +- Allow python data types ``True``, ``False`` and ``None`` + """ + + def __init__(self, syntax: CSyntaxType = CSyntaxType.json , currentCfg : dict = {}) -> None: + """ +**Method: __init__** + Constructor + +**Args:** + **syntax** (*CSyntaxType*) optional + default: `json` , `python` + If set to `python`, then python data types are allowed as part of json file. + + **currentCfg** (*dict*) optional + Internally used to aggregate imported json files. + """ self.lImportedFiles = [] self.recursive_level = 0 self.syntax = syntax self.currentCfg = currentCfg self.lUpdatedParams = [] + + def __sNormalizePath(self, sPath : str) -> str: + """ +**Method: __sNormalizePath** + Python struggles with + + - UNC paths + e.g. ``\\hi-z4939\ccstg\....`` + - escape sequences in windows paths + e.g. ``c:\autotest\tuner \t`` will be interpreted as tab, the result + after processing it with an regexp would be ``c:\autotest uner`` + + In order to solve this problems any slash will be replaced from backslash + to slash, only the two UNC backslashes must be kept if contained. + +**Args:** + **sPath** (*string*) + Absolute or relative path as input. + + Allows environment variables with ``%variable%`` or ``${variable}`` syntax. + +**Returns:** + **sPath** (*string*) + normalized path as string + """ + # make all backslashes to slash, but mask + # UNC indicator \\ before and restore after. + def __mkslash(sPath : str) -> str: + if sPath.strip()=='': + return '' + + sNPath=re.sub(r"\\\\",r"#!#!#",sPath.strip()) + sNPath=re.sub(r"\\",r"/",sNPath) + sNPath=re.sub(r"#!#!#",r"\\\\",sNPath) + + return sNPath + if sPath.strip()=='': + return '' + + # TML Syntax uses %Name%-syntax to reference an system- or framework + # environment variable. Linux requires ${Name} to do the same. + # Therefore change on Linux systems to ${Name}-syntax to make + # expandvars working here, too. + # This makes same TML code working on both platforms + if platform.system().lower()!="windows": + sPath=re.sub("%(.*?)%","${\\1}",sPath) + + #in a windows system normpath turns all slashes to backslash + #this is unwanted. Therefore turn back after normpath execution. + sNPath=os.path.normpath(os.path.expandvars(sPath.strip())) + #make all backslashes to slash, but mask + #UNC indicator \\ before and restore after. + sNPath=__mkslash(sNPath) + + return sNPath - ''' - Method: __processImportFiles this is custom decorder of object_pairs_hook function. - This method helps to import json file which is provided in '[import]' keyword into current json file. - Returns: - Dictionary is parsed from json file. - ''' - def __processImportFiles(self, input_data): + + def __processImportFiles(self, input_data : dict) -> dict: + ''' +**Method: __processImportFiles** + this is a custom decorder of ``json.loads object_pairs_hook`` function. + + This method helps to import json files which are provided in ``"[import]"`` keyword into the current json file. + +**Args:** + **input_data** (*dict*) + dictionary from json file as input + +**Returns:** + **out_dict** (*dict*) + dictionary as output + + dictionary is extended if ``"[import]"`` found and properly imported. + ''' out_dict = {} + for key, value in input_data: if re.match('^\s*\[\s*import\s*\]\s*', key.lower()): abs_path_file = os.path.abspath(value) - + # Use recursive_level and lImportedFiles to avoid cyclic import self.recursive_level = self.recursive_level + 1 # increase recursive level + # length of lImportedFiles should equal to recursive_level self.lImportedFiles = self.lImportedFiles[:self.recursive_level] if abs_path_file in self.lImportedFiles: - raise Exception('Cyclic imported json file \'%s\'' %str(abs_path_file)) + raise Exception(f"Cyclic imported json file '{abs_path_file}'!") - oJsonImport = self.jsonLoad(value, masterFile=False) + oJsonImport = self.jsonLoad(abs_path_file, masterFile=False) out_dict.update(oJsonImport) + self.recursive_level = self.recursive_level - 1 # descrease recursive level else: out_dict[key] = value return out_dict - ''' - Method: __removeComments loads json config file which allows comments inside - Args: - jsonFile: string - Returns: - lJsonData: list, list of string data from jsonFile after removing comment(s). - ''' - def __removeComments(self, jsonFile): - jsonPath = '' - if '/' in jsonFile: - for item in jsonFile.split('/')[:-1]: - jsonPath += item + '/' - else: - for item in jsonFile.split('\\')[:-1]: - jsonPath += item + '\\' + def __load_and_removeComments(self, jsonFile : str) -> str: + """ +**Method: __load_and_removeComments** + loads a given json file and filters all C/C++ style comments. + +**Args:** + **jsonFile** (*string*) + path (absolute/relative/) file to be processed. + The path can contain windows/linux style environment variables. + + !ATTENTION! This is dangerous + +**Returns:** + **sContentCleaned** (*string*) + string version of json file after removing all comments. + """ + + def replacer(match): + s = match.group(0) + if s.startswith('/'): + return "" + else: + return s + file=open(jsonFile,mode='r') + sContent=file.read() + file.close() + + pattern = re.compile(r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE) + sContentCleaned=re.sub(pattern, replacer, sContent) + + return sContentCleaned + + + def __nestedParamHandler(self, sInputStr : str) -> str: ''' - Removes comment parts in json file then store in temporary json file - ''' - lJsonData = [] +**Method: __nestedParamHandler** + This method handles nested variables in parameter names or values. Variable syntax is ${Variable_Name}. - with open(jsonFile) as fr: - for line in fr: - if re.match('^\s*//', line): - continue - elif '//' in line: - reEx1 = re.search("(\s*{*\s*\'.+\')\s*:\s*(\'.+\'\s*,*)*\s*(.*)", line) - if reEx1 is None: - reEx1 = re.search("(\s*{*\s*\".+\")\s*:\s*(\".+\"\s*,*)*\s*(.*)", line) - if reEx1 is None: - line = re.sub('//.*', '', line) - elif reEx1.group(1) is not None and reEx1.group(2) is not None: - line = reEx1.group(1) + ": " + reEx1.group(2) if reEx1.group(3) is None else \ - reEx1.group(1) + ": " + reEx1.group(2) + re.sub('//.*', '', reEx1.group(3)) - else: - reEx2 = re.search("(\s*{*\s*\'.+\')\s*:\s*(.+,*)\s*//\s*.*", line) - if reEx2 is None: - reEx2 = re.search("(\s*{*\s*\".+\")\s*:\s*(.+,*)\s*(//\s*.*)*", line) - if reEx2 is not None: - line = reEx2.group(1) + ": " + re.sub('//.*', '', reEx2.group(2)) - - lJsonData.append(line) - return lJsonData, jsonPath - - ''' - private __nestedParamHandler: This method handles the nested variable in param names or value - in updated json config file. - Args: - sInputStr: string - param name or value which contains nested variable - Returns: - sStrHandled: string - ''' - def __nestedParamHandler(self, sInputStr): +**Args:** + **sInputStr** (*string*) + Parameter name or value which contains a nested variable. + +**Returns:** + **sStrHandled** (*string*) + String which contains the resolved variable. + ''' #globals().update(currentCfg) referVars = re.findall('(\${\s*.*?\s*})', sInputStr) @@ -231,7 +339,7 @@ def __nestedParamHandler(self, sInputStr): exec(sExec, globals(), ldict) tmpValue = ldict['value'] except: - raise Exception('The variable %s is not available' % (var)) + raise Exception(f"The variable '{var}' is not available!") sInputStr = re.sub('\\' + var, tmpValue, sInputStr) if isinstance(tmpValue, str) else \ re.sub('\\' + var, str(tmpValue), sInputStr) continue @@ -247,7 +355,7 @@ def __nestedParamHandler(self, sInputStr): exec(sExec, globals(), ldict) tmpValue = ldict['value'] except: - raise Exception('The variable %s is not available!!!' % (fullVariable)) + raise Exception("fThe variable '{fullVariable}' is not available!") pattern = re.sub('\[', '\\[', fullVariable) pattern = re.sub('\]', '\\]', pattern) sInputStr = re.sub('\\' + pattern, '\'' + tmpValue + '\'', sInputStr) if isinstance(tmpValue, str) else \ @@ -271,16 +379,22 @@ def __nestedParamHandler(self, sInputStr): sStrHandled = fullVariable return sStrHandled - ''' - private __updateAndReplaceNestedParam: this method replaces all nested params in key and value of Json object - Args: - oJson: dict - currentCfg: dict - Returns: - oJsonOut: dict - ''' - def __updateAndReplaceNestedParam(self, oJson, recursive=False): - + + def __updateAndReplaceNestedParam(self, oJson : dict, recursive : bool = False): + ''' +**Method: __updateAndReplaceNestedParam** + This method replaces all nested parameters in key and value of a json object . + +**Args:** + **oJson** (*dict*) + Input Json object as dictionary. This dictionary will be searched for all ``${variable}`` occurences. + If found it will be replaced with it's current value. + +**Returns:** + **oJsonOut** (*dict*) + Output Json object as dictionary with all variables resolved. + ''' + if bool(self.currentCfg) and not recursive: for k, v in self.currentCfg.items(): globals().update({k:v}) @@ -301,7 +415,7 @@ def __updateAndReplaceNestedParam(self, oJson, recursive=False): try: exec(sExec, globals()) except: - raise Exception("Could not set variable \'%s\' with value \'%s\'" %(k, v)) + raise Exception(f"Could not set variable '{k}' with value '{v}'!") else: tmpJson[k] = v bNested = False @@ -321,7 +435,7 @@ def __updateAndReplaceNestedParam(self, oJson, recursive=False): v = ldict['value'] if v.strip()==valueAfterProcessed else \ v.replace(valueAfterProcessed, str(ldict['value'])) except: - raise Exception('The variable %s is not available!!!' % (tmpValueAfterProcessed)) + raise Exception(f"The variable '{tmpValueAfterProcessed}' is not available!") if bNested: if '[' in k: @@ -329,7 +443,7 @@ def __updateAndReplaceNestedParam(self, oJson, recursive=False): try: exec(sExec, globals()) except: - raise Exception("Could not set variable \'%s\' with value \'%s\'" %(k, v)) + raise Exception(f"Could not set variable '{k}' with value '{v}'!") else: tmpJson[k] = v bNested = False @@ -343,7 +457,7 @@ def __updateAndReplaceNestedParam(self, oJson, recursive=False): try: exec(sExec, globals()) except: - raise Exception("Could not set variable \'%s\' with value \'%s\'" %(k, v)) + raise Exception(f"Could not set variable '{k}' with value '{v}'!") else: tmpJson[k] = v @@ -353,43 +467,63 @@ def __updateAndReplaceNestedParam(self, oJson, recursive=False): return oJson - def jsonLoad(self, jFile, masterFile=True): + + def jsonLoad(self, jFile : str, masterFile : bool = True): ''' - Method: jsonLoad loads the json file then parses to dict object - - Args: - jFile: string, json file input - Returns: - oJson: dict +**Method: jsonLoad** + This function is the entry point of JsonPreprocessor. + + It loads the json file, preprocesses it and returns the preprocessed result as data structure. + +**Args:** + **jFile** (*string*) + relative/absolute path to main json file. + + ``%envvariable%`` and ``${envvariable}`` can be used, too in order to access environment variables. + +**Returns:** + **oJson** (*dict*) + preprocessed json file(s) as data structure ''' + jFile=jFile.strip() + + if not re.match("^[a-zA-Z]:",jFile) and not re.match("^[\\/]",jFile): + jFile=self.__sNormalizePath(os.path.dirname(sys.argv[0])+"/"+jFile) + + if not(os.path.isfile(jFile)): + raise Exception(f"File '{jFile}' is not existing!") + + self.lImportedFiles.append(os.path.abspath(jFile)) + (jsonPath,tail)=os.path.split(jFile) + try: - lJsonData, jsonPath = self.__removeComments(jFile) + sJsonData= self.__load_and_removeComments(os.path.abspath(jFile)) except Exception as reason: - raise Exception("Could not read json configuration file %s due to: %s \n\ - Please input 'utf-8' format in Json configuration file only" %(jFile, reason)) + raise Exception(f"Could not read json file '{jFile}' due to: '{reason}'!") + currentDir = os.getcwd() - self.lImportedFiles.append(os.path.abspath(jFile)) os.chdir(jsonPath) + CJSONDecoder = None if self.syntax != CSyntaxType.json: if self.syntax == CSyntaxType.python: CJSONDecoder = CPythonJSONDecoder else: - raise Exception('Provided syntax \'%s\' is not supported.' %self.syntax) + raise Exception(f"Provided syntax '{self.syntax}' is not supported.") try: - oJson = json.loads("\n".join(lJsonData), + oJson = json.loads(sJsonData, cls=CJSONDecoder , object_pairs_hook=self.__processImportFiles) except Exception as error: - raise Exception("JSON configuration file '%s': %s" %(jFile, error)) + raise Exception(f"json file '{jFile}': '{error}'") os.chdir(currentDir) + if masterFile: for k, v in oJson.items(): globals().update({k:v}) oJson = self.__updateAndReplaceNestedParam(oJson) - # oJson['JsonPath'] = jsonPath # is JsonPath required? return oJson \ No newline at end of file diff --git a/JsonPreprocessor/__init__.py b/JsonPreprocessor/__init__.py index 8043fb51..d897a8bb 100644 --- a/JsonPreprocessor/__init__.py +++ b/JsonPreprocessor/__init__.py @@ -11,4 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from .CJsonPreprocessor import CJsonPreprocessor \ No newline at end of file +from .CJsonPreprocessor import CJsonPreprocessor +from .CJsonPreprocessor import CSyntaxType + diff --git a/config/CConfig.py b/config/CConfig.py index 19b5e276..e040ea49 100644 --- a/config/CConfig.py +++ b/config/CConfig.py @@ -86,7 +86,7 @@ def __init__(self, sReferencePath="."): # 1. basic setup stuff self.__dictConfig['sPackageName'] = "JsonPreprocessor" - self.__dictConfig['sVersion'] = "0.1.0" + self.__dictConfig['sVersion'] = "0.2.0" self.__dictConfig['sAuthor'] = "Mai Dinh Nam Son" self.__dictConfig['sAuthorEMail'] = "son.maidinhnam@vn.bosch.com" self.__dictConfig['sDescription'] = "This package provides a preprocessor for json files" diff --git a/sample/001_sample_comments.py b/sample/001_sample_comments.py new file mode 100644 index 00000000..93018399 --- /dev/null +++ b/sample/001_sample_comments.py @@ -0,0 +1,37 @@ +# Copyright 2020-2022 Robert Bosch Car Multimedia GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################# + +## This example also shows how to use comments +## in json files. + +import sys + +sys.path.append('D:\B\python-jsonpreprocessor') + +from JsonPreprocessor import CJsonPreprocessor + +from pprint import pprint + +prepro=CJsonPreprocessor() + +# you can load the base json file with +# - relative path to your python program +# - absolute path +# - paths containting environment variables by means of +# %envvariable% syntax +data=prepro.jsonLoad(".\json\json_with_comment.json") + +pprint(data) + diff --git a/sample/003_sample_import.py b/sample/003_sample_import.py new file mode 100644 index 00000000..71aa1c94 --- /dev/null +++ b/sample/003_sample_import.py @@ -0,0 +1,37 @@ +# Copyright 2020-2022 Robert Bosch Car Multimedia GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################# + +## This example also shows how to import json files +## into json files. + +import sys + +sys.path.append('D:\B\python-jsonpreprocessor') + +from JsonPreprocessor import CJsonPreprocessor + +from pprint import pprint + +prepro=CJsonPreprocessor() + +# you can load the base json file with +# - relative path to your python program +# - absolute path +# - paths containting environment variables by means of +# %envvariable% syntax +data=prepro.jsonLoad(".\json\json_with_import.json") + +pprint(data) + diff --git a/sample/005_sample_python_syntax.py b/sample/005_sample_python_syntax.py new file mode 100644 index 00000000..48459831 --- /dev/null +++ b/sample/005_sample_python_syntax.py @@ -0,0 +1,40 @@ +# Copyright 2020-2022 Robert Bosch Car Multimedia GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################# + +## This example also shows how to use python-syntax +## as part of json files. + +import sys + +sys.path.append('D:\B\python-jsonpreprocessor') + +from JsonPreprocessor import CJsonPreprocessor +from JsonPreprocessor import CSyntaxType + +from pprint import pprint + +# CSyntaxType.python activates recognition of python +# syntax as part of json files +prepro=CJsonPreprocessor(syntax=CSyntaxType.python) + +# you can load the base json file with +# - relative path to your python program +# - absolute path +# - paths containting environment variables by means of +# %envvariable% syntax +data=prepro.jsonLoad(".\json\json_with_python_syntax.json") + +pprint(data) + diff --git a/sample/007_sample_use_of_variables.py b/sample/007_sample_use_of_variables.py new file mode 100644 index 00000000..e7b4023a --- /dev/null +++ b/sample/007_sample_use_of_variables.py @@ -0,0 +1,37 @@ +# Copyright 2020-2022 Robert Bosch Car Multimedia GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################# + +## This example also shows how to use comments +## in json files. + +import sys + +sys.path.append('D:\B\python-jsonpreprocessor') + +from JsonPreprocessor import CJsonPreprocessor + +from pprint import pprint + +prepro=CJsonPreprocessor() + +# you can load the base json file with +# - relative path to your python program +# - absolute path +# - paths containting environment variables by means of +# %envvariable% syntax +data=prepro.jsonLoad(".\json\json_with_variables.json") + +pprint(data) + diff --git a/sample/json/json_with_comment.json b/sample/json/json_with_comment.json new file mode 100644 index 00000000..97ba1a01 --- /dev/null +++ b/sample/json/json_with_comment.json @@ -0,0 +1,48 @@ +/*Copyright 2020-2022 Robert Bosch Car Multimedia GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +// You can write anywhere one line comments + +/* +This way you can +write anywhere multiline +comments +*/ + +{ + /* + This way you can + write anywhere multiline + comments + */ + + // You can write anywhere one line comments + "myVar1" : "val1", + + "myVar2" : "http://www.google.de", + "myVar3" : "val3", // You can write anywhere one line comments + "abc" : // You can write anywhere one line comments + { + /* + This way you can + write anywhere multiline + comments + */ + "myVar4" : "val4" + }, + "def" : + { + "myVar5" : "val5" // You can write anywhere one line comments + } +} \ No newline at end of file diff --git a/sample/json/json_with_import.json b/sample/json/json_with_import.json new file mode 100644 index 00000000..60bdc833 --- /dev/null +++ b/sample/json/json_with_import.json @@ -0,0 +1,52 @@ +/*Copyright 2020-2022 Robert Bosch Car Multimedia GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +/* +imports of json files are done by means of the +[import] keyword. + +All imported data will be replace the node which +has the [import] keyword. + +[import] can be done at any location in your json +data structure. This allows to structure big json files +into any architecture you require. +*/ +{ + "myVar1" : "val1", + + "myVar2" : "http://www.google.de", + "abc" : + { + /* + import of json files should be always a relative path + to the current file. This allows later to shift whole + json directories to other places without braking the + internal strucutre. + + All imported data will be located in this case below + node "abc" and replace the [import] node. + */ + "[import]" : "./second_file.json" + }, + "def" : + { + //All imported data will be located in this case below + //node "def" and replace the [import] node. + //this file is imported in this example two times as + //re-usable data structure. + //one time here, a second time in "second_file.json" + "[import]" : "./subfolder/third_file.json" + } +} \ No newline at end of file diff --git a/sample/json/json_with_python_syntax.json b/sample/json/json_with_python_syntax.json new file mode 100644 index 00000000..40522e76 --- /dev/null +++ b/sample/json/json_with_python_syntax.json @@ -0,0 +1,37 @@ +/*Copyright 2020-2022 Robert Bosch Car Multimedia GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ +{ + //instead of `true` you can use the python-syntax `True` + "myVar1" : True, + "myVar1_" : true, + + //instead of `frue` you can use the python-syntax `False` + "myVar2" : False, + "myVar2_" : false, + + //instead of `null` you can use the python-syntax `None` + "myVar3" : None, + "myVar3_" : null, + + "abc" : + { + //this is a string -> there is no change + "myVar4" : "True" + }, + "def" : + { + //this is a string -> there is no change + "myVar5" : "False" + } +} \ No newline at end of file diff --git a/sample/json/json_with_variables.json b/sample/json/json_with_variables.json new file mode 100644 index 00000000..59439a39 --- /dev/null +++ b/sample/json/json_with_variables.json @@ -0,0 +1,45 @@ +/*Copyright 2020-2022 Robert Bosch Car Multimedia GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +/* +every node can be used by means of ${node} syntax +as variable once it was defined. +This works also with [import] of json data. As per +order the [import ] appears in the code the nodes +can be referenced by means of ${syntax} as variable. + */ + +{ + // create some initial data + "myVar1" : "val1", + "myVar2" : "val2", + "abc" : { + "arList" : ["a","b","c"] + }, + + //give myVar3 the value of "myVar1" + "myVar3" : "${myVar1}", + + //give myVar4 the value of ${abc}['arList'][1] + "myVar4" : "${abc}['arList'][1]", + + //give myVar4 the value of ${abc}['arList'] + "myVar5" : "${abc}['arList']", + + //add a new entry to node "abc" + "${abc}['new_entry']" : "new_entry", + + //give myVar6 the value new value of node "abc" + "myVar6" : "${abc}" +} \ No newline at end of file diff --git a/sample/json/second_file.json b/sample/json/second_file.json new file mode 100644 index 00000000..e112566b --- /dev/null +++ b/sample/json/second_file.json @@ -0,0 +1,23 @@ +/*Copyright 2020-2022 Robert Bosch Car Multimedia GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ +{ + "second_myVar1" : true, + + //All imported data will be located in this case below + //the root node of this file. + //The import is done again relative to this file. + "[import]" : "./subfolder/third_file.json", + + "second_myVar2" : "http://www.ebay.de" +} \ No newline at end of file diff --git a/sample/json/subfolder/third_file.json b/sample/json/subfolder/third_file.json new file mode 100644 index 00000000..925ee1dd --- /dev/null +++ b/sample/json/subfolder/third_file.json @@ -0,0 +1,17 @@ +/*Copyright 2020-2022 Robert Bosch Car Multimedia GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ +{ + "third_myVar1" : "val1", + "third_myVar2" : "http://www.amazon.de" +} \ No newline at end of file