From dddff95212339569c2edbbde8228c43bf3eaea49 Mon Sep 17 00:00:00 2001 From: Andreas Lauser <andreas.lauser@mercedes-benz.com> Date: Thu, 5 Dec 2024 14:18:21 +0100 Subject: [PATCH 1/2] resolve SNREFs in comparam subsets and comparam specs since it seems that nobody ever tried to use odxtools with comparam subsets and comparam specs that use SNREFs, this did not crop up earlier... Signed-off-by: Andreas Lauser <andreas.lauser@mercedes-benz.com> Signed-off-by: Gerrit Ecke <gerrit.ecke@mercedes-benz.com> --- odxtools/database.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/odxtools/database.py b/odxtools/database.py index f8d81801..74b9edcd 100644 --- a/odxtools/database.py +++ b/odxtools/database.py @@ -20,6 +20,7 @@ from .exceptions import odxraise, odxrequire from .nameditemlist import NamedItemList from .odxlink import OdxLinkDatabase, OdxLinkId +from .snrefcontext import SnRefContext class Database: @@ -139,6 +140,16 @@ def refresh(self) -> None: for dlc in self.diag_layer_containers: dlc._resolve_odxlinks(self._odxlinks) + # resolve short name references for containers which do not do + # inheritance (we can call directly call _resolve_snrefs()) + context = SnRefContext() + context.database = self + + for subset in self.comparam_subsets: + subset._resolve_snrefs(context) + for spec in self.comparam_specs: + spec._resolve_snrefs(context) + # let the diaglayers sort out the inherited objects and the # short name references for dlc in self.diag_layer_containers: From 8361b71d7923410706eb74a766509d4b34f9746b Mon Sep 17 00:00:00 2001 From: Andreas Lauser <andreas.lauser@mercedes-benz.com> Date: Thu, 5 Dec 2024 12:44:40 +0100 Subject: [PATCH 2/2] Introduce `OdxCategory` The spec defines `OdxCategory` as the base for any top-level content tag in an ODX XML file. odxtools currently implements `DIAG-LAYER-CONTAINER`, `COMPARAM-SPEC` and `COMPARAM-SUBSET` (all of them are relevant for diagnostics based on UDS). Currently missing are the categories `ECU-CONFIG` (variant coding), `FLASH` (firmware blobs for flashing), `FUNCTION-DICTIONARY` (functionality distributed over multiple ECUs) and `MULTIPLE-ECU-JOB-SPEC` (multiple-ecu jobs). Signed-off-by: Andreas Lauser <andreas.lauser@mercedes-benz.com> Signed-off-by: Christian Hackenbeck <christian.hackenbeck@mercedes-benz.com> --- odxtools/comparamspec.py | 70 ++++------------ odxtools/comparamsubset.py | 81 +++++------------- odxtools/database.py | 13 ++- odxtools/diaglayercontainer.py | 54 ++++-------- odxtools/odxcategory.py | 83 +++++++++++++++++++ .../templates/comparam-spec.odx-c.xml.jinja2 | 25 +----- .../comparam-subset.odx-cs.xml.jinja2 | 26 +----- .../diag_layer_container.odx-d.xml.jinja2 | 29 +------ .../macros/printOdxCategory.xml.jinja2 | 28 +++++++ 9 files changed, 182 insertions(+), 227 deletions(-) create mode 100644 odxtools/odxcategory.py create mode 100644 odxtools/templates/macros/printOdxCategory.xml.jinja2 diff --git a/odxtools/comparamspec.py b/odxtools/comparamspec.py index d02f35b7..2cc93bfe 100644 --- a/odxtools/comparamspec.py +++ b/odxtools/comparamspec.py @@ -1,66 +1,39 @@ # SPDX-License-Identifier: MIT from dataclasses import dataclass -from typing import Any, Dict, List, Optional +from typing import TYPE_CHECKING, Any, Dict, List from xml.etree import ElementTree -from .admindata import AdminData -from .companydata import CompanyData -from .element import IdentifiableElement -from .exceptions import odxrequire from .nameditemlist import NamedItemList +from .odxcategory import OdxCategory from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId from .protstack import ProtStack from .snrefcontext import SnRefContext -from .specialdatagroup import SpecialDataGroup from .utils import dataclass_fields_asdict +if TYPE_CHECKING: + from .database import Database + @dataclass -class ComparamSpec(IdentifiableElement): - admin_data: Optional[AdminData] - company_datas: NamedItemList[CompanyData] - sdgs: List[SpecialDataGroup] +class ComparamSpec(OdxCategory): prot_stacks: NamedItemList[ProtStack] @staticmethod def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ComparamSpec": - short_name = odxrequire(et_element.findtext("SHORT-NAME")) - doc_frags = [OdxDocFragment(short_name, str(et_element.tag))] - kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags)) + cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="COMPARAM-SPEC") + doc_frags = cat.odx_id.doc_fragments + kwargs = dataclass_fields_asdict(cat) - admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags) - company_datas = NamedItemList([ - CompanyData.from_et(cde, doc_frags) - for cde in et_element.iterfind("COMPANY-DATAS/COMPANY-DATA") - ]) - sdgs = [ - SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG") - ] prot_stacks = NamedItemList([ ProtStack.from_et(dl_element, doc_frags) for dl_element in et_element.iterfind("PROT-STACKS/PROT-STACK") ]) - return ComparamSpec( - admin_data=admin_data, - company_datas=company_datas, - sdgs=sdgs, - prot_stacks=prot_stacks, - **kwargs) + return ComparamSpec(prot_stacks=prot_stacks, **kwargs) def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: - odxlinks: Dict[OdxLinkId, Any] = {} - odxlinks[self.odx_id] = self - - if self.admin_data is not None: - odxlinks.update(self.admin_data._build_odxlinks()) - - for cd in self.company_datas: - odxlinks.update(cd._build_odxlinks()) - - for sdg in self.sdgs: - odxlinks.update(sdg._build_odxlinks()) + odxlinks = super()._build_odxlinks() for ps in self.prot_stacks: odxlinks.update(ps._build_odxlinks()) @@ -68,27 +41,16 @@ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: return odxlinks def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: - if self.admin_data is not None: - self.admin_data._resolve_odxlinks(odxlinks) - - for cd in self.company_datas: - cd._resolve_odxlinks(odxlinks) - - for sdg in self.sdgs: - sdg._resolve_odxlinks(odxlinks) + super()._resolve_odxlinks(odxlinks) for ps in self.prot_stacks: ps._resolve_odxlinks(odxlinks) - def _resolve_snrefs(self, context: SnRefContext) -> None: - if self.admin_data is not None: - self.admin_data._resolve_snrefs(context) + def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None: + super()._finalize_init(database, odxlinks) - for cd in self.company_datas: - cd._resolve_snrefs(context) - - for sdg in self.sdgs: - sdg._resolve_snrefs(context) + def _resolve_snrefs(self, context: SnRefContext) -> None: + super()._resolve_snrefs(context) for ps in self.prot_stacks: ps._resolve_snrefs(context) diff --git a/odxtools/comparamsubset.py b/odxtools/comparamsubset.py index 5e6ecad8..2c27d44d 100644 --- a/odxtools/comparamsubset.py +++ b/odxtools/comparamsubset.py @@ -1,50 +1,41 @@ # SPDX-License-Identifier: MIT from dataclasses import dataclass -from typing import Any, Dict, List, Optional +from typing import TYPE_CHECKING, Any, Dict, List, Optional from xml.etree import ElementTree -from .admindata import AdminData -from .companydata import CompanyData from .comparam import Comparam from .complexcomparam import ComplexComparam from .dataobjectproperty import DataObjectProperty -from .element import IdentifiableElement -from .exceptions import odxrequire from .nameditemlist import NamedItemList +from .odxcategory import OdxCategory from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId from .snrefcontext import SnRefContext -from .specialdatagroup import SpecialDataGroup from .unitspec import UnitSpec from .utils import dataclass_fields_asdict +if TYPE_CHECKING: + from .database import Database + @dataclass -class ComparamSubset(IdentifiableElement): - # mandatory in ODX 2.2, but non existent in ODX 2.0 +class ComparamSubset(OdxCategory): + # mandatory in ODX 2.2, but non-existent in ODX 2.0 category: Optional[str] - data_object_props: NamedItemList[DataObjectProperty] + comparams: NamedItemList[Comparam] complex_comparams: NamedItemList[ComplexComparam] + data_object_props: NamedItemList[DataObjectProperty] unit_spec: Optional[UnitSpec] - admin_data: Optional[AdminData] - company_datas: NamedItemList[CompanyData] - sdgs: List[SpecialDataGroup] @staticmethod def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ComparamSubset": - category = et_element.get("CATEGORY") - - short_name = odxrequire(et_element.findtext("SHORT-NAME")) - doc_frags = [OdxDocFragment(short_name, str(et_element.tag))] - kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags)) + cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="COMPARAM-SUBSET") + doc_frags = cat.odx_id.doc_fragments + kwargs = dataclass_fields_asdict(cat) - admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags) - company_datas = NamedItemList([ - CompanyData.from_et(cde, doc_frags) - for cde in et_element.iterfind("COMPANY-DATAS/COMPANY-DATA") - ]) + category = et_element.get("CATEGORY") data_object_props = NamedItemList([ DataObjectProperty.from_et(el, doc_frags) @@ -61,25 +52,16 @@ def from_et(et_element: ElementTree.Element, else: unit_spec = None - sdgs = [ - SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG") - ] - return ComparamSubset( category=category, - admin_data=admin_data, - company_datas=company_datas, data_object_props=data_object_props, comparams=comparams, complex_comparams=complex_comparams, unit_spec=unit_spec, - sdgs=sdgs, **kwargs) def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: - odxlinks: Dict[OdxLinkId, Any] = {} - if self.odx_id is not None: - odxlinks[self.odx_id] = self + odxlinks = super()._build_odxlinks() for dop in self.data_object_props: odxlinks[dop.odx_id] = dop @@ -93,19 +75,11 @@ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: if self.unit_spec: odxlinks.update(self.unit_spec._build_odxlinks()) - if self.admin_data is not None: - odxlinks.update(self.admin_data._build_odxlinks()) - - if self.company_datas is not None: - for cd in self.company_datas: - odxlinks.update(cd._build_odxlinks()) - - for sdg in self.sdgs: - odxlinks.update(sdg._build_odxlinks()) - return odxlinks def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: + super()._resolve_odxlinks(odxlinks) + for dop in self.data_object_props: dop._resolve_odxlinks(odxlinks) @@ -118,17 +92,12 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: if self.unit_spec: self.unit_spec._resolve_odxlinks(odxlinks) - if self.admin_data is not None: - self.admin_data._resolve_odxlinks(odxlinks) - - if self.company_datas is not None: - for cd in self.company_datas: - cd._resolve_odxlinks(odxlinks) - - for sdg in self.sdgs: - sdg._resolve_odxlinks(odxlinks) + def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None: + super()._finalize_init(database, odxlinks) def _resolve_snrefs(self, context: SnRefContext) -> None: + super()._resolve_snrefs(context) + for dop in self.data_object_props: dop._resolve_snrefs(context) @@ -140,13 +109,3 @@ def _resolve_snrefs(self, context: SnRefContext) -> None: if self.unit_spec: self.unit_spec._resolve_snrefs(context) - - if self.admin_data is not None: - self.admin_data._resolve_snrefs(context) - - if self.company_datas is not None: - for cd in self.company_datas: - cd._resolve_snrefs(context) - - for sdg in self.sdgs: - sdg._resolve_snrefs(context) diff --git a/odxtools/database.py b/odxtools/database.py index 74b9edcd..991143e3 100644 --- a/odxtools/database.py +++ b/odxtools/database.py @@ -145,15 +145,20 @@ def refresh(self) -> None: context = SnRefContext() context.database = self + # let the diaglayers sort out the inherited objects + for subset in self.comparam_subsets: + subset._finalize_init(self, self._odxlinks) + for spec in self.comparam_specs: + spec._finalize_init(self, self._odxlinks) + for dlc in self.diag_layer_containers: + dlc._finalize_init(self, self._odxlinks) + for subset in self.comparam_subsets: subset._resolve_snrefs(context) for spec in self.comparam_specs: spec._resolve_snrefs(context) - - # let the diaglayers sort out the inherited objects and the - # short name references for dlc in self.diag_layer_containers: - dlc._finalize_init(self, self._odxlinks) + dlc._resolve_snrefs(context) def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: result: Dict[OdxLinkId, Any] = {} diff --git a/odxtools/diaglayercontainer.py b/odxtools/diaglayercontainer.py index de2d3c9d..e1c1c327 100644 --- a/odxtools/diaglayercontainer.py +++ b/odxtools/diaglayercontainer.py @@ -1,22 +1,19 @@ # SPDX-License-Identifier: MIT from dataclasses import dataclass from itertools import chain -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union +from typing import TYPE_CHECKING, Any, Dict, List, Union from xml.etree import ElementTree -from .admindata import AdminData -from .companydata import CompanyData from .diaglayers.basevariant import BaseVariant from .diaglayers.diaglayer import DiagLayer from .diaglayers.ecushareddata import EcuSharedData from .diaglayers.ecuvariant import EcuVariant from .diaglayers.functionalgroup import FunctionalGroup from .diaglayers.protocol import Protocol -from .element import IdentifiableElement -from .exceptions import odxrequire from .nameditemlist import NamedItemList +from .odxcategory import OdxCategory from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId -from .specialdatagroup import SpecialDataGroup +from .snrefcontext import SnRefContext from .utils import dataclass_fields_asdict if TYPE_CHECKING: @@ -24,15 +21,12 @@ @dataclass -class DiagLayerContainer(IdentifiableElement): - admin_data: Optional[AdminData] - company_datas: NamedItemList[CompanyData] +class DiagLayerContainer(OdxCategory): ecu_shared_datas: NamedItemList[EcuSharedData] protocols: NamedItemList[Protocol] functional_groups: NamedItemList[FunctionalGroup] base_variants: NamedItemList[BaseVariant] ecu_variants: NamedItemList[EcuVariant] - sdgs: List[SpecialDataGroup] @property def ecus(self) -> NamedItemList[EcuVariant]: @@ -54,17 +48,10 @@ def __post_init__(self) -> None: def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagLayerContainer": - short_name = odxrequire(et_element.findtext("SHORT-NAME")) - # create the current ODX "document fragment" (description of the - # current document for references and IDs) - doc_frags = [OdxDocFragment(short_name, "CONTAINER")] - kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags)) + cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="CONTAINER") + doc_frags = cat.odx_id.doc_fragments + kwargs = dataclass_fields_asdict(cat) - admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags) - company_datas = NamedItemList([ - CompanyData.from_et(cde, doc_frags) - for cde in et_element.iterfind("COMPANY-DATAS/COMPANY-DATA") - ]) ecu_shared_datas = NamedItemList([ EcuSharedData.from_et(dl_element, doc_frags) for dl_element in et_element.iterfind("ECU-SHARED-DATAS/ECU-SHARED-DATA") @@ -85,30 +72,17 @@ def from_et(et_element: ElementTree.Element, EcuVariant.from_et(dl_element, doc_frags) for dl_element in et_element.iterfind("ECU-VARIANTS/ECU-VARIANT") ]) - sdgs = [ - SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG") - ] return DiagLayerContainer( - admin_data=admin_data, - company_datas=company_datas, ecu_shared_datas=ecu_shared_datas, protocols=protocols, functional_groups=functional_groups, base_variants=base_variants, ecu_variants=ecu_variants, - sdgs=sdgs, **kwargs) def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: - result = {self.odx_id: self} - - if self.admin_data is not None: - result.update(self.admin_data._build_odxlinks()) - for cd in self.company_datas: - result.update(cd._build_odxlinks()) - for sdg in self.sdgs: - result.update(sdg._build_odxlinks()) + result = super()._build_odxlinks() for ecu_shared_data in self.ecu_shared_datas: result.update(ecu_shared_data._build_odxlinks()) @@ -124,12 +98,7 @@ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: return result def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: - if self.admin_data is not None: - self.admin_data._resolve_odxlinks(odxlinks) - for cd in self.company_datas: - cd._resolve_odxlinks(odxlinks) - for sdg in self.sdgs: - sdg._resolve_odxlinks(odxlinks) + super()._resolve_odxlinks(odxlinks) for ecu_shared_data in self.ecu_shared_datas: ecu_shared_data._resolve_odxlinks(odxlinks) @@ -143,6 +112,8 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: ecu_variant._resolve_odxlinks(odxlinks) def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None: + super()._finalize_init(database, odxlinks) + for ecu_shared_data in self.ecu_shared_datas: ecu_shared_data._finalize_init(database, odxlinks) for protocol in self.protocols: @@ -154,6 +125,9 @@ def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> Non for ecu_variant in self.ecu_variants: ecu_variant._finalize_init(database, odxlinks) + def _resolve_snrefs(self, context: SnRefContext) -> None: + super()._resolve_snrefs(context) + @property def diag_layers(self) -> NamedItemList[DiagLayer]: return self._diag_layers diff --git a/odxtools/odxcategory.py b/odxtools/odxcategory.py new file mode 100644 index 00000000..777a346c --- /dev/null +++ b/odxtools/odxcategory.py @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: MIT +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any, Dict, List, Optional +from xml.etree import ElementTree + +from .admindata import AdminData +from .companydata import CompanyData +from .element import IdentifiableElement +from .exceptions import odxrequire +from .nameditemlist import NamedItemList +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId +from .snrefcontext import SnRefContext +from .specialdatagroup import SpecialDataGroup +from .utils import dataclass_fields_asdict + +if TYPE_CHECKING: + from .database import Database + + +@dataclass +class OdxCategory(IdentifiableElement): + """This is the base class for all top-level container classes in ODX""" + + admin_data: Optional[AdminData] + company_datas: NamedItemList[CompanyData] + sdgs: List[SpecialDataGroup] + + @staticmethod + def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "OdxCategory": + raise Exception("Calling `._from_et()` is not allowed for OdxCategory. " + "Use `OdxCategory.category_from_et()`!") + + @staticmethod + def category_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *, + doc_type: str) -> "OdxCategory": + + short_name = odxrequire(et_element.findtext("SHORT-NAME")) + # create the current ODX "document fragment" (description of the + # current document for references and IDs) + doc_frags = [OdxDocFragment(short_name, doc_type)] + kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags)) + + admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags) + company_datas = NamedItemList([ + CompanyData.from_et(cde, doc_frags) + for cde in et_element.iterfind("COMPANY-DATAS/COMPANY-DATA") + ]) + sdgs = [ + SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG") + ] + + return OdxCategory(admin_data=admin_data, company_datas=company_datas, sdgs=sdgs, **kwargs) + + def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: + result = {self.odx_id: self} + + if self.admin_data is not None: + result.update(self.admin_data._build_odxlinks()) + for cd in self.company_datas: + result.update(cd._build_odxlinks()) + for sdg in self.sdgs: + result.update(sdg._build_odxlinks()) + + return result + + def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: + if self.admin_data is not None: + self.admin_data._resolve_odxlinks(odxlinks) + for cd in self.company_datas: + cd._resolve_odxlinks(odxlinks) + for sdg in self.sdgs: + sdg._resolve_odxlinks(odxlinks) + + def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None: + pass + + def _resolve_snrefs(self, context: SnRefContext) -> None: + if self.admin_data is not None: + self.admin_data._resolve_snrefs(context) + for cd in self.company_datas: + cd._resolve_snrefs(context) + for sdg in self.sdgs: + sdg._resolve_snrefs(context) diff --git a/odxtools/templates/comparam-spec.odx-c.xml.jinja2 b/odxtools/templates/comparam-spec.odx-c.xml.jinja2 index c72f233b..f539ed9b 100644 --- a/odxtools/templates/comparam-spec.odx-c.xml.jinja2 +++ b/odxtools/templates/comparam-spec.odx-c.xml.jinja2 @@ -5,32 +5,15 @@ # This template writes an .odx-c file for a communication # parameter specification. -#} -{%- import('macros/printAdminData.xml.jinja2') as pad -%} -{%- import('macros/printCompanyData.xml.jinja2') as pcd -%} +{%- import('macros/printOdxCategory.xml.jinja2') as poc %} {%- import('macros/printProtStack.xml.jinja2') as pps %} -{%- import('macros/printDescription.xml.jinja2') as pd %} {#- -#} <?xml version="1.0" encoding="UTF-8" standalone="no" ?> -<ODX MODEL-VERSION="2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="odx.xsd"> <!-- Written using odxtools {{odxtools_version}} --> - <COMPARAM-SPEC ID="{{comparam_spec.odx_id.local_id}}"> - <SHORT-NAME>{{comparam_spec.short_name}}</SHORT-NAME> - {%- if comparam_spec.long_name is not none %} - <LONG-NAME>{{comparam_spec.long_name|e}}</LONG-NAME> - {%- endif %} - {{pd.printDescription(comparam_spec.description)}} - {%- if comparam_spec.admin_data is not none %} - {{- pad.printAdminData(comparam_spec.admin_data) | indent(3) }} - {%- endif %} - {%- if comparam_spec.company_datas %} - <COMPANY-DATAS> - {%- for cd in comparam_spec.company_datas %} - {{- pcd.printCompanyData(cd) | indent(5) -}} - {%- endfor %} - </COMPANY-DATAS> - {%- endif %} - +<ODX MODEL-VERSION="2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="odx.xsd"> + <COMPARAM-SPEC {{- poc.printOdxCategoryAttribs(comparam_spec) }}> + {{- poc.printOdxCategorySubtags(comparam_spec)|indent(3) }} {%- if comparam_spec.prot_stacks %} <PROT-STACKS> {%- for ps in comparam_spec.prot_stacks %} diff --git a/odxtools/templates/comparam-subset.odx-cs.xml.jinja2 b/odxtools/templates/comparam-subset.odx-cs.xml.jinja2 index 70043c6b..477e6ca8 100644 --- a/odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +++ b/odxtools/templates/comparam-subset.odx-cs.xml.jinja2 @@ -5,36 +5,18 @@ # This template writes an .odx-cs file for a communication # parameter subset. -#} +{%- import('macros/printOdxCategory.xml.jinja2') as poc %} {%- import('macros/printComparam.xml.jinja2') as pcp -%} -{%- import('macros/printAdminData.xml.jinja2') as pad -%} -{%- import('macros/printCompanyData.xml.jinja2') as pcd -%} {%- import('macros/printDOP.xml.jinja2') as pdop %} {%- import('macros/printUnitSpec.xml.jinja2') as pus %} -{%- import('macros/printSpecialData.xml.jinja2') as psd %} {%- import('macros/printDescription.xml.jinja2') as pd %} {#- -#} <?xml version="1.0" encoding="UTF-8" standalone="no" ?> -<ODX MODEL-VERSION="2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="odx.xsd"> <!-- Written using odxtools {{odxtools_version}} --> - <COMPARAM-SUBSET ID="{{comparam_subset.odx_id.local_id}}" - CATEGORY="{{comparam_subset.category}}" > - <SHORT-NAME>{{comparam_subset.short_name}}</SHORT-NAME> - {%- if comparam_subset.long_name is not none %} - <LONG-NAME>{{comparam_subset.long_name|e}}</LONG-NAME> - {%- endif %} - {{pd.printDescription(comparam_subset.description)}} - {%- if comparam_subset.admin_data is not none %} - {{- pad.printAdminData(comparam_subset.admin_data) | indent(3) }} - {%- endif %} - {%- if comparam_subset.company_datas %} - <COMPANY-DATAS> - {%- for cd in comparam_subset.company_datas %} - {{- pcd.printCompanyData(cd) | indent(5, first=True) }} - {%- endfor %} - </COMPANY-DATAS> - {%- endif %} - {{- psd.printSpecialDataGroups(comparam_subset.sdgs)|indent(3, first=True) }} +<ODX MODEL-VERSION="2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="odx.xsd"> + <COMPARAM-SUBSET {{- poc.printOdxCategoryAttribs(comparam_subset) }} {{make_xml_attrib("CATEGORY", comparam_subset.category)}}> + {{- poc.printOdxCategorySubtags(comparam_subset)|indent(3) }} {%- if comparam_subset.comparams %} <COMPARAMS> {%- for cp in comparam_subset.comparams %} diff --git a/odxtools/templates/diag_layer_container.odx-d.xml.jinja2 b/odxtools/templates/diag_layer_container.odx-d.xml.jinja2 index b90d7cc0..3ef83b7d 100644 --- a/odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +++ b/odxtools/templates/diag_layer_container.odx-d.xml.jinja2 @@ -2,9 +2,7 @@ # # SPDX-License-Identifier: MIT -#} -{%- import('macros/printAdminData.xml.jinja2') as pad -%} -{%- import('macros/printCompanyData.xml.jinja2') as pcd -%} -{%- import('macros/printSpecialData.xml.jinja2') as psd %} +{%- import('macros/printOdxCategory.xml.jinja2') as poc %} {%- import('macros/printEcuSharedData.xml.jinja2') as pecusd -%} {%- import('macros/printProtocol.xml.jinja2') as pprot %} {%- import('macros/printFunctionalGroup.xml.jinja2') as pfuncgroup %} @@ -14,29 +12,10 @@ {#- -#} <?xml version="1.0" encoding="UTF-8" standalone="no" ?> +<!-- Written using odxtools {{odxtools_version}} --> <ODX MODEL-VERSION="2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="odx.xsd"> - <!-- Written using odxtools {{odxtools_version}} --> - <DIAG-LAYER-CONTAINER ID="{{dlc.odx_id.local_id}}"> - <SHORT-NAME>{{dlc.short_name}}</SHORT-NAME> -{%- if dlc.long_name %} - <LONG-NAME>{{dlc.long_name|e}}</LONG-NAME> -{%- endif %} -{%- if dlc.description %} - <DESC> -{{dlc.description}} - </DESC> -{%- endif %} -{%- if dlc.admin_data %} - {{pad.printAdminData(dlc.admin_data)|indent(2)}} -{%- endif %} -{%- if dlc.company_datas %} - <COMPANY-DATAS> - {%- for cd in dlc.company_datas %} - {{pcd.printCompanyData(cd)|indent(3)}} - {%- endfor %} - </COMPANY-DATAS> -{%- endif %} - {{- psd.printSpecialDataGroups(dlc.sdgs)|indent(2, first=True) }} + <DIAG-LAYER-CONTAINER {{- poc.printOdxCategoryAttribs(dlc) }}> + {{- poc.printOdxCategorySubtags(dlc)|indent(3) }} {%- if dlc.protocols %} <PROTOCOLS> {%- for dl in dlc.protocols %} diff --git a/odxtools/templates/macros/printOdxCategory.xml.jinja2 b/odxtools/templates/macros/printOdxCategory.xml.jinja2 new file mode 100644 index 00000000..5e5b5589 --- /dev/null +++ b/odxtools/templates/macros/printOdxCategory.xml.jinja2 @@ -0,0 +1,28 @@ +{#- -*- mode: sgml; tab-width: 1; indent-tabs-mode: nil -*- + # + # SPDX-License-Identifier: MIT +-#} + +{%- import('macros/printElementId.xml.jinja2') as peid %} +{%- import('macros/printAdminData.xml.jinja2') as pad -%} +{%- import('macros/printCompanyData.xml.jinja2') as pcd -%} +{%- import('macros/printSpecialData.xml.jinja2') as psd %} + +{%- macro printOdxCategoryAttribs(obj) -%} +{#- #} {{- peid.printElementIdAttribs(obj) }} +{%- endmacro -%} + +{%- macro printOdxCategorySubtags(obj) -%} +{{ peid.printElementIdSubtags(obj) }} +{%- if obj.admin_data %} +{{pad.printAdminData(obj.admin_data)|indent(2)}} +{%- endif %} +{%- if obj.company_datas %} +<COMPANY-DATAS> +{%- for cd in obj.company_datas %} +{{pcd.printCompanyData(cd)|indent(3)}} +{%- endfor %} +</COMPANY-DATAS> +{%- endif %} +{{- psd.printSpecialDataGroups(obj.sdgs)|indent(2, first=True) }} +{%- endmacro -%}