diff --git a/cyclonedx/model/tool.py b/cyclonedx/model/tool.py
index bb639bbe..4b056519 100644
--- a/cyclonedx/model/tool.py
+++ b/cyclonedx/model/tool.py
@@ -26,7 +26,6 @@
from sortedcontainers import SortedSet
from .._internal.compare import ComparableTuple as _ComparableTuple
-from ..exception.serialization import CycloneDxDeserializationException
from ..schema import SchemaVersion
from ..schema.schema import SchemaVersion1Dot4, SchemaVersion1Dot5, SchemaVersion1Dot6
from . import ExternalReference, HashType, _HashTypeRepositorySerializationHelper
@@ -308,7 +307,8 @@ def json_denormalize(cls, o: Union[List[Dict[str, Any]], Dict[str, Any]],
services = map(lambda s: Service.from_json( # type:ignore[attr-defined]
s), o.get('services', ()))
elif isinstance(o, Iterable):
- tools = map(lambda t: Tool.from_json(t), o) # type:ignore[attr-defined]
+ tools = map(lambda t: Tool.from_json( # type:ignore[attr-defined]
+ t), o)
return ToolRepository(components=components, services=services, tools=tools)
@classmethod
@@ -349,23 +349,19 @@ def xml_denormalize(cls, o: Element, *,
prop_info: 'ObjectMetadataLibrary.SerializableProperty',
ctx: Type[Any],
**kwargs: Any) -> ToolRepository:
- tools = []
+ ns_map = {'bom': default_ns or ''}
+ # Do not iterate over `o` and do not check for expected `.tag` of items.
+ # This check could have been done by schema validators before even deserializing.
+ tools = None
components = None
services = None
- for e in o:
- tag = e.tag if default_ns is None else e.tag.replace(f'{{{default_ns}}}', '')
- if tag == 'tool':
- tools.append(Tool.from_xml( # type:ignore[attr-defined]
- e, default_ns))
- elif tag == 'components':
- components = map(lambda s: Component.from_xml( # type:ignore[attr-defined]
- s, default_ns), e)
- elif tag == 'services':
- services = map(lambda s: Service.from_xml( # type:ignore[attr-defined]
- s, default_ns), e)
- else:
- raise CycloneDxDeserializationException(f'unexpected: {e!r}')
- return ToolRepository(
- tools=tools,
- components=components,
- services=services)
+ ts = o.findall('bom:tool', ns_map)
+ if len(ts) > 0:
+ tools = map(lambda t: Tool.from_xml( # type:ignore[attr-defined]
+ t, default_ns), ts)
+ else:
+ components = map(lambda c: Component.from_xml( # type:ignore[attr-defined]
+ c, default_ns), o.iterfind('./bom:components/bom:component', ns_map))
+ services = map(lambda s: Service.from_xml( # type:ignore[attr-defined]
+ s, default_ns), o.iterfind('./bom:services/bom:service', ns_map))
+ return ToolRepository(components=components, services=services, tools=tools)
diff --git a/tests/_data/own/xml/1.5/invalid-tool.xml b/tests/_data/own/xml/1.5/invalid-tool.xml
deleted file mode 100644
index f57259b9..00000000
--- a/tests/_data/own/xml/1.5/invalid-tool.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/tests/test_deserialize_xml.py b/tests/test_deserialize_xml.py
index 5ebbc64d..26cc34ec 100644
--- a/tests/test_deserialize_xml.py
+++ b/tests/test_deserialize_xml.py
@@ -14,17 +14,16 @@
#
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OWASP Foundation. All Rights Reserved.
-from os.path import join
+
from typing import Any, Callable
from unittest import TestCase
from unittest.mock import patch
from ddt import ddt, named_data
-from cyclonedx.exception.serialization import CycloneDxDeserializationException
from cyclonedx.model.bom import Bom
from cyclonedx.schema import OutputFormat, SchemaVersion
-from tests import OWN_DATA_DIRECTORY, DeepCompareMixin, SnapshotMixin, mksname
+from tests import DeepCompareMixin, SnapshotMixin, mksname
from tests._data.models import (
all_get_bom_funct_valid_immut,
all_get_bom_funct_valid_reversible_migrate,
@@ -46,9 +45,3 @@ def test_prepared(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
bom = Bom.from_xml(s)
self.assertBomDeepEqual(expected, bom,
fuzzy_deps=get_bom in all_get_bom_funct_with_incomplete_deps)
-
- def test_unexpected_toolrepository_item(self) -> None:
- with open(join(OWN_DATA_DIRECTORY, 'xml', '1.5', 'invalid-tool.xml')) as input_xml:
- with self.assertRaisesRegex(CycloneDxDeserializationException,
- r"^unexpected: $"):
- Bom.from_xml(input_xml)