From 0a3ae26f8fe50e1dc03fb72fb7fdba51654c7f8b Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Tue, 19 Sep 2023 09:52:31 +0200
Subject: [PATCH 01/42] chore: init 5.0.0-dev

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/__init__.py | 2 +-
 docs/conf.py          | 2 +-
 pyproject.toml        | 6 +++++-
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/cyclonedx/__init__.py b/cyclonedx/__init__.py
index 4c24779f6..53b0998ac 100644
--- a/cyclonedx/__init__.py
+++ b/cyclonedx/__init__.py
@@ -20,4 +20,4 @@
 
 # !! version is managed by semantic_release
 # do not use typing here, or else `semantic_release` might have issues finding the variable
-__version__ = "4.2.2"
+__version__ = "5.0.0-alpha.1"
diff --git a/docs/conf.py b/docs/conf.py
index abafb2571..9faa5c7ae 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -22,7 +22,7 @@
 
 # The full version, including alpha/beta/rc tags
 # !! version is managed by semantic_release
-release = '4.2.2'
+release = '5.0.0-alpha.1'
 
 # -- General configuration ---------------------------------------------------
 
diff --git a/pyproject.toml b/pyproject.toml
index e18acfe3e..097b08f11 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
 [tool.poetry]
 name = "cyclonedx-python-lib"
 # !! version is managed by semantic_release
-version = "4.2.2"
+version = "5.0.0-alpha.1"
 description = "A library for producing CycloneDX SBOM (Software Bill of Materials) files."
 authors = ["Paul Horton <phorton@sonatype.com>"]
 maintainers = [
@@ -94,3 +94,7 @@ prerelease = false
 match = "(feat|fix|tests|style|docs|chore)"
 prerelease = true
 prerelease_token = "alpha"
+[tool.semantic_release.branches."major-dev"]
+match = "\\d+\\.0\\.0-dev"
+prerelease = true
+prerelease_token = "alpha"

From 1571d21057b11f11cb81e74a5a702f7f30582b09 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Tue, 19 Sep 2023 10:46:17 +0200
Subject: [PATCH 02/42] Drop py37 (#441)

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .github/workflows/python.yml     | 15 +++---
 .mypy.ini                        |  4 +-
 CONTRIBUTING.md                  |  4 +-
 cyclonedx/model/__init__.py      | 60 +++++++++++-----------
 cyclonedx/model/bom.py           | 35 +++++++------
 cyclonedx/model/component.py     | 86 ++++++++++++++++----------------
 cyclonedx/model/dependency.py    |  4 +-
 cyclonedx/model/issue.py         | 12 ++---
 cyclonedx/model/release_note.py  | 22 ++++----
 cyclonedx/model/service.py       | 32 ++++++------
 cyclonedx/model/vulnerability.py | 84 +++++++++++++++----------------
 pyproject.toml                   | 20 ++++----
 tests/base.py                    | 29 +++++------
 tox.ini                          | 12 ++---
 14 files changed, 206 insertions(+), 213 deletions(-)

diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index ebb67faa9..c94d51b68 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -46,7 +46,7 @@ jobs:
       - name: Install dependencies
         run: poetry install --no-root
       - name: Run tox
-        run: poetry run tox -e flake8 -s false
+        run: poetry run tox run -e flake8 -s false
 
   static-code-analysis:
     name: StaticCodingAnalysis (py${{ matrix.python-version}} ${{ matrix.toxenv-factor }})
@@ -62,7 +62,7 @@ jobs:
             toxenv-factor: 'locked'
           - # test with the lowest dependencies
             os: ubuntu-latest
-            python-version: '3.7'
+            python-version: '3.8'
             toxenv-factor: 'lowest'
     steps:
       - name: Checkout
@@ -82,7 +82,7 @@ jobs:
       - name: Install dependencies
         run: poetry install --no-root
       - name: Run tox
-        run: poetry run tox -e mypy-${{ matrix.toxenv-factor }} -s false
+        run: poetry run tox run -e mypy-${{ matrix.toxenv-factor }} -s false
 
   build-and-test:
     name: Test (${{ matrix.os }} py${{ matrix.python-version }} ${{ matrix.toxenv-factor }})
@@ -96,13 +96,12 @@ jobs:
           - "3.11" # highest supported
           - "3.10"
           - "3.9"
-          - "3.8"
-          - "3.7"  # lowest supported
+          - "3.8"  # lowest supported
         toxenv-factor: ['locked']
         include:
           - # test with the lowest dependencies
             os: ubuntu-latest
-            python-version: '3.7'
+            python-version: '3.8'
             toxenv-factor: 'lowest'
     steps:
       - name: Disabled Git auto EOL CRLF transforms
@@ -135,7 +134,7 @@ jobs:
       - name: Ensure build successful
         run: poetry build
       - name: Run tox
-        run: poetry run tox -e py-${{ matrix.toxenv-factor }} -s false
+        run: poetry run tox run -e py-${{ matrix.toxenv-factor }} -s false
       - name: Generate coverage reports
         shell: bash
         run: |
@@ -186,7 +185,7 @@ jobs:
         # see https://github.com/actions/setup-python
         uses: actions/setup-python@v4
         with:
-          python-version: '>=3.7 <=3.11'  # supported version range
+          python-version: '>=3.8 <=3.11'  # supported version range
       - name: Validate Python Environment
         shell: python
         run: |
diff --git a/.mypy.ini b/.mypy.ini
index f3dc121d9..c15c04ab1 100644
--- a/.mypy.ini
+++ b/.mypy.ini
@@ -26,9 +26,7 @@ no_implicit_optional        = True
 warn_redundant_casts        = True
 warn_return_any             = True
 no_implicit_reexport        = True
-
-# needed to silence some py37|py38 differences
-warn_unused_ignores         = False
+warn_unused_ignores         = True
 
 [mypy-pytest.*]
 ignore_missing_imports = True
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 13a45baaa..c4cfa73b2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -23,7 +23,7 @@ Get it all applied via:
 
 ```shell
 poetry run isort .
-poetry run flake8 cyclonedx/ tests/ typings/
+poetry run autopep8 -ir cyclonedx/ tests/ typings/
 ```
 
 ## Documentation
@@ -45,7 +45,7 @@ make html
 Run all tests in dedicated environments, via:
 
 ```shell
-poetry run tox
+poetry run tox run
 ```
 
 ## Sign off your commits
diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
index 59b45cca7..47f709a10 100644
--- a/cyclonedx/model/__init__.py
+++ b/cyclonedx/model/__init__.py
@@ -129,7 +129,7 @@ def __init__(self, *, flow: DataFlow, classification: str) -> None:
         self.flow = flow
         self.classification = classification
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def flow(self) -> DataFlow:
         """
@@ -153,7 +153,7 @@ def flow(self) -> DataFlow:
     def flow(self, flow: DataFlow) -> None:
         self._flow = flow
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_name('.')
     def classification(self) -> str:
         """
@@ -207,7 +207,7 @@ def __init__(self, *, content: str, content_type: str = DEFAULT_CONTENT_TYPE,
         self.encoding = encoding
         self.content = content
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     @serializable.xml_name('content-type')
     def content_type(self) -> str:
@@ -223,7 +223,7 @@ def content_type(self) -> str:
     def content_type(self, content_type: str) -> None:
         self._content_type = content_type
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def encoding(self) -> Optional[Encoding]:
         """
@@ -238,7 +238,7 @@ def encoding(self) -> Optional[Encoding]:
     def encoding(self, encoding: Optional[Encoding]) -> None:
         self._encoding = encoding
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_name('.')
     def content(self) -> str:
         """
@@ -347,7 +347,7 @@ def __init__(self, *, alg: HashAlgorithm, content: str) -> None:
         self.alg = alg
         self.content = content
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def alg(self) -> HashAlgorithm:
         """
@@ -362,7 +362,7 @@ def alg(self) -> HashAlgorithm:
     def alg(self, alg: HashAlgorithm) -> None:
         self._alg = alg
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_name('.')
     def content(self) -> str:
         """
@@ -442,7 +442,7 @@ def __init__(self, uri: str) -> None:
             )
         self._uri = uri
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('.')
     @serializable.xml_name('.')
     def uri(self) -> str:
@@ -499,7 +499,7 @@ def __init__(self, *, type: ExternalReferenceType, url: XsUri, comment: Optional
         self.type = type
         self.hashes = hashes or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def url(self) -> XsUri:
         """
@@ -528,7 +528,7 @@ def comment(self) -> Optional[str]:
     def comment(self, comment: Optional[str]) -> None:
         self._comment = comment
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def type(self) -> ExternalReferenceType:
         """
@@ -546,7 +546,7 @@ def type(self) -> ExternalReferenceType:
     def type(self, type: ExternalReferenceType) -> None:
         self._type = type
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'hash')
@@ -775,7 +775,7 @@ def __init__(self, *, name: str, value: str) -> None:
         self.name = name
         self.value = value
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def name(self) -> str:
         """
@@ -792,7 +792,7 @@ def name(self) -> str:
     def name(self, name: str) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_name('.')
     def value(self) -> str:
         """
@@ -842,7 +842,7 @@ def __init__(self, *, content: str, content_type: Optional[str] = None,
         self.content_type = content_type or NoteText.DEFAULT_CONTENT_TYPE
         self.encoding = encoding
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_name('.')
     def content(self) -> str:
         """
@@ -857,7 +857,7 @@ def content(self) -> str:
     def content(self, content: str) -> None:
         self._content = content
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     @serializable.xml_name('content-type')
     def content_type(self) -> Optional[str]:
@@ -875,7 +875,7 @@ def content_type(self) -> Optional[str]:
     def content_type(self, content_type: str) -> None:
         self._content_type = content_type
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def encoding(self) -> Optional[Encoding]:
         """
@@ -940,7 +940,7 @@ def text(self) -> NoteText:
     def text(self, text: NoteText) -> None:
         self._text = text
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def locale(self) -> Optional[str]:
         """
@@ -1003,7 +1003,7 @@ def __init__(self, *, name: Optional[str] = None, phone: Optional[str] = None, e
         self.email = email
         self.phone = phone
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def name(self) -> Optional[str]:
         """
@@ -1018,7 +1018,7 @@ def name(self) -> Optional[str]:
     def name(self, name: Optional[str]) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def email(self) -> Optional[str]:
         """
@@ -1033,7 +1033,7 @@ def email(self) -> Optional[str]:
     def email(self, email: Optional[str]) -> None:
         self._email = email
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def phone(self) -> Optional[str]:
         """
@@ -1086,7 +1086,7 @@ def __init__(self, *, name: Optional[str] = None, urls: Optional[Iterable[XsUri]
         self.urls = urls or []  # type: ignore
         self.contacts = contacts or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def name(self) -> Optional[str]:
         """
@@ -1101,7 +1101,7 @@ def name(self) -> Optional[str]:
     def name(self, name: Optional[str]) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('url')
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'url')
     @serializable.xml_sequence(2)
@@ -1118,7 +1118,7 @@ def urls(self) -> "SortedSet[XsUri]":
     def urls(self, urls: Iterable[XsUri]) -> None:
         self._urls = SortedSet(urls)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('contact')
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'contact')
     @serializable.xml_sequence(3)
@@ -1172,7 +1172,7 @@ def __init__(self, *, vendor: Optional[str] = None, name: Optional[str] = None,
         self.hashes = hashes or []  # type: ignore
         self.external_references = external_references or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def vendor(self) -> Optional[str]:
         """
@@ -1187,7 +1187,7 @@ def vendor(self) -> Optional[str]:
     def vendor(self, vendor: Optional[str]) -> None:
         self._vendor = vendor
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def name(self) -> Optional[str]:
         """
@@ -1202,7 +1202,7 @@ def name(self) -> Optional[str]:
     def name(self, name: Optional[str]) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def version(self) -> Optional[str]:
         """
@@ -1217,7 +1217,7 @@ def version(self) -> Optional[str]:
     def version(self, version: Optional[str]) -> None:
         self._version = version
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'hash')
     @serializable.xml_sequence(4)
     def hashes(self) -> "SortedSet[HashType]":
@@ -1233,7 +1233,7 @@ def hashes(self) -> "SortedSet[HashType]":
     def hashes(self, hashes: Iterable[HashType]) -> None:
         self._hashes = SortedSet(hashes)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
     @serializable.xml_sequence(5)
@@ -1289,7 +1289,7 @@ def __init__(self, *, timestamp: Optional[datetime] = None, name: Optional[str]
         self.name = name
         self.email = email
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(serializable.helpers.XsdDateTime)
     def timestamp(self) -> Optional[datetime]:
         """
@@ -1362,7 +1362,7 @@ class Copyright:
     def __init__(self, *, text: str) -> None:
         self.text = text
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_name('.')
     def text(self) -> str:
         """
diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
index 25ed9e4e6..5c559a089 100644
--- a/cyclonedx/model/bom.py
+++ b/cyclonedx/model/bom.py
@@ -83,7 +83,7 @@ def __init__(self, *, tools: Optional[Iterable[Tool]] = None,
         if not tools:
             self.tools.add(ThisTool)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(serializable.helpers.XsdDateTime)
     @serializable.xml_sequence(1)
     def timestamp(self) -> datetime:
@@ -99,7 +99,7 @@ def timestamp(self) -> datetime:
     def timestamp(self, timestamp: datetime) -> None:
         self._timestamp = timestamp
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'tool')
     @serializable.xml_sequence(2)
     def tools(self) -> "SortedSet[Tool]":
@@ -115,7 +115,7 @@ def tools(self) -> "SortedSet[Tool]":
     def tools(self, tools: Iterable[Tool]) -> None:
         self._tools = SortedSet(tools)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'author')
     @serializable.xml_sequence(3)
     def authors(self) -> "SortedSet[OrganizationalContact]":
@@ -135,7 +135,7 @@ def authors(self) -> "SortedSet[OrganizationalContact]":
     def authors(self, authors: Iterable[OrganizationalContact]) -> None:
         self._authors = SortedSet(authors)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(4)
     def component(self) -> Optional[Component]:
         """
@@ -160,7 +160,7 @@ def component(self, component: Component) -> None:
         """
         self._component = component
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(5)
     def manufacture(self) -> Optional[OrganizationalEntity]:
         """
@@ -175,7 +175,7 @@ def manufacture(self) -> Optional[OrganizationalEntity]:
     def manufacture(self, manufacture: Optional[OrganizationalEntity]) -> None:
         self._manufacture = manufacture
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(6)
     def supplier(self) -> Optional[OrganizationalEntity]:
         """
@@ -192,7 +192,7 @@ def supplier(self) -> Optional[OrganizationalEntity]:
     def supplier(self, supplier: Optional[OrganizationalEntity]) -> None:
         self._supplier = supplier
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'licenses')
@@ -210,7 +210,7 @@ def licenses(self) -> "SortedSet[LicenseChoice]":
     def licenses(self, licenses: Iterable[LicenseChoice]) -> None:
         self._licenses = SortedSet(licenses)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
@@ -247,8 +247,7 @@ def __repr__(self) -> str:
         return f'<BomMetaData timestamp={self.timestamp}, component={self.component}>'
 
 
-@serializable.serializable_class(
-    ignore_during_deserialization=['$schema', 'bom_format', 'spec_version'])  # type: ignore[misc]
+@serializable.serializable_class(ignore_during_deserialization=['$schema', 'bom_format', 'spec_version'])
 class Bom:
     """
     This is our internal representation of a bill-of-materials (BOM).
@@ -297,7 +296,7 @@ def __init__(self, *, components: Optional[Iterable[Component]] = None,
         self.version = version
         self.dependencies = SortedSet(dependencies) or SortedSet()
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(UrnUuidHelper)
     @serializable.view(SchemaVersion1Dot1)
     @serializable.view(SchemaVersion1Dot2)
@@ -318,7 +317,7 @@ def serial_number(self) -> UUID:
     def serial_number(self, serial_number: UUID) -> None:
         self._serial_number = serial_number
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
@@ -339,7 +338,7 @@ def metadata(self) -> BomMetaData:
     def metadata(self, metadata: BomMetaData) -> None:
         self._metadata = metadata
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.include_none(SchemaVersion1Dot0)
     @serializable.include_none(SchemaVersion1Dot1)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'component')
@@ -397,7 +396,7 @@ def has_component(self, component: Component) -> bool:
         """
         return component in self.components
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
@@ -416,7 +415,7 @@ def services(self) -> "SortedSet[Service]":
     def services(self, services: Iterable[Service]) -> None:
         self._services = SortedSet(services)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot1)
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
@@ -474,7 +473,7 @@ def has_vulnerabilities(self) -> bool:
         """
         return bool(self.vulnerabilities)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'vulnerability')
     @serializable.xml_sequence(8)
@@ -491,7 +490,7 @@ def vulnerabilities(self) -> "SortedSet[Vulnerability]":
     def vulnerabilities(self, vulnerabilities: Iterable[Vulnerability]) -> None:
         self._vulnerabilities = SortedSet(vulnerabilities)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def version(self) -> int:
         return self._version
@@ -500,7 +499,7 @@ def version(self) -> int:
     def version(self, version: int) -> None:
         self._version = version
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py
index 4833db136..f3fd386d3 100644
--- a/cyclonedx/model/component.py
+++ b/cyclonedx/model/component.py
@@ -80,7 +80,7 @@ def __init__(self, *, uid: Optional[str] = None, url: Optional[XsUri] = None,
         self.committer = committer
         self.message = message
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def uid(self) -> Optional[str]:
         """
@@ -96,7 +96,7 @@ def uid(self) -> Optional[str]:
     def uid(self, uid: Optional[str]) -> None:
         self._uid = uid
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def url(self) -> Optional[XsUri]:
         """
@@ -111,7 +111,7 @@ def url(self) -> Optional[XsUri]:
     def url(self, url: Optional[XsUri]) -> None:
         self._url = url
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def author(self) -> Optional[IdentifiableAction]:
         """
@@ -126,7 +126,7 @@ def author(self) -> Optional[IdentifiableAction]:
     def author(self, author: Optional[IdentifiableAction]) -> None:
         self._author = author
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(4)
     def committer(self) -> Optional[IdentifiableAction]:
         """
@@ -141,7 +141,7 @@ def committer(self) -> Optional[IdentifiableAction]:
     def committer(self, committer: Optional[IdentifiableAction]) -> None:
         self._committer = committer
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(5)
     def message(self) -> Optional[str]:
         """
@@ -195,7 +195,7 @@ def __init__(self, *, licenses: Optional[Iterable[LicenseChoice]] = None,
         self.licenses = licenses or []  # type: ignore
         self.copyright = copyright or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'license')
     def licenses(self) -> "SortedSet[LicenseChoice]":
         """
@@ -210,7 +210,7 @@ def licenses(self) -> "SortedSet[LicenseChoice]":
     def licenses(self, licenses: Iterable[LicenseChoice]) -> None:
         self._licenses = SortedSet(licenses)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'text')
     def copyright(self) -> "SortedSet[Copyright]":
         """
@@ -356,7 +356,7 @@ def __init__(self, *, type: PatchClassification, diff: Optional[Diff] = None,
         self.diff = diff
         self.resolves = resolves or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def type(self) -> PatchClassification:
         """
@@ -389,7 +389,7 @@ def diff(self) -> Optional[Diff]:
     def diff(self, diff: Optional[Diff]) -> None:
         self._diff = diff
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'issue')
     def resolves(self) -> "SortedSet[IssueType]":
         """
@@ -453,7 +453,7 @@ def __init__(self, *, ancestors: Optional[Iterable['Component']] = None,
         self.patches = patches or []  # type: ignore
         self.notes = notes
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'component')
     @serializable.xml_sequence(1)
     def ancestors(self) -> "SortedSet['Component']":
@@ -475,7 +475,7 @@ def ancestors(self) -> "SortedSet['Component']":
     def ancestors(self, ancestors: Iterable['Component']) -> None:
         self._ancestors = SortedSet(ancestors)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'component')
     @serializable.xml_sequence(2)
     def descendants(self) -> "SortedSet['Component']":
@@ -492,7 +492,7 @@ def descendants(self) -> "SortedSet['Component']":
     def descendants(self, descendants: Iterable['Component']) -> None:
         self._descendants = SortedSet(descendants)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'component')
     @serializable.xml_sequence(3)
     def variants(self) -> "SortedSet['Component']":
@@ -510,7 +510,7 @@ def variants(self) -> "SortedSet['Component']":
     def variants(self, variants: Iterable['Component']) -> None:
         self._variants = SortedSet(variants)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'commit')
     @serializable.xml_sequence(4)
     def commits(self) -> "SortedSet[Commit]":
@@ -527,7 +527,7 @@ def commits(self) -> "SortedSet[Commit]":
     def commits(self, commits: Iterable[Commit]) -> None:
         self._commits = SortedSet(commits)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
@@ -547,7 +547,7 @@ def patches(self) -> "SortedSet[Patch]":
     def patches(self, patches: Iterable[Patch]) -> None:
         self._patches = SortedSet(patches)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(6)
     def notes(self) -> Optional[str]:
         """
@@ -597,7 +597,7 @@ def __init__(self, *, tag_id: str, name: str, version: Optional[str] = None,
         self.text = text
         self.url = url
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def tag_id(self) -> str:
         """
@@ -612,7 +612,7 @@ def tag_id(self) -> str:
     def tag_id(self, tag_id: str) -> None:
         self._tag_id = tag_id
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def name(self) -> str:
         """
@@ -627,7 +627,7 @@ def name(self) -> str:
     def name(self, name: str) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def version(self) -> Optional[str]:
         """
@@ -642,7 +642,7 @@ def version(self) -> Optional[str]:
     def version(self, version: Optional[str]) -> None:
         self._version = version
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def tag_version(self) -> Optional[int]:
         """
@@ -657,7 +657,7 @@ def tag_version(self) -> Optional[int]:
     def tag_version(self, tag_version: Optional[int]) -> None:
         self._tag_version = tag_version
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def patch(self) -> Optional[bool]:
         """
@@ -813,7 +813,7 @@ def __init__(self, *, name: str, type: ComponentType = ComponentType.LIBRARY,
 
         self.__dependencies: "SortedSet[BomRef]" = SortedSet()
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def type(self) -> ComponentType:
         """
@@ -846,7 +846,7 @@ def mime_type(self) -> Optional[str]:
     def mime_type(self, mime_type: Optional[str]) -> None:
         self._mime_type = mime_type
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('bom-ref')
     @serializable.type_mapping(BomRefHelper)
     @serializable.view(SchemaVersion1Dot1)
@@ -867,7 +867,7 @@ def bom_ref(self) -> BomRef:
         """
         return self._bom_ref
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
@@ -886,7 +886,7 @@ def supplier(self) -> Optional[OrganizationalEntity]:
     def supplier(self, supplier: Optional[OrganizationalEntity]) -> None:
         self._supplier = supplier
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
@@ -904,7 +904,7 @@ def author(self) -> Optional[str]:
     def author(self, author: Optional[str]) -> None:
         self._author = author
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def publisher(self) -> Optional[str]:
         """
@@ -919,7 +919,7 @@ def publisher(self) -> Optional[str]:
     def publisher(self, publisher: Optional[str]) -> None:
         self._publisher = publisher
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(4)
     def group(self) -> Optional[str]:
         """
@@ -938,7 +938,7 @@ def group(self) -> Optional[str]:
     def group(self, group: Optional[str]) -> None:
         self._group = group
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(5)
     def name(self) -> str:
         """
@@ -957,7 +957,7 @@ def name(self) -> str:
     def name(self, name: str) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.include_none(SchemaVersion1Dot0, "")
     @serializable.include_none(SchemaVersion1Dot1, "")
     @serializable.include_none(SchemaVersion1Dot2, "")
@@ -979,7 +979,7 @@ def version(self) -> Optional[str]:
     def version(self, version: Optional[str]) -> None:
         self._version = version
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(7)
     def description(self) -> Optional[str]:
         """
@@ -994,7 +994,7 @@ def description(self) -> Optional[str]:
     def description(self, description: Optional[str]) -> None:
         self._description = description
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(8)
     def scope(self) -> Optional[ComponentScope]:
         """
@@ -1011,7 +1011,7 @@ def scope(self) -> Optional[ComponentScope]:
     def scope(self, scope: Optional[ComponentScope]) -> None:
         self._scope = scope
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'hash')
     @serializable.xml_sequence(9)
     def hashes(self) -> "SortedSet[HashType]":
@@ -1027,7 +1027,7 @@ def hashes(self) -> "SortedSet[HashType]":
     def hashes(self, hashes: Iterable[HashType]) -> None:
         self._hashes = SortedSet(hashes)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot1)
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
@@ -1047,7 +1047,7 @@ def licenses(self) -> "SortedSet[LicenseChoice]":
     def licenses(self, licenses: Iterable[LicenseChoice]) -> None:
         self._licenses = SortedSet(licenses)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(11)
     def copyright(self) -> Optional[str]:
         """
@@ -1063,7 +1063,7 @@ def copyright(self) -> Optional[str]:
     def copyright(self, copyright: Optional[str]) -> None:
         self._copyright = copyright
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(12)
     def cpe(self) -> Optional[str]:
         """
@@ -1079,7 +1079,7 @@ def cpe(self) -> Optional[str]:
     def cpe(self, cpe: Optional[str]) -> None:
         self._cpe = cpe
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(PackageUrl)
     @serializable.xml_sequence(13)
     def purl(self) -> Optional[PackageURL]:
@@ -1098,7 +1098,7 @@ def purl(self) -> Optional[PackageURL]:
     def purl(self, purl: Optional[PackageURL]) -> None:
         self._purl = purl
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
@@ -1116,7 +1116,7 @@ def swid(self) -> Optional[Swid]:
     def swid(self, swid: Optional[Swid]) -> None:
         self._swid = swid
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot0)
     @serializable.xml_sequence(18)
     def modified(self) -> bool:
@@ -1126,7 +1126,7 @@ def modified(self) -> bool:
     def modified(self, modified: bool) -> None:
         self._modified = modified
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot1)
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
@@ -1146,7 +1146,7 @@ def pedigree(self) -> Optional[Pedigree]:
     def pedigree(self, pedigree: Optional[Pedigree]) -> None:
         self._pedigree = pedigree
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot1)
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
@@ -1167,7 +1167,7 @@ def external_references(self) -> "SortedSet[ExternalReference]":
     def external_references(self, external_references: Iterable[ExternalReference]) -> None:
         self._external_references = SortedSet(external_references)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
@@ -1186,7 +1186,7 @@ def properties(self) -> "SortedSet[Property]":
     def properties(self, properties: Iterable[Property]) -> None:
         self._properties = SortedSet(properties)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'component')
     @serializable.xml_sequence(19)
     def components(self) -> "SortedSet['Component']":
@@ -1204,7 +1204,7 @@ def components(self) -> "SortedSet['Component']":
     def components(self, components: Iterable['Component']) -> None:
         self._components = SortedSet(components)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_sequence(20)
@@ -1221,7 +1221,7 @@ def evidence(self) -> Optional[ComponentEvidence]:
     def evidence(self, evidence: Optional[ComponentEvidence]) -> None:
         self._evidence = evidence
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_sequence(21)
     def release_notes(self) -> Optional[ReleaseNotes]:
diff --git a/cyclonedx/model/dependency.py b/cyclonedx/model/dependency.py
index 141052375..d275b1600 100644
--- a/cyclonedx/model/dependency.py
+++ b/cyclonedx/model/dependency.py
@@ -60,7 +60,7 @@ def __init__(self, ref: BomRef, dependencies: Optional[Iterable["Dependency"]] =
         self.ref = ref
         self.dependencies = SortedSet(dependencies or [])
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(BomRefHelper)
     @serializable.xml_attribute()
     def ref(self) -> BomRef:
@@ -70,7 +70,7 @@ def ref(self) -> BomRef:
     def ref(self, ref: BomRef) -> None:
         self._ref = ref
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('dependsOn')
     @serializable.type_mapping(DependencyDependencies)
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'dependency')
diff --git a/cyclonedx/model/issue.py b/cyclonedx/model/issue.py
index 554f27723..8584fb0a5 100644
--- a/cyclonedx/model/issue.py
+++ b/cyclonedx/model/issue.py
@@ -120,7 +120,7 @@ def __init__(self, *, type: IssueClassification, id: Optional[str] = None, name:
         self.source = source
         self.references = references or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_attribute()
     def type(self) -> IssueClassification:
         """
@@ -135,7 +135,7 @@ def type(self) -> IssueClassification:
     def type(self, type: IssueClassification) -> None:
         self._type = type
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def id(self) -> Optional[str]:
         """
@@ -150,7 +150,7 @@ def id(self) -> Optional[str]:
     def id(self, id: Optional[str]) -> None:
         self._id = id
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def name(self) -> Optional[str]:
         """
@@ -165,7 +165,7 @@ def name(self) -> Optional[str]:
     def name(self, name: Optional[str]) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def description(self) -> Optional[str]:
         """
@@ -180,7 +180,7 @@ def description(self) -> Optional[str]:
     def description(self, description: Optional[str]) -> None:
         self._description = description
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(4)
     def source(self) -> Optional[IssueTypeSource]:
         """
@@ -195,7 +195,7 @@ def source(self) -> Optional[IssueTypeSource]:
     def source(self, source: Optional[IssueTypeSource]) -> None:
         self._source = source
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'url')
     @serializable.xml_sequence(5)
     def references(self) -> "SortedSet[XsUri]":
diff --git a/cyclonedx/model/release_note.py b/cyclonedx/model/release_note.py
index eb9423810..c5164352f 100644
--- a/cyclonedx/model/release_note.py
+++ b/cyclonedx/model/release_note.py
@@ -53,7 +53,7 @@ def __init__(self, *, type: str, title: Optional[str] = None, featured_image: Op
         self.notes = notes or []  # type: ignore
         self.properties = properties or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def type(self) -> str:
         """
@@ -79,7 +79,7 @@ def type(self) -> str:
     def type(self, type: str) -> None:
         self._type = type
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def title(self) -> Optional[str]:
         """
@@ -91,7 +91,7 @@ def title(self) -> Optional[str]:
     def title(self, title: Optional[str]) -> None:
         self._title = title
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def featured_image(self) -> Optional[XsUri]:
         """
@@ -103,7 +103,7 @@ def featured_image(self) -> Optional[XsUri]:
     def featured_image(self, featured_image: Optional[XsUri]) -> None:
         self._featured_image = featured_image
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(4)
     def social_image(self) -> Optional[XsUri]:
         """
@@ -115,7 +115,7 @@ def social_image(self) -> Optional[XsUri]:
     def social_image(self, social_image: Optional[XsUri]) -> None:
         self._social_image = social_image
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(5)
     def description(self) -> Optional[str]:
         """
@@ -127,7 +127,7 @@ def description(self) -> Optional[str]:
     def description(self, description: Optional[str]) -> None:
         self._description = description
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(serializable.helpers.XsdDateTime)
     @serializable.xml_sequence(6)
     def timestamp(self) -> Optional[datetime]:
@@ -140,7 +140,7 @@ def timestamp(self) -> Optional[datetime]:
     def timestamp(self, timestamp: Optional[datetime]) -> None:
         self._timestamp = timestamp
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'alias')
     @serializable.xml_sequence(7)
     def aliases(self) -> "SortedSet[str]":
@@ -157,7 +157,7 @@ def aliases(self) -> "SortedSet[str]":
     def aliases(self, aliases: Iterable[str]) -> None:
         self._aliases = SortedSet(aliases)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'tag')
     @serializable.xml_sequence(8)
     def tags(self) -> "SortedSet[str]":
@@ -173,7 +173,7 @@ def tags(self) -> "SortedSet[str]":
     def tags(self, tags: Iterable[str]) -> None:
         self._tags = SortedSet(tags)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'issue')
     @serializable.xml_sequence(9)
     def resolves(self) -> "SortedSet[IssueType]":
@@ -189,7 +189,7 @@ def resolves(self) -> "SortedSet[IssueType]":
     def resolves(self, resolves: Iterable[IssueType]) -> None:
         self._resolves = SortedSet(resolves)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'note')
     @serializable.xml_sequence(10)
     def notes(self) -> "SortedSet[Note]":
@@ -206,7 +206,7 @@ def notes(self) -> "SortedSet[Note]":
     def notes(self, notes: Iterable[Note]) -> None:
         self._notes = SortedSet(notes)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
     @serializable.xml_sequence(11)
     def properties(self) -> "SortedSet[Property]":
diff --git a/cyclonedx/model/service.py b/cyclonedx/model/service.py
index e951c31a6..7dbbccf75 100644
--- a/cyclonedx/model/service.py
+++ b/cyclonedx/model/service.py
@@ -65,7 +65,7 @@ def __init__(self, *, name: str, bom_ref: Optional[Union[str, BomRef]] = None,
                  services: Optional[Iterable['Service']] = None,
                  release_notes: Optional[ReleaseNotes] = None,
                  ) -> None:
-        if type(bom_ref) == BomRef:
+        if isinstance(bom_ref, BomRef):
             self._bom_ref = bom_ref
         else:
             self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else str(uuid4()))
@@ -84,7 +84,7 @@ def __init__(self, *, name: str, bom_ref: Optional[Union[str, BomRef]] = None,
         self.release_notes = release_notes
         self.properties = properties or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('bom-ref')
     @serializable.type_mapping(BomRefHelper)
     @serializable.xml_attribute()
@@ -101,7 +101,7 @@ def bom_ref(self) -> BomRef:
         """
         return self._bom_ref
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def provider(self) -> Optional[OrganizationalEntity]:
         """
@@ -116,7 +116,7 @@ def provider(self) -> Optional[OrganizationalEntity]:
     def provider(self, provider: Optional[OrganizationalEntity]) -> None:
         self._provider = provider
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def group(self) -> Optional[str]:
         """
@@ -132,7 +132,7 @@ def group(self) -> Optional[str]:
     def group(self, group: Optional[str]) -> None:
         self._group = group
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def name(self) -> str:
         """
@@ -147,7 +147,7 @@ def name(self) -> str:
     def name(self, name: str) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(4)
     def version(self) -> Optional[str]:
         """
@@ -162,7 +162,7 @@ def version(self) -> Optional[str]:
     def version(self, version: Optional[str]) -> None:
         self._version = version
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(5)
     def description(self) -> Optional[str]:
         """
@@ -177,7 +177,7 @@ def description(self) -> Optional[str]:
     def description(self, description: Optional[str]) -> None:
         self._description = description
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'endpoint')
     @serializable.xml_sequence(6)
     def endpoints(self) -> "SortedSet[XsUri]":
@@ -193,7 +193,7 @@ def endpoints(self) -> "SortedSet[XsUri]":
     def endpoints(self, endpoints: Iterable[XsUri]) -> None:
         self._endpoints = SortedSet(endpoints)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(7)
     def authenticated(self) -> Optional[bool]:
         """
@@ -211,7 +211,7 @@ def authenticated(self) -> Optional[bool]:
     def authenticated(self, authenticated: Optional[bool]) -> None:
         self._authenticated = authenticated
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('x-trust-boundary')
     @serializable.xml_name('x-trust-boundary')
     @serializable.xml_sequence(8)
@@ -231,7 +231,7 @@ def x_trust_boundary(self) -> Optional[bool]:
     def x_trust_boundary(self, x_trust_boundary: Optional[bool]) -> None:
         self._x_trust_boundary = x_trust_boundary
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'classification')
     @serializable.xml_sequence(9)
     def data(self) -> "SortedSet[DataClassification]":
@@ -247,7 +247,7 @@ def data(self) -> "SortedSet[DataClassification]":
     def data(self, data: Iterable[DataClassification]) -> None:
         self._data = SortedSet(data)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'licenses')
     @serializable.xml_sequence(10)
     def licenses(self) -> "SortedSet[LicenseChoice]":
@@ -263,7 +263,7 @@ def licenses(self) -> "SortedSet[LicenseChoice]":
     def licenses(self, licenses: Iterable[LicenseChoice]) -> None:
         self._licenses = SortedSet(licenses)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
     @serializable.xml_sequence(11)
     def external_references(self) -> "SortedSet[ExternalReference]":
@@ -279,7 +279,7 @@ def external_references(self) -> "SortedSet[ExternalReference]":
     def external_references(self, external_references: Iterable[ExternalReference]) -> None:
         self._external_references = SortedSet(external_references)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'service')
     @serializable.xml_sequence(13)
     def services(self) -> "SortedSet['Service']":
@@ -299,7 +299,7 @@ def services(self) -> "SortedSet['Service']":
     def services(self, services: Iterable['Service']) -> None:
         self._services = SortedSet(services)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_sequence(14)
     def release_notes(self) -> Optional[ReleaseNotes]:
@@ -315,7 +315,7 @@ def release_notes(self) -> Optional[ReleaseNotes]:
     def release_notes(self, release_notes: Optional[ReleaseNotes]) -> None:
         self._release_notes = release_notes
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py
index 66f6cbb94..07f284a34 100644
--- a/cyclonedx/model/vulnerability.py
+++ b/cyclonedx/model/vulnerability.py
@@ -77,7 +77,7 @@ def __init__(self, *, version: Optional[str] = None, range: Optional[str] = None
         self.range = range
         self.status = status
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def version(self) -> Optional[str]:
         """
@@ -89,7 +89,7 @@ def version(self) -> Optional[str]:
     def version(self, version: Optional[str]) -> None:
         self._version = version
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def range(self) -> Optional[str]:
         """
@@ -106,7 +106,7 @@ def range(self) -> Optional[str]:
     def range(self, range: Optional[str]) -> None:
         self._range = range
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def status(self) -> Optional[ImpactAnalysisAffectedStatus]:
         """
@@ -154,7 +154,7 @@ def __init__(self, *, ref: str, versions: Optional[Iterable[BomTargetVersionRang
         self.ref = ref
         self.versions = versions or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def ref(self) -> str:
         """
@@ -166,7 +166,7 @@ def ref(self) -> str:
     def ref(self, ref: str) -> None:
         self._ref = ref
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'version')
     @serializable.xml_sequence(2)
     def versions(self) -> "SortedSet[BomTargetVersionRange]":
@@ -222,7 +222,7 @@ def __init__(self, *, state: Optional[ImpactAnalysisState] = None,
         self.responses = responses or []  # type: ignore
         self.detail = detail
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def state(self) -> Optional[ImpactAnalysisState]:
         """
@@ -237,7 +237,7 @@ def state(self) -> Optional[ImpactAnalysisState]:
     def state(self, state: Optional[ImpactAnalysisState]) -> None:
         self._state = state
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def justification(self) -> Optional[ImpactAnalysisJustification]:
         """
@@ -252,7 +252,7 @@ def justification(self) -> Optional[ImpactAnalysisJustification]:
     def justification(self, justification: Optional[ImpactAnalysisJustification]) -> None:
         self._justification = justification
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('response')
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'response')
     @serializable.xml_sequence(3)
@@ -271,7 +271,7 @@ def responses(self) -> "SortedSet[ImpactAnalysisResponse]":
     def responses(self, responses: Iterable[ImpactAnalysisResponse]) -> None:
         self._responses = SortedSet(responses)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(4)
     def detail(self) -> Optional[str]:
         """
@@ -313,7 +313,7 @@ def __init__(self, *, url: XsUri, title: Optional[str] = None) -> None:
         self.title = title
         self.url = url
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def title(self) -> Optional[str]:
         """
@@ -325,7 +325,7 @@ def title(self) -> Optional[str]:
     def title(self, title: Optional[str]) -> None:
         self._title = title
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def url(self) -> XsUri:
         """
@@ -373,7 +373,7 @@ def __init__(self, *, name: Optional[str] = None, url: Optional[XsUri] = None) -
         self.name = name
         self.url = url
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def name(self) -> Optional[str]:
         """
@@ -385,7 +385,7 @@ def name(self) -> Optional[str]:
     def name(self, name: Optional[str]) -> None:
         self._name = name
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def url(self) -> Optional[XsUri]:
         """
@@ -436,7 +436,7 @@ def __init__(self, *, id: Optional[str] = None, source: Optional[VulnerabilitySo
         self.id = id
         self.source = source
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def id(self) -> Optional[str]:
         """
@@ -448,7 +448,7 @@ def id(self) -> Optional[str]:
     def id(self, id: Optional[str]) -> None:
         self._id = id
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def source(self) -> Optional[VulnerabilitySource]:
         """
@@ -644,7 +644,7 @@ def __init__(self, *, source: Optional[VulnerabilitySource] = None, score: Optio
         if vector and method:
             self.vector = method.get_localised_vector(vector=vector)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def source(self) -> Optional[VulnerabilitySource]:
         """
@@ -656,7 +656,7 @@ def source(self) -> Optional[VulnerabilitySource]:
     def source(self, source: Optional[VulnerabilitySource]) -> None:
         self._source = source
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.string_format('.1f')
     @serializable.xml_sequence(2)
     def score(self) -> Optional[Decimal]:
@@ -669,7 +669,7 @@ def score(self) -> Optional[Decimal]:
     def score(self, score: Optional[Decimal]) -> None:
         self._score = score
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(3)
     def severity(self) -> Optional[VulnerabilitySeverity]:
         """
@@ -681,7 +681,7 @@ def severity(self) -> Optional[VulnerabilitySeverity]:
     def severity(self, severity: Optional[VulnerabilitySeverity]) -> None:
         self._severity = severity
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(4)
     def method(self) -> Optional[VulnerabilityScoreSource]:
         """
@@ -693,7 +693,7 @@ def method(self) -> Optional[VulnerabilityScoreSource]:
     def method(self, score_source: Optional[VulnerabilityScoreSource]) -> None:
         self._method = score_source
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(5)
     def vector(self) -> Optional[str]:
         """
@@ -705,7 +705,7 @@ def vector(self) -> Optional[str]:
     def vector(self, vector: Optional[str]) -> None:
         self._vector = vector
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(6)
     def justification(self) -> Optional[str]:
         """
@@ -761,7 +761,7 @@ def __init__(self, *, organizations: Optional[Iterable[OrganizationalEntity]] =
         self.organizations = organizations or []  # type: ignore
         self.individuals = individuals or []  # type: ignore
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'organization')
     @serializable.xml_sequence(1)
     def organizations(self) -> "SortedSet[OrganizationalEntity]":
@@ -777,7 +777,7 @@ def organizations(self) -> "SortedSet[OrganizationalEntity]":
     def organizations(self, organizations: Iterable[OrganizationalEntity]) -> None:
         self._organizations = SortedSet(organizations)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'individual')
     @serializable.xml_sequence(2)
     def individuals(self) -> "SortedSet[OrganizationalContact]":
@@ -836,7 +836,7 @@ def __init__(self, *, bom_ref: Optional[Union[str, BomRef]] = None, id: Optional
                  # Deprecated Parameters kept for backwards compatibility
                  source_name: Optional[str] = None, source_url: Optional[str] = None,
                  recommendations: Optional[Iterable[str]] = None) -> None:
-        if type(bom_ref) == BomRef:
+        if isinstance(bom_ref, BomRef):
             self._bom_ref = bom_ref
         else:
             self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else str(uuid4()))
@@ -868,7 +868,7 @@ def __init__(self, *, bom_ref: Optional[Union[str, BomRef]] = None, id: Optional
             if not recommendation:
                 self.recommendation = next(iter(recommendations))
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.json_name('bom-ref')
     @serializable.type_mapping(BomRefHelper)
     @serializable.xml_attribute()
@@ -884,7 +884,7 @@ def bom_ref(self) -> BomRef:
         """
         return self._bom_ref
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(1)
     def id(self) -> Optional[str]:
         """
@@ -899,7 +899,7 @@ def id(self) -> Optional[str]:
     def id(self, id: Optional[str]) -> None:
         self._id = id
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(2)
     def source(self) -> Optional[VulnerabilitySource]:
         """
@@ -914,7 +914,7 @@ def source(self) -> Optional[VulnerabilitySource]:
     def source(self, source: Optional[VulnerabilitySource]) -> None:
         self._source = source
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
     @serializable.xml_sequence(3)
     def references(self) -> "SortedSet[VulnerabilityReference]":
@@ -933,7 +933,7 @@ def references(self) -> "SortedSet[VulnerabilityReference]":
     def references(self, references: Iterable[VulnerabilityReference]) -> None:
         self._references = SortedSet(references)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'rating')
     @serializable.xml_sequence(4)
     def ratings(self) -> "SortedSet[VulnerabilityRating]":
@@ -949,7 +949,7 @@ def ratings(self) -> "SortedSet[VulnerabilityRating]":
     def ratings(self, ratings: Iterable[VulnerabilityRating]) -> None:
         self._ratings = SortedSet(ratings)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'cwe')
     @serializable.xml_sequence(5)
     def cwes(self) -> "SortedSet[int]":
@@ -968,7 +968,7 @@ def cwes(self) -> "SortedSet[int]":
     def cwes(self, cwes: Iterable[int]) -> None:
         self._cwes = SortedSet(cwes)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(6)
     def description(self) -> Optional[str]:
         """
@@ -983,7 +983,7 @@ def description(self) -> Optional[str]:
     def description(self, description: Optional[str]) -> None:
         self._description = description
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(7)
     def detail(self) -> Optional[str]:
         """
@@ -999,7 +999,7 @@ def detail(self) -> Optional[str]:
     def detail(self, detail: Optional[str]) -> None:
         self._detail = detail
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(8)
     def recommendation(self) -> Optional[str]:
         """
@@ -1014,7 +1014,7 @@ def recommendation(self) -> Optional[str]:
     def recommendation(self, recommendation: Optional[str]) -> None:
         self._recommendation = recommendation
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'advisory')
     @serializable.xml_sequence(9)
     def advisories(self) -> "SortedSet[VulnerabilityAdvisory]":
@@ -1030,7 +1030,7 @@ def advisories(self) -> "SortedSet[VulnerabilityAdvisory]":
     def advisories(self, advisories: Iterable[VulnerabilityAdvisory]) -> None:
         self._advisories = SortedSet(advisories)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(serializable.helpers.XsdDateTime)
     @serializable.xml_sequence(10)
     def created(self) -> Optional[datetime]:
@@ -1046,7 +1046,7 @@ def created(self) -> Optional[datetime]:
     def created(self, created: Optional[datetime]) -> None:
         self._created = created
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(serializable.helpers.XsdDateTime)
     @serializable.xml_sequence(11)
     def published(self) -> Optional[datetime]:
@@ -1062,7 +1062,7 @@ def published(self) -> Optional[datetime]:
     def published(self, published: Optional[datetime]) -> None:
         self._published = published
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.type_mapping(serializable.helpers.XsdDateTime)
     @serializable.xml_sequence(12)
     def updated(self) -> Optional[datetime]:
@@ -1078,7 +1078,7 @@ def updated(self) -> Optional[datetime]:
     def updated(self, updated: Optional[datetime]) -> None:
         self._updated = updated
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(13)
     def credits(self) -> Optional[VulnerabilityCredits]:
         """
@@ -1093,7 +1093,7 @@ def credits(self) -> Optional[VulnerabilityCredits]:
     def credits(self, credits: Optional[VulnerabilityCredits]) -> None:
         self._credits = credits
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'tool')
     @serializable.xml_sequence(14)
     def tools(self) -> "SortedSet[Tool]":
@@ -1109,7 +1109,7 @@ def tools(self) -> "SortedSet[Tool]":
     def tools(self, tools: Iterable[Tool]) -> None:
         self._tools = SortedSet(tools)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_sequence(15)
     def analysis(self) -> Optional[VulnerabilityAnalysis]:
         """
@@ -1124,7 +1124,7 @@ def analysis(self) -> Optional[VulnerabilityAnalysis]:
     def analysis(self, analysis: Optional[VulnerabilityAnalysis]) -> None:
         self._analysis = analysis
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'target')
     @serializable.xml_sequence(16)
     def affects(self) -> "SortedSet[BomTarget]":
@@ -1140,7 +1140,7 @@ def affects(self) -> "SortedSet[BomTarget]":
     def affects(self, affects_targets: Iterable[BomTarget]) -> None:
         self._affects = SortedSet(affects_targets)
 
-    @property  # type: ignore[misc]
+    @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
     @serializable.xml_sequence(17)
     def properties(self) -> "SortedSet[Property]":
diff --git a/pyproject.toml b/pyproject.toml
index 097b08f11..8f889159c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -36,7 +36,6 @@ classifiers = [
   'Topic :: Software Development',
   'Topic :: System :: Software Distribution',
   'License :: OSI Approved :: Apache Software License',
-  'Programming Language :: Python :: 3.7',
   'Programming Language :: Python :: 3.8',
   'Programming Language :: Python :: 3.9',
   'Programming Language :: Python :: 3.10',
@@ -52,7 +51,7 @@ keywords = [
 
 [tool.poetry.dependencies]
 # ATTENTION: keep `deps.lowest.r` file in sync
-python = "^3.7"
+python = "^3.8"
 packageurl-python = ">= 0.11"
 py-serializable = "^0.11.1"
 sortedcontainers = "^2.4.0"
@@ -60,16 +59,17 @@ license-expression = "^30"
 
 [tool.poetry.dev-dependencies]
 ddt = "1.6.0"
-coverage = "7.2.7"
-flake8 = "5.0.4" # last version supporting Python 3.7
-flake8-annotations = "2.9.1" # last version supporting Python 3.7
-flake8-bugbear = "22.12.6" # last version supporting Python 3.7
-flake8-isort = "4.2.0"
-isort = "5.11.5" # last version supporting Python 3.7
+coverage = "7.3.1"
+flake8 = { version="6.1.0", python=">=3.8.1" }
+flake8-annotations = { version="3.0.1", python=">=3.8.1" }
+flake8-bugbear = { version="23.9.16", python=">=3.8.1" }
+flake8-isort = "6.1.0 "
+isort = "5.12.0"
+autopep8 = "2.0.4"
 jsonschema = "4.17.3"
-mypy = "1.4.1"
+mypy = "1.5.1"
 lxml = "4.9.3"
-tox = "3.28.0"
+tox = "4.11.3"
 xmldiff = "2.6.3"
 
 [tool.semantic_release]
diff --git a/tests/base.py b/tests/base.py
index c844396c8..1727fa35e 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -45,22 +45,19 @@
 class BaseJsonTestCase(TestCase):
 
     def assertValidAgainstSchema(self, bom_json: str, schema_version: SchemaVersion) -> None:
-        if sys.version_info >= (3, 7):
-            schema_fn = os.path.join(
-                CDX_SCHEMA_DIRECTORY,
-                f'bom-{schema_version.name.replace("_", ".").replace("V", "")}.schema.json'
-            )
-            with open(schema_fn) as schema_fd:
-                schema_doc = json.load(schema_fd)
-
-            try:
-                json_validate(instance=json.loads(bom_json), schema=schema_doc)
-            except ValidationError as e:
-                self.assertTrue(False, f'Failed to validate SBOM against JSON schema: {str(e)}')
-
-            self.assertTrue(True)
-        else:
-            self.assertTrue(True, 'JSON Schema Validation is not possible in Python < 3.7')
+        schema_fn = os.path.join(
+            CDX_SCHEMA_DIRECTORY,
+            f'bom-{schema_version.name.replace("_", ".").replace("V", "")}.schema.json'
+        )
+        with open(schema_fn) as schema_fd:
+            schema_doc = json.load(schema_fd)
+
+        try:
+            json_validate(instance=json.loads(bom_json), schema=schema_doc)
+        except ValidationError as e:
+            self.assertTrue(False, f'Failed to validate SBOM against JSON schema: {str(e)}')
+
+        self.assertTrue(True)
 
     @staticmethod
     def _sort_json_dict(item: object) -> Any:
diff --git a/tox.ini b/tox.ini
index de97d0e62..5f6bc97eb 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,12 +4,11 @@
 # and then run "tox" from this directory.
 
 [tox]
-minversion = 3.10
+minversion = 4.0
 envlist =
     flake8
     mypy-{locked,lowest}
-    py{311,310,39,38,37}-{locked,lowest}
-isolated_build = True
+    py{311,310,39,38}-{locked,lowest}
 skip_missing_interpreters = True
 usedevelop = False
 download = False
@@ -17,7 +16,7 @@ download = False
 [testenv]
 # settings in this category apply to all other testenv, if not overwritten
 skip_install = True
-whitelist_externals = poetry
+allowlist_externals = poetry
 commands_pre =
     {envpython} --version
     poetry install -v
@@ -33,11 +32,11 @@ setenv =
 commands =
     # mypy config is in own file: `.mypy.ini`
     !lowest: poetry run mypy
-     lowest: poetry run mypy --python-version=3.7
+     lowest: poetry run mypy --python-version=3.8
 
 [testenv:flake8]
 commands =
-    poetry run flake8 cyclonedx/ tests/
+    poetry run flake8 cyclonedx/ tests/ typings/
 
 [flake8]
 ## keep in sync with isort config - in `isort.cfg` file
@@ -54,3 +53,4 @@ ignore =
     ANN101,ANN102
     # ignore ANN401 for dynamically typed *args and **kwargs
     ANN401
+    B028

From 5cb695ebf9989f9bdefaa6823f5814d5c2fe9998 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Tue, 19 Sep 2023 11:08:21 +0200
Subject: [PATCH 03/42] chore(build): test before release

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .github/workflows/release.yml | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index bc3415e2d..c770a7c9e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -42,7 +42,31 @@ env:
   POETRY_VERSION: "1.4.1"
 
 jobs:
+  quicktest:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout code
+        # see https://github.com/actions/checkout
+        uses: actions/checkout@v4
+      - name: Setup Python Environment
+        # see https://github.com/actions/setup-python
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ env.PYTHON_VERSION_DEFAULT }}
+          architecture: 'x64'
+      - name: Install poetry
+        # see https://github.com/marketplace/actions/setup-poetry
+        uses: Gr1N/setup-poetry@v8
+        with:
+          poetry-version: ${{ env.POETRY_VERSION }}
+      - name: Install dependencies
+        run: poetry install --no-root
+      - name: Run tox
+        run: poetry run tox run -e py -s false
+
   release:
+    needs:
+      - quicktest
     # https://github.community/t/how-do-i-specify-job-dependency-running-in-another-workflow/16482
     # limit this to being run on regular commits, not the commits that semantic-release will create
     # but also allow manual workflow dispatch

From a4f5ec5d63d576c04bcef5c0b6641f6c47164cfb Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Tue, 19 Sep 2023 18:21:10 +0200
Subject: [PATCH 04/42] feat: add CycloneDX document validators to public API
 (#433)

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .github/workflows/python.yml                  |   40 +-
 .isort.cfg                                    |    2 +
 CONTRIBUTING.md                               |    4 +-
 cyclonedx/exception/__init__.py               |    5 +
 cyclonedx/schema/_res/.editorconfig           |   10 +
 cyclonedx/schema/_res/.gitattributes          |    6 +
 cyclonedx/schema/_res/README.md               |   30 +
 cyclonedx/schema/_res/__init__.py             |   60 +
 .../bom-1.0.SNAPSHOT.xsd}                     |    4 +-
 .../bom-1.1.SNAPSHOT.xsd}                     |   11 +-
 .../bom-1.2-strict.SNAPSHOT.schema.json}      |   20 +-
 .../bom-1.2.SNAPSHOT.schema.json}             |   25 +-
 .../bom-1.2.SNAPSHOT.xsd}                     |   17 +-
 .../bom-1.3-strict.SNAPSHOT.schema.json}      |   19 +-
 .../bom-1.3.SNAPSHOT.schema.json}             |   27 +-
 .../bom-1.3.SNAPSHOT.xsd}                     |   23 +-
 .../bom-1.4.SNAPSHOT.schema.json}             |   15 +-
 .../bom-1.4.SNAPSHOT.xsd}                     |   10 +-
 .../schema/_res/jsf-0.82.SNAPSHOT.schema.json |  240 ++
 .../spdx.SNAPSHOT.schema.json}                | 1057 +++----
 .../{spdx.xsd => _res/spdx.SNAPSHOT.xsd}      | 2521 ++++++++++-------
 cyclonedx/schema/bom-1.2-strict.schema.json   | 1020 -------
 cyclonedx/schema/bom-1.3-strict.schema.json   | 1085 -------
 cyclonedx/schema/bom-1.3.proto                |  452 ---
 cyclonedx/schema/ext/bom-descriptor-0.9.xsd   |  175 --
 cyclonedx/schema/ext/bom-descriptor-1.0.xsd   |  183 --
 cyclonedx/schema/ext/dependency-graph-1.0.xsd |   70 -
 .../vulnerability-1.0-SNAPSHOT.schema.json    |  182 --
 cyclonedx/schema/ext/vulnerability-1.0.xsd    |  291 --
 cyclonedx/spdx.py                             |    5 +-
 cyclonedx/validation/__init__.py              |   73 +
 cyclonedx/validation/json.py                  |  112 +
 cyclonedx/validation/xml.py                   |   84 +
 deps.lowest.r                                 |    7 -
 docs/conf.py                                  |    5 +-
 docs/contributing.rst                         |   84 +-
 docs/examples.rst                             |    6 +-
 docs/install.rst                              |   18 +
 docs/requirements.txt                         |    6 +-
 .../{build_and_serialize.py => complex.py}    |   34 +-
 pyproject.toml                                |   18 +-
 tests/__init__.py                             |    6 +-
 tests/_data/own/.gitattributes                |    2 +
 tests/{fixtures => _data/own}/README.md       |    0
 .../own}/json/1.2/bom_dependencies.json       |    0
 .../json/1.2/bom_dependencies_component.json  |    0
 .../json/1.2/bom_external_references.json     |    0
 .../json/1.2/bom_issue_275_components.json    |    0
 .../json/1.2/bom_issue_328_components.json    |    0
 .../own}/json/1.2/bom_services_complex.json   |    0
 .../own}/json/1.2/bom_services_nested.json    |    0
 .../own}/json/1.2/bom_services_simple.json    |    0
 .../own}/json/1.2/bom_setuptools.json         |    0
 .../json/1.2/bom_setuptools_complete.json     |    0
 .../json/1.2/bom_setuptools_no_version.json   |    0
 .../json/1.2/bom_setuptools_with_cpe.json     |    0
 .../own}/json/1.2/bom_toml_1.json             |    0
 .../own}/json/1.2/bom_with_full_metadata.json |    0
 .../own}/json/1.3/bom_dependencies.json       |    0
 .../json/1.3/bom_dependencies_component.json  |    0
 .../json/1.3/bom_external_references.json     |    0
 .../json/1.3/bom_issue_275_components.json    |    0
 .../json/1.3/bom_issue_328_components.json    |    0
 .../own}/json/1.3/bom_services_complex.json   |    0
 .../own}/json/1.3/bom_services_nested.json    |    0
 .../own}/json/1.3/bom_services_simple.json    |    0
 .../own}/json/1.3/bom_setuptools.json         |    0
 .../json/1.3/bom_setuptools_complete.json     |    0
 .../json/1.3/bom_setuptools_no_version.json   |    0
 .../json/1.3/bom_setuptools_with_cpe.json     |    0
 .../own}/json/1.3/bom_toml_1.json             |    0
 .../own}/json/1.3/bom_with_full_metadata.json |    0
 .../own}/json/1.4/bom_dependencies.json       |    0
 .../json/1.4/bom_dependencies_component.json  |    0
 .../json/1.4/bom_external_references.json     |    0
 .../json/1.4/bom_issue_275_components.json    |    0
 .../json/1.4/bom_issue_328_components.json    |    0
 .../own}/json/1.4/bom_services_complex.json   |    0
 .../own}/json/1.4/bom_services_nested.json    |    0
 .../own}/json/1.4/bom_services_simple.json    |    0
 .../own}/json/1.4/bom_setuptools.json         |    0
 .../json/1.4/bom_setuptools_complete.json     |    0
 .../json/1.4/bom_setuptools_no_version.json   |    0
 .../json/1.4/bom_setuptools_with_cpe.json     |    0
 .../bom_setuptools_with_release_notes.json    |    0
 .../bom_setuptools_with_vulnerabilities.json  |    0
 .../own}/json/1.4/bom_toml_1.json             |    0
 .../1.4/bom_with_dependencies_hanging.json    |    0
 .../own}/json/1.4/bom_with_full_metadata.json |    0
 .../own}/xml/1.0/bom_empty.xml                |    0
 .../own}/xml/1.0/bom_issue_275_components.xml |    0
 .../own}/xml/1.0/bom_issue_328_components.xml |    0
 .../own}/xml/1.0/bom_setuptools.xml           |    0
 .../own}/xml/1.0/bom_setuptools_complete.xml  |    0
 .../xml/1.0/bom_setuptools_no_version.xml     |    0
 .../own}/xml/1.0/bom_setuptools_with_cpe.xml  |    0
 .../1.0/bom_toml_hashes_and_references.xml    |    0
 .../own}/xml/1.1/bom_dependencies.xml         |    0
 .../own}/xml/1.1/bom_empty.xml                |    0
 .../own}/xml/1.1/bom_external_references.xml  |    0
 .../own}/xml/1.1/bom_issue_275_components.xml |    0
 .../own}/xml/1.1/bom_issue_328_components.xml |    0
 .../own}/xml/1.1/bom_setuptools.xml           |    0
 .../own}/xml/1.1/bom_setuptools_complete.xml  |    0
 .../xml/1.1/bom_setuptools_no_version.xml     |    0
 .../own}/xml/1.1/bom_setuptools_with_cpe.xml  |    0
 .../bom_setuptools_with_vulnerabilities.xml   |    0
 .../1.1/bom_toml_hashes_and_references.xml    |    0
 .../own}/xml/1.2/bom_dependencies.xml         |    0
 .../xml/1.2/bom_dependencies_component.xml    |    0
 .../own}/xml/1.2/bom_external_references.xml  |    0
 .../own}/xml/1.2/bom_issue_275_components.xml |    0
 .../own}/xml/1.2/bom_issue_328_components.xml |    0
 .../own}/xml/1.2/bom_services_complex.xml     |    0
 .../own}/xml/1.2/bom_services_nested.xml      |    0
 .../own}/xml/1.2/bom_services_simple.xml      |    0
 .../own}/xml/1.2/bom_setuptools.xml           |    0
 .../own}/xml/1.2/bom_setuptools_complete.xml  |    0
 .../xml/1.2/bom_setuptools_no_version.xml     |    0
 .../own}/xml/1.2/bom_setuptools_with_cpe.xml  |    0
 .../bom_setuptools_with_vulnerabilities.xml   |    0
 .../1.2/bom_toml_hashes_and_references.xml    |    0
 .../own}/xml/1.2/bom_with_full_metadata.xml   |    0
 .../own}/xml/1.3/bom_dependencies.xml         |    0
 .../xml/1.3/bom_dependencies_component.xml    |    0
 .../own}/xml/1.3/bom_external_references.xml  |    0
 .../own}/xml/1.3/bom_issue_275_components.xml |    0
 .../own}/xml/1.3/bom_issue_328_components.xml |    0
 .../own}/xml/1.3/bom_services_complex.xml     |    0
 .../own}/xml/1.3/bom_services_nested.xml      |    0
 .../own}/xml/1.3/bom_services_simple.xml      |    0
 .../own}/xml/1.3/bom_setuptools.xml           |    0
 .../own}/xml/1.3/bom_setuptools_complete.xml  |    0
 .../xml/1.3/bom_setuptools_no_version.xml     |    0
 .../own}/xml/1.3/bom_setuptools_with_cpe.xml  |    0
 .../bom_setuptools_with_vulnerabilities.xml   |    0
 .../1.3/bom_toml_hashes_and_references.xml    |    0
 .../own}/xml/1.3/bom_with_full_metadata.xml   |    0
 .../own}/xml/1.4/bom_dependencies.xml         |    0
 .../xml/1.4/bom_dependencies_component.xml    |    0
 .../own}/xml/1.4/bom_external_references.xml  |    0
 .../own}/xml/1.4/bom_issue_275_components.xml |    0
 .../own}/xml/1.4/bom_issue_328_components.xml |    0
 .../own}/xml/1.4/bom_services_complex.xml     |    0
 .../own}/xml/1.4/bom_services_nested.xml      |    0
 .../own}/xml/1.4/bom_services_simple.xml      |    0
 .../own}/xml/1.4/bom_setuptools.xml           |    0
 .../own}/xml/1.4/bom_setuptools_complete.xml  |    0
 .../xml/1.4/bom_setuptools_no_version.xml     |    0
 .../own}/xml/1.4/bom_setuptools_with_cpe.xml  |    0
 .../1.4/bom_setuptools_with_release_notes.xml |    0
 .../bom_setuptools_with_vulnerabilities.xml   |    0
 .../1.4/bom_toml_hashes_and_references.xml    |    0
 .../xml/1.4/bom_with_dependencies_hanging.xml |    0
 .../own}/xml/1.4/bom_with_full_metadata.xml   |    0
 .../own}/xml/1.4/webgoat-6.1.xml              |    0
 tests/_data/schemaTestData/.gitattributes     |    2 +
 .../schemaTestData/1.0/valid-bom-1.0.xml      |   69 +
 .../1.0/valid-component-hashes-1.0.xml        |   19 +
 .../1.1/invalid-component-ref-1.1.xml         |   15 +
 .../1.1/invalid-component-type-1.1.xml        |    9 +
 .../1.1/invalid-empty-component-1.1.xml       |    7 +
 .../1.1/invalid-hash-alg-1.1.xml              |   16 +
 .../1.1/invalid-hash-md5-1.1.xml              |   16 +
 .../1.1/invalid-hash-sha1-1.1.xml             |   16 +
 .../1.1/invalid-hash-sha256-1.1.xml           |   16 +
 .../1.1/invalid-hash-sha512-1.1.xml           |   16 +
 .../1.1/invalid-license-choice-1.1.xml        |   26 +
 .../1.1/invalid-license-encoding-1.1.xml      |   27 +
 .../1.1/invalid-license-id-1.1.xml            |   27 +
 .../1.1/invalid-license-id-count-1.1.xml      |   27 +
 .../1.1/invalid-license-name-count-1.1.xml    |   27 +
 .../invalid-missing-component-type-1.1.xml    |    9 +
 .../1.1/invalid-namespace-1.1.xml             |  118 +
 .../schemaTestData/1.1/invalid-scope-1.1.xml  |   10 +
 .../1.1/invalid-serialnumber-1.1.xml          |  118 +
 .../schemaTestData/1.1/valid-bom-1.1.xml      |  118 +
 .../1.1/valid-component-hashes-1.1.xml        |   18 +
 .../1.1/valid-component-ref-1.1.xml           |   19 +
 .../1.1/valid-component-types-1.1.xml         |   29 +
 .../1.1/valid-empty-components-1.1.xml        |    5 +
 .../1.1/valid-external-elements-1.1.xml       |  158 ++
 .../1.1/valid-license-expression-1.1.xml      |   23 +
 .../1.1/valid-license-id-1.1.xml              |   25 +
 .../1.1/valid-license-name-1.1.xml            |   25 +
 .../1.1/valid-minimal-viable-1.1.xml          |    9 +
 .../1.1/valid-random-attributes-1.1.xml       |  118 +
 .../1.1/valid-xml-signature-1.1.xml           |  177 ++
 .../1.2/invalid-bomformat-1.2.json            |    8 +
 .../1.2/invalid-component-ref-1.2.json        |   20 +
 .../1.2/invalid-component-ref-1.2.xml         |   15 +
 .../1.2/invalid-component-swid-1.2.json       |   18 +
 .../1.2/invalid-component-swid-1.2.xml        |   11 +
 .../1.2/invalid-component-type-1.2.json       |   13 +
 .../1.2/invalid-component-type-1.2.xml        |    9 +
 .../1.2/invalid-dependency-1.2.json           |   37 +
 .../1.2/invalid-dependency-1.2.xml            |   23 +
 .../1.2/invalid-empty-component-1.2.xml       |    7 +
 .../1.2/invalid-hash-alg-1.2.json             |   32 +
 .../1.2/invalid-hash-alg-1.2.xml              |   16 +
 .../1.2/invalid-hash-md5-1.2.json             |   32 +
 .../1.2/invalid-hash-md5-1.2.xml              |   16 +
 .../1.2/invalid-hash-sha1-1.2.json            |   32 +
 .../1.2/invalid-hash-sha1-1.2.xml             |   16 +
 .../1.2/invalid-hash-sha256-1.2.json          |   32 +
 .../1.2/invalid-hash-sha256-1.2.xml           |   16 +
 .../1.2/invalid-hash-sha512-1.2.json          |   32 +
 .../1.2/invalid-hash-sha512-1.2.xml           |   16 +
 .../1.2/invalid-issue-type-1.2.json           |   48 +
 .../1.2/invalid-issue-type-1.2.xml            |   37 +
 .../1.2/invalid-license-choice-1.2.json       |   23 +
 .../1.2/invalid-license-choice-1.2.xml        |   26 +
 .../1.2/invalid-license-encoding-1.2.json     |   28 +
 .../1.2/invalid-license-encoding-1.2.xml      |   27 +
 .../1.2/invalid-license-id-1.2.json           |   22 +
 .../1.2/invalid-license-id-1.2.xml            |   27 +
 .../1.2/invalid-license-id-count-1.2.xml      |   27 +
 .../1.2/invalid-license-name-count-1.2.xml    |   27 +
 .../1.2/invalid-metadata-timestamp-1.2.json   |   10 +
 .../1.2/invalid-metadata-timestamp-1.2.xml    |    7 +
 .../invalid-missing-component-type-1.2.xml    |    9 +
 .../1.2/invalid-namespace-1.2.xml             |  118 +
 .../1.2/invalid-patch-type-1.2.json           |   48 +
 .../1.2/invalid-patch-type-1.2.xml            |   37 +
 .../schemaTestData/1.2/invalid-scope-1.2.json |   14 +
 .../schemaTestData/1.2/invalid-scope-1.2.xml  |   10 +
 .../1.2/invalid-serialnumber-1.2.json         |    8 +
 .../1.2/invalid-serialnumber-1.2.xml          |  118 +
 .../1.2/invalid-service-data-1.2.json         |   20 +
 .../1.2/invalid-service-data-1.2.xml          |   11 +
 .../1.2/skip_invalid-empty-component-1.2.json |   12 +
 ...ip_invalid-missing-component-type-1.2.json |   13 +
 .../1.2/valid-assembly-1.2.json               |   30 +
 .../schemaTestData/1.2/valid-assembly-1.2.xml |   25 +
 .../schemaTestData/1.2/valid-bom-1.2.json     |  177 ++
 .../schemaTestData/1.2/valid-bom-1.2.xml      |  181 ++
 .../1.2/valid-component-hashes-1.2.json       |   63 +
 .../1.2/valid-component-hashes-1.2.xml        |   23 +
 .../1.2/valid-component-ref-1.2.json          |   20 +
 .../1.2/valid-component-ref-1.2.xml           |   19 +
 .../1.2/valid-component-swid-1.2.json         |   19 +
 .../1.2/valid-component-swid-1.2.xml          |   11 +
 .../1.2/valid-component-swid-full-1.2.json    |   24 +
 .../1.2/valid-component-swid-full-1.2.xml     |   13 +
 .../1.2/valid-component-types-1.2.json        |   48 +
 .../1.2/valid-component-types-1.2.xml         |   37 +
 .../1.2/valid-dependency-1.2.json             |   38 +
 .../1.2/valid-dependency-1.2.xml              |   23 +
 .../1.2/valid-empty-components-1.2.json       |    8 +
 .../1.2/valid-empty-components-1.2.xml        |    5 +
 .../1.2/valid-external-elements-1.2.xml       |  158 ++
 .../1.2/valid-license-expression-1.2.json     |   20 +
 .../1.2/valid-license-expression-1.2.xml      |   23 +
 .../1.2/valid-license-id-1.2.json             |   22 +
 .../1.2/valid-license-id-1.2.xml              |   25 +
 .../1.2/valid-license-name-1.2.json           |   22 +
 .../1.2/valid-license-name-1.2.xml            |   25 +
 .../1.2/valid-metadata-author-1.2.json        |   16 +
 .../1.2/valid-metadata-author-1.2.xml         |   13 +
 .../1.2/valid-metadata-manufacture-1.2.json   |   21 +
 .../1.2/valid-metadata-manufacture-1.2.xml    |   14 +
 .../1.2/valid-metadata-supplier-1.2.json      |   21 +
 .../1.2/valid-metadata-supplier-1.2.xml       |   14 +
 .../1.2/valid-metadata-timestamp-1.2.json     |   10 +
 .../1.2/valid-metadata-timestamp-1.2.xml      |    7 +
 .../1.2/valid-metadata-tool-1.2.json          |   26 +
 .../1.2/valid-metadata-tool-1.2.xml           |   17 +
 .../1.2/valid-minimal-viable-1.2.json         |   13 +
 .../1.2/valid-minimal-viable-1.2.xml          |    9 +
 .../schemaTestData/1.2/valid-patch-1.2.json   |   88 +
 .../schemaTestData/1.2/valid-patch-1.2.xml    |   70 +
 .../1.2/valid-random-attributes-1.2.xml       |  118 +
 .../schemaTestData/1.2/valid-service-1.2.json |  101 +
 .../schemaTestData/1.2/valid-service-1.2.xml  |   66 +
 .../1.2/valid-service-empty-objects-1.2.json  |   22 +
 .../1.2/valid-service-empty-objects-1.2.xml   |   16 +
 .../1.2/valid-xml-signature-1.2.xml           |  177 ++
 .../1.3/invalid-bomformat-1.3.json            |    8 +
 .../1.3/invalid-component-ref-1.3.json        |   20 +
 .../1.3/invalid-component-ref-1.3.xml         |   15 +
 .../1.3/invalid-component-swid-1.3.json       |   18 +
 .../1.3/invalid-component-swid-1.3.xml        |   11 +
 .../1.3/invalid-component-type-1.3.json       |   13 +
 .../1.3/invalid-component-type-1.3.xml        |    9 +
 .../1.3/invalid-dependency-1.3.json           |   37 +
 .../1.3/invalid-dependency-1.3.xml            |   23 +
 .../1.3/invalid-empty-component-1.3.json      |   11 +
 .../1.3/invalid-empty-component-1.3.xml       |    7 +
 .../1.3/invalid-hash-alg-1.3.json             |   32 +
 .../1.3/invalid-hash-alg-1.3.xml              |   16 +
 .../1.3/invalid-hash-md5-1.3.json             |   32 +
 .../1.3/invalid-hash-md5-1.3.xml              |   16 +
 .../1.3/invalid-hash-sha1-1.3.json            |   32 +
 .../1.3/invalid-hash-sha1-1.3.xml             |   16 +
 .../1.3/invalid-hash-sha256-1.3.json          |   32 +
 .../1.3/invalid-hash-sha256-1.3.xml           |   16 +
 .../1.3/invalid-hash-sha512-1.3.json          |   32 +
 .../1.3/invalid-hash-sha512-1.3.xml           |   16 +
 .../1.3/invalid-issue-type-1.3.json           |   48 +
 .../1.3/invalid-issue-type-1.3.xml            |   37 +
 .../1.3/invalid-license-choice-1.3.json       |   23 +
 .../1.3/invalid-license-choice-1.3.xml        |   26 +
 .../1.3/invalid-license-encoding-1.3.json     |   28 +
 .../1.3/invalid-license-encoding-1.3.xml      |   27 +
 .../1.3/invalid-license-id-1.3.json           |   22 +
 .../1.3/invalid-license-id-1.3.xml            |   27 +
 .../1.3/invalid-license-id-count-1.3.xml      |   27 +
 .../1.3/invalid-license-name-count-1.3.xml    |   27 +
 .../1.3/invalid-metadata-license-1.3.json     |   16 +
 .../1.3/invalid-metadata-license-1.3.xml      |   11 +
 .../1.3/invalid-metadata-timestamp-1.3.json   |   10 +
 .../1.3/invalid-metadata-timestamp-1.3.xml    |    7 +
 .../invalid-missing-component-type-1.3.json   |   12 +
 .../invalid-missing-component-type-1.3.xml    |    9 +
 .../1.3/invalid-namespace-1.3.xml             |  118 +
 .../1.3/invalid-patch-type-1.3.json           |   48 +
 .../1.3/invalid-patch-type-1.3.xml            |   37 +
 .../schemaTestData/1.3/invalid-scope-1.3.json |   14 +
 .../schemaTestData/1.3/invalid-scope-1.3.xml  |   10 +
 .../1.3/invalid-serialnumber-1.3.json         |    8 +
 .../1.3/invalid-serialnumber-1.3.xml          |  118 +
 .../1.3/invalid-service-data-1.3.json         |   20 +
 .../1.3/invalid-service-data-1.3.xml          |   11 +
 .../1.3/valid-assembly-1.3.json               |   30 +
 .../schemaTestData/1.3/valid-assembly-1.3.xml |   25 +
 .../schemaTestData/1.3/valid-bom-1.3.json     |  177 ++
 .../schemaTestData/1.3/valid-bom-1.3.xml      |  181 ++
 .../1.3/valid-component-hashes-1.3.json       |   63 +
 .../1.3/valid-component-hashes-1.3.xml        |   23 +
 .../1.3/valid-component-ref-1.3.json          |   20 +
 .../1.3/valid-component-ref-1.3.xml           |   19 +
 .../1.3/valid-component-swid-1.3.json         |   19 +
 .../1.3/valid-component-swid-1.3.xml          |   11 +
 .../1.3/valid-component-swid-full-1.3.json    |   24 +
 .../1.3/valid-component-swid-full-1.3.xml     |   13 +
 .../1.3/valid-component-types-1.3.json        |   48 +
 .../1.3/valid-component-types-1.3.xml         |   37 +
 .../1.3/valid-compositions-1.3.json           |   65 +
 .../1.3/valid-compositions-1.3.xml            |   51 +
 .../1.3/valid-dependency-1.3.json             |   38 +
 .../1.3/valid-dependency-1.3.xml              |   23 +
 .../1.3/valid-empty-components-1.3.json       |    8 +
 .../1.3/valid-empty-components-1.3.xml        |    5 +
 .../1.3/valid-evidence-1.3.json               |   53 +
 .../schemaTestData/1.3/valid-evidence-1.3.xml |   35 +
 .../1.3/valid-external-elements-1.3.xml       |  158 ++
 .../1.3/valid-external-reference-1.3.json     |   38 +
 .../1.3/valid-external-reference-1.3.xml      |   27 +
 .../1.3/valid-license-expression-1.3.json     |   20 +
 .../1.3/valid-license-expression-1.3.xml      |   23 +
 .../1.3/valid-license-id-1.3.json             |   22 +
 .../1.3/valid-license-id-1.3.xml              |   25 +
 .../1.3/valid-license-name-1.3.json           |   22 +
 .../1.3/valid-license-name-1.3.xml            |   25 +
 .../1.3/valid-metadata-author-1.3.json        |   16 +
 .../1.3/valid-metadata-author-1.3.xml         |   13 +
 .../1.3/valid-metadata-license-1.3.json       |   16 +
 .../1.3/valid-metadata-license-1.3.xml        |   11 +
 .../1.3/valid-metadata-manufacture-1.3.json   |   21 +
 .../1.3/valid-metadata-manufacture-1.3.xml    |   14 +
 .../1.3/valid-metadata-supplier-1.3.json      |   21 +
 .../1.3/valid-metadata-supplier-1.3.xml       |   14 +
 .../1.3/valid-metadata-timestamp-1.3.json     |   10 +
 .../1.3/valid-metadata-timestamp-1.3.xml      |    7 +
 .../1.3/valid-metadata-tool-1.3.json          |   26 +
 .../1.3/valid-metadata-tool-1.3.xml           |   17 +
 .../1.3/valid-minimal-viable-1.3.json         |   13 +
 .../1.3/valid-minimal-viable-1.3.xml          |    9 +
 .../schemaTestData/1.3/valid-patch-1.3.json   |   88 +
 .../schemaTestData/1.3/valid-patch-1.3.xml    |   70 +
 .../1.3/valid-properties-1.3.json             |   55 +
 .../1.3/valid-properties-1.3.xml              |   34 +
 .../1.3/valid-random-attributes-1.3.xml       |  118 +
 .../schemaTestData/1.3/valid-service-1.3.json |  101 +
 .../schemaTestData/1.3/valid-service-1.3.xml  |   66 +
 .../1.3/valid-service-empty-objects-1.3.json  |   22 +
 .../1.3/valid-service-empty-objects-1.3.xml   |   16 +
 .../1.3/valid-xml-signature-1.3.xml           |  177 ++
 .../1.4/invalid-bomformat-1.4.json            |    8 +
 .../1.4/invalid-component-ref-1.4.json        |   20 +
 .../1.4/invalid-component-ref-1.4.xml         |   15 +
 .../1.4/invalid-component-swid-1.4.json       |   18 +
 .../1.4/invalid-component-swid-1.4.xml        |   11 +
 .../1.4/invalid-component-type-1.4.json       |   13 +
 .../1.4/invalid-component-type-1.4.xml        |    9 +
 .../1.4/invalid-dependency-1.4.json           |   37 +
 .../1.4/invalid-dependency-1.4.xml            |   23 +
 .../1.4/invalid-empty-component-1.4.json      |   11 +
 .../1.4/invalid-empty-component-1.4.xml       |    7 +
 .../1.4/invalid-hash-alg-1.4.json             |   32 +
 .../1.4/invalid-hash-alg-1.4.xml              |   16 +
 .../1.4/invalid-hash-md5-1.4.json             |   32 +
 .../1.4/invalid-hash-md5-1.4.xml              |   16 +
 .../1.4/invalid-hash-sha1-1.4.json            |   32 +
 .../1.4/invalid-hash-sha1-1.4.xml             |   16 +
 .../1.4/invalid-hash-sha256-1.4.json          |   32 +
 .../1.4/invalid-hash-sha256-1.4.xml           |   16 +
 .../1.4/invalid-hash-sha512-1.4.json          |   32 +
 .../1.4/invalid-hash-sha512-1.4.xml           |   16 +
 .../1.4/invalid-issue-type-1.4.json           |   48 +
 .../1.4/invalid-issue-type-1.4.xml            |   37 +
 .../1.4/invalid-license-choice-1.4.json       |   23 +
 .../1.4/invalid-license-choice-1.4.xml        |   26 +
 .../1.4/invalid-license-encoding-1.4.json     |   28 +
 .../1.4/invalid-license-encoding-1.4.xml      |   27 +
 .../1.4/invalid-license-id-1.4.json           |   22 +
 .../1.4/invalid-license-id-1.4.xml            |   27 +
 .../1.4/invalid-license-id-count-1.4.xml      |   27 +
 .../1.4/invalid-license-name-count-1.4.xml    |   27 +
 .../1.4/invalid-metadata-license-1.4.json     |   16 +
 .../1.4/invalid-metadata-license-1.4.xml      |   11 +
 .../1.4/invalid-metadata-timestamp-1.4.json   |   10 +
 .../1.4/invalid-metadata-timestamp-1.4.xml    |    7 +
 .../invalid-missing-component-type-1.4.json   |   12 +
 .../invalid-missing-component-type-1.4.xml    |    9 +
 .../1.4/invalid-namespace-1.4.xml             |  118 +
 .../1.4/invalid-patch-type-1.4.json           |   48 +
 .../1.4/invalid-patch-type-1.4.xml            |   37 +
 .../schemaTestData/1.4/invalid-scope-1.4.json |   14 +
 .../schemaTestData/1.4/invalid-scope-1.4.xml  |   10 +
 .../1.4/invalid-serialnumber-1.4.json         |    8 +
 .../1.4/invalid-serialnumber-1.4.xml          |  118 +
 .../1.4/invalid-service-data-1.4.json         |   20 +
 .../1.4/invalid-service-data-1.4.xml          |   11 +
 .../1.4/valid-assembly-1.4.json               |   30 +
 .../schemaTestData/1.4/valid-assembly-1.4.xml |   25 +
 .../schemaTestData/1.4/valid-bom-1.4.json     |  177 ++
 .../schemaTestData/1.4/valid-bom-1.4.xml      |  181 ++
 .../1.4/valid-component-hashes-1.4.json       |   63 +
 .../1.4/valid-component-hashes-1.4.xml        |   23 +
 .../1.4/valid-component-ref-1.4.json          |   20 +
 .../1.4/valid-component-ref-1.4.xml           |   19 +
 .../1.4/valid-component-swid-1.4.json         |   19 +
 .../1.4/valid-component-swid-1.4.xml          |   11 +
 .../1.4/valid-component-swid-full-1.4.json    |   24 +
 .../1.4/valid-component-swid-full-1.4.xml     |   13 +
 .../1.4/valid-component-types-1.4.json        |   48 +
 .../1.4/valid-component-types-1.4.xml         |   37 +
 .../1.4/valid-compositions-1.4.json           |   65 +
 .../1.4/valid-compositions-1.4.xml            |   51 +
 .../1.4/valid-dependency-1.4.json             |   38 +
 .../1.4/valid-dependency-1.4.xml              |   23 +
 .../1.4/valid-empty-components-1.4.json       |    8 +
 .../1.4/valid-empty-components-1.4.xml        |    5 +
 .../1.4/valid-evidence-1.4.json               |   53 +
 .../schemaTestData/1.4/valid-evidence-1.4.xml |   35 +
 .../1.4/valid-external-elements-1.4.xml       |  158 ++
 .../1.4/valid-external-reference-1.4.json     |   38 +
 .../1.4/valid-external-reference-1.4.xml      |   27 +
 .../1.4/valid-license-expression-1.4.json     |   20 +
 .../1.4/valid-license-expression-1.4.xml      |   23 +
 .../1.4/valid-license-id-1.4.json             |   22 +
 .../1.4/valid-license-id-1.4.xml              |   25 +
 .../1.4/valid-license-name-1.4.json           |   22 +
 .../1.4/valid-license-name-1.4.xml            |   25 +
 .../1.4/valid-metadata-author-1.4.json        |   16 +
 .../1.4/valid-metadata-author-1.4.xml         |   13 +
 .../1.4/valid-metadata-license-1.4.json       |   16 +
 .../1.4/valid-metadata-license-1.4.xml        |   11 +
 .../1.4/valid-metadata-manufacture-1.4.json   |   21 +
 .../1.4/valid-metadata-manufacture-1.4.xml    |   14 +
 .../1.4/valid-metadata-supplier-1.4.json      |   21 +
 .../1.4/valid-metadata-supplier-1.4.xml       |   14 +
 .../1.4/valid-metadata-timestamp-1.4.json     |   10 +
 .../1.4/valid-metadata-timestamp-1.4.xml      |    7 +
 .../1.4/valid-metadata-tool-1.4.json          |   26 +
 .../1.4/valid-metadata-tool-1.4.xml           |   17 +
 .../1.4/valid-minimal-viable-1.4.json         |   12 +
 .../1.4/valid-minimal-viable-1.4.xml          |    8 +
 .../schemaTestData/1.4/valid-patch-1.4.json   |   88 +
 .../schemaTestData/1.4/valid-patch-1.4.xml    |   70 +
 .../1.4/valid-properties-1.4.json             |   55 +
 .../1.4/valid-properties-1.4.xml              |   34 +
 .../1.4/valid-random-attributes-1.4.xml       |  118 +
 .../1.4/valid-release-notes-1.4.json          |  194 ++
 .../1.4/valid-release-notes-1.4.xml           |  149 +
 .../schemaTestData/1.4/valid-service-1.4.json |  101 +
 .../schemaTestData/1.4/valid-service-1.4.xml  |   66 +
 .../1.4/valid-service-empty-objects-1.4.json  |   22 +
 .../1.4/valid-service-empty-objects-1.4.xml   |   16 +
 .../1.4/valid-signatures-1.4.json             |   78 +
 .../1.4/valid-vulnerability-1.4.json          |  140 +
 .../1.4/valid-vulnerability-1.4.xml           |  127 +
 .../1.4/valid-xml-signature-1.4.xml           |  177 ++
 tests/_data/schemaTestData/README.md          |    2 +
 tests/_data/schemaTestData/fetch.sh           |   21 +
 tests/base.py                                 |   48 +-
 tests/test_component.py                       |    7 +-
 tests/test_deserialize_json.py                |    9 +-
 tests/test_deserialize_xml.py                 |    8 +-
 tests/test_output_json.py                     |    9 +-
 tests/test_output_xml.py                      |    9 +-
 tests/test_real_world_examples.py             |    8 +-
 tests/test_schema__res.py                     |   44 +
 tests/test_spdx.py                            |    7 +-
 tests/test_validation_json.py                 |  110 +
 tests/test_validation_xml.py                  |   76 +
 tools/schema-downloader.py                    |  109 +
 tox.ini                                       |   12 +-
 499 files changed, 15182 insertions(+), 5259 deletions(-)
 create mode 100644 cyclonedx/schema/_res/.editorconfig
 create mode 100644 cyclonedx/schema/_res/.gitattributes
 create mode 100644 cyclonedx/schema/_res/README.md
 create mode 100644 cyclonedx/schema/_res/__init__.py
 rename cyclonedx/schema/{bom-1.0.xsd => _res/bom-1.0.SNAPSHOT.xsd} (99%)
 rename cyclonedx/schema/{bom-1.1.xsd => _res/bom-1.1.SNAPSHOT.xsd} (99%)
 rename cyclonedx/schema/{bom-1.2b.schema.json => _res/bom-1.2-strict.SNAPSHOT.schema.json} (98%)
 rename cyclonedx/schema/{bom-1.2.schema.json => _res/bom-1.2.SNAPSHOT.schema.json} (98%)
 rename cyclonedx/schema/{bom-1.2.xsd => _res/bom-1.2.SNAPSHOT.xsd} (99%)
 rename cyclonedx/schema/{bom-1.3a.schema.json => _res/bom-1.3-strict.SNAPSHOT.schema.json} (98%)
 rename cyclonedx/schema/{bom-1.3.schema.json => _res/bom-1.3.SNAPSHOT.schema.json} (98%)
 rename cyclonedx/schema/{bom-1.3.xsd => _res/bom-1.3.SNAPSHOT.xsd} (99%)
 rename cyclonedx/schema/{bom-1.4.schema.json => _res/bom-1.4.SNAPSHOT.schema.json} (98%)
 rename cyclonedx/schema/{bom-1.4.xsd => _res/bom-1.4.SNAPSHOT.xsd} (99%)
 create mode 100644 cyclonedx/schema/_res/jsf-0.82.SNAPSHOT.schema.json
 rename cyclonedx/schema/{spdx.schema.json => _res/spdx.SNAPSHOT.schema.json} (84%)
 rename cyclonedx/schema/{spdx.xsd => _res/spdx.SNAPSHOT.xsd} (86%)
 delete mode 100644 cyclonedx/schema/bom-1.2-strict.schema.json
 delete mode 100644 cyclonedx/schema/bom-1.3-strict.schema.json
 delete mode 100644 cyclonedx/schema/bom-1.3.proto
 delete mode 100644 cyclonedx/schema/ext/bom-descriptor-0.9.xsd
 delete mode 100644 cyclonedx/schema/ext/bom-descriptor-1.0.xsd
 delete mode 100644 cyclonedx/schema/ext/dependency-graph-1.0.xsd
 delete mode 100644 cyclonedx/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json
 delete mode 100644 cyclonedx/schema/ext/vulnerability-1.0.xsd
 create mode 100644 cyclonedx/validation/__init__.py
 create mode 100644 cyclonedx/validation/json.py
 create mode 100644 cyclonedx/validation/xml.py
 delete mode 100644 deps.lowest.r
 rename examples/{build_and_serialize.py => complex.py} (56%)
 create mode 100644 tests/_data/own/.gitattributes
 rename tests/{fixtures => _data/own}/README.md (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_dependencies.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_dependencies_component.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_external_references.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_issue_275_components.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_issue_328_components.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_services_complex.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_services_nested.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_services_simple.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_setuptools.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_setuptools_complete.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_setuptools_no_version.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_setuptools_with_cpe.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_toml_1.json (100%)
 rename tests/{fixtures => _data/own}/json/1.2/bom_with_full_metadata.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_dependencies.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_dependencies_component.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_external_references.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_issue_275_components.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_issue_328_components.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_services_complex.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_services_nested.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_services_simple.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_setuptools.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_setuptools_complete.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_setuptools_no_version.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_setuptools_with_cpe.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_toml_1.json (100%)
 rename tests/{fixtures => _data/own}/json/1.3/bom_with_full_metadata.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_dependencies.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_dependencies_component.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_external_references.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_issue_275_components.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_issue_328_components.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_services_complex.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_services_nested.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_services_simple.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_setuptools.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_setuptools_complete.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_setuptools_no_version.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_setuptools_with_cpe.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_setuptools_with_release_notes.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_setuptools_with_vulnerabilities.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_toml_1.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_with_dependencies_hanging.json (100%)
 rename tests/{fixtures => _data/own}/json/1.4/bom_with_full_metadata.json (100%)
 rename tests/{fixtures => _data/own}/xml/1.0/bom_empty.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.0/bom_issue_275_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.0/bom_issue_328_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.0/bom_setuptools.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.0/bom_setuptools_complete.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.0/bom_setuptools_no_version.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.0/bom_setuptools_with_cpe.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.0/bom_toml_hashes_and_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_dependencies.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_empty.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_external_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_issue_275_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_issue_328_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_setuptools.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_setuptools_complete.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_setuptools_no_version.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_setuptools_with_cpe.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_setuptools_with_vulnerabilities.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.1/bom_toml_hashes_and_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_dependencies.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_dependencies_component.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_external_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_issue_275_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_issue_328_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_services_complex.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_services_nested.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_services_simple.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_setuptools.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_setuptools_complete.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_setuptools_no_version.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_setuptools_with_cpe.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_setuptools_with_vulnerabilities.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_toml_hashes_and_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.2/bom_with_full_metadata.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_dependencies.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_dependencies_component.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_external_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_issue_275_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_issue_328_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_services_complex.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_services_nested.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_services_simple.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_setuptools.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_setuptools_complete.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_setuptools_no_version.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_setuptools_with_cpe.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_setuptools_with_vulnerabilities.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_toml_hashes_and_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.3/bom_with_full_metadata.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_dependencies.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_dependencies_component.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_external_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_issue_275_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_issue_328_components.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_services_complex.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_services_nested.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_services_simple.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_setuptools.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_setuptools_complete.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_setuptools_no_version.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_setuptools_with_cpe.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_setuptools_with_release_notes.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_setuptools_with_vulnerabilities.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_toml_hashes_and_references.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_with_dependencies_hanging.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/bom_with_full_metadata.xml (100%)
 rename tests/{fixtures => _data/own}/xml/1.4/webgoat-6.1.xml (100%)
 create mode 100644 tests/_data/schemaTestData/.gitattributes
 create mode 100644 tests/_data/schemaTestData/1.0/valid-bom-1.0.xml
 create mode 100644 tests/_data/schemaTestData/1.0/valid-component-hashes-1.0.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-component-ref-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-component-type-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-empty-component-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-hash-alg-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-hash-md5-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-hash-sha1-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-hash-sha256-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-hash-sha512-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-license-choice-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-license-encoding-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-license-id-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-license-id-count-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-license-name-count-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-missing-component-type-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-namespace-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-scope-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/invalid-serialnumber-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-bom-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-component-hashes-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-component-ref-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-component-types-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-empty-components-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-external-elements-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-license-expression-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-license-id-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-license-name-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-minimal-viable-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-random-attributes-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.1/valid-xml-signature-1.1.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-bomformat-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-component-ref-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-component-ref-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-component-swid-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-component-swid-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-component-type-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-component-type-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-dependency-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-dependency-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-empty-component-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-alg-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-alg-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-md5-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-md5-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-sha1-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-sha1-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-sha256-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-sha256-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-sha512-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-hash-sha512-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-issue-type-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-issue-type-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-license-choice-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-license-choice-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-license-encoding-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-license-encoding-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-license-id-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-license-id-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-license-id-count-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-license-name-count-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-metadata-timestamp-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-metadata-timestamp-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-missing-component-type-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-namespace-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-patch-type-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-patch-type-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-scope-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-scope-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-serialnumber-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-serialnumber-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-service-data-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/invalid-service-data-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/skip_invalid-empty-component-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/skip_invalid-missing-component-type-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-assembly-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-assembly-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-bom-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-bom-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-hashes-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-hashes-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-ref-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-ref-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-swid-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-swid-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-swid-full-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-swid-full-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-types-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-component-types-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-dependency-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-dependency-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-empty-components-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-empty-components-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-external-elements-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-license-expression-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-license-expression-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-license-id-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-license-id-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-license-name-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-license-name-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-author-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-author-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-manufacture-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-manufacture-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-supplier-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-supplier-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-timestamp-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-timestamp-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-tool-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-metadata-tool-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-minimal-viable-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-minimal-viable-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-patch-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-patch-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-random-attributes-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-service-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-service-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-service-empty-objects-1.2.json
 create mode 100644 tests/_data/schemaTestData/1.2/valid-service-empty-objects-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.2/valid-xml-signature-1.2.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-bomformat-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-component-ref-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-component-ref-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-component-swid-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-component-swid-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-component-type-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-component-type-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-dependency-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-dependency-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-empty-component-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-empty-component-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-alg-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-alg-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-md5-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-md5-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-sha1-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-sha1-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-sha256-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-sha256-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-sha512-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-hash-sha512-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-issue-type-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-issue-type-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-license-choice-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-license-choice-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-license-encoding-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-license-encoding-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-license-id-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-license-id-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-license-id-count-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-license-name-count-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-metadata-license-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-metadata-license-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-metadata-timestamp-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-metadata-timestamp-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-missing-component-type-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-missing-component-type-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-namespace-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-patch-type-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-patch-type-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-scope-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-scope-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-serialnumber-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-serialnumber-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-service-data-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/invalid-service-data-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-assembly-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-assembly-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-bom-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-bom-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-hashes-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-hashes-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-ref-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-ref-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-swid-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-swid-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-swid-full-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-swid-full-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-types-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-component-types-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-compositions-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-compositions-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-dependency-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-dependency-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-empty-components-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-empty-components-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-evidence-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-evidence-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-external-elements-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-external-reference-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-external-reference-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-license-expression-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-license-expression-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-license-id-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-license-id-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-license-name-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-license-name-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-author-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-author-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-license-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-license-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-manufacture-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-manufacture-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-supplier-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-supplier-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-timestamp-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-timestamp-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-tool-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-metadata-tool-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-minimal-viable-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-minimal-viable-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-patch-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-patch-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-properties-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-properties-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-random-attributes-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-service-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-service-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-service-empty-objects-1.3.json
 create mode 100644 tests/_data/schemaTestData/1.3/valid-service-empty-objects-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.3/valid-xml-signature-1.3.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-bomformat-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-component-ref-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-component-ref-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-component-swid-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-component-swid-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-component-type-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-component-type-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-dependency-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-dependency-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-empty-component-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-empty-component-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-alg-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-alg-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-md5-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-md5-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-sha1-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-sha1-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-sha256-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-sha256-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-sha512-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-hash-sha512-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-issue-type-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-issue-type-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-license-choice-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-license-choice-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-license-encoding-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-license-encoding-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-license-id-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-license-id-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-license-id-count-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-license-name-count-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-metadata-license-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-metadata-license-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-metadata-timestamp-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-metadata-timestamp-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-missing-component-type-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-missing-component-type-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-namespace-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-patch-type-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-patch-type-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-scope-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-scope-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-serialnumber-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-serialnumber-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-service-data-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/invalid-service-data-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-assembly-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-assembly-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-bom-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-bom-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-hashes-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-hashes-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-ref-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-ref-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-swid-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-swid-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-swid-full-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-swid-full-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-types-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-component-types-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-compositions-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-compositions-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-dependency-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-dependency-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-empty-components-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-empty-components-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-evidence-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-evidence-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-external-elements-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-external-reference-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-external-reference-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-license-expression-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-license-expression-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-license-id-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-license-id-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-license-name-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-license-name-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-author-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-author-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-license-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-license-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-manufacture-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-manufacture-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-supplier-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-supplier-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-timestamp-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-timestamp-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-tool-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-metadata-tool-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-minimal-viable-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-minimal-viable-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-patch-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-patch-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-properties-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-properties-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-random-attributes-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-release-notes-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-release-notes-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-service-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-service-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-service-empty-objects-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-service-empty-objects-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-signatures-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-vulnerability-1.4.json
 create mode 100644 tests/_data/schemaTestData/1.4/valid-vulnerability-1.4.xml
 create mode 100644 tests/_data/schemaTestData/1.4/valid-xml-signature-1.4.xml
 create mode 100644 tests/_data/schemaTestData/README.md
 create mode 100755 tests/_data/schemaTestData/fetch.sh
 create mode 100644 tests/test_schema__res.py
 create mode 100644 tests/test_validation_json.py
 create mode 100644 tests/test_validation_xml.py
 create mode 100644 tools/schema-downloader.py

diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index c94d51b68..6d6f69d2c 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -49,21 +49,21 @@ jobs:
         run: poetry run tox run -e flake8 -s false
 
   static-code-analysis:
-    name: StaticCodingAnalysis (py${{ matrix.python-version}} ${{ matrix.toxenv-factor }})
+    name: StaticCodingAnalysis (py${{ matrix.python-version}} ${{ matrix.toxenv-factors }})
     runs-on: ${{ matrix.os }}
     timeout-minutes: 10
     strategy:
       fail-fast: false
       matrix:
         include:
-          - # test with the locked dependencies
+          - # test with the latest dependencies
             os: ubuntu-latest
             python-version: '3.11'
-            toxenv-factor: 'locked'
+            toxenv-factors: '-current'
           - # test with the lowest dependencies
             os: ubuntu-latest
             python-version: '3.8'
-            toxenv-factor: 'lowest'
+            toxenv-factors: '-lowest'
     steps:
       - name: Checkout
         # see https://github.com/actions/checkout
@@ -82,10 +82,10 @@ jobs:
       - name: Install dependencies
         run: poetry install --no-root
       - name: Run tox
-        run: poetry run tox run -e mypy-${{ matrix.toxenv-factor }} -s false
+        run: poetry run tox run -e mypy${{ matrix.toxenv-factors }} -s false
 
   build-and-test:
-    name: Test (${{ matrix.os }} py${{ matrix.python-version }} ${{ matrix.toxenv-factor }})
+    name: Test (${{ matrix.os }} py${{ matrix.python-version }} ${{ matrix.toxenv-factors }})
     runs-on: ${{ matrix.os }}
     timeout-minutes: 15
     strategy:
@@ -97,12 +97,9 @@ jobs:
           - "3.10"
           - "3.9"
           - "3.8"  # lowest supported
-        toxenv-factor: ['locked']
-        include:
-          - # test with the lowest dependencies
-            os: ubuntu-latest
-            python-version: '3.8'
-            toxenv-factor: 'lowest'
+        toxenv-factors:
+          - '-allExtras'
+          - '-noExtras'
     steps:
       - name: Disabled Git auto EOL CRLF transforms
         run: |
@@ -134,14 +131,14 @@ jobs:
       - name: Ensure build successful
         run: poetry build
       - name: Run tox
-        run: poetry run tox run -e py-${{ matrix.toxenv-factor }} -s false
+        run: poetry run tox run -e py${{ matrix.toxenv-factors }} -s false
       - name: Generate coverage reports
         shell: bash
         run: |
           set -eux
           poetry run coverage report
-          poetry run coverage xml -o "$REPORTS_DIR/coverage.${{ matrix.os }}_py${{ matrix.python-version }}_${{ matrix.toxenv-factor }}.cobertura.xml"
-          # poetry run coverage lcov -o "$REPORTS_DIR/coverage.${{ matrix.os }}_py${{ matrix.python-version }}_${{ matrix.toxenv-factor }}.lcov.xml"
+          poetry run coverage xml -o "$REPORTS_DIR/coverage.${{ matrix.os }}_py${{ matrix.python-version }}_${{ matrix.toxenv-factors }}.cobertura.xml"
+          # poetry run coverage lcov -o "$REPORTS_DIR/coverage.${{ matrix.os }}_py${{ matrix.python-version }}_${{ matrix.toxenv-factors }}.lcov.xml"
       - name: Artifact reports
         if: ${{ ! cancelled() }}
         # see https://github.com/actions/upload-artifact
@@ -174,9 +171,16 @@ jobs:
           coverage-reports: ${{ env.REPORTS_DIR }}/coverage.*
 
   examples:
-    name: Examples
+    name: Examples E:${{ matrix.install-extras || '<none>' }}
     runs-on: ubuntu-latest
-    timeout-minutes: 15
+    timeout-minutes: 10
+    strategy:
+      fail-fast: false
+      matrix:
+        install-extras:
+          - '' # none
+          - json-validation
+          - xml-validation
     steps:
       - name: Checkout
         # see https://github.com/actions/checkout
@@ -197,7 +201,7 @@ jobs:
         with:
           poetry-version: ${{ env.POETRY_VERSION }}
       - name: Install package and prod dependencies
-        run: poetry install --only=main -vvv
+        run: poetry install --only=main --extras='${{ matrix.install-extras }}' -vvv
       - name: run all examples
         run: >
           find examples -type f -name '*.py' -print0
diff --git a/.isort.cfg b/.isort.cfg
index 2b28db047..7a30df968 100644
--- a/.isort.cfg
+++ b/.isort.cfg
@@ -20,3 +20,5 @@ src_paths =
     cyclonedx
     tests
     typings
+    examples
+    tools
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c4cfa73b2..b8b34b7ab 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,7 +12,7 @@ This project uses [poetry]. Have it installed and setup first.
 To install dev-dependencies and tools:
 
 ```shell
-poetry install
+poetry install --all-extras
 ```
 
 ## Code style
@@ -23,7 +23,7 @@ Get it all applied via:
 
 ```shell
 poetry run isort .
-poetry run autopep8 -ir cyclonedx/ tests/ typings/
+poetry run autopep8 -ir cyclonedx/ tests/ typings/ examples/
 ```
 
 ## Documentation
diff --git a/cyclonedx/exception/__init__.py b/cyclonedx/exception/__init__.py
index dc915bfba..1845b0063 100644
--- a/cyclonedx/exception/__init__.py
+++ b/cyclonedx/exception/__init__.py
@@ -25,3 +25,8 @@ class CycloneDxException(Exception):
     Root exception thrown by this library.
     """
     pass
+
+
+class MissingOptionalDependencyException(CycloneDxException):
+    """Validation did not happen, due to missing dependencies."""
+    pass
diff --git a/cyclonedx/schema/_res/.editorconfig b/cyclonedx/schema/_res/.editorconfig
new file mode 100644
index 000000000..6fe0e5e40
--- /dev/null
+++ b/cyclonedx/schema/_res/.editorconfig
@@ -0,0 +1,10 @@
+
+# fix settings for files that are copied over, to keep them as is
+[*.SNAPSHOT.xsd]
+indent_size = 4
+indent_style = space
+trim_trailing_whitespace = false
+[*.SNAPSHOT.schema.json]
+indent_size = 2
+indent_style = space
+trim_trailing_whitespace = false
\ No newline at end of file
diff --git a/cyclonedx/schema/_res/.gitattributes b/cyclonedx/schema/_res/.gitattributes
new file mode 100644
index 000000000..41a9eb424
--- /dev/null
+++ b/cyclonedx/schema/_res/.gitattributes
@@ -0,0 +1,6 @@
+# snapshots are vendored for offline use
+*.SNAPSHOT.*    linguist-vendored
+
+# specs are vendored for offline use
+*.xsd           linguist-vendored
+*.schema.json   linguist-vendored
diff --git a/cyclonedx/schema/_res/README.md b/cyclonedx/schema/_res/README.md
new file mode 100644
index 000000000..d7df06985
--- /dev/null
+++ b/cyclonedx/schema/_res/README.md
@@ -0,0 +1,30 @@
+# Resources: Schema files
+
+some schema for offline use as download via [script](../../../tools/schema-downloader.py).
+original sources: <https://github.com/CycloneDX/specification/tree/master/schema>
+
+Currently using version
+[fd4d383658196992364e5d62568a48c431ace515](https://github.com/CycloneDX/specification/commit/fd4d383658196992364e5d62568a48c431ace515)
+
+| file | note |
+|------|------|
+| [`bom-1.0.SNAPSHOT.xsd`](bom-1.0.SNAPSHOT.xsd) | applied changes: 1 |
+| [`bom-1.1.SNAPSHOT.xsd`](bom-1.1.SNAPSHOT.xsd) | applied changes: 1 |
+| [`bom-1.2.SNAPSHOT.xsd`](bom-1.2.SNAPSHOT.xsd) | applied changes: 1 |
+| [`bom-1.3.SNAPSHOT.xsd`](bom-1.3.SNAPSHOT.xsd) | applied changes: 1 |
+| [`bom-1.4.SNAPSHOT.xsd`](bom-1.4.SNAPSHOT.xsd) | applied changes: 1 |
+| [`bom-1.2.SNAPSHOT.schema.json`](bom-1.2.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
+| [`bom-1.3.SNAPSHOT.schema.json`](bom-1.3.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
+| [`bom-1.4.SNAPSHOT.schema.json`](bom-1.4.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
+| [`bom-1.2-strict.SNAPSHOT.schema.json`](bom-1.2-strict.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
+| [`bom-1.3-strict.SNAPSHOT.schema.json`](bom-1.3-strict.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
+| [`spdx.SNAPSHOT.xsd`](spdx.SNAPSHOT.xsd) | |
+| [`spdx.SNAPSHOT.schema.json`](spdx.SNAPSHOT.schema.json) | |
+| [`jsf-0.82.SNAPSHOT.schema.json`](jsf-0.82.SNAPSHOT.schema.json) | |
+
+changes:
+1. `https?://cyclonedx.org/schema/spdx` was replaced with `spdx.SNAPSHOT.xsd`
+2. `spdx.schema.json` was replaced with `spdx.SNAPSHOT.schema.json`
+3. `jsf-0.82.schema.json` was replaced with `jsf-0.82.SNAPSHOT.schema.json`
+4. `properties.$schema.enum` was fixed to match `$id`
+5. `required.version` removed, as it is actually optional with default value
diff --git a/cyclonedx/schema/_res/__init__.py b/cyclonedx/schema/_res/__init__.py
new file mode 100644
index 000000000..13b30823e
--- /dev/null
+++ b/cyclonedx/schema/_res/__init__.py
@@ -0,0 +1,60 @@
+# encoding: utf-8
+
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from os.path import dirname, join
+from typing import Dict, Optional
+
+from .. import SchemaVersion
+
+"""
+Content in here is internal, not for public use.
+Breaking changes without notice may happen.
+"""
+
+__DIR = dirname(__file__)
+
+BOM_XML: Dict[SchemaVersion, Optional[str]] = {
+    SchemaVersion.V1_4: join(__DIR, 'bom-1.4.SNAPSHOT.xsd'),
+    SchemaVersion.V1_3: join(__DIR, 'bom-1.3.SNAPSHOT.xsd'),
+    SchemaVersion.V1_2: join(__DIR, 'bom-1.2.SNAPSHOT.xsd'),
+    SchemaVersion.V1_1: join(__DIR, 'bom-1.1.SNAPSHOT.xsd'),
+    SchemaVersion.V1_0: join(__DIR, 'bom-1.0.SNAPSHOT.xsd'),
+}
+
+BOM_JSON: Dict[SchemaVersion, Optional[str]] = {
+    SchemaVersion.V1_4: join(__DIR, 'bom-1.4.SNAPSHOT.schema.json'),
+    SchemaVersion.V1_3: join(__DIR, 'bom-1.3.SNAPSHOT.schema.json'),
+    SchemaVersion.V1_2: join(__DIR, 'bom-1.2.SNAPSHOT.schema.json'),
+    # <= v1.1 is not defined in JSON
+    SchemaVersion.V1_1: None,
+    SchemaVersion.V1_0: None,
+}
+
+BOM_JSON_STRICT: Dict[SchemaVersion, Optional[str]] = {
+    # >= v1.4 is already strict - no special file here
+    SchemaVersion.V1_4: join(__DIR, 'bom-1.4.SNAPSHOT.schema.json'),
+    # <= 1.3 need special files
+    SchemaVersion.V1_3: join(__DIR, 'bom-1.3-strict.SNAPSHOT.schema.json'),
+    SchemaVersion.V1_2: join(__DIR, 'bom-1.2-strict.SNAPSHOT.schema.json'),
+    # <= v1.1 is not defined in JSON
+    SchemaVersion.V1_1: None,
+    SchemaVersion.V1_0: None,
+}
+
+SPDX_JSON = join(__DIR, 'spdx.SNAPSHOT.schema.json')
+SPDX_XML = join(__DIR, 'spdx.SNAPSHOT.xsd')
+
+JSF = join(__DIR, 'jsf-0.82.SNAPSHOT.schema.json')
diff --git a/cyclonedx/schema/bom-1.0.xsd b/cyclonedx/schema/_res/bom-1.0.SNAPSHOT.xsd
similarity index 99%
rename from cyclonedx/schema/bom-1.0.xsd
rename to cyclonedx/schema/_res/bom-1.0.SNAPSHOT.xsd
index 815ed9ee8..64d0e33f9 100644
--- a/cyclonedx/schema/bom-1.0.xsd
+++ b/cyclonedx/schema/_res/bom-1.0.SNAPSHOT.xsd
@@ -7,9 +7,9 @@
            targetNamespace="http://cyclonedx.org/schema/bom/1.0"
            vc:minVersion="1.0"
            vc:maxVersion="1.1"
-           version="1.0">
+           version="1.0.1">
 
-    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.xsd"/>
+    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.SNAPSHOT.xsd"/>
 
     <xs:complexType name="component">
         <xs:sequence>
diff --git a/cyclonedx/schema/bom-1.1.xsd b/cyclonedx/schema/_res/bom-1.1.SNAPSHOT.xsd
similarity index 99%
rename from cyclonedx/schema/bom-1.1.xsd
rename to cyclonedx/schema/_res/bom-1.1.SNAPSHOT.xsd
index 1e7bc1e05..f21e9907d 100644
--- a/cyclonedx/schema/bom-1.1.xsd
+++ b/cyclonedx/schema/_res/bom-1.1.SNAPSHOT.xsd
@@ -24,7 +24,7 @@ limitations under the License.
            vc:maxVersion="1.1"
            version="1.1">
 
-    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.xsd"/>
+    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.SNAPSHOT.xsd"/>
 
     <xs:annotation>
         <xs:documentation>
@@ -38,6 +38,13 @@ limitations under the License.
         </xs:documentation>
     </xs:annotation>
 
+    <xs:simpleType name="refType">
+        <xs:annotation>
+            <xs:documentation>Identifier-DataType for interlinked elements.</xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string" />
+    </xs:simpleType>
+
     <xs:complexType name="componentsType">
         <xs:sequence minOccurs="0" maxOccurs="unbounded">
             <xs:element name="component" type="bom:component"/>
@@ -201,7 +208,7 @@ limitations under the License.
                 </xs:documentation>
             </xs:annotation>
         </xs:attribute>
-        <xs:attribute name="bom-ref" type="xs:string">
+        <xs:attribute name="bom-ref" type="bom:refType">
             <xs:annotation>
                 <xs:documentation>
                     An optional identifier which can be used to reference the component elsewhere in the BOM.
diff --git a/cyclonedx/schema/bom-1.2b.schema.json b/cyclonedx/schema/_res/bom-1.2-strict.SNAPSHOT.schema.json
similarity index 98%
rename from cyclonedx/schema/bom-1.2b.schema.json
rename to cyclonedx/schema/_res/bom-1.2-strict.SNAPSHOT.schema.json
index be21fb161..682cf739d 100644
--- a/cyclonedx/schema/bom-1.2b.schema.json
+++ b/cyclonedx/schema/_res/bom-1.2-strict.SNAPSHOT.schema.json
@@ -6,15 +6,14 @@
   "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
   "required": [
     "bomFormat",
-    "specVersion",
-    "version"
+    "specVersion"
   ],
   "additionalProperties": false,
   "properties": {
     "$schema": {
       "type": "string",
       "enum": [
-        "http://cyclonedx.org/schema/bom-1.2a.schema.json"
+        "http://cyclonedx.org/schema/bom-1.2b.schema.json"
       ]
     },
     "bomFormat": {
@@ -87,6 +86,10 @@
     }
   },
   "definitions": {
+    "refType": {
+      "$comment": "Identifier-DataType for interlinked elements.",
+      "type": "string"
+    },
     "metadata": {
       "type": "object",
       "title": "BOM Metadata Object",
@@ -261,7 +264,7 @@
           "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
         },
         "bom-ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "BOM Reference",
           "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique.",
           "default": "",
@@ -595,7 +598,7 @@
       "additionalProperties": false,
       "properties": {
         "id": {
-          "$ref": "spdx.schema.json",
+          "$ref": "spdx.SNAPSHOT.schema.json",
           "title": "License ID (SPDX)",
           "description": "A valid SPDX license ID",
           "examples": ["Apache-2.0"]
@@ -859,8 +862,7 @@
       "additionalProperties": false,
       "properties": {
         "ref": {
-          "type": "string",
-          "format": "string",
+          "$ref": "#/definitions/refType",
           "title": "Reference",
           "description": "References a component by the components bom-ref attribute"
         },
@@ -868,7 +870,7 @@
           "type": "array",
           "uniqueItems": true,
           "items": {
-            "type": "string"
+            "$ref": "#/definitions/refType"
           },
           "title": "Depends On",
           "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
@@ -884,7 +886,7 @@
       "additionalProperties": false,
       "properties": {
         "bom-ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "BOM Reference",
           "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique.",
           "default": "",
diff --git a/cyclonedx/schema/bom-1.2.schema.json b/cyclonedx/schema/_res/bom-1.2.SNAPSHOT.schema.json
similarity index 98%
rename from cyclonedx/schema/bom-1.2.schema.json
rename to cyclonedx/schema/_res/bom-1.2.SNAPSHOT.schema.json
index 2e44d9422..d23f683b5 100644
--- a/cyclonedx/schema/bom-1.2.schema.json
+++ b/cyclonedx/schema/_res/bom-1.2.SNAPSHOT.schema.json
@@ -1,13 +1,12 @@
 {
   "$schema": "http://json-schema.org/draft-07/schema#",
-  "$id": "http://cyclonedx.org/schema/bom-1.2a.schema.json",
+  "$id": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
   "type": "object",
   "title": "CycloneDX Software Bill-of-Material Specification",
   "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
   "required": [
     "bomFormat",
-    "specVersion",
-    "version"
+    "specVersion"
   ],
   "properties": {
     "bomFormat": {
@@ -80,6 +79,10 @@
     }
   },
   "definitions": {
+    "refType": {
+      "$comment": "Identifier-DataType for interlinked elements.",
+      "type": "string"
+    },
     "metadata": {
       "type": "object",
       "title": "BOM Metadata Object",
@@ -143,7 +146,7 @@
           "description": "The date and time (timestamp) when the document was created."
         },
         "hashes": {
-          "$id": "#/properties/hashes",
+          "$id": "#/definitions/tool/properties/hashes",
           "type": "array",
           "items": {"$ref": "#/definitions/hash"},
           "title": "Hashes",
@@ -249,7 +252,7 @@
           "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
         },
         "bom-ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "BOM Reference",
           "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique.",
           "default": "",
@@ -432,7 +435,7 @@
           "title": "External References"
         },
         "components": {
-          "$id": "#/properties/components",
+          "$id": "#/definitions/component/properties/components",
           "type": "array",
           "items": {"$ref": "#/definitions/component"},
           "uniqueItems": true,
@@ -577,7 +580,7 @@
       ],
       "properties": {
         "id": {
-          "$ref": "spdx.schema.json",
+          "$ref": "spdx.SNAPSHOT.schema.json",
           "title": "License ID (SPDX)",
           "description": "A valid SPDX license ID",
           "examples": ["Apache-2.0"]
@@ -833,7 +836,7 @@
       ],
       "properties": {
         "ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "format": "string",
           "title": "Reference",
           "description": "References a component by the components bom-ref attribute"
@@ -842,7 +845,7 @@
           "type": "array",
           "uniqueItems": true,
           "items": {
-            "type": "string"
+            "$ref": "#/definitions/refType"
           },
           "title": "Depends On",
           "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
@@ -857,7 +860,7 @@
       ],
       "properties": {
         "bom-ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "BOM Reference",
           "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique.",
           "default": "",
@@ -957,7 +960,7 @@
           "title": "External References"
         },
         "services": {
-          "$id": "#/properties/services",
+          "$id": "#/definitions/service/properties/services",
           "type": "array",
           "items": {"$ref": "#/definitions/service"},
           "uniqueItems": true,
diff --git a/cyclonedx/schema/bom-1.2.xsd b/cyclonedx/schema/_res/bom-1.2.SNAPSHOT.xsd
similarity index 99%
rename from cyclonedx/schema/bom-1.2.xsd
rename to cyclonedx/schema/_res/bom-1.2.SNAPSHOT.xsd
index 2eb7e4864..763e6ee66 100644
--- a/cyclonedx/schema/bom-1.2.xsd
+++ b/cyclonedx/schema/_res/bom-1.2.SNAPSHOT.xsd
@@ -24,7 +24,7 @@ limitations under the License.
            vc:maxVersion="1.1"
            version="1.2.1">
 
-    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.xsd"/>
+    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.SNAPSHOT.xsd"/>
 
     <xs:annotation>
         <xs:documentation>
@@ -38,6 +38,13 @@ limitations under the License.
         </xs:documentation>
     </xs:annotation>
 
+    <xs:simpleType name="refType">
+        <xs:annotation>
+            <xs:documentation>Identifier-DataType for interlinked elements.</xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string" />
+    </xs:simpleType>
+
     <xs:complexType name="metadata">
         <xs:sequence minOccurs="0" maxOccurs="1">
             <xs:element name="timestamp" type="xs:dateTime" minOccurs="0">
@@ -395,7 +402,7 @@ limitations under the License.
                 </xs:documentation>
             </xs:annotation>
         </xs:attribute>
-        <xs:attribute name="bom-ref" type="xs:string">
+        <xs:attribute name="bom-ref" type="bom:refType">
             <xs:annotation>
                 <xs:documentation>
                     An optional identifier which can be used to reference the component elsewhere in the BOM.
@@ -1144,7 +1151,7 @@ limitations under the License.
         <xs:sequence minOccurs="0" maxOccurs="unbounded">
             <xs:element name="dependency" type="bom:dependencyType"/>
         </xs:sequence>
-        <xs:attribute name="ref" type="xs:string" use="required">
+        <xs:attribute name="ref" type="bom:refType" use="required">
             <xs:annotation>
                 <xs:documentation>References a component or service by the its bom-ref attribute</xs:documentation>
             </xs:annotation>
@@ -1302,7 +1309,7 @@ limitations under the License.
                 </xs:annotation>
             </xs:any>
         </xs:sequence>
-        <xs:attribute name="bom-ref" type="xs:string">
+        <xs:attribute name="bom-ref" type="bom:refType">
             <xs:annotation>
                 <xs:documentation>
                     An optional identifier which can be used to reference the service elsewhere in the BOM.
@@ -1415,4 +1422,4 @@ limitations under the License.
             <xs:field xpath="@bom-ref"/>
         </xs:unique>
     </xs:element>
-</xs:schema>
\ No newline at end of file
+</xs:schema>
diff --git a/cyclonedx/schema/bom-1.3a.schema.json b/cyclonedx/schema/_res/bom-1.3-strict.SNAPSHOT.schema.json
similarity index 98%
rename from cyclonedx/schema/bom-1.3a.schema.json
rename to cyclonedx/schema/_res/bom-1.3-strict.SNAPSHOT.schema.json
index 41b0b9453..a11426201 100644
--- a/cyclonedx/schema/bom-1.3a.schema.json
+++ b/cyclonedx/schema/_res/bom-1.3-strict.SNAPSHOT.schema.json
@@ -6,15 +6,14 @@
   "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
   "required": [
     "bomFormat",
-    "specVersion",
-    "version"
+    "specVersion"
   ],
   "additionalProperties": false,
   "properties": {
     "$schema": {
       "type": "string",
       "enum": [
-        "http://cyclonedx.org/schema/bom-1.3.schema.json"
+        "http://cyclonedx.org/schema/bom-1.3a.schema.json"
       ]
     },
     "bomFormat": {
@@ -94,6 +93,10 @@
     }
   },
   "definitions": {
+    "refType": {
+      "$comment": "Identifier-DataType for interlinked elements.",
+      "type": "string"
+    },
     "metadata": {
       "type": "object",
       "title": "BOM Metadata Object",
@@ -267,7 +270,7 @@
           "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
         },
         "bom-ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "BOM Reference",
           "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique."
         },
@@ -563,7 +566,7 @@
       "additionalProperties": false,
       "properties": {
         "id": {
-          "$ref": "spdx.schema.json",
+          "$ref": "spdx.SNAPSHOT.schema.json",
           "title": "License ID (SPDX)",
           "description": "A valid SPDX license ID",
           "examples": ["Apache-2.0"]
@@ -852,7 +855,7 @@
       "additionalProperties": false,
       "properties": {
         "ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "Reference",
           "description": "References a component by the components bom-ref attribute"
         },
@@ -860,7 +863,7 @@
           "type": "array",
           "uniqueItems": true,
           "items": {
-            "type": "string"
+            "$ref": "#/definitions/refType"
           },
           "title": "Depends On",
           "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
@@ -876,7 +879,7 @@
       "additionalProperties": false,
       "properties": {
         "bom-ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "BOM Reference",
           "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique."
         },
diff --git a/cyclonedx/schema/bom-1.3.schema.json b/cyclonedx/schema/_res/bom-1.3.SNAPSHOT.schema.json
similarity index 98%
rename from cyclonedx/schema/bom-1.3.schema.json
rename to cyclonedx/schema/_res/bom-1.3.SNAPSHOT.schema.json
index fdec97367..a269ebd75 100644
--- a/cyclonedx/schema/bom-1.3.schema.json
+++ b/cyclonedx/schema/_res/bom-1.3.SNAPSHOT.schema.json
@@ -1,13 +1,12 @@
 {
   "$schema": "http://json-schema.org/draft-07/schema#",
-  "$id": "http://cyclonedx.org/schema/bom-1.3.schema.json",
+  "$id": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
   "type": "object",
   "title": "CycloneDX Software Bill-of-Material Specification",
   "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
   "required": [
     "bomFormat",
-    "specVersion",
-    "version"
+    "specVersion"
   ],
   "properties": {
     "bomFormat": {
@@ -87,6 +86,10 @@
     }
   },
   "definitions": {
+    "refType": {
+      "$comment": "Identifier-DataType for interlinked elements.",
+      "type": "string"
+    },
     "metadata": {
       "type": "object",
       "title": "BOM Metadata Object",
@@ -158,7 +161,7 @@
           "description": "The date and time (timestamp) when the document was created."
         },
         "hashes": {
-          "$id": "#/properties/hashes",
+          "$id": "#/definitions/tool/properties/hashes",
           "type": "array",
           "items": {"$ref": "#/definitions/hash"},
           "title": "Hashes",
@@ -255,7 +258,7 @@
           "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
         },
         "bom-ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "BOM Reference",
           "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique."
         },
@@ -395,7 +398,7 @@
           "title": "External References"
         },
         "components": {
-          "$id": "#/properties/components",
+          "$id": "#/definitions/component/properties/components",
           "type": "array",
           "items": {"$ref": "#/definitions/component"},
           "uniqueItems": true,
@@ -546,7 +549,7 @@
       ],
       "properties": {
         "id": {
-          "$ref": "spdx.schema.json",
+          "$ref": "spdx.SNAPSHOT.schema.json",
           "title": "License ID (SPDX)",
           "description": "A valid SPDX license ID",
           "examples": ["Apache-2.0"]
@@ -809,7 +812,7 @@
           ]
         },
         "hashes": {
-          "$id": "#/properties/hashes",
+          "$id": "#/definitions/externalReference/properties/hashes",
           "type": "array",
           "items": {"$ref": "#/definitions/hash"},
           "title": "Hashes",
@@ -826,7 +829,7 @@
       ],
       "properties": {
         "ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "Reference",
           "description": "References a component by the components bom-ref attribute"
         },
@@ -834,7 +837,7 @@
           "type": "array",
           "uniqueItems": true,
           "items": {
-            "type": "string"
+            "$ref": "#/definitions/refType"
           },
           "title": "Depends On",
           "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
@@ -849,7 +852,7 @@
       ],
       "properties": {
         "bom-ref": {
-          "type": "string",
+          "$ref": "#/definitions/refType",
           "title": "BOM Reference",
           "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique."
         },
@@ -918,7 +921,7 @@
           "title": "External References"
         },
         "services": {
-          "$id": "#/properties/services",
+          "$id": "#/definitions/service/properties/services",
           "type": "array",
           "items": {"$ref": "#/definitions/service"},
           "uniqueItems": true,
diff --git a/cyclonedx/schema/bom-1.3.xsd b/cyclonedx/schema/_res/bom-1.3.SNAPSHOT.xsd
similarity index 99%
rename from cyclonedx/schema/bom-1.3.xsd
rename to cyclonedx/schema/_res/bom-1.3.SNAPSHOT.xsd
index 904d63698..150de4449 100644
--- a/cyclonedx/schema/bom-1.3.xsd
+++ b/cyclonedx/schema/_res/bom-1.3.SNAPSHOT.xsd
@@ -24,7 +24,7 @@ limitations under the License.
            vc:maxVersion="1.1"
            version="1.3.1">
 
-    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.xsd"/>
+    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.SNAPSHOT.xsd"/>
 
     <xs:annotation>
         <xs:documentation>
@@ -35,6 +35,13 @@ limitations under the License.
         </xs:documentation>
     </xs:annotation>
 
+    <xs:simpleType name="refType">
+        <xs:annotation>
+            <xs:documentation>Identifier-DataType for interlinked elements.</xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string" />
+    </xs:simpleType>
+
     <xs:complexType name="metadata">
         <xs:sequence minOccurs="0" maxOccurs="1">
             <xs:element name="timestamp" type="xs:dateTime" minOccurs="0">
@@ -400,7 +407,7 @@ limitations under the License.
                 </xs:documentation>
             </xs:annotation>
         </xs:attribute>
-        <xs:attribute name="bom-ref" type="xs:string">
+        <xs:attribute name="bom-ref" type="bom:refType">
             <xs:annotation>
                 <xs:documentation>
                     An optional identifier which can be used to reference the component elsewhere in the BOM.
@@ -555,7 +562,9 @@ limitations under the License.
                     <xs:documentation>A hardware device such as a processor, or chip-set. A hardware device
                         containing firmware should include a component for the physical hardware itself, and another
                         component of type 'firmware' or 'operating-system' (whichever is relevant), describing
-                        information about the software running on the device.</xs:documentation>
+                        information about the software running on the device.
+                        See also the list of known device properties: https://github.com/CycloneDX/cyclonedx-property-taxonomy/blob/main/cdx/device.md
+                    </xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
             <xs:enumeration value="firmware">
@@ -1156,7 +1165,7 @@ limitations under the License.
         <xs:sequence minOccurs="0" maxOccurs="unbounded">
             <xs:element name="dependency" type="bom:dependencyType"/>
         </xs:sequence>
-        <xs:attribute name="ref" type="xs:string" use="required">
+        <xs:attribute name="ref" type="bom:refType" use="required">
             <xs:annotation>
                 <xs:documentation>References a component or service by the its bom-ref attribute</xs:documentation>
             </xs:annotation>
@@ -1309,7 +1318,7 @@ limitations under the License.
                 </xs:annotation>
             </xs:any>
         </xs:sequence>
-        <xs:attribute name="bom-ref" type="xs:string">
+        <xs:attribute name="bom-ref" type="bom:refType">
             <xs:annotation>
                 <xs:documentation>
                     An optional identifier which can be used to reference the service elsewhere in the BOM.
@@ -1502,7 +1511,7 @@ limitations under the License.
     </xs:simpleType>
 
     <xs:complexType name="bomReferenceType">
-        <xs:attribute name="ref" type="xs:string" use="required">
+        <xs:attribute name="ref" type="bom:refType" use="required">
             <xs:annotation>
                 <xs:documentation>References a component or service by the its bom-ref attribute</xs:documentation>
             </xs:annotation>
@@ -1628,4 +1637,4 @@ limitations under the License.
             <xs:field xpath="@bom-ref"/>
         </xs:unique>
     </xs:element>
-</xs:schema>
\ No newline at end of file
+</xs:schema>
diff --git a/cyclonedx/schema/bom-1.4.schema.json b/cyclonedx/schema/_res/bom-1.4.SNAPSHOT.schema.json
similarity index 98%
rename from cyclonedx/schema/bom-1.4.schema.json
rename to cyclonedx/schema/_res/bom-1.4.SNAPSHOT.schema.json
index 85684d769..1a8858104 100644
--- a/cyclonedx/schema/bom-1.4.schema.json
+++ b/cyclonedx/schema/_res/bom-1.4.SNAPSHOT.schema.json
@@ -6,8 +6,7 @@
   "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
   "required": [
     "bomFormat",
-    "specVersion",
-    "version"
+    "specVersion"
   ],
   "additionalProperties": false,
   "properties": {
@@ -282,7 +281,7 @@
             "file"
           ],
           "title": "Component Type",
-          "description": "Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component. Types include:\n\n* __application__ = A software application. Refer to [https://en.wikipedia.org/wiki/Application_software](https://en.wikipedia.org/wiki/Application_software) for information about applications.\n* __framework__ = A software framework. Refer to [https://en.wikipedia.org/wiki/Software_framework](https://en.wikipedia.org/wiki/Software_framework) for information on how frameworks vary slightly from libraries.\n* __library__ = A software library. Refer to [https://en.wikipedia.org/wiki/Library_(computing)](https://en.wikipedia.org/wiki/Library_(computing))\n for information about libraries. All third-party and open source reusable components will likely be a library. If the library also has key features of a framework, then it should be classified as a framework. If not, or is unknown, then specifying library is RECOMMENDED.\n* __container__ = A packaging and/or runtime format, not specific to any particular technology, which isolates software inside the container from software outside of a container through virtualization technology. Refer to [https://en.wikipedia.org/wiki/OS-level_virtualization](https://en.wikipedia.org/wiki/OS-level_virtualization)\n* __operating-system__ = A software operating system without regard to deployment model (i.e. installed on physical hardware, virtual machine, image, etc) Refer to [https://en.wikipedia.org/wiki/Operating_system](https://en.wikipedia.org/wiki/Operating_system)\n* __device__ = A hardware device such as a processor, or chip-set. A hardware device containing firmware SHOULD include a component for the physical hardware itself, and another component of type 'firmware' or 'operating-system' (whichever is relevant), describing information about the software running on the device.\n* __firmware__ = A special type of software that provides low-level control over a devices hardware. Refer to [https://en.wikipedia.org/wiki/Firmware](https://en.wikipedia.org/wiki/Firmware)\n* __file__ = A computer file. Refer to [https://en.wikipedia.org/wiki/Computer_file](https://en.wikipedia.org/wiki/Computer_file) for information about files.",
+          "description": "Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component. Types include:\n\n* __application__ = A software application. Refer to [https://en.wikipedia.org/wiki/Application_software](https://en.wikipedia.org/wiki/Application_software) for information about applications.\n* __framework__ = A software framework. Refer to [https://en.wikipedia.org/wiki/Software_framework](https://en.wikipedia.org/wiki/Software_framework) for information on how frameworks vary slightly from libraries.\n* __library__ = A software library. Refer to [https://en.wikipedia.org/wiki/Library_(computing)](https://en.wikipedia.org/wiki/Library_(computing))\n for information about libraries. All third-party and open source reusable components will likely be a library. If the library also has key features of a framework, then it should be classified as a framework. If not, or is unknown, then specifying library is RECOMMENDED.\n* __container__ = A packaging and/or runtime format, not specific to any particular technology, which isolates software inside the container from software outside of a container through virtualization technology. Refer to [https://en.wikipedia.org/wiki/OS-level_virtualization](https://en.wikipedia.org/wiki/OS-level_virtualization)\n* __operating-system__ = A software operating system without regard to deployment model (i.e. installed on physical hardware, virtual machine, image, etc) Refer to [https://en.wikipedia.org/wiki/Operating_system](https://en.wikipedia.org/wiki/Operating_system)\n* __device__ = A hardware device such as a processor, or chip-set. A hardware device containing firmware SHOULD include a component for the physical hardware itself, and another component of type 'firmware' or 'operating-system' (whichever is relevant), describing information about the software running on the device.\n  See also the list of [known device properties](https://github.com/CycloneDX/cyclonedx-property-taxonomy/blob/main/cdx/device.md).\n* __firmware__ = A special type of software that provides low-level control over a devices hardware. Refer to [https://en.wikipedia.org/wiki/Firmware](https://en.wikipedia.org/wiki/Firmware)\n* __file__ = A computer file. Refer to [https://en.wikipedia.org/wiki/Computer_file](https://en.wikipedia.org/wiki/Computer_file) for information about files.",
           "examples": ["library"]
         },
         "mime-type": {
@@ -611,7 +610,7 @@
       "additionalProperties": false,
       "properties": {
         "id": {
-          "$ref": "spdx.schema.json",
+          "$ref": "spdx.SNAPSHOT.schema.json",
           "title": "License ID (SPDX)",
           "description": "A valid SPDX license ID",
           "examples": ["Apache-2.0"]
@@ -1488,7 +1487,7 @@
           "type": "array",
           "title": "CWEs",
           "description": "List of Common Weaknesses Enumerations (CWEs) codes that describes this vulnerability. For example 399 (of https://cwe.mitre.org/data/definitions/399.html)",
-          "examples": ["399"],
+          "examples": [399],
           "additionalItems": false,
           "items": {
             "$ref": "#/definitions/cwe"
@@ -1641,7 +1640,7 @@
                     },
                     "range": {
                       "description": "A version range specified in Package URL Version Range syntax (vers) which is defined at https://github.com/package-url/purl-spec/VERSION-RANGE-SPEC.rst",
-                      "$ref": "#/definitions/version"
+                      "$ref": "#/definitions/range"
                     },
                     "status": {
                       "description": "The vulnerability status for the version or range of versions.",
@@ -1689,9 +1688,9 @@
       "maxLength": 1024
     },
     "signature": {
-      "$ref": "jsf-0.82.schema.json#/definitions/signature",
+      "$ref": "jsf-0.82.SNAPSHOT.schema.json#/definitions/signature",
       "title": "Signature",
       "description": "Enveloped signature in [JSON Signature Format (JSF)](https://cyberphone.github.io/doc/security/jsf.html)."
     }
   }
-}
\ No newline at end of file
+}
diff --git a/cyclonedx/schema/bom-1.4.xsd b/cyclonedx/schema/_res/bom-1.4.SNAPSHOT.xsd
similarity index 99%
rename from cyclonedx/schema/bom-1.4.xsd
rename to cyclonedx/schema/_res/bom-1.4.SNAPSHOT.xsd
index 9cf8af240..4b3b250d4 100644
--- a/cyclonedx/schema/bom-1.4.xsd
+++ b/cyclonedx/schema/_res/bom-1.4.SNAPSHOT.xsd
@@ -24,7 +24,7 @@ limitations under the License.
            vc:maxVersion="1.1"
            version="1.4.2">
 
-    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.xsd"/>
+    <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.SNAPSHOT.xsd"/>
 
     <xs:annotation>
         <xs:documentation>
@@ -577,7 +577,9 @@ limitations under the License.
                     <xs:documentation>A hardware device such as a processor, or chip-set. A hardware device
                         containing firmware SHOULD include a component for the physical hardware itself, and another
                         component of type 'firmware' or 'operating-system' (whichever is relevant), describing
-                        information about the software running on the device.</xs:documentation>
+                        information about the software running on the device.
+                        See also the list of known device properties: https://github.com/CycloneDX/cyclonedx-property-taxonomy/blob/main/cdx/device.md
+                    </xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
             <xs:enumeration value="firmware">
@@ -1969,7 +1971,7 @@ limitations under the License.
                         <xs:element name="target">
                             <xs:complexType>
                                 <xs:sequence minOccurs="0" maxOccurs="1">
-                                    <xs:element name="ref" minOccurs="1" maxOccurs="1">
+                                    <xs:element name="ref" type="bom:refType" minOccurs="1" maxOccurs="1">
                                         <xs:annotation>
                                             <xs:documentation>References a component or service by the objects bom-ref.</xs:documentation>
                                         </xs:annotation>
@@ -2414,4 +2416,4 @@ limitations under the License.
             <xs:field xpath="@bom-ref"/>
         </xs:unique>
     </xs:element>
-</xs:schema>
\ No newline at end of file
+</xs:schema>
diff --git a/cyclonedx/schema/_res/jsf-0.82.SNAPSHOT.schema.json b/cyclonedx/schema/_res/jsf-0.82.SNAPSHOT.schema.json
new file mode 100644
index 000000000..f46bfb1e5
--- /dev/null
+++ b/cyclonedx/schema/_res/jsf-0.82.SNAPSHOT.schema.json
@@ -0,0 +1,240 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "$id": "http://cyclonedx.org/schema/jsf-0.82.schema.json",
+  "type": "object",
+  "title": "JSON Signature Format (JSF) standard",
+  "$comment" : "JSON Signature Format schema is published under the terms of the Apache License 2.0. JSF was developed by Anders Rundgren (anders.rundgren.net@gmail.com) as a part of the OpenKeyStore project. This schema supports the entirely of the JSF standard excluding 'extensions'.",
+  "definitions": {
+    "signature": {
+      "type": "object",
+      "title": "Signature",
+      "oneOf": [
+        {
+          "additionalProperties": false,
+          "properties": {
+            "signers": {
+              "type": "array",
+              "title": "Signature",
+              "description": "Unique top level property for Multiple Signatures. (multisignature)",
+              "items": {"$ref": "#/definitions/signer"}
+            }
+          }
+        },
+        {
+          "additionalProperties": false,
+          "properties": {
+            "chain": {
+              "type": "array",
+              "title": "Signature",
+              "description": "Unique top level property for Signature Chains. (signaturechain)",
+              "items": {"$ref": "#/definitions/signer"}
+            }
+          }
+        },
+        {
+          "title": "Signature",
+          "description": "Unique top level property for simple signatures. (signaturecore)",
+          "$ref": "#/definitions/signer"
+        }
+      ]
+    },
+    "signer": {
+      "type": "object",
+      "title": "Signature",
+      "required": [
+        "algorithm",
+        "value"
+      ],
+      "additionalProperties": false,
+      "properties": {
+        "algorithm": {
+          "oneOf": [
+            {
+              "type": "string",
+              "title": "Algorithm",
+              "description": "Signature algorithm. The currently recognized JWA [RFC7518] and RFC8037 [RFC8037] asymmetric key algorithms. Note: Unlike RFC8037 [RFC8037] JSF requires explicit Ed* algorithm names instead of \"EdDSA\".",
+              "enum": [
+                "RS256",
+                "RS384",
+                "RS512",
+                "PS256",
+                "PS384",
+                "PS512",
+                "ES256",
+                "ES384",
+                "ES512",
+                "Ed25519",
+                "Ed448",
+                "HS256",
+                "HS384",
+                "HS512"
+              ]
+            },
+            {
+              "type": "string",
+              "title": "Algorithm",
+              "description": "Signature algorithm. Note: If proprietary signature algorithms are added, they must be expressed as URIs.",
+              "format": "uri"
+            }
+          ]
+        },
+        "keyId": {
+          "type": "string",
+          "title": "Key ID",
+          "description": "Optional. Application specific string identifying the signature key."
+        },
+        "publicKey": {
+          "title": "Public key",
+          "description": "Optional. Public key object.",
+          "$ref": "#/definitions/publicKey"
+        },
+        "certificatePath": {
+          "type": "array",
+          "title": "Certificate path",
+          "description": "Optional. Sorted array of X.509 [RFC5280] certificates, where the first element must contain the signature certificate. The certificate path must be contiguous but is not required to be complete.",
+          "items": {
+            "type": "string"
+          }
+        },
+        "excludes": {
+          "type": "array",
+          "title": "Excludes",
+          "description": "Optional. Array holding the names of one or more application level properties that must be excluded from the signature process. Note that the \"excludes\" property itself, must also be excluded from the signature process. Since both the \"excludes\" property and the associated data it points to are unsigned, a conforming JSF implementation must provide options for specifying which properties to accept.",
+          "items": {
+            "type": "string"
+          }
+        },
+        "value": {
+          "type": "string",
+          "title": "Signature",
+          "description": "The signature data. Note that the binary representation must follow the JWA [RFC7518] specifications."
+        }
+      }
+    },
+    "keyType": {
+      "type": "string",
+      "title": "Key type",
+      "description": "Key type indicator.",
+      "enum": [
+        "EC",
+        "OKP",
+        "RSA"
+      ]
+    },
+    "publicKey": {
+      "title": "Public key",
+      "description": "Optional. Public key object.",
+      "type": "object",
+      "required": [
+        "kty"
+      ],
+      "additionalProperties": true,
+      "properties": {
+        "kty": {
+          "$ref": "#/definitions/keyType"
+        }
+      },
+      "allOf": [
+        {
+          "if": {
+            "properties": { "kty": { "const": "EC" } }
+          },
+          "then": {
+            "required": [
+              "kty",
+              "crv",
+              "x",
+              "y"
+            ],
+            "additionalProperties": false,
+            "properties": {
+              "kty": {
+                "$ref": "#/definitions/keyType"
+              },
+              "crv": {
+                "type": "string",
+                "title": "Curve name",
+                "description": "EC curve name.",
+                "enum": [
+                  "P-256",
+                  "P-384",
+                  "P-521"
+                ]
+              },
+              "x": {
+                "type": "string",
+                "title": "Coordinate",
+                "description": "EC curve point X. The length of this field must be the full size of a coordinate for the curve specified in the \"crv\" parameter. For example, if the value of \"crv\" is \"P-521\", the decoded argument must be 66 bytes."
+              },
+              "y": {
+                "type": "string",
+                "title": "Coordinate",
+                "description": "EC curve point Y. The length of this field must be the full size of a coordinate for the curve specified in the \"crv\" parameter. For example, if the value of \"crv\" is \"P-256\", the decoded argument must be 32 bytes."
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": { "kty": { "const": "OKP" } }
+          },
+          "then": {
+            "required": [
+              "kty",
+              "crv",
+              "x"
+            ],
+            "additionalProperties": false,
+            "properties": {
+              "kty": {
+                "$ref": "#/definitions/keyType"
+              },
+              "crv": {
+                "type": "string",
+                "title": "Curve name",
+                "description": "EdDSA curve name.",
+                "enum": [
+                  "Ed25519",
+                  "Ed448"
+                ]
+              },
+              "x": {
+                "type": "string",
+                "title": "Coordinate",
+                "description": "EdDSA curve point X. The length of this field must be the full size of a coordinate for the curve specified in the \"crv\" parameter. For example, if the value of \"crv\" is \"Ed25519\", the decoded argument must be 32 bytes."
+              }
+            }
+          }
+        },
+        {
+          "if": {
+            "properties": { "kty": { "const": "RSA" } }
+          },
+          "then": {
+            "required": [
+              "kty",
+              "n",
+              "e"
+            ],
+            "additionalProperties": false,
+            "properties": {
+              "kty": {
+                "$ref": "#/definitions/keyType"
+              },
+              "n": {
+                "type": "string",
+                "title": "Modulus",
+                "description": "RSA modulus."
+              },
+              "e": {
+                "type": "string",
+                "title": "Exponent",
+                "description": "RSA exponent."
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
+}
diff --git a/cyclonedx/schema/spdx.schema.json b/cyclonedx/schema/_res/spdx.SNAPSHOT.schema.json
similarity index 84%
rename from cyclonedx/schema/spdx.schema.json
rename to cyclonedx/schema/_res/spdx.SNAPSHOT.schema.json
index 26013fa6b..f04d013c7 100644
--- a/cyclonedx/schema/spdx.schema.json
+++ b/cyclonedx/schema/_res/spdx.SNAPSHOT.schema.json
@@ -1,538 +1,621 @@
 {
   "$schema": "http://json-schema.org/draft-07/schema#",
   "$id": "http://cyclonedx.org/schema/spdx.schema.json",
-  "$comment": "v1.0-3.17",
+  "$comment": "v1.0-3.21",
   "type": "string",
   "enum": [
-    "CC-BY-NC-ND-2.0",
-    "SGI-B-2.0",
-    "LPPL-1.3c",
-    "NIST-PD-fallback",
-    "libtiff",
-    "XSkat",
-    "PDDL-1.0",
-    "KiCad-libraries-exception",
-    "CC-BY-NC-SA-1.0",
-    "GFDL-1.1-no-invariants-only",
-    "Xerox",
-    "LPPL-1.1",
-    "VOSTROM",
-    "UCL-1.0",
-    "ADSL",
-    "OSL-2.0",
+    "0BSD",
     "AAL",
-    "FDK-AAC",
-    "W3C-20150513",
+    "Abstyles",
+    "AdaCore-doc",
+    "Adobe-2006",
+    "Adobe-Glyph",
+    "ADSL",
     "AFL-1.1",
-    "W3C",
-    "Sleepycat",
-    "CECILL-1.1",
-    "mpich2",
-    "SISSL",
-    "NLOD-1.0",
-    "ANTLR-PD",
-    "GPL-3.0-only",
-    "gnuplot",
-    "NLOD-2.0",
-    "BSD-3-Clause-Open-MPI",
-    "LiLiQ-P-1.1",
-    "BSD-3-Clause-Clear",
-    "FSFUL",
-    "CC-BY-NC-SA-2.0-UK",
-    "CERN-OHL-S-2.0",
-    "Spencer-94",
-    "CERN-OHL-1.2",
-    "GFDL-1.1-or-later",
+    "AFL-1.2",
+    "AFL-2.0",
+    "AFL-2.1",
+    "AFL-3.0",
+    "Afmparse",
+    "AGPL-1.0",
+    "AGPL-1.0-only",
     "AGPL-1.0-or-later",
-    "Wsuipa",
+    "AGPL-3.0",
+    "AGPL-3.0-only",
+    "AGPL-3.0-or-later",
+    "Aladdin",
+    "AMDPLPA",
     "AML",
-    "BSD-2-Clause",
-    "DSDP",
-    "CC-BY-2.5",
-    "MIT-CMU",
-    "Beerware",
-    "Sendmail",
-    "TU-Berlin-1.0",
-    "CNRI-Jython",
-    "mplus",
-    "CPOL-1.02",
-    "BSD-3-Clause-No-Nuclear-License-2014",
-    "ISC",
-    "CC-BY-SA-4.0",
-    "Eurosym",
-    "LGPL-3.0-only",
-    "OLDAP-1.3",
-    "GFDL-1.1-invariants-or-later",
-    "Glulxe",
-    "SimPL-2.0",
-    "CDLA-Permissive-2.0",
-    "GPL-2.0-with-font-exception",
-    "OGL-UK-2.0",
-    "CC-BY-SA-3.0-DE",
-    "CC-BY-ND-1.0",
-    "GFDL-1.1",
-    "CC-BY-4.0",
-    "OpenSSL",
-    "TU-Berlin-2.0",
-    "DOC",
-    "GFDL-1.2-no-invariants-or-later",
-    "QPL-1.0",
-    "OLDAP-2.8",
-    "OML",
-    "OLDAP-2.7",
-    "NIST-PD",
-    "Bitstream-Vera",
-    "GFDL-1.2-or-later",
-    "OFL-1.1-RFN",
-    "Bahyph",
-    "Barr",
-    "COIL-1.0",
-    "GFDL-1.3",
-    "CECILL-B",
-    "JPNIC",
-    "Zed",
-    "ICU",
-    "CC-BY-NC-SA-2.5",
-    "CC-BY-ND-3.0-DE",
-    "bzip2-1.0.5",
-    "SPL-1.0",
-    "YPL-1.0",
-    "OSET-PL-2.1",
-    "Noweb",
-    "RPSL-1.0",
-    "BSD-3-Clause-LBNL",
-    "CDLA-Sharing-1.0",
-    "CECILL-1.0",
     "AMPAS",
+    "ANTLR-PD",
+    "ANTLR-PD-fallback",
+    "Apache-1.0",
+    "Apache-1.1",
+    "Apache-2.0",
     "APAFML",
-    "CC-BY-ND-3.0",
-    "D-FSL-1.0",
-    "CC-BY-NC-3.0",
-    "libpng-2.0",
-    "PolyForm-Noncommercial-1.0.0",
-    "dvipdfm",
-    "GFDL-1.3-or-later",
-    "OGTSL",
-    "NPL-1.1",
-    "GPL-3.0",
-    "CERN-OHL-P-2.0",
-    "BlueOak-1.0.0",
-    "AGPL-3.0-or-later",
-    "blessing",
-    "ImageMagick",
+    "APL-1.0",
+    "App-s2p",
+    "APSL-1.0",
+    "APSL-1.1",
+    "APSL-1.2",
     "APSL-2.0",
-    "MIT-advertising",
-    "curl",
-    "CC0-1.0",
-    "Zimbra-1.4",
-    "SSPL-1.0",
-    "psutils",
-    "CC-BY-SA-2.0-UK",
-    "PSF-2.0",
-    "Net-SNMP",
-    "NAIST-2003",
-    "GFDL-1.2-invariants-or-later",
-    "SGI-B-1.0",
-    "NBPL-1.0",
-    "GFDL-1.2-invariants-only",
-    "W3C-19980720",
-    "OFL-1.0-no-RFN",
-    "NetCDF",
-    "TMate",
-    "NOSL",
-    "CNRI-Python-GPL-Compatible",
+    "Arphic-1999",
+    "Artistic-1.0",
+    "Artistic-1.0-cl8",
+    "Artistic-1.0-Perl",
+    "Artistic-2.0",
+    "ASWF-Digital-Assets-1.0",
+    "ASWF-Digital-Assets-1.1",
+    "Baekmuk",
+    "Bahyph",
+    "Barr",
+    "Beerware",
+    "Bitstream-Charter",
+    "Bitstream-Vera",
+    "BitTorrent-1.0",
+    "BitTorrent-1.1",
+    "blessing",
+    "BlueOak-1.0.0",
+    "Boehm-GC",
+    "Borceux",
+    "Brian-Gladman-3-Clause",
     "BSD-1-Clause",
-    "CC-BY-NC-SA-3.0-DE",
+    "BSD-2-Clause",
+    "BSD-2-Clause-FreeBSD",
+    "BSD-2-Clause-NetBSD",
+    "BSD-2-Clause-Patent",
+    "BSD-2-Clause-Views",
+    "BSD-3-Clause",
+    "BSD-3-Clause-Attribution",
+    "BSD-3-Clause-Clear",
+    "BSD-3-Clause-LBNL",
     "BSD-3-Clause-Modification",
-    "GLWTPL",
-    "GFDL-1.3-only",
-    "OLDAP-2.2",
-    "CC-BY-ND-4.0",
-    "CC-BY-NC-ND-3.0-DE",
-    "EUPL-1.0",
-    "Linux-OpenIB",
-    "LGPL-2.0-or-later",
-    "OSL-1.1",
-    "Spencer-86",
-    "LGPL-2.0",
-    "CC-PDDC",
-    "CC-BY-NC-ND-3.0",
-    "CDL-1.0",
-    "Elastic-2.0",
-    "CC-BY-2.0",
     "BSD-3-Clause-No-Military-License",
-    "IJG",
-    "LPPL-1.3a",
-    "SAX-PD",
-    "BitTorrent-1.0",
-    "OLDAP-2.0",
-    "Giftware",
+    "BSD-3-Clause-No-Nuclear-License",
+    "BSD-3-Clause-No-Nuclear-License-2014",
+    "BSD-3-Clause-No-Nuclear-Warranty",
+    "BSD-3-Clause-Open-MPI",
+    "BSD-4-Clause",
+    "BSD-4-Clause-Shortened",
+    "BSD-4-Clause-UC",
+    "BSD-4.3RENO",
+    "BSD-4.3TAHOE",
+    "BSD-Advertising-Acknowledgement",
+    "BSD-Attribution-HPND-disclaimer",
+    "BSD-Protection",
+    "BSD-Source-Code",
+    "BSL-1.0",
+    "BUSL-1.1",
+    "bzip2-1.0.5",
+    "bzip2-1.0.6",
     "C-UDA-1.0",
-    "LGPL-2.0+",
-    "Rdisc",
-    "GPL-2.0-with-classpath-exception",
+    "CAL-1.0",
+    "CAL-1.0-Combined-Work-Exception",
+    "Caldera",
+    "CATOSL-1.1",
+    "CC-BY-1.0",
+    "CC-BY-2.0",
+    "CC-BY-2.5",
+    "CC-BY-2.5-AU",
+    "CC-BY-3.0",
+    "CC-BY-3.0-AT",
+    "CC-BY-3.0-DE",
+    "CC-BY-3.0-IGO",
+    "CC-BY-3.0-NL",
     "CC-BY-3.0-US",
-    "CDDL-1.0",
-    "Xnet",
-    "CPL-1.0",
-    "LGPL-3.0-or-later",
-    "NASA-1.3",
-    "BUSL-1.1",
-    "etalab-2.0",
-    "MIT-open-group",
-    "OLDAP-1.4",
-    "GFDL-1.1-invariants-only",
-    "RPL-1.1",
+    "CC-BY-4.0",
+    "CC-BY-NC-1.0",
+    "CC-BY-NC-2.0",
+    "CC-BY-NC-2.5",
+    "CC-BY-NC-3.0",
+    "CC-BY-NC-3.0-DE",
+    "CC-BY-NC-4.0",
+    "CC-BY-NC-ND-1.0",
+    "CC-BY-NC-ND-2.0",
     "CC-BY-NC-ND-2.5",
-    "FSFULLR",
-    "Saxpath",
-    "NTP-0",
-    "SISSL-1.2",
-    "GPL-3.0-or-later",
-    "Apache-1.1",
+    "CC-BY-NC-ND-3.0",
+    "CC-BY-NC-ND-3.0-DE",
+    "CC-BY-NC-ND-3.0-IGO",
+    "CC-BY-NC-ND-4.0",
+    "CC-BY-NC-SA-1.0",
+    "CC-BY-NC-SA-2.0",
+    "CC-BY-NC-SA-2.0-DE",
+    "CC-BY-NC-SA-2.0-FR",
+    "CC-BY-NC-SA-2.0-UK",
+    "CC-BY-NC-SA-2.5",
+    "CC-BY-NC-SA-3.0",
+    "CC-BY-NC-SA-3.0-DE",
+    "CC-BY-NC-SA-3.0-IGO",
+    "CC-BY-NC-SA-4.0",
+    "CC-BY-ND-1.0",
+    "CC-BY-ND-2.0",
+    "CC-BY-ND-2.5",
+    "CC-BY-ND-3.0",
+    "CC-BY-ND-3.0-DE",
+    "CC-BY-ND-4.0",
+    "CC-BY-SA-1.0",
+    "CC-BY-SA-2.0",
+    "CC-BY-SA-2.0-UK",
     "CC-BY-SA-2.1-JP",
-    "AGPL-3.0-only",
-    "GPL-2.0-with-autoconf-exception",
-    "Artistic-2.0",
-    "App-s2p",
-    "Unicode-DFS-2015",
-    "diffmark",
-    "SNIA",
     "CC-BY-SA-2.5",
-    "Linux-man-pages-copyleft",
-    "HPND-sell-variant",
-    "ZPL-2.1",
-    "BSD-4-Clause-UC",
-    "LAL-1.2",
-    "AGPL-1.0-only",
-    "MIT-enna",
+    "CC-BY-SA-3.0",
+    "CC-BY-SA-3.0-AT",
+    "CC-BY-SA-3.0-DE",
+    "CC-BY-SA-3.0-IGO",
+    "CC-BY-SA-4.0",
+    "CC-PDDC",
+    "CC0-1.0",
+    "CDDL-1.0",
+    "CDDL-1.1",
+    "CDL-1.0",
+    "CDLA-Permissive-1.0",
+    "CDLA-Permissive-2.0",
+    "CDLA-Sharing-1.0",
+    "CECILL-1.0",
+    "CECILL-1.1",
+    "CECILL-2.0",
+    "CECILL-2.1",
+    "CECILL-B",
+    "CECILL-C",
+    "CERN-OHL-1.1",
+    "CERN-OHL-1.2",
+    "CERN-OHL-P-2.0",
+    "CERN-OHL-S-2.0",
+    "CERN-OHL-W-2.0",
+    "CFITSIO",
+    "checkmk",
+    "ClArtistic",
+    "Clips",
+    "CMU-Mach",
+    "CNRI-Jython",
+    "CNRI-Python",
+    "CNRI-Python-GPL-Compatible",
+    "COIL-1.0",
+    "Community-Spec-1.0",
     "Condor-1.1",
-    "Naumen",
-    "GFDL-1.3-no-invariants-or-later",
-    "RPL-1.5",
-    "PolyForm-Small-Business-1.0.0",
-    "EFL-1.0",
-    "MirOS",
-    "CC-BY-2.5-AU",
-    "Afmparse",
-    "MPL-2.0-no-copyleft-exception",
-    "LiLiQ-Rplus-1.1",
-    "AFL-1.2",
-    "OSL-1.0",
-    "GPL-1.0-only",
-    "APSL-1.0",
-    "OGL-Canada-2.0",
+    "copyleft-next-0.3.0",
+    "copyleft-next-0.3.1",
+    "Cornell-Lossless-JPEG",
     "CPAL-1.0",
-    "Latex2e",
-    "Zend-2.0",
-    "Unlicense",
-    "xpp",
-    "CC-BY-NC-1.0",
-    "GPL-3.0-with-autoconf-exception",
-    "CC-BY-NC-SA-3.0",
-    "TCP-wrappers",
-    "SCEA",
-    "SSH-short",
-    "CC-BY-3.0-NL",
-    "SchemeReport",
-    "CC-BY-3.0",
-    "MPL-2.0",
-    "Unicode-TOU",
-    "CC-BY-NC-ND-1.0",
+    "CPL-1.0",
+    "CPOL-1.02",
+    "Crossword",
+    "CrystalStacker",
+    "CUA-OPL-1.0",
+    "Cube",
+    "curl",
+    "D-FSL-1.0",
+    "diffmark",
+    "DL-DE-BY-2.0",
+    "DOC",
+    "Dotseqn",
+    "DRL-1.0",
+    "DSDP",
+    "dtoa",
+    "dvipdfm",
+    "ECL-1.0",
+    "ECL-2.0",
+    "eCos-2.0",
+    "EFL-1.0",
+    "EFL-2.0",
+    "eGenix",
+    "Elastic-2.0",
     "Entessa",
-    "BSD-3-Clause-No-Nuclear-License",
-    "SWL",
-    "GFDL-1.2-no-invariants-only",
-    "Parity-7.0.0",
-    "OLDAP-2.2.1",
-    "SGI-B-1.1",
-    "FTL",
-    "OLDAP-2.4",
-    "CC-BY-NC-4.0",
-    "bzip2-1.0.6",
-    "copyleft-next-0.3.0",
-    "MakeIndex",
-    "NRL",
-    "GFDL-1.3-invariants-or-later",
-    "CC-BY-NC-2.0",
-    "SugarCRM-1.1.3",
-    "AFL-2.1",
-    "GPL-2.0-only",
-    "GFDL-1.3-invariants-only",
-    "TORQUE-1.1",
-    "Ruby",
-    "X11",
-    "Borceux",
-    "Libpng",
-    "X11-distribute-modifications-variant",
-    "Frameworx-1.0",
-    "NCGL-UK-2.0",
-    "CECILL-2.1",
-    "CC-BY-3.0-AT",
-    "CNRI-Python",
-    "NCSA",
-    "gSOAP-1.3b",
-    "EUPL-1.1",
-    "AMDPLPA",
-    "Imlib2",
-    "CDDL-1.1",
-    "WTFPL",
-    "LPL-1.0",
+    "EPICS",
     "EPL-1.0",
-    "BSD-3-Clause-Attribution",
-    "OSL-3.0",
-    "RHeCos-1.1",
-    "PHP-3.0",
-    "BSD-Protection",
-    "CC-BY-NC-3.0-DE",
-    "APL-1.0",
+    "EPL-2.0",
+    "ErlPL-1.1",
+    "etalab-2.0",
     "EUDatagrid",
-    "GPL-1.0",
-    "SHL-0.5",
-    "CC-BY-SA-2.0",
-    "CC-BY-SA-3.0-AT",
-    "CC-BY-NC-SA-3.0-IGO",
-    "Adobe-2006",
-    "Newsletr",
-    "Nunit",
-    "Multics",
-    "OGL-UK-1.0",
-    "Vim",
-    "eCos-2.0",
-    "Zimbra-1.3",
-    "eGenix",
-    "IBM-pibs",
-    "BitTorrent-1.1",
-    "OFL-1.1-no-RFN",
-    "psfrag",
-    "CC-BY-ND-2.0",
-    "SHL-0.51",
+    "EUPL-1.0",
+    "EUPL-1.1",
+    "EUPL-1.2",
+    "Eurosym",
+    "Fair",
+    "FDK-AAC",
+    "Frameworx-1.0",
     "FreeBSD-DOC",
-    "Python-2.0",
-    "Mup",
-    "BSD-4-Clause-Shortened",
-    "CC-BY-NC-SA-4.0",
-    "HPND",
-    "OLDAP-2.6",
-    "MPL-1.1",
+    "FreeImage",
+    "FSFAP",
+    "FSFUL",
+    "FSFULLR",
+    "FSFULLRWD",
+    "FTL",
+    "GD",
+    "GFDL-1.1",
+    "GFDL-1.1-invariants-only",
+    "GFDL-1.1-invariants-or-later",
+    "GFDL-1.1-no-invariants-only",
+    "GFDL-1.1-no-invariants-or-later",
+    "GFDL-1.1-only",
+    "GFDL-1.1-or-later",
+    "GFDL-1.2",
+    "GFDL-1.2-invariants-only",
+    "GFDL-1.2-invariants-or-later",
+    "GFDL-1.2-no-invariants-only",
+    "GFDL-1.2-no-invariants-or-later",
+    "GFDL-1.2-only",
+    "GFDL-1.2-or-later",
+    "GFDL-1.3",
+    "GFDL-1.3-invariants-only",
+    "GFDL-1.3-invariants-or-later",
+    "GFDL-1.3-no-invariants-only",
+    "GFDL-1.3-no-invariants-or-later",
+    "GFDL-1.3-only",
+    "GFDL-1.3-or-later",
+    "Giftware",
+    "GL2PS",
+    "Glide",
+    "Glulxe",
+    "GLWTPL",
+    "gnuplot",
+    "GPL-1.0",
+    "GPL-1.0+",
+    "GPL-1.0-only",
+    "GPL-1.0-or-later",
+    "GPL-2.0",
+    "GPL-2.0+",
+    "GPL-2.0-only",
+    "GPL-2.0-or-later",
+    "GPL-2.0-with-autoconf-exception",
+    "GPL-2.0-with-bison-exception",
+    "GPL-2.0-with-classpath-exception",
+    "GPL-2.0-with-font-exception",
     "GPL-2.0-with-GCC-exception",
+    "GPL-3.0",
+    "GPL-3.0+",
+    "GPL-3.0-only",
+    "GPL-3.0-or-later",
+    "GPL-3.0-with-autoconf-exception",
+    "GPL-3.0-with-GCC-exception",
+    "Graphics-Gems",
+    "gSOAP-1.3b",
     "HaskellReport",
-    "ECL-1.0",
+    "Hippocratic-2.1",
+    "HP-1986",
+    "HPND",
+    "HPND-export-US",
+    "HPND-Markus-Kuhn",
+    "HPND-sell-variant",
+    "HPND-sell-variant-MIT-disclaimer",
+    "HTMLTIDY",
+    "IBM-pibs",
+    "ICU",
+    "IEC-Code-Components-EULA",
+    "IJG",
+    "IJG-short",
+    "ImageMagick",
+    "iMatix",
+    "Imlib2",
+    "Info-ZIP",
+    "Inner-Net-2.0",
+    "Intel",
+    "Intel-ACPI",
+    "Interbase-1.0",
+    "IPA",
+    "IPL-1.0",
+    "ISC",
+    "Jam",
+    "JasPer-2.0",
+    "JPL-image",
+    "JPNIC",
+    "JSON",
+    "Kazlib",
+    "Knuth-CTAN",
+    "LAL-1.2",
+    "LAL-1.3",
+    "Latex2e",
+    "Latex2e-translated-notice",
+    "Leptonica",
+    "LGPL-2.0",
+    "LGPL-2.0+",
+    "LGPL-2.0-only",
+    "LGPL-2.0-or-later",
+    "LGPL-2.1",
+    "LGPL-2.1+",
+    "LGPL-2.1-only",
     "LGPL-2.1-or-later",
-    "OFL-1.0",
-    "APSL-1.1",
-    "MITNFA",
-    "CECILL-2.0",
-    "Crossword",
-    "Aladdin",
-    "Baekmuk",
-    "XFree86-1.1",
-    "GPL-1.0-or-later",
-    "CERN-OHL-W-2.0",
-    "CC-BY-SA-1.0",
-    "NTP",
-    "PHP-3.01",
-    "OCLC-2.0",
-    "CC-BY-3.0-DE",
-    "CC-BY-NC-2.5",
-    "Zlib",
-    "CATOSL-1.1",
+    "LGPL-3.0",
     "LGPL-3.0+",
-    "CAL-1.0",
-    "NPL-1.0",
-    "SMLNJ",
-    "GPL-2.0+",
-    "OLDAP-2.5",
-    "JasPer-2.0",
-    "GPL-2.0-or-later",
-    "BSD-2-Clause-Patent",
+    "LGPL-3.0-only",
+    "LGPL-3.0-or-later",
+    "LGPLLR",
+    "Libpng",
+    "libpng-2.0",
+    "libselinux-1.0",
+    "libtiff",
+    "libutil-David-Nugent",
+    "LiLiQ-P-1.1",
+    "LiLiQ-R-1.1",
+    "LiLiQ-Rplus-1.1",
+    "Linux-man-pages-1-para",
+    "Linux-man-pages-copyleft",
+    "Linux-man-pages-copyleft-2-para",
+    "Linux-man-pages-copyleft-var",
+    "Linux-OpenIB",
+    "LOOP",
+    "LPL-1.0",
+    "LPL-1.02",
+    "LPPL-1.0",
+    "LPPL-1.1",
+    "LPPL-1.2",
+    "LPPL-1.3a",
+    "LPPL-1.3c",
+    "LZMA-SDK-9.11-to-9.20",
+    "LZMA-SDK-9.22",
+    "MakeIndex",
+    "Martin-Birgmeier",
+    "metamail",
+    "Minpack",
+    "MirOS",
+    "MIT",
+    "MIT-0",
+    "MIT-advertising",
+    "MIT-CMU",
+    "MIT-enna",
+    "MIT-feh",
+    "MIT-Festival",
+    "MIT-Modern-Variant",
+    "MIT-open-group",
+    "MIT-Wu",
+    "MITNFA",
+    "Motosoto",
+    "mpi-permissive",
+    "mpich2",
+    "MPL-1.0",
+    "MPL-1.1",
+    "MPL-2.0",
+    "MPL-2.0-no-copyleft-exception",
+    "mplus",
+    "MS-LPL",
+    "MS-PL",
     "MS-RL",
-    "CUA-OPL-1.0",
-    "IPA",
+    "MTLL",
+    "MulanPSL-1.0",
+    "MulanPSL-2.0",
+    "Multics",
+    "Mup",
+    "NAIST-2003",
+    "NASA-1.3",
+    "Naumen",
+    "NBPL-1.0",
+    "NCGL-UK-2.0",
+    "NCSA",
+    "Net-SNMP",
+    "NetCDF",
+    "Newsletr",
+    "NGPL",
+    "NICTA-1.0",
+    "NIST-PD",
+    "NIST-PD-fallback",
+    "NIST-Software",
+    "NLOD-1.0",
+    "NLOD-2.0",
     "NLPL",
+    "Nokia",
+    "NOSL",
+    "Noweb",
+    "NPL-1.0",
+    "NPL-1.1",
+    "NPOSL-3.0",
+    "NRL",
+    "NTP",
+    "NTP-0",
+    "Nunit",
     "O-UDA-1.0",
-    "MIT-Modern-Variant",
-    "OLDAP-1.2",
-    "BSD-2-Clause-FreeBSD",
-    "Info-ZIP",
-    "CC-BY-NC-SA-2.0-FR",
-    "0BSD",
-    "Unicode-DFS-2016",
+    "OCCT-PL",
+    "OCLC-2.0",
+    "ODbL-1.0",
+    "ODC-By-1.0",
+    "OFFIS",
+    "OFL-1.0",
+    "OFL-1.0-no-RFN",
     "OFL-1.0-RFN",
-    "Intel",
-    "AFL-2.0",
-    "GL2PS",
-    "TAPR-OHL-1.0",
-    "Apache-1.0",
-    "MTLL",
-    "Motosoto",
+    "OFL-1.1",
+    "OFL-1.1-no-RFN",
+    "OFL-1.1-RFN",
+    "OGC-1.0",
+    "OGDL-Taiwan-1.0",
+    "OGL-Canada-2.0",
+    "OGL-UK-1.0",
+    "OGL-UK-2.0",
+    "OGL-UK-3.0",
+    "OGTSL",
+    "OLDAP-1.1",
+    "OLDAP-1.2",
+    "OLDAP-1.3",
+    "OLDAP-1.4",
+    "OLDAP-2.0",
+    "OLDAP-2.0.1",
+    "OLDAP-2.1",
+    "OLDAP-2.2",
+    "OLDAP-2.2.1",
+    "OLDAP-2.2.2",
+    "OLDAP-2.3",
+    "OLDAP-2.4",
+    "OLDAP-2.5",
+    "OLDAP-2.6",
+    "OLDAP-2.7",
+    "OLDAP-2.8",
+    "OLFL-1.3",
+    "OML",
+    "OpenPBS-2.3",
+    "OpenSSL",
+    "OPL-1.0",
+    "OPL-UK-3.0",
+    "OPUBL-1.0",
+    "OSET-PL-2.1",
+    "OSL-1.0",
+    "OSL-1.1",
+    "OSL-2.0",
+    "OSL-2.1",
+    "OSL-3.0",
+    "Parity-6.0.0",
+    "Parity-7.0.0",
+    "PDDL-1.0",
+    "PHP-3.0",
+    "PHP-3.01",
+    "Plexus",
+    "PolyForm-Noncommercial-1.0.0",
+    "PolyForm-Small-Business-1.0.0",
+    "PostgreSQL",
+    "PSF-2.0",
+    "psfrag",
+    "psutils",
+    "Python-2.0",
+    "Python-2.0.1",
+    "Qhull",
+    "QPL-1.0",
+    "QPL-1.0-INRIA-2004",
+    "Rdisc",
+    "RHeCos-1.1",
+    "RPL-1.1",
+    "RPL-1.5",
+    "RPSL-1.0",
     "RSA-MD",
-    "Community-Spec-1.0",
-    "ODC-By-1.0",
-    "zlib-acknowledgement",
-    "DL-DE-BY-2.0",
-    "VSL-1.0",
-    "LiLiQ-R-1.1",
-    "OPL-1.0",
-    "GPL-3.0+",
-    "MulanPSL-2.0",
-    "APSL-1.2",
-    "OGDL-Taiwan-1.0",
     "RSCPL",
-    "OGC-1.0",
-    "EFL-2.0",
-    "CAL-1.0-Combined-Work-Exception",
-    "MS-PL",
-    "Plexus",
+    "Ruby",
+    "SAX-PD",
+    "Saxpath",
+    "SCEA",
+    "SchemeReport",
+    "Sendmail",
     "Sendmail-8.23",
-    "Cube",
-    "JSON",
-    "EUPL-1.2",
-    "Adobe-Glyph",
-    "FreeImage",
-    "Watcom-1.0",
-    "Jam",
-    "Hippocratic-2.1",
-    "OLDAP-2.0.1",
-    "CC-BY-NC-SA-2.0",
-    "Nokia",
-    "OCCT-PL",
-    "ErlPL-1.1",
+    "SGI-B-1.0",
+    "SGI-B-1.1",
+    "SGI-B-2.0",
+    "SGP4",
+    "SHL-0.5",
+    "SHL-0.51",
+    "SimPL-2.0",
+    "SISSL",
+    "SISSL-1.2",
+    "Sleepycat",
+    "SMLNJ",
+    "SMPPL",
+    "SNIA",
+    "snprintf",
+    "Spencer-86",
+    "Spencer-94",
+    "Spencer-99",
+    "SPL-1.0",
+    "SSH-OpenSSH",
+    "SSH-short",
+    "SSPL-1.0",
+    "StandardML-NJ",
+    "SugarCRM-1.1.3",
+    "SunPro",
+    "SWL",
+    "Symlinks",
+    "TAPR-OHL-1.0",
+    "TCL",
+    "TCP-wrappers",
+    "TermReadKey",
+    "TMate",
+    "TORQUE-1.1",
     "TOSL",
-    "OSL-2.1",
-    "ClArtistic",
+    "TPDL",
+    "TPL-1.0",
+    "TTWL",
+    "TU-Berlin-1.0",
+    "TU-Berlin-2.0",
+    "UCAR",
+    "UCL-1.0",
+    "Unicode-DFS-2015",
+    "Unicode-DFS-2016",
+    "Unicode-TOU",
+    "UnixCrypt",
+    "Unlicense",
+    "UPL-1.0",
+    "Vim",
+    "VOSTROM",
+    "VSL-1.0",
+    "W3C",
+    "W3C-19980720",
+    "W3C-20150513",
+    "w3m",
+    "Watcom-1.0",
+    "Widget-Workshop",
+    "Wsuipa",
+    "WTFPL",
+    "wxWindows",
+    "X11",
+    "X11-distribute-modifications-variant",
+    "Xdebug-1.03",
+    "Xerox",
+    "Xfig",
+    "XFree86-1.1",
     "xinetd",
-    "GPL-3.0-with-GCC-exception",
-    "ODbL-1.0",
-    "MIT",
-    "LGPL-2.1+",
-    "LGPL-2.1-only",
-    "CrystalStacker",
-    "ECL-2.0",
-    "LPPL-1.0",
-    "iMatix",
-    "CC-BY-NC-ND-3.0-IGO",
-    "BSD-Source-Code",
-    "Parity-6.0.0",
-    "TCL",
-    "Arphic-1999",
-    "CC-BY-SA-3.0",
-    "Caldera",
-    "AGPL-1.0",
-    "IPL-1.0",
-    "LAL-1.3",
-    "EPICS",
-    "NGPL",
-    "DRL-1.0",
-    "BSD-2-Clause-NetBSD",
-    "ZPL-1.1",
-    "GD",
-    "LPPL-1.2",
-    "Dotseqn",
-    "Spencer-99",
-    "OLDAP-2.3",
+    "xlock",
+    "Xnet",
+    "xpp",
+    "XSkat",
+    "YPL-1.0",
     "YPL-1.1",
-    "Fair",
-    "Qhull",
-    "GFDL-1.1-no-invariants-or-later",
-    "CECILL-C",
-    "MulanPSL-1.0",
-    "OLDAP-1.1",
-    "OLDAP-2.1",
-    "LPL-1.02",
-    "UPL-1.0",
-    "Abstyles",
+    "Zed",
+    "Zend-2.0",
+    "Zimbra-1.3",
+    "Zimbra-1.4",
+    "Zlib",
+    "zlib-acknowledgement",
+    "ZPL-1.1",
     "ZPL-2.0",
-    "MIT-0",
-    "LGPL-2.0-only",
-    "GFDL-1.3-no-invariants-only",
-    "AGPL-3.0",
-    "EPL-2.0",
-    "AFL-3.0",
-    "CDLA-Permissive-1.0",
-    "Artistic-1.0",
-    "CC-BY-NC-ND-4.0",
-    "HTMLTIDY",
-    "Glide",
-    "FSFAP",
-    "LGPLLR",
-    "OGL-UK-3.0",
-    "GFDL-1.2",
-    "SSH-OpenSSH",
-    "GFDL-1.1-only",
-    "MIT-feh",
-    "MPL-1.0",
-    "PostgreSQL",
-    "OLDAP-2.2.2",
-    "SMPPL",
-    "OFL-1.1",
-    "Leptonica",
-    "CERN-OHL-1.1",
-    "BSD-3-Clause-No-Nuclear-Warranty",
-    "CC-BY-ND-2.5",
-    "CC-BY-1.0",
-    "GFDL-1.2-only",
-    "OPUBL-1.0",
-    "libselinux-1.0",
-    "BSD-3-Clause",
-    "ANTLR-PD-fallback",
-    "copyleft-next-0.3.1",
-    "GPL-1.0+",
-    "wxWindows",
-    "LGPL-3.0",
-    "LGPL-2.1",
-    "StandardML-NJ",
-    "BSD-4-Clause",
-    "GPL-2.0-with-bison-exception",
-    "Apache-2.0",
-    "Artistic-1.0-cl8",
-    "GPL-2.0",
-    "Intel-ACPI",
-    "BSL-1.0",
-    "Artistic-1.0-Perl",
-    "BSD-2-Clause-Views",
-    "Interbase-1.0",
-    "NPOSL-3.0",
-    "FLTK-exception",
-    "Bootloader-exception",
-    "WxWindows-exception-3.1",
-    "Linux-syscall-note",
-    "Qt-LGPL-exception-1.1",
-    "LLVM-exception",
-    "PS-or-PDF-font-exception-20170817",
-    "GCC-exception-3.1",
+    "ZPL-2.1",
+    "389-exception",
+    "Asterisk-exception",
+    "Autoconf-exception-2.0",
     "Autoconf-exception-3.0",
-    "LGPL-3.0-linking-exception",
-    "GCC-exception-2.0",
+    "Autoconf-exception-generic",
+    "Autoconf-exception-macro",
     "Bison-exception-2.2",
-    "openvpn-openssl-exception",
-    "Libtool-exception",
-    "Autoconf-exception-2.0",
+    "Bootloader-exception",
+    "Classpath-exception-2.0",
+    "CLISP-exception-2.0",
+    "cryptsetup-OpenSSL-exception",
+    "DigiRule-FOSS-exception",
+    "eCos-exception-2.0",
+    "Fawkes-Runtime-exception",
+    "FLTK-exception",
+    "Font-exception-2.0",
+    "freertos-exception-2.0",
+    "GCC-exception-2.0",
+    "GCC-exception-3.1",
+    "GNAT-exception",
+    "gnu-javamail-exception",
+    "GPL-3.0-interface-exception",
+    "GPL-3.0-linking-exception",
     "GPL-3.0-linking-source-exception",
     "GPL-CC-1.0",
-    "OCaml-LGPL-linking-exception",
-    "Universal-FOSS-exception-1.0",
+    "GStreamer-exception-2005",
+    "GStreamer-exception-2008",
     "i2p-gpl-java-exception",
-    "CLISP-exception-2.0",
+    "KiCad-libraries-exception",
+    "LGPL-3.0-linking-exception",
+    "libpri-OpenH323-exception",
+    "Libtool-exception",
+    "Linux-syscall-note",
+    "LLGPL",
+    "LLVM-exception",
+    "LZMA-exception",
+    "mif-exception",
+    "Nokia-Qt-exception-1.1",
+    "OCaml-LGPL-linking-exception",
     "OCCT-exception-1.0",
-    "Qwt-exception-1.0",
-    "gnu-javamail-exception",
-    "u-boot-exception-2.0",
-    "freertos-exception-2.0",
-    "Qt-GPL-exception-1.0",
     "OpenJDK-assembly-exception-1.0",
+    "openvpn-openssl-exception",
+    "PS-or-PDF-font-exception-20170817",
+    "QPL-1.0-INRIA-2004-exception",
+    "Qt-GPL-exception-1.0",
+    "Qt-LGPL-exception-1.1",
+    "Qwt-exception-1.0",
+    "SHL-2.0",
     "SHL-2.1",
-    "mif-exception",
-    "Fawkes-Runtime-exception",
+    "SWI-exception",
     "Swift-exception",
-    "GPL-3.0-linking-exception",
-    "SHL-2.0",
-    "Classpath-exception-2.0",
-    "LZMA-exception",
-    "Font-exception-2.0",
-    "Nokia-Qt-exception-1.1",
-    "DigiRule-FOSS-exception",
-    "eCos-exception-2.0",
-    "389-exception"
+    "u-boot-exception-2.0",
+    "Universal-FOSS-exception-1.0",
+    "vsftpd-openssl-exception",
+    "WxWindows-exception-3.1",
+    "x11vnc-openssl-exception"
   ]
-}
\ No newline at end of file
+}
diff --git a/cyclonedx/schema/spdx.xsd b/cyclonedx/schema/_res/spdx.SNAPSHOT.xsd
similarity index 86%
rename from cyclonedx/schema/spdx.xsd
rename to cyclonedx/schema/_res/spdx.SNAPSHOT.xsd
index 4fb43642d..5d086dbe1 100644
--- a/cyclonedx/schema/spdx.xsd
+++ b/cyclonedx/schema/_res/spdx.SNAPSHOT.xsd
@@ -2,239 +2,234 @@
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified"
            targetNamespace="http://cyclonedx.org/schema/spdx"
-           version="1.0-3.17">
+           version="1.0-3.21">
 
     <xs:simpleType name="licenseId">
         <xs:restriction base="xs:string">
             <!-- Licenses -->
-            <xs:enumeration value="CC-BY-NC-ND-2.0">
-                <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic</xs:documentation>
-                </xs:annotation>
-            </xs:enumeration>
-            <xs:enumeration value="SGI-B-2.0">
+            <xs:enumeration value="0BSD">
                 <xs:annotation>
-                    <xs:documentation>SGI Free Software License B v2.0</xs:documentation>
+                    <xs:documentation>BSD Zero Clause License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LPPL-1.3c">
+            <xs:enumeration value="AAL">
                 <xs:annotation>
-                    <xs:documentation>LaTeX Project Public License v1.3c</xs:documentation>
+                    <xs:documentation>Attribution Assurance License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NIST-PD-fallback">
+            <xs:enumeration value="Abstyles">
                 <xs:annotation>
-                    <xs:documentation>NIST Public Domain Notice with license fallback</xs:documentation>
+                    <xs:documentation>Abstyles License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="libtiff">
+            <xs:enumeration value="AdaCore-doc">
                 <xs:annotation>
-                    <xs:documentation>libtiff License</xs:documentation>
+                    <xs:documentation>AdaCore Doc License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="XSkat">
+            <xs:enumeration value="Adobe-2006">
                 <xs:annotation>
-                    <xs:documentation>XSkat License</xs:documentation>
+                    <xs:documentation>Adobe Systems Incorporated Source Code License Agreement</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="PDDL-1.0">
+            <xs:enumeration value="Adobe-Glyph">
                 <xs:annotation>
-                    <xs:documentation>Open Data Commons Public Domain Dedication &amp; License 1.0</xs:documentation>
+                    <xs:documentation>Adobe Glyph List License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="KiCad-libraries-exception">
+            <xs:enumeration value="ADSL">
                 <xs:annotation>
-                    <xs:documentation>KiCad Libraries Exception</xs:documentation>
+                    <xs:documentation>Amazon Digital Services License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-1.0">
+            <xs:enumeration value="AFL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 1.0 Generic</xs:documentation>
+                    <xs:documentation>Academic Free License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.1-no-invariants-only">
+            <xs:enumeration value="AFL-1.2">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.1 only - no invariants</xs:documentation>
+                    <xs:documentation>Academic Free License v1.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Xerox">
+            <xs:enumeration value="AFL-2.0">
                 <xs:annotation>
-                    <xs:documentation>Xerox License</xs:documentation>
+                    <xs:documentation>Academic Free License v2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LPPL-1.1">
+            <xs:enumeration value="AFL-2.1">
                 <xs:annotation>
-                    <xs:documentation>LaTeX Project Public License v1.1</xs:documentation>
+                    <xs:documentation>Academic Free License v2.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="VOSTROM">
+            <xs:enumeration value="AFL-3.0">
                 <xs:annotation>
-                    <xs:documentation>VOSTROM Public License for Open Source</xs:documentation>
+                    <xs:documentation>Academic Free License v3.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="UCL-1.0">
+            <xs:enumeration value="Afmparse">
                 <xs:annotation>
-                    <xs:documentation>Upstream Compatibility License v1.0</xs:documentation>
+                    <xs:documentation>Afmparse License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ADSL">
+            <xs:enumeration value="AGPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Amazon Digital Services License</xs:documentation>
+                    <xs:documentation>Affero General Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OSL-2.0">
+            <xs:enumeration value="AGPL-1.0-only">
                 <xs:annotation>
-                    <xs:documentation>Open Software License 2.0</xs:documentation>
+                    <xs:documentation>Affero General Public License v1.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AAL">
+            <xs:enumeration value="AGPL-1.0-or-later">
                 <xs:annotation>
-                    <xs:documentation>Attribution Assurance License</xs:documentation>
+                    <xs:documentation>Affero General Public License v1.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="FDK-AAC">
+            <xs:enumeration value="AGPL-3.0">
                 <xs:annotation>
-                    <xs:documentation>Fraunhofer FDK AAC Codec Library</xs:documentation>
+                    <xs:documentation>GNU Affero General Public License v3.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="W3C-20150513">
+            <xs:enumeration value="AGPL-3.0-only">
                 <xs:annotation>
-                    <xs:documentation>W3C Software Notice and Document License (2015-05-13)</xs:documentation>
+                    <xs:documentation>GNU Affero General Public License v3.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AFL-1.1">
+            <xs:enumeration value="AGPL-3.0-or-later">
                 <xs:annotation>
-                    <xs:documentation>Academic Free License v1.1</xs:documentation>
+                    <xs:documentation>GNU Affero General Public License v3.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="W3C">
+            <xs:enumeration value="Aladdin">
                 <xs:annotation>
-                    <xs:documentation>W3C Software Notice and License (2002-12-31)</xs:documentation>
+                    <xs:documentation>Aladdin Free Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Sleepycat">
+            <xs:enumeration value="AMDPLPA">
                 <xs:annotation>
-                    <xs:documentation>Sleepycat License</xs:documentation>
+                    <xs:documentation>AMD&apos;s plpa_map.c License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CECILL-1.1">
+            <xs:enumeration value="AML">
                 <xs:annotation>
-                    <xs:documentation>CeCILL Free Software License Agreement v1.1</xs:documentation>
+                    <xs:documentation>Apple MIT License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="mpich2">
+            <xs:enumeration value="AMPAS">
                 <xs:annotation>
-                    <xs:documentation>mpich2 License</xs:documentation>
+                    <xs:documentation>Academy of Motion Picture Arts and Sciences BSD</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SISSL">
+            <xs:enumeration value="ANTLR-PD">
                 <xs:annotation>
-                    <xs:documentation>Sun Industry Standards Source License v1.1</xs:documentation>
+                    <xs:documentation>ANTLR Software Rights Notice</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NLOD-1.0">
+            <xs:enumeration value="ANTLR-PD-fallback">
                 <xs:annotation>
-                    <xs:documentation>Norwegian Licence for Open Government Data (NLOD) 1.0</xs:documentation>
+                    <xs:documentation>ANTLR Software Rights Notice with license fallback</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ANTLR-PD">
+            <xs:enumeration value="Apache-1.0">
                 <xs:annotation>
-                    <xs:documentation>ANTLR Software Rights Notice</xs:documentation>
+                    <xs:documentation>Apache License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-3.0-only">
+            <xs:enumeration value="Apache-1.1">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v3.0 only</xs:documentation>
+                    <xs:documentation>Apache License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="gnuplot">
+            <xs:enumeration value="Apache-2.0">
                 <xs:annotation>
-                    <xs:documentation>gnuplot License</xs:documentation>
+                    <xs:documentation>Apache License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NLOD-2.0">
+            <xs:enumeration value="APAFML">
                 <xs:annotation>
-                    <xs:documentation>Norwegian Licence for Open Government Data (NLOD) 2.0</xs:documentation>
+                    <xs:documentation>Adobe Postscript AFM License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-Open-MPI">
+            <xs:enumeration value="APL-1.0">
                 <xs:annotation>
-                    <xs:documentation>BSD 3-Clause Open MPI variant</xs:documentation>
+                    <xs:documentation>Adaptive Public License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LiLiQ-P-1.1">
+            <xs:enumeration value="App-s2p">
                 <xs:annotation>
-                    <xs:documentation>Licence Libre du Québec – Permissive version 1.1</xs:documentation>
+                    <xs:documentation>App::s2p License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-Clear">
+            <xs:enumeration value="APSL-1.0">
                 <xs:annotation>
-                    <xs:documentation>BSD 3-Clause Clear License</xs:documentation>
+                    <xs:documentation>Apple Public Source License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="FSFUL">
+            <xs:enumeration value="APSL-1.1">
                 <xs:annotation>
-                    <xs:documentation>FSF Unlimited License</xs:documentation>
+                    <xs:documentation>Apple Public Source License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-2.0-UK">
+            <xs:enumeration value="APSL-1.2">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 2.0 England and Wales</xs:documentation>
+                    <xs:documentation>Apple Public Source License 1.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CERN-OHL-S-2.0">
+            <xs:enumeration value="APSL-2.0">
                 <xs:annotation>
-                    <xs:documentation>CERN Open Hardware Licence Version 2 - Strongly Reciprocal</xs:documentation>
+                    <xs:documentation>Apple Public Source License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Spencer-94">
+            <xs:enumeration value="Arphic-1999">
                 <xs:annotation>
-                    <xs:documentation>Spencer License 94</xs:documentation>
+                    <xs:documentation>Arphic Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CERN-OHL-1.2">
+            <xs:enumeration value="Artistic-1.0">
                 <xs:annotation>
-                    <xs:documentation>CERN Open Hardware Licence v1.2</xs:documentation>
+                    <xs:documentation>Artistic License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.1-or-later">
+            <xs:enumeration value="Artistic-1.0-cl8">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.1 or later</xs:documentation>
+                    <xs:documentation>Artistic License 1.0 w/clause 8</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AGPL-1.0-or-later">
+            <xs:enumeration value="Artistic-1.0-Perl">
                 <xs:annotation>
-                    <xs:documentation>Affero General Public License v1.0 or later</xs:documentation>
+                    <xs:documentation>Artistic License 1.0 (Perl)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Wsuipa">
+            <xs:enumeration value="Artistic-2.0">
                 <xs:annotation>
-                    <xs:documentation>Wsuipa License</xs:documentation>
+                    <xs:documentation>Artistic License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AML">
+            <xs:enumeration value="ASWF-Digital-Assets-1.0">
                 <xs:annotation>
-                    <xs:documentation>Apple MIT License</xs:documentation>
+                    <xs:documentation>ASWF Digital Assets License version 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-2-Clause">
+            <xs:enumeration value="ASWF-Digital-Assets-1.1">
                 <xs:annotation>
-                    <xs:documentation>BSD 2-Clause &quot;Simplified&quot; License</xs:documentation>
+                    <xs:documentation>ASWF Digital Assets License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="DSDP">
+            <xs:enumeration value="Baekmuk">
                 <xs:annotation>
-                    <xs:documentation>DSDP License</xs:documentation>
+                    <xs:documentation>Baekmuk License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-2.5">
+            <xs:enumeration value="Bahyph">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 2.5 Generic</xs:documentation>
+                    <xs:documentation>Bahyph License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MIT-CMU">
+            <xs:enumeration value="Barr">
                 <xs:annotation>
-                    <xs:documentation>CMU License</xs:documentation>
+                    <xs:documentation>Barr License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
             <xs:enumeration value="Beerware">
@@ -242,284 +237,289 @@
                     <xs:documentation>Beerware License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Sendmail">
+            <xs:enumeration value="Bitstream-Charter">
                 <xs:annotation>
-                    <xs:documentation>Sendmail License</xs:documentation>
+                    <xs:documentation>Bitstream Charter Font License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="TU-Berlin-1.0">
+            <xs:enumeration value="Bitstream-Vera">
                 <xs:annotation>
-                    <xs:documentation>Technische Universitaet Berlin License 1.0</xs:documentation>
+                    <xs:documentation>Bitstream Vera Font License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CNRI-Jython">
+            <xs:enumeration value="BitTorrent-1.0">
                 <xs:annotation>
-                    <xs:documentation>CNRI Jython License</xs:documentation>
+                    <xs:documentation>BitTorrent Open Source License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="mplus">
+            <xs:enumeration value="BitTorrent-1.1">
                 <xs:annotation>
-                    <xs:documentation>mplus Font License</xs:documentation>
+                    <xs:documentation>BitTorrent Open Source License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CPOL-1.02">
+            <xs:enumeration value="blessing">
                 <xs:annotation>
-                    <xs:documentation>Code Project Open License 1.02</xs:documentation>
+                    <xs:documentation>SQLite Blessing</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-No-Nuclear-License-2014">
+            <xs:enumeration value="BlueOak-1.0.0">
                 <xs:annotation>
-                    <xs:documentation>BSD 3-Clause No Nuclear License 2014</xs:documentation>
+                    <xs:documentation>Blue Oak Model License 1.0.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ISC">
+            <xs:enumeration value="Boehm-GC">
                 <xs:annotation>
-                    <xs:documentation>ISC License</xs:documentation>
+                    <xs:documentation>Boehm-Demers-Weiser GC License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-4.0">
+            <xs:enumeration value="Borceux">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 4.0 International</xs:documentation>
+                    <xs:documentation>Borceux license</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Eurosym">
+            <xs:enumeration value="Brian-Gladman-3-Clause">
                 <xs:annotation>
-                    <xs:documentation>Eurosym License</xs:documentation>
+                    <xs:documentation>Brian Gladman 3-Clause License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-3.0-only">
+            <xs:enumeration value="BSD-1-Clause">
                 <xs:annotation>
-                    <xs:documentation>GNU Lesser General Public License v3.0 only</xs:documentation>
+                    <xs:documentation>BSD 1-Clause License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-1.3">
+            <xs:enumeration value="BSD-2-Clause">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v1.3</xs:documentation>
+                    <xs:documentation>BSD 2-Clause &quot;Simplified&quot; License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.1-invariants-or-later">
+            <xs:enumeration value="BSD-2-Clause-FreeBSD">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.1 or later - invariants</xs:documentation>
+                    <xs:documentation>BSD 2-Clause FreeBSD License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Glulxe">
+            <xs:enumeration value="BSD-2-Clause-NetBSD">
                 <xs:annotation>
-                    <xs:documentation>Glulxe License</xs:documentation>
+                    <xs:documentation>BSD 2-Clause NetBSD License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SimPL-2.0">
+            <xs:enumeration value="BSD-2-Clause-Patent">
                 <xs:annotation>
-                    <xs:documentation>Simple Public License 2.0</xs:documentation>
+                    <xs:documentation>BSD-2-Clause Plus Patent License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CDLA-Permissive-2.0">
+            <xs:enumeration value="BSD-2-Clause-Views">
                 <xs:annotation>
-                    <xs:documentation>Community Data License Agreement Permissive 2.0</xs:documentation>
+                    <xs:documentation>BSD 2-Clause with views sentence</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0-with-font-exception">
+            <xs:enumeration value="BSD-3-Clause">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 w/Font exception</xs:documentation>
+                    <xs:documentation>BSD 3-Clause &quot;New&quot; or &quot;Revised&quot; License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OGL-UK-2.0">
+            <xs:enumeration value="BSD-3-Clause-Attribution">
                 <xs:annotation>
-                    <xs:documentation>Open Government Licence v2.0</xs:documentation>
+                    <xs:documentation>BSD with attribution</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-3.0-DE">
+            <xs:enumeration value="BSD-3-Clause-Clear">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 3.0 Germany</xs:documentation>
+                    <xs:documentation>BSD 3-Clause Clear License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-ND-1.0">
+            <xs:enumeration value="BSD-3-Clause-LBNL">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution No Derivatives 1.0 Generic</xs:documentation>
+                    <xs:documentation>Lawrence Berkeley National Labs BSD variant license</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.1">
+            <xs:enumeration value="BSD-3-Clause-Modification">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.1</xs:documentation>
+                    <xs:documentation>BSD 3-Clause Modification</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-4.0">
+            <xs:enumeration value="BSD-3-Clause-No-Military-License">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 4.0 International</xs:documentation>
+                    <xs:documentation>BSD 3-Clause No Military License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OpenSSL">
+            <xs:enumeration value="BSD-3-Clause-No-Nuclear-License">
                 <xs:annotation>
-                    <xs:documentation>OpenSSL License</xs:documentation>
+                    <xs:documentation>BSD 3-Clause No Nuclear License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="TU-Berlin-2.0">
+            <xs:enumeration value="BSD-3-Clause-No-Nuclear-License-2014">
                 <xs:annotation>
-                    <xs:documentation>Technische Universitaet Berlin License 2.0</xs:documentation>
+                    <xs:documentation>BSD 3-Clause No Nuclear License 2014</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="DOC">
+            <xs:enumeration value="BSD-3-Clause-No-Nuclear-Warranty">
                 <xs:annotation>
-                    <xs:documentation>DOC License</xs:documentation>
+                    <xs:documentation>BSD 3-Clause No Nuclear Warranty</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.2-no-invariants-or-later">
+            <xs:enumeration value="BSD-3-Clause-Open-MPI">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.2 or later - no invariants</xs:documentation>
+                    <xs:documentation>BSD 3-Clause Open MPI variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="QPL-1.0">
+            <xs:enumeration value="BSD-4-Clause">
                 <xs:annotation>
-                    <xs:documentation>Q Public License 1.0</xs:documentation>
+                    <xs:documentation>BSD 4-Clause &quot;Original&quot; or &quot;Old&quot; License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.8">
+            <xs:enumeration value="BSD-4-Clause-Shortened">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.8</xs:documentation>
+                    <xs:documentation>BSD 4 Clause Shortened</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OML">
+            <xs:enumeration value="BSD-4-Clause-UC">
                 <xs:annotation>
-                    <xs:documentation>Open Market License</xs:documentation>
+                    <xs:documentation>BSD-4-Clause (University of California-Specific)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.7">
+            <xs:enumeration value="BSD-4.3RENO">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.7</xs:documentation>
+                    <xs:documentation>BSD 4.3 RENO License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NIST-PD">
+            <xs:enumeration value="BSD-4.3TAHOE">
                 <xs:annotation>
-                    <xs:documentation>NIST Public Domain Notice</xs:documentation>
+                    <xs:documentation>BSD 4.3 TAHOE License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Bitstream-Vera">
+            <xs:enumeration value="BSD-Advertising-Acknowledgement">
                 <xs:annotation>
-                    <xs:documentation>Bitstream Vera Font License</xs:documentation>
+                    <xs:documentation>BSD Advertising Acknowledgement License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.2-or-later">
+            <xs:enumeration value="BSD-Attribution-HPND-disclaimer">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.2 or later</xs:documentation>
+                    <xs:documentation>BSD with Attribution and HPND disclaimer</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OFL-1.1-RFN">
+            <xs:enumeration value="BSD-Protection">
                 <xs:annotation>
-                    <xs:documentation>SIL Open Font License 1.1 with Reserved Font Name</xs:documentation>
+                    <xs:documentation>BSD Protection License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Bahyph">
+            <xs:enumeration value="BSD-Source-Code">
                 <xs:annotation>
-                    <xs:documentation>Bahyph License</xs:documentation>
+                    <xs:documentation>BSD Source Code Attribution</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Barr">
+            <xs:enumeration value="BSL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Barr License</xs:documentation>
+                    <xs:documentation>Boost Software License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="COIL-1.0">
+            <xs:enumeration value="BUSL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Copyfree Open Innovation License</xs:documentation>
+                    <xs:documentation>Business Source License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.3">
+            <xs:enumeration value="bzip2-1.0.5">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.3</xs:documentation>
+                    <xs:documentation>bzip2 and libbzip2 License v1.0.5</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CECILL-B">
+            <xs:enumeration value="bzip2-1.0.6">
                 <xs:annotation>
-                    <xs:documentation>CeCILL-B Free Software License Agreement</xs:documentation>
+                    <xs:documentation>bzip2 and libbzip2 License v1.0.6</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="JPNIC">
+            <xs:enumeration value="C-UDA-1.0">
                 <xs:annotation>
-                    <xs:documentation>Japan Network Information Center License</xs:documentation>
+                    <xs:documentation>Computational Use of Data Agreement v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Zed">
+            <xs:enumeration value="CAL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Zed License</xs:documentation>
+                    <xs:documentation>Cryptographic Autonomy License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ICU">
+            <xs:enumeration value="CAL-1.0-Combined-Work-Exception">
                 <xs:annotation>
-                    <xs:documentation>ICU License</xs:documentation>
+                    <xs:documentation>Cryptographic Autonomy License 1.0 (Combined Work Exception)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-2.5">
+            <xs:enumeration value="Caldera">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 2.5 Generic</xs:documentation>
+                    <xs:documentation>Caldera License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-ND-3.0-DE">
+            <xs:enumeration value="CATOSL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution No Derivatives 3.0 Germany</xs:documentation>
+                    <xs:documentation>Computer Associates Trusted Open Source License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="bzip2-1.0.5">
+            <xs:enumeration value="CC-BY-1.0">
                 <xs:annotation>
-                    <xs:documentation>bzip2 and libbzip2 License v1.0.5</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 1.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SPL-1.0">
+            <xs:enumeration value="CC-BY-2.0">
                 <xs:annotation>
-                    <xs:documentation>Sun Public License v1.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 2.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="YPL-1.0">
+            <xs:enumeration value="CC-BY-2.5">
                 <xs:annotation>
-                    <xs:documentation>Yahoo! Public License v1.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 2.5 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OSET-PL-2.1">
+            <xs:enumeration value="CC-BY-2.5-AU">
                 <xs:annotation>
-                    <xs:documentation>OSET Public License version 2.1</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 2.5 Australia</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Noweb">
+            <xs:enumeration value="CC-BY-3.0">
                 <xs:annotation>
-                    <xs:documentation>Noweb License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 3.0 Unported</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="RPSL-1.0">
+            <xs:enumeration value="CC-BY-3.0-AT">
                 <xs:annotation>
-                    <xs:documentation>RealNetworks Public Source License v1.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 3.0 Austria</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-LBNL">
+            <xs:enumeration value="CC-BY-3.0-DE">
                 <xs:annotation>
-                    <xs:documentation>Lawrence Berkeley National Labs BSD variant license</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 3.0 Germany</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CDLA-Sharing-1.0">
+            <xs:enumeration value="CC-BY-3.0-IGO">
                 <xs:annotation>
-                    <xs:documentation>Community Data License Agreement Sharing 1.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 3.0 IGO</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CECILL-1.0">
+            <xs:enumeration value="CC-BY-3.0-NL">
                 <xs:annotation>
-                    <xs:documentation>CeCILL Free Software License Agreement v1.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 3.0 Netherlands</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AMPAS">
+            <xs:enumeration value="CC-BY-3.0-US">
                 <xs:annotation>
-                    <xs:documentation>Academy of Motion Picture Arts and Sciences BSD</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 3.0 United States</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="APAFML">
+            <xs:enumeration value="CC-BY-4.0">
                 <xs:annotation>
-                    <xs:documentation>Adobe Postscript AFM License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution 4.0 International</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-ND-3.0">
+            <xs:enumeration value="CC-BY-NC-1.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution No Derivatives 3.0 Unported</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial 1.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="D-FSL-1.0">
+            <xs:enumeration value="CC-BY-NC-2.0">
                 <xs:annotation>
-                    <xs:documentation>Deutsche Freie Software Lizenz</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial 2.0 Generic</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CC-BY-NC-2.5">
+                <xs:annotation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial 2.5 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
             <xs:enumeration value="CC-BY-NC-3.0">
@@ -527,294 +527,679 @@
                     <xs:documentation>Creative Commons Attribution Non Commercial 3.0 Unported</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="libpng-2.0">
+            <xs:enumeration value="CC-BY-NC-3.0-DE">
                 <xs:annotation>
-                    <xs:documentation>PNG Reference Library version 2</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial 3.0 Germany</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="PolyForm-Noncommercial-1.0.0">
+            <xs:enumeration value="CC-BY-NC-4.0">
                 <xs:annotation>
-                    <xs:documentation>PolyForm Noncommercial License 1.0.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial 4.0 International</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="dvipdfm">
+            <xs:enumeration value="CC-BY-NC-ND-1.0">
                 <xs:annotation>
-                    <xs:documentation>dvipdfm License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.3-or-later">
+            <xs:enumeration value="CC-BY-NC-ND-2.0">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.3 or later</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OGTSL">
+            <xs:enumeration value="CC-BY-NC-ND-2.5">
                 <xs:annotation>
-                    <xs:documentation>Open Group Test Suite License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NPL-1.1">
+            <xs:enumeration value="CC-BY-NC-ND-3.0">
                 <xs:annotation>
-                    <xs:documentation>Netscape Public License v1.1</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-3.0">
+            <xs:enumeration value="CC-BY-NC-ND-3.0-DE">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v3.0 only</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 3.0 Germany</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CERN-OHL-P-2.0">
+            <xs:enumeration value="CC-BY-NC-ND-3.0-IGO">
                 <xs:annotation>
-                    <xs:documentation>CERN Open Hardware Licence Version 2 - Permissive</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BlueOak-1.0.0">
+            <xs:enumeration value="CC-BY-NC-ND-4.0">
                 <xs:annotation>
-                    <xs:documentation>Blue Oak Model License 1.0.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 4.0 International</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AGPL-3.0-or-later">
+            <xs:enumeration value="CC-BY-NC-SA-1.0">
                 <xs:annotation>
-                    <xs:documentation>GNU Affero General Public License v3.0 or later</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 1.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="blessing">
+            <xs:enumeration value="CC-BY-NC-SA-2.0">
                 <xs:annotation>
-                    <xs:documentation>SQLite Blessing</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 2.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ImageMagick">
+            <xs:enumeration value="CC-BY-NC-SA-2.0-DE">
                 <xs:annotation>
-                    <xs:documentation>ImageMagick License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 2.0 Germany</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="APSL-2.0">
+            <xs:enumeration value="CC-BY-NC-SA-2.0-FR">
                 <xs:annotation>
-                    <xs:documentation>Apple Public Source License 2.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution-NonCommercial-ShareAlike 2.0 France</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MIT-advertising">
+            <xs:enumeration value="CC-BY-NC-SA-2.0-UK">
                 <xs:annotation>
-                    <xs:documentation>Enlightenment License (e16)</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 2.0 England and Wales</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="curl">
+            <xs:enumeration value="CC-BY-NC-SA-2.5">
                 <xs:annotation>
-                    <xs:documentation>curl License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 2.5 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC0-1.0">
+            <xs:enumeration value="CC-BY-NC-SA-3.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Zero v1.0 Universal</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 3.0 Unported</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Zimbra-1.4">
+            <xs:enumeration value="CC-BY-NC-SA-3.0-DE">
                 <xs:annotation>
-                    <xs:documentation>Zimbra Public License v1.4</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 3.0 Germany</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SSPL-1.0">
+            <xs:enumeration value="CC-BY-NC-SA-3.0-IGO">
                 <xs:annotation>
-                    <xs:documentation>Server Side Public License, v 1</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 3.0 IGO</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="psutils">
+            <xs:enumeration value="CC-BY-NC-SA-4.0">
                 <xs:annotation>
-                    <xs:documentation>psutils License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 4.0 International</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-2.0-UK">
+            <xs:enumeration value="CC-BY-ND-1.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 2.0 England and Wales</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution No Derivatives 1.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="PSF-2.0">
+            <xs:enumeration value="CC-BY-ND-2.0">
                 <xs:annotation>
-                    <xs:documentation>Python Software Foundation License 2.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution No Derivatives 2.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Net-SNMP">
+            <xs:enumeration value="CC-BY-ND-2.5">
                 <xs:annotation>
-                    <xs:documentation>Net-SNMP License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution No Derivatives 2.5 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NAIST-2003">
+            <xs:enumeration value="CC-BY-ND-3.0">
                 <xs:annotation>
-                    <xs:documentation>Nara Institute of Science and Technology License (2003)</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution No Derivatives 3.0 Unported</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.2-invariants-or-later">
+            <xs:enumeration value="CC-BY-ND-3.0-DE">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.2 or later - invariants</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution No Derivatives 3.0 Germany</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SGI-B-1.0">
+            <xs:enumeration value="CC-BY-ND-4.0">
                 <xs:annotation>
-                    <xs:documentation>SGI Free Software License B v1.0</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution No Derivatives 4.0 International</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NBPL-1.0">
+            <xs:enumeration value="CC-BY-SA-1.0">
                 <xs:annotation>
-                    <xs:documentation>Net Boolean Public License v1</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 1.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.2-invariants-only">
+            <xs:enumeration value="CC-BY-SA-2.0">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.2 only - invariants</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 2.0 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="W3C-19980720">
+            <xs:enumeration value="CC-BY-SA-2.0-UK">
                 <xs:annotation>
-                    <xs:documentation>W3C Software Notice and License (1998-07-20)</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 2.0 England and Wales</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OFL-1.0-no-RFN">
+            <xs:enumeration value="CC-BY-SA-2.1-JP">
                 <xs:annotation>
-                    <xs:documentation>SIL Open Font License 1.0 with no Reserved Font Name</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 2.1 Japan</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NetCDF">
+            <xs:enumeration value="CC-BY-SA-2.5">
                 <xs:annotation>
-                    <xs:documentation>NetCDF license</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 2.5 Generic</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="TMate">
+            <xs:enumeration value="CC-BY-SA-3.0">
                 <xs:annotation>
-                    <xs:documentation>TMate Open Source License</xs:documentation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 3.0 Unported</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CC-BY-SA-3.0-AT">
+                <xs:annotation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 3.0 Austria</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CC-BY-SA-3.0-DE">
+                <xs:annotation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 3.0 Germany</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CC-BY-SA-3.0-IGO">
+                <xs:annotation>
+                    <xs:documentation>Creative Commons Attribution-ShareAlike 3.0 IGO</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CC-BY-SA-4.0">
+                <xs:annotation>
+                    <xs:documentation>Creative Commons Attribution Share Alike 4.0 International</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CC-PDDC">
+                <xs:annotation>
+                    <xs:documentation>Creative Commons Public Domain Dedication and Certification</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CC0-1.0">
+                <xs:annotation>
+                    <xs:documentation>Creative Commons Zero v1.0 Universal</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CDDL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Common Development and Distribution License 1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CDDL-1.1">
+                <xs:annotation>
+                    <xs:documentation>Common Development and Distribution License 1.1</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CDL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Common Documentation License 1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CDLA-Permissive-1.0">
+                <xs:annotation>
+                    <xs:documentation>Community Data License Agreement Permissive 1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CDLA-Permissive-2.0">
+                <xs:annotation>
+                    <xs:documentation>Community Data License Agreement Permissive 2.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CDLA-Sharing-1.0">
+                <xs:annotation>
+                    <xs:documentation>Community Data License Agreement Sharing 1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CECILL-1.0">
+                <xs:annotation>
+                    <xs:documentation>CeCILL Free Software License Agreement v1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CECILL-1.1">
+                <xs:annotation>
+                    <xs:documentation>CeCILL Free Software License Agreement v1.1</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CECILL-2.0">
+                <xs:annotation>
+                    <xs:documentation>CeCILL Free Software License Agreement v2.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CECILL-2.1">
+                <xs:annotation>
+                    <xs:documentation>CeCILL Free Software License Agreement v2.1</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CECILL-B">
+                <xs:annotation>
+                    <xs:documentation>CeCILL-B Free Software License Agreement</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CECILL-C">
+                <xs:annotation>
+                    <xs:documentation>CeCILL-C Free Software License Agreement</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CERN-OHL-1.1">
+                <xs:annotation>
+                    <xs:documentation>CERN Open Hardware Licence v1.1</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CERN-OHL-1.2">
+                <xs:annotation>
+                    <xs:documentation>CERN Open Hardware Licence v1.2</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CERN-OHL-P-2.0">
+                <xs:annotation>
+                    <xs:documentation>CERN Open Hardware Licence Version 2 - Permissive</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CERN-OHL-S-2.0">
+                <xs:annotation>
+                    <xs:documentation>CERN Open Hardware Licence Version 2 - Strongly Reciprocal</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CERN-OHL-W-2.0">
+                <xs:annotation>
+                    <xs:documentation>CERN Open Hardware Licence Version 2 - Weakly Reciprocal</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CFITSIO">
+                <xs:annotation>
+                    <xs:documentation>CFITSIO License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="checkmk">
+                <xs:annotation>
+                    <xs:documentation>Checkmk License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="ClArtistic">
+                <xs:annotation>
+                    <xs:documentation>Clarified Artistic License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Clips">
+                <xs:annotation>
+                    <xs:documentation>Clips License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CMU-Mach">
+                <xs:annotation>
+                    <xs:documentation>CMU Mach License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CNRI-Jython">
+                <xs:annotation>
+                    <xs:documentation>CNRI Jython License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CNRI-Python">
+                <xs:annotation>
+                    <xs:documentation>CNRI Python License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CNRI-Python-GPL-Compatible">
+                <xs:annotation>
+                    <xs:documentation>CNRI Python Open Source GPL Compatible License Agreement</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="COIL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Copyfree Open Innovation License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Community-Spec-1.0">
+                <xs:annotation>
+                    <xs:documentation>Community Specification License 1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Condor-1.1">
+                <xs:annotation>
+                    <xs:documentation>Condor Public License v1.1</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="copyleft-next-0.3.0">
+                <xs:annotation>
+                    <xs:documentation>copyleft-next 0.3.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="copyleft-next-0.3.1">
+                <xs:annotation>
+                    <xs:documentation>copyleft-next 0.3.1</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Cornell-Lossless-JPEG">
+                <xs:annotation>
+                    <xs:documentation>Cornell Lossless JPEG License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CPAL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Common Public Attribution License 1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CPL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Common Public License 1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CPOL-1.02">
+                <xs:annotation>
+                    <xs:documentation>Code Project Open License 1.02</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Crossword">
+                <xs:annotation>
+                    <xs:documentation>Crossword License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CrystalStacker">
+                <xs:annotation>
+                    <xs:documentation>CrystalStacker License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="CUA-OPL-1.0">
+                <xs:annotation>
+                    <xs:documentation>CUA Office Public License v1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Cube">
+                <xs:annotation>
+                    <xs:documentation>Cube License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="curl">
+                <xs:annotation>
+                    <xs:documentation>curl License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="D-FSL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Deutsche Freie Software Lizenz</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="diffmark">
+                <xs:annotation>
+                    <xs:documentation>diffmark license</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="DL-DE-BY-2.0">
+                <xs:annotation>
+                    <xs:documentation>Data licence Germany – attribution – version 2.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="DOC">
+                <xs:annotation>
+                    <xs:documentation>DOC License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Dotseqn">
+                <xs:annotation>
+                    <xs:documentation>Dotseqn License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="DRL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Detection Rule License 1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="DSDP">
+                <xs:annotation>
+                    <xs:documentation>DSDP License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="dtoa">
+                <xs:annotation>
+                    <xs:documentation>David M. Gay dtoa License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="dvipdfm">
+                <xs:annotation>
+                    <xs:documentation>dvipdfm License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="ECL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Educational Community License v1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="ECL-2.0">
+                <xs:annotation>
+                    <xs:documentation>Educational Community License v2.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="eCos-2.0">
+                <xs:annotation>
+                    <xs:documentation>eCos license version 2.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="EFL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Eiffel Forum License v1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="EFL-2.0">
+                <xs:annotation>
+                    <xs:documentation>Eiffel Forum License v2.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="eGenix">
+                <xs:annotation>
+                    <xs:documentation>eGenix.com Public License 1.1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Elastic-2.0">
+                <xs:annotation>
+                    <xs:documentation>Elastic License 2.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="Entessa">
+                <xs:annotation>
+                    <xs:documentation>Entessa Public License v1.0</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="EPICS">
+                <xs:annotation>
+                    <xs:documentation>EPICS Open License</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="EPL-1.0">
+                <xs:annotation>
+                    <xs:documentation>Eclipse Public License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NOSL">
+            <xs:enumeration value="EPL-2.0">
                 <xs:annotation>
-                    <xs:documentation>Netizen Open Source License</xs:documentation>
+                    <xs:documentation>Eclipse Public License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CNRI-Python-GPL-Compatible">
+            <xs:enumeration value="ErlPL-1.1">
                 <xs:annotation>
-                    <xs:documentation>CNRI Python Open Source GPL Compatible License Agreement</xs:documentation>
+                    <xs:documentation>Erlang Public License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-1-Clause">
+            <xs:enumeration value="etalab-2.0">
                 <xs:annotation>
-                    <xs:documentation>BSD 1-Clause License</xs:documentation>
+                    <xs:documentation>Etalab Open License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-3.0-DE">
+            <xs:enumeration value="EUDatagrid">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 3.0 Germany</xs:documentation>
+                    <xs:documentation>EU DataGrid Software License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-Modification">
+            <xs:enumeration value="EUPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>BSD 3-Clause Modification</xs:documentation>
+                    <xs:documentation>European Union Public License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GLWTPL">
+            <xs:enumeration value="EUPL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Good Luck With That Public License</xs:documentation>
+                    <xs:documentation>European Union Public License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.3-only">
+            <xs:enumeration value="EUPL-1.2">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.3 only</xs:documentation>
+                    <xs:documentation>European Union Public License 1.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.2">
+            <xs:enumeration value="Eurosym">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.2</xs:documentation>
+                    <xs:documentation>Eurosym License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-ND-4.0">
+            <xs:enumeration value="Fair">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution No Derivatives 4.0 International</xs:documentation>
+                    <xs:documentation>Fair License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-ND-3.0-DE">
+            <xs:enumeration value="FDK-AAC">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 3.0 Germany</xs:documentation>
+                    <xs:documentation>Fraunhofer FDK AAC Codec Library</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EUPL-1.0">
+            <xs:enumeration value="Frameworx-1.0">
                 <xs:annotation>
-                    <xs:documentation>European Union Public License 1.0</xs:documentation>
+                    <xs:documentation>Frameworx Open License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Linux-OpenIB">
+            <xs:enumeration value="FreeBSD-DOC">
                 <xs:annotation>
-                    <xs:documentation>Linux Kernel Variant of OpenIB.org license</xs:documentation>
+                    <xs:documentation>FreeBSD Documentation License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-2.0-or-later">
+            <xs:enumeration value="FreeImage">
                 <xs:annotation>
-                    <xs:documentation>GNU Library General Public License v2 or later</xs:documentation>
+                    <xs:documentation>FreeImage Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OSL-1.1">
+            <xs:enumeration value="FSFAP">
                 <xs:annotation>
-                    <xs:documentation>Open Software License 1.1</xs:documentation>
+                    <xs:documentation>FSF All Permissive License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Spencer-86">
+            <xs:enumeration value="FSFUL">
                 <xs:annotation>
-                    <xs:documentation>Spencer License 86</xs:documentation>
+                    <xs:documentation>FSF Unlimited License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-2.0">
+            <xs:enumeration value="FSFULLR">
                 <xs:annotation>
-                    <xs:documentation>GNU Library General Public License v2 only</xs:documentation>
+                    <xs:documentation>FSF Unlimited License (with License Retention)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-PDDC">
+            <xs:enumeration value="FSFULLRWD">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Public Domain Dedication and Certification</xs:documentation>
+                    <xs:documentation>FSF Unlimited License (With License Retention and Warranty Disclaimer)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-ND-3.0">
+            <xs:enumeration value="FTL">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported</xs:documentation>
+                    <xs:documentation>Freetype Project License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CDL-1.0">
+            <xs:enumeration value="GD">
                 <xs:annotation>
-                    <xs:documentation>Common Documentation License 1.0</xs:documentation>
+                    <xs:documentation>GD License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Elastic-2.0">
+            <xs:enumeration value="GFDL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Elastic License 2.0</xs:documentation>
+                    <xs:documentation>GNU Free Documentation License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-2.0">
+            <xs:enumeration value="GFDL-1.1-invariants-only">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 2.0 Generic</xs:documentation>
+                    <xs:documentation>GNU Free Documentation License v1.1 only - invariants</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-No-Military-License">
+            <xs:enumeration value="GFDL-1.1-invariants-or-later">
                 <xs:annotation>
-                    <xs:documentation>BSD 3-Clause No Military License</xs:documentation>
+                    <xs:documentation>GNU Free Documentation License v1.1 or later - invariants</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="IJG">
+            <xs:enumeration value="GFDL-1.1-no-invariants-only">
                 <xs:annotation>
-                    <xs:documentation>Independent JPEG Group License</xs:documentation>
+                    <xs:documentation>GNU Free Documentation License v1.1 only - no invariants</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LPPL-1.3a">
+            <xs:enumeration value="GFDL-1.1-no-invariants-or-later">
                 <xs:annotation>
-                    <xs:documentation>LaTeX Project Public License v1.3a</xs:documentation>
+                    <xs:documentation>GNU Free Documentation License v1.1 or later - no invariants</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SAX-PD">
+            <xs:enumeration value="GFDL-1.1-only">
                 <xs:annotation>
-                    <xs:documentation>Sax Public Domain Notice</xs:documentation>
+                    <xs:documentation>GNU Free Documentation License v1.1 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BitTorrent-1.0">
+            <xs:enumeration value="GFDL-1.1-or-later">
                 <xs:annotation>
-                    <xs:documentation>BitTorrent Open Source License v1.0</xs:documentation>
+                    <xs:documentation>GNU Free Documentation License v1.1 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.0">
+            <xs:enumeration value="GFDL-1.2">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)</xs:documentation>
+                    <xs:documentation>GNU Free Documentation License v1.2</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.2-invariants-only">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.2 only - invariants</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.2-invariants-or-later">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.2 or later - invariants</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.2-no-invariants-only">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.2 only - no invariants</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.2-no-invariants-or-later">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.2 or later - no invariants</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.2-only">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.2 only</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.2-or-later">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.2 or later</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.3">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.3</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.3-invariants-only">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.3 only - invariants</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.3-invariants-or-later">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.3 or later - invariants</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.3-no-invariants-only">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.3 only - no invariants</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.3-no-invariants-or-later">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.3 or later - no invariants</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.3-only">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.3 only</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GFDL-1.3-or-later">
+                <xs:annotation>
+                    <xs:documentation>GNU Free Documentation License v1.3 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
             <xs:enumeration value="Giftware">
@@ -822,284 +1207,304 @@
                     <xs:documentation>Giftware License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="C-UDA-1.0">
+            <xs:enumeration value="GL2PS">
                 <xs:annotation>
-                    <xs:documentation>Computational Use of Data Agreement v1.0</xs:documentation>
+                    <xs:documentation>GL2PS License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-2.0+">
+            <xs:enumeration value="Glide">
                 <xs:annotation>
-                    <xs:documentation>GNU Library General Public License v2 or later</xs:documentation>
+                    <xs:documentation>3dfx Glide License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Rdisc">
+            <xs:enumeration value="Glulxe">
                 <xs:annotation>
-                    <xs:documentation>Rdisc License</xs:documentation>
+                    <xs:documentation>Glulxe License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0-with-classpath-exception">
+            <xs:enumeration value="GLWTPL">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 w/Classpath exception</xs:documentation>
+                    <xs:documentation>Good Luck With That Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-3.0-US">
+            <xs:enumeration value="gnuplot">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 3.0 United States</xs:documentation>
+                    <xs:documentation>gnuplot License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CDDL-1.0">
+            <xs:enumeration value="GPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Common Development and Distribution License 1.0</xs:documentation>
+                    <xs:documentation>GNU General Public License v1.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Xnet">
+            <xs:enumeration value="GPL-1.0+">
                 <xs:annotation>
-                    <xs:documentation>X.Net License</xs:documentation>
+                    <xs:documentation>GNU General Public License v1.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CPL-1.0">
+            <xs:enumeration value="GPL-1.0-only">
                 <xs:annotation>
-                    <xs:documentation>Common Public License 1.0</xs:documentation>
+                    <xs:documentation>GNU General Public License v1.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-3.0-or-later">
+            <xs:enumeration value="GPL-1.0-or-later">
                 <xs:annotation>
-                    <xs:documentation>GNU Lesser General Public License v3.0 or later</xs:documentation>
+                    <xs:documentation>GNU General Public License v1.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NASA-1.3">
+            <xs:enumeration value="GPL-2.0">
                 <xs:annotation>
-                    <xs:documentation>NASA Open Source Agreement 1.3</xs:documentation>
+                    <xs:documentation>GNU General Public License v2.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BUSL-1.1">
+            <xs:enumeration value="GPL-2.0+">
                 <xs:annotation>
-                    <xs:documentation>Business Source License 1.1</xs:documentation>
+                    <xs:documentation>GNU General Public License v2.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="etalab-2.0">
+            <xs:enumeration value="GPL-2.0-only">
                 <xs:annotation>
-                    <xs:documentation>Etalab Open License 2.0</xs:documentation>
+                    <xs:documentation>GNU General Public License v2.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MIT-open-group">
+            <xs:enumeration value="GPL-2.0-or-later">
                 <xs:annotation>
-                    <xs:documentation>MIT Open Group variant</xs:documentation>
+                    <xs:documentation>GNU General Public License v2.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-1.4">
+            <xs:enumeration value="GPL-2.0-with-autoconf-exception">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v1.4</xs:documentation>
+                    <xs:documentation>GNU General Public License v2.0 w/Autoconf exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.1-invariants-only">
+            <xs:enumeration value="GPL-2.0-with-bison-exception">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.1 only - invariants</xs:documentation>
+                    <xs:documentation>GNU General Public License v2.0 w/Bison exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="RPL-1.1">
+            <xs:enumeration value="GPL-2.0-with-classpath-exception">
+                <xs:annotation>
+                    <xs:documentation>GNU General Public License v2.0 w/Classpath exception</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GPL-2.0-with-font-exception">
+                <xs:annotation>
+                    <xs:documentation>GNU General Public License v2.0 w/Font exception</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GPL-2.0-with-GCC-exception">
+                <xs:annotation>
+                    <xs:documentation>GNU General Public License v2.0 w/GCC Runtime Library exception</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GPL-3.0">
+                <xs:annotation>
+                    <xs:documentation>GNU General Public License v3.0 only</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="GPL-3.0+">
                 <xs:annotation>
-                    <xs:documentation>Reciprocal Public License 1.1</xs:documentation>
+                    <xs:documentation>GNU General Public License v3.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-ND-2.5">
+            <xs:enumeration value="GPL-3.0-only">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic</xs:documentation>
+                    <xs:documentation>GNU General Public License v3.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="FSFULLR">
+            <xs:enumeration value="GPL-3.0-or-later">
                 <xs:annotation>
-                    <xs:documentation>FSF Unlimited License (with License Retention)</xs:documentation>
+                    <xs:documentation>GNU General Public License v3.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Saxpath">
+            <xs:enumeration value="GPL-3.0-with-autoconf-exception">
                 <xs:annotation>
-                    <xs:documentation>Saxpath License</xs:documentation>
+                    <xs:documentation>GNU General Public License v3.0 w/Autoconf exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NTP-0">
+            <xs:enumeration value="GPL-3.0-with-GCC-exception">
                 <xs:annotation>
-                    <xs:documentation>NTP No Attribution</xs:documentation>
+                    <xs:documentation>GNU General Public License v3.0 w/GCC Runtime Library exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SISSL-1.2">
+            <xs:enumeration value="Graphics-Gems">
                 <xs:annotation>
-                    <xs:documentation>Sun Industry Standards Source License v1.2</xs:documentation>
+                    <xs:documentation>Graphics Gems License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-3.0-or-later">
+            <xs:enumeration value="gSOAP-1.3b">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v3.0 or later</xs:documentation>
+                    <xs:documentation>gSOAP Public License v1.3b</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Apache-1.1">
+            <xs:enumeration value="HaskellReport">
                 <xs:annotation>
-                    <xs:documentation>Apache License 1.1</xs:documentation>
+                    <xs:documentation>Haskell Language Report License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-2.1-JP">
+            <xs:enumeration value="Hippocratic-2.1">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 2.1 Japan</xs:documentation>
+                    <xs:documentation>Hippocratic License 2.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AGPL-3.0-only">
+            <xs:enumeration value="HP-1986">
                 <xs:annotation>
-                    <xs:documentation>GNU Affero General Public License v3.0 only</xs:documentation>
+                    <xs:documentation>Hewlett-Packard 1986 License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0-with-autoconf-exception">
+            <xs:enumeration value="HPND">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 w/Autoconf exception</xs:documentation>
+                    <xs:documentation>Historical Permission Notice and Disclaimer</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Artistic-2.0">
+            <xs:enumeration value="HPND-export-US">
                 <xs:annotation>
-                    <xs:documentation>Artistic License 2.0</xs:documentation>
+                    <xs:documentation>HPND with US Government export control warning</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="App-s2p">
+            <xs:enumeration value="HPND-Markus-Kuhn">
                 <xs:annotation>
-                    <xs:documentation>App::s2p License</xs:documentation>
+                    <xs:documentation>Historical Permission Notice and Disclaimer - Markus Kuhn variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Unicode-DFS-2015">
+            <xs:enumeration value="HPND-sell-variant">
                 <xs:annotation>
-                    <xs:documentation>Unicode License Agreement - Data Files and Software (2015)</xs:documentation>
+                    <xs:documentation>Historical Permission Notice and Disclaimer - sell variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="diffmark">
+            <xs:enumeration value="HPND-sell-variant-MIT-disclaimer">
                 <xs:annotation>
-                    <xs:documentation>diffmark license</xs:documentation>
+                    <xs:documentation>HPND sell variant with MIT disclaimer</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SNIA">
+            <xs:enumeration value="HTMLTIDY">
                 <xs:annotation>
-                    <xs:documentation>SNIA Public License 1.1</xs:documentation>
+                    <xs:documentation>HTML Tidy License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-2.5">
+            <xs:enumeration value="IBM-pibs">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 2.5 Generic</xs:documentation>
+                    <xs:documentation>IBM PowerPC Initialization and Boot Software</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Linux-man-pages-copyleft">
+            <xs:enumeration value="ICU">
                 <xs:annotation>
-                    <xs:documentation>Linux man-pages Copyleft</xs:documentation>
+                    <xs:documentation>ICU License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="HPND-sell-variant">
+            <xs:enumeration value="IEC-Code-Components-EULA">
                 <xs:annotation>
-                    <xs:documentation>Historical Permission Notice and Disclaimer - sell variant</xs:documentation>
+                    <xs:documentation>IEC    Code Components End-user licence agreement</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ZPL-2.1">
+            <xs:enumeration value="IJG">
                 <xs:annotation>
-                    <xs:documentation>Zope Public License 2.1</xs:documentation>
+                    <xs:documentation>Independent JPEG Group License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-4-Clause-UC">
+            <xs:enumeration value="IJG-short">
                 <xs:annotation>
-                    <xs:documentation>BSD-4-Clause (University of California-Specific)</xs:documentation>
+                    <xs:documentation>Independent JPEG Group License - short</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LAL-1.2">
+            <xs:enumeration value="ImageMagick">
                 <xs:annotation>
-                    <xs:documentation>Licence Art Libre 1.2</xs:documentation>
+                    <xs:documentation>ImageMagick License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AGPL-1.0-only">
+            <xs:enumeration value="iMatix">
                 <xs:annotation>
-                    <xs:documentation>Affero General Public License v1.0 only</xs:documentation>
+                    <xs:documentation>iMatix Standard Function Library Agreement</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MIT-enna">
+            <xs:enumeration value="Imlib2">
                 <xs:annotation>
-                    <xs:documentation>enna License</xs:documentation>
+                    <xs:documentation>Imlib2 License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Condor-1.1">
+            <xs:enumeration value="Info-ZIP">
                 <xs:annotation>
-                    <xs:documentation>Condor Public License v1.1</xs:documentation>
+                    <xs:documentation>Info-ZIP License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Naumen">
+            <xs:enumeration value="Inner-Net-2.0">
                 <xs:annotation>
-                    <xs:documentation>Naumen Public License</xs:documentation>
+                    <xs:documentation>Inner Net License v2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.3-no-invariants-or-later">
+            <xs:enumeration value="Intel">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.3 or later - no invariants</xs:documentation>
+                    <xs:documentation>Intel Open Source License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="RPL-1.5">
+            <xs:enumeration value="Intel-ACPI">
                 <xs:annotation>
-                    <xs:documentation>Reciprocal Public License 1.5</xs:documentation>
+                    <xs:documentation>Intel ACPI Software License Agreement</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="PolyForm-Small-Business-1.0.0">
+            <xs:enumeration value="Interbase-1.0">
                 <xs:annotation>
-                    <xs:documentation>PolyForm Small Business License 1.0.0</xs:documentation>
+                    <xs:documentation>Interbase Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EFL-1.0">
+            <xs:enumeration value="IPA">
                 <xs:annotation>
-                    <xs:documentation>Eiffel Forum License v1.0</xs:documentation>
+                    <xs:documentation>IPA Font License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MirOS">
+            <xs:enumeration value="IPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>The MirOS Licence</xs:documentation>
+                    <xs:documentation>IBM Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-2.5-AU">
+            <xs:enumeration value="ISC">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 2.5 Australia</xs:documentation>
+                    <xs:documentation>ISC License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Afmparse">
+            <xs:enumeration value="Jam">
                 <xs:annotation>
-                    <xs:documentation>Afmparse License</xs:documentation>
+                    <xs:documentation>Jam License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MPL-2.0-no-copyleft-exception">
+            <xs:enumeration value="JasPer-2.0">
                 <xs:annotation>
-                    <xs:documentation>Mozilla Public License 2.0 (no copyleft exception)</xs:documentation>
+                    <xs:documentation>JasPer License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LiLiQ-Rplus-1.1">
+            <xs:enumeration value="JPL-image">
                 <xs:annotation>
-                    <xs:documentation>Licence Libre du Québec – Réciprocité forte version 1.1</xs:documentation>
+                    <xs:documentation>JPL Image Use Policy</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AFL-1.2">
+            <xs:enumeration value="JPNIC">
                 <xs:annotation>
-                    <xs:documentation>Academic Free License v1.2</xs:documentation>
+                    <xs:documentation>Japan Network Information Center License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OSL-1.0">
+            <xs:enumeration value="JSON">
                 <xs:annotation>
-                    <xs:documentation>Open Software License 1.0</xs:documentation>
+                    <xs:documentation>JSON License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-1.0-only">
+            <xs:enumeration value="Kazlib">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v1.0 only</xs:documentation>
+                    <xs:documentation>Kazlib License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="APSL-1.0">
+            <xs:enumeration value="Knuth-CTAN">
                 <xs:annotation>
-                    <xs:documentation>Apple Public Source License 1.0</xs:documentation>
+                    <xs:documentation>Knuth CTAN License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OGL-Canada-2.0">
+            <xs:enumeration value="LAL-1.2">
                 <xs:annotation>
-                    <xs:documentation>Open Government Licence - Canada</xs:documentation>
+                    <xs:documentation>Licence Art Libre 1.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CPAL-1.0">
+            <xs:enumeration value="LAL-1.3">
                 <xs:annotation>
-                    <xs:documentation>Common Public Attribution License 1.0</xs:documentation>
+                    <xs:documentation>Licence Art Libre 1.3</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
             <xs:enumeration value="Latex2e">
@@ -1107,1515 +1512,1520 @@
                     <xs:documentation>Latex2e License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Zend-2.0">
+            <xs:enumeration value="Latex2e-translated-notice">
                 <xs:annotation>
-                    <xs:documentation>Zend License v2.0</xs:documentation>
+                    <xs:documentation>Latex2e with translated notice permission</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Unlicense">
+            <xs:enumeration value="Leptonica">
                 <xs:annotation>
-                    <xs:documentation>The Unlicense</xs:documentation>
+                    <xs:documentation>Leptonica License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="xpp">
+            <xs:enumeration value="LGPL-2.0">
                 <xs:annotation>
-                    <xs:documentation>XPP License</xs:documentation>
+                    <xs:documentation>GNU Library General Public License v2 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-1.0">
+            <xs:enumeration value="LGPL-2.0+">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial 1.0 Generic</xs:documentation>
+                    <xs:documentation>GNU Library General Public License v2 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-3.0-with-autoconf-exception">
+            <xs:enumeration value="LGPL-2.0-only">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v3.0 w/Autoconf exception</xs:documentation>
+                    <xs:documentation>GNU Library General Public License v2 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-3.0">
+            <xs:enumeration value="LGPL-2.0-or-later">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 3.0 Unported</xs:documentation>
+                    <xs:documentation>GNU Library General Public License v2 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="TCP-wrappers">
+            <xs:enumeration value="LGPL-2.1">
                 <xs:annotation>
-                    <xs:documentation>TCP Wrappers License</xs:documentation>
+                    <xs:documentation>GNU Lesser General Public License v2.1 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SCEA">
+            <xs:enumeration value="LGPL-2.1+">
                 <xs:annotation>
-                    <xs:documentation>SCEA Shared Source License</xs:documentation>
+                    <xs:documentation>GNU Lesser General Public License v2.1 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SSH-short">
+            <xs:enumeration value="LGPL-2.1-only">
                 <xs:annotation>
-                    <xs:documentation>SSH short notice</xs:documentation>
+                    <xs:documentation>GNU Lesser General Public License v2.1 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-3.0-NL">
+            <xs:enumeration value="LGPL-2.1-or-later">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 3.0 Netherlands</xs:documentation>
+                    <xs:documentation>GNU Lesser General Public License v2.1 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SchemeReport">
+            <xs:enumeration value="LGPL-3.0">
                 <xs:annotation>
-                    <xs:documentation>Scheme Language Report License</xs:documentation>
+                    <xs:documentation>GNU Lesser General Public License v3.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-3.0">
+            <xs:enumeration value="LGPL-3.0+">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 3.0 Unported</xs:documentation>
+                    <xs:documentation>GNU Lesser General Public License v3.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MPL-2.0">
+            <xs:enumeration value="LGPL-3.0-only">
                 <xs:annotation>
-                    <xs:documentation>Mozilla Public License 2.0</xs:documentation>
+                    <xs:documentation>GNU Lesser General Public License v3.0 only</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Unicode-TOU">
+            <xs:enumeration value="LGPL-3.0-or-later">
                 <xs:annotation>
-                    <xs:documentation>Unicode Terms of Use</xs:documentation>
+                    <xs:documentation>GNU Lesser General Public License v3.0 or later</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-ND-1.0">
+            <xs:enumeration value="LGPLLR">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic</xs:documentation>
+                    <xs:documentation>Lesser General Public License For Linguistic Resources</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Entessa">
+            <xs:enumeration value="Libpng">
                 <xs:annotation>
-                    <xs:documentation>Entessa Public License v1.0</xs:documentation>
+                    <xs:documentation>libpng License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-No-Nuclear-License">
+            <xs:enumeration value="libpng-2.0">
                 <xs:annotation>
-                    <xs:documentation>BSD 3-Clause No Nuclear License</xs:documentation>
+                    <xs:documentation>PNG Reference Library version 2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SWL">
+            <xs:enumeration value="libselinux-1.0">
                 <xs:annotation>
-                    <xs:documentation>Scheme Widget Library (SWL) Software License Agreement</xs:documentation>
+                    <xs:documentation>libselinux public domain notice</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.2-no-invariants-only">
+            <xs:enumeration value="libtiff">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.2 only - no invariants</xs:documentation>
+                    <xs:documentation>libtiff License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Parity-7.0.0">
+            <xs:enumeration value="libutil-David-Nugent">
                 <xs:annotation>
-                    <xs:documentation>The Parity Public License 7.0.0</xs:documentation>
+                    <xs:documentation>libutil David Nugent License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.2.1">
+            <xs:enumeration value="LiLiQ-P-1.1">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.2.1</xs:documentation>
+                    <xs:documentation>Licence Libre du Québec – Permissive version 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SGI-B-1.1">
+            <xs:enumeration value="LiLiQ-R-1.1">
                 <xs:annotation>
-                    <xs:documentation>SGI Free Software License B v1.1</xs:documentation>
+                    <xs:documentation>Licence Libre du Québec – Réciprocité version 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="FTL">
+            <xs:enumeration value="LiLiQ-Rplus-1.1">
                 <xs:annotation>
-                    <xs:documentation>Freetype Project License</xs:documentation>
+                    <xs:documentation>Licence Libre du Québec – Réciprocité forte version 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.4">
+            <xs:enumeration value="Linux-man-pages-1-para">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.4</xs:documentation>
+                    <xs:documentation>Linux man-pages - 1 paragraph</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-4.0">
+            <xs:enumeration value="Linux-man-pages-copyleft">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial 4.0 International</xs:documentation>
+                    <xs:documentation>Linux man-pages Copyleft</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="bzip2-1.0.6">
+            <xs:enumeration value="Linux-man-pages-copyleft-2-para">
                 <xs:annotation>
-                    <xs:documentation>bzip2 and libbzip2 License v1.0.6</xs:documentation>
+                    <xs:documentation>Linux man-pages Copyleft - 2 paragraphs</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="copyleft-next-0.3.0">
+            <xs:enumeration value="Linux-man-pages-copyleft-var">
                 <xs:annotation>
-                    <xs:documentation>copyleft-next 0.3.0</xs:documentation>
+                    <xs:documentation>Linux man-pages Copyleft Variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MakeIndex">
+            <xs:enumeration value="Linux-OpenIB">
                 <xs:annotation>
-                    <xs:documentation>MakeIndex License</xs:documentation>
+                    <xs:documentation>Linux Kernel Variant of OpenIB.org license</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NRL">
+            <xs:enumeration value="LOOP">
                 <xs:annotation>
-                    <xs:documentation>NRL License</xs:documentation>
+                    <xs:documentation>Common Lisp LOOP License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.3-invariants-or-later">
+            <xs:enumeration value="LPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.3 or later - invariants</xs:documentation>
+                    <xs:documentation>Lucent Public License Version 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-2.0">
+            <xs:enumeration value="LPL-1.02">
+                <xs:annotation>
+                    <xs:documentation>Lucent Public License v1.02</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="LPPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial 2.0 Generic</xs:documentation>
+                    <xs:documentation>LaTeX Project Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SugarCRM-1.1.3">
+            <xs:enumeration value="LPPL-1.1">
                 <xs:annotation>
-                    <xs:documentation>SugarCRM Public License v1.1.3</xs:documentation>
+                    <xs:documentation>LaTeX Project Public License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AFL-2.1">
+            <xs:enumeration value="LPPL-1.2">
                 <xs:annotation>
-                    <xs:documentation>Academic Free License v2.1</xs:documentation>
+                    <xs:documentation>LaTeX Project Public License v1.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0-only">
+            <xs:enumeration value="LPPL-1.3a">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 only</xs:documentation>
+                    <xs:documentation>LaTeX Project Public License v1.3a</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.3-invariants-only">
+            <xs:enumeration value="LPPL-1.3c">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.3 only - invariants</xs:documentation>
+                    <xs:documentation>LaTeX Project Public License v1.3c</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="TORQUE-1.1">
+            <xs:enumeration value="LZMA-SDK-9.11-to-9.20">
                 <xs:annotation>
-                    <xs:documentation>TORQUE v2.5+ Software License v1.1</xs:documentation>
+                    <xs:documentation>LZMA SDK License (versions 9.11 to 9.20)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Ruby">
+            <xs:enumeration value="LZMA-SDK-9.22">
                 <xs:annotation>
-                    <xs:documentation>Ruby License</xs:documentation>
+                    <xs:documentation>LZMA SDK License (versions 9.22 and beyond)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="X11">
+            <xs:enumeration value="MakeIndex">
                 <xs:annotation>
-                    <xs:documentation>X11 License</xs:documentation>
+                    <xs:documentation>MakeIndex License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Borceux">
+            <xs:enumeration value="Martin-Birgmeier">
                 <xs:annotation>
-                    <xs:documentation>Borceux license</xs:documentation>
+                    <xs:documentation>Martin Birgmeier License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Libpng">
+            <xs:enumeration value="metamail">
                 <xs:annotation>
-                    <xs:documentation>libpng License</xs:documentation>
+                    <xs:documentation>metamail License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="X11-distribute-modifications-variant">
+            <xs:enumeration value="Minpack">
                 <xs:annotation>
-                    <xs:documentation>X11 License Distribution Modification Variant</xs:documentation>
+                    <xs:documentation>Minpack License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Frameworx-1.0">
+            <xs:enumeration value="MirOS">
                 <xs:annotation>
-                    <xs:documentation>Frameworx Open License 1.0</xs:documentation>
+                    <xs:documentation>The MirOS Licence</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NCGL-UK-2.0">
+            <xs:enumeration value="MIT">
                 <xs:annotation>
-                    <xs:documentation>Non-Commercial Government Licence</xs:documentation>
+                    <xs:documentation>MIT License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CECILL-2.1">
+            <xs:enumeration value="MIT-0">
                 <xs:annotation>
-                    <xs:documentation>CeCILL Free Software License Agreement v2.1</xs:documentation>
+                    <xs:documentation>MIT No Attribution</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-3.0-AT">
+            <xs:enumeration value="MIT-advertising">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 3.0 Austria</xs:documentation>
+                    <xs:documentation>Enlightenment License (e16)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CNRI-Python">
+            <xs:enumeration value="MIT-CMU">
                 <xs:annotation>
-                    <xs:documentation>CNRI Python License</xs:documentation>
+                    <xs:documentation>CMU License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NCSA">
+            <xs:enumeration value="MIT-enna">
                 <xs:annotation>
-                    <xs:documentation>University of Illinois/NCSA Open Source License</xs:documentation>
+                    <xs:documentation>enna License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="gSOAP-1.3b">
+            <xs:enumeration value="MIT-feh">
                 <xs:annotation>
-                    <xs:documentation>gSOAP Public License v1.3b</xs:documentation>
+                    <xs:documentation>feh License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EUPL-1.1">
+            <xs:enumeration value="MIT-Festival">
                 <xs:annotation>
-                    <xs:documentation>European Union Public License 1.1</xs:documentation>
+                    <xs:documentation>MIT Festival Variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AMDPLPA">
+            <xs:enumeration value="MIT-Modern-Variant">
                 <xs:annotation>
-                    <xs:documentation>AMD&apos;s plpa_map.c License</xs:documentation>
+                    <xs:documentation>MIT License Modern Variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Imlib2">
+            <xs:enumeration value="MIT-open-group">
                 <xs:annotation>
-                    <xs:documentation>Imlib2 License</xs:documentation>
+                    <xs:documentation>MIT Open Group variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CDDL-1.1">
+            <xs:enumeration value="MIT-Wu">
                 <xs:annotation>
-                    <xs:documentation>Common Development and Distribution License 1.1</xs:documentation>
+                    <xs:documentation>MIT Tom Wu Variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="WTFPL">
+            <xs:enumeration value="MITNFA">
                 <xs:annotation>
-                    <xs:documentation>Do What The F*ck You Want To Public License</xs:documentation>
+                    <xs:documentation>MIT +no-false-attribs license</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LPL-1.0">
+            <xs:enumeration value="Motosoto">
                 <xs:annotation>
-                    <xs:documentation>Lucent Public License Version 1.0</xs:documentation>
+                    <xs:documentation>Motosoto License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EPL-1.0">
+            <xs:enumeration value="mpi-permissive">
                 <xs:annotation>
-                    <xs:documentation>Eclipse Public License 1.0</xs:documentation>
+                    <xs:documentation>mpi Permissive License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-Attribution">
+            <xs:enumeration value="mpich2">
                 <xs:annotation>
-                    <xs:documentation>BSD with attribution</xs:documentation>
+                    <xs:documentation>mpich2 License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OSL-3.0">
+            <xs:enumeration value="MPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Open Software License 3.0</xs:documentation>
+                    <xs:documentation>Mozilla Public License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="RHeCos-1.1">
+            <xs:enumeration value="MPL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Red Hat eCos Public License v1.1</xs:documentation>
+                    <xs:documentation>Mozilla Public License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="PHP-3.0">
+            <xs:enumeration value="MPL-2.0">
                 <xs:annotation>
-                    <xs:documentation>PHP License v3.0</xs:documentation>
+                    <xs:documentation>Mozilla Public License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-Protection">
+            <xs:enumeration value="MPL-2.0-no-copyleft-exception">
                 <xs:annotation>
-                    <xs:documentation>BSD Protection License</xs:documentation>
+                    <xs:documentation>Mozilla Public License 2.0 (no copyleft exception)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-3.0-DE">
+            <xs:enumeration value="mplus">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial 3.0 Germany</xs:documentation>
+                    <xs:documentation>mplus Font License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="APL-1.0">
+            <xs:enumeration value="MS-LPL">
                 <xs:annotation>
-                    <xs:documentation>Adaptive Public License 1.0</xs:documentation>
+                    <xs:documentation>Microsoft Limited Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EUDatagrid">
+            <xs:enumeration value="MS-PL">
                 <xs:annotation>
-                    <xs:documentation>EU DataGrid Software License</xs:documentation>
+                    <xs:documentation>Microsoft Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-1.0">
+            <xs:enumeration value="MS-RL">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v1.0 only</xs:documentation>
+                    <xs:documentation>Microsoft Reciprocal License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SHL-0.5">
+            <xs:enumeration value="MTLL">
                 <xs:annotation>
-                    <xs:documentation>Solderpad Hardware License v0.5</xs:documentation>
+                    <xs:documentation>Matrix Template Library License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-2.0">
+            <xs:enumeration value="MulanPSL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 2.0 Generic</xs:documentation>
+                    <xs:documentation>Mulan Permissive Software License, Version 1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-3.0-AT">
+            <xs:enumeration value="MulanPSL-2.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 3.0 Austria</xs:documentation>
+                    <xs:documentation>Mulan Permissive Software License, Version 2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-3.0-IGO">
+            <xs:enumeration value="Multics">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 3.0 IGO</xs:documentation>
+                    <xs:documentation>Multics License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Adobe-2006">
+            <xs:enumeration value="Mup">
                 <xs:annotation>
-                    <xs:documentation>Adobe Systems Incorporated Source Code License Agreement</xs:documentation>
+                    <xs:documentation>Mup License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Newsletr">
+            <xs:enumeration value="NAIST-2003">
                 <xs:annotation>
-                    <xs:documentation>Newsletr License</xs:documentation>
+                    <xs:documentation>Nara Institute of Science and Technology License (2003)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Nunit">
+            <xs:enumeration value="NASA-1.3">
                 <xs:annotation>
-                    <xs:documentation>Nunit License</xs:documentation>
+                    <xs:documentation>NASA Open Source Agreement 1.3</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Multics">
+            <xs:enumeration value="Naumen">
                 <xs:annotation>
-                    <xs:documentation>Multics License</xs:documentation>
+                    <xs:documentation>Naumen Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OGL-UK-1.0">
+            <xs:enumeration value="NBPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Open Government Licence v1.0</xs:documentation>
+                    <xs:documentation>Net Boolean Public License v1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Vim">
+            <xs:enumeration value="NCGL-UK-2.0">
                 <xs:annotation>
-                    <xs:documentation>Vim License</xs:documentation>
+                    <xs:documentation>Non-Commercial Government Licence</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="eCos-2.0">
+            <xs:enumeration value="NCSA">
                 <xs:annotation>
-                    <xs:documentation>eCos license version 2.0</xs:documentation>
+                    <xs:documentation>University of Illinois/NCSA Open Source License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Zimbra-1.3">
+            <xs:enumeration value="Net-SNMP">
                 <xs:annotation>
-                    <xs:documentation>Zimbra Public License v1.3</xs:documentation>
+                    <xs:documentation>Net-SNMP License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="eGenix">
+            <xs:enumeration value="NetCDF">
                 <xs:annotation>
-                    <xs:documentation>eGenix.com Public License 1.1.0</xs:documentation>
+                    <xs:documentation>NetCDF license</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="IBM-pibs">
+            <xs:enumeration value="Newsletr">
                 <xs:annotation>
-                    <xs:documentation>IBM PowerPC Initialization and Boot Software</xs:documentation>
+                    <xs:documentation>Newsletr License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BitTorrent-1.1">
+            <xs:enumeration value="NGPL">
                 <xs:annotation>
-                    <xs:documentation>BitTorrent Open Source License v1.1</xs:documentation>
+                    <xs:documentation>Nethack General Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OFL-1.1-no-RFN">
+            <xs:enumeration value="NICTA-1.0">
                 <xs:annotation>
-                    <xs:documentation>SIL Open Font License 1.1 with no Reserved Font Name</xs:documentation>
+                    <xs:documentation>NICTA Public Software License, Version 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="psfrag">
+            <xs:enumeration value="NIST-PD">
                 <xs:annotation>
-                    <xs:documentation>psfrag License</xs:documentation>
+                    <xs:documentation>NIST Public Domain Notice</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-ND-2.0">
+            <xs:enumeration value="NIST-PD-fallback">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution No Derivatives 2.0 Generic</xs:documentation>
+                    <xs:documentation>NIST Public Domain Notice with license fallback</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SHL-0.51">
+            <xs:enumeration value="NIST-Software">
                 <xs:annotation>
-                    <xs:documentation>Solderpad Hardware License, Version 0.51</xs:documentation>
+                    <xs:documentation>NIST Software License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="FreeBSD-DOC">
+            <xs:enumeration value="NLOD-1.0">
                 <xs:annotation>
-                    <xs:documentation>FreeBSD Documentation License</xs:documentation>
+                    <xs:documentation>Norwegian Licence for Open Government Data (NLOD) 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Python-2.0">
+            <xs:enumeration value="NLOD-2.0">
                 <xs:annotation>
-                    <xs:documentation>Python License 2.0</xs:documentation>
+                    <xs:documentation>Norwegian Licence for Open Government Data (NLOD) 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Mup">
+            <xs:enumeration value="NLPL">
                 <xs:annotation>
-                    <xs:documentation>Mup License</xs:documentation>
+                    <xs:documentation>No Limit Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-4-Clause-Shortened">
+            <xs:enumeration value="Nokia">
                 <xs:annotation>
-                    <xs:documentation>BSD 4 Clause Shortened</xs:documentation>
+                    <xs:documentation>Nokia Open Source License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-4.0">
+            <xs:enumeration value="NOSL">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 4.0 International</xs:documentation>
+                    <xs:documentation>Netizen Open Source License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="HPND">
+            <xs:enumeration value="Noweb">
                 <xs:annotation>
-                    <xs:documentation>Historical Permission Notice and Disclaimer</xs:documentation>
+                    <xs:documentation>Noweb License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.6">
+            <xs:enumeration value="NPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.6</xs:documentation>
+                    <xs:documentation>Netscape Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MPL-1.1">
+            <xs:enumeration value="NPL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Mozilla Public License 1.1</xs:documentation>
+                    <xs:documentation>Netscape Public License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0-with-GCC-exception">
+            <xs:enumeration value="NPOSL-3.0">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 w/GCC Runtime Library exception</xs:documentation>
+                    <xs:documentation>Non-Profit Open Software License 3.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="HaskellReport">
+            <xs:enumeration value="NRL">
                 <xs:annotation>
-                    <xs:documentation>Haskell Language Report License</xs:documentation>
+                    <xs:documentation>NRL License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ECL-1.0">
+            <xs:enumeration value="NTP">
                 <xs:annotation>
-                    <xs:documentation>Educational Community License v1.0</xs:documentation>
+                    <xs:documentation>NTP License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-2.1-or-later">
+            <xs:enumeration value="NTP-0">
                 <xs:annotation>
-                    <xs:documentation>GNU Lesser General Public License v2.1 or later</xs:documentation>
+                    <xs:documentation>NTP No Attribution</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OFL-1.0">
+            <xs:enumeration value="Nunit">
                 <xs:annotation>
-                    <xs:documentation>SIL Open Font License 1.0</xs:documentation>
+                    <xs:documentation>Nunit License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="APSL-1.1">
+            <xs:enumeration value="O-UDA-1.0">
                 <xs:annotation>
-                    <xs:documentation>Apple Public Source License 1.1</xs:documentation>
+                    <xs:documentation>Open Use of Data Agreement v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MITNFA">
+            <xs:enumeration value="OCCT-PL">
                 <xs:annotation>
-                    <xs:documentation>MIT +no-false-attribs license</xs:documentation>
+                    <xs:documentation>Open CASCADE Technology Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CECILL-2.0">
+            <xs:enumeration value="OCLC-2.0">
                 <xs:annotation>
-                    <xs:documentation>CeCILL Free Software License Agreement v2.0</xs:documentation>
+                    <xs:documentation>OCLC Research Public License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Crossword">
+            <xs:enumeration value="ODbL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Crossword License</xs:documentation>
+                    <xs:documentation>Open Data Commons Open Database License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Aladdin">
+            <xs:enumeration value="ODC-By-1.0">
                 <xs:annotation>
-                    <xs:documentation>Aladdin Free Public License</xs:documentation>
+                    <xs:documentation>Open Data Commons Attribution License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Baekmuk">
+            <xs:enumeration value="OFFIS">
                 <xs:annotation>
-                    <xs:documentation>Baekmuk License</xs:documentation>
+                    <xs:documentation>OFFIS License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="XFree86-1.1">
+            <xs:enumeration value="OFL-1.0">
                 <xs:annotation>
-                    <xs:documentation>XFree86 License 1.1</xs:documentation>
+                    <xs:documentation>SIL Open Font License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-1.0-or-later">
+            <xs:enumeration value="OFL-1.0-no-RFN">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v1.0 or later</xs:documentation>
+                    <xs:documentation>SIL Open Font License 1.0 with no Reserved Font Name</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CERN-OHL-W-2.0">
+            <xs:enumeration value="OFL-1.0-RFN">
                 <xs:annotation>
-                    <xs:documentation>CERN Open Hardware Licence Version 2 - Weakly Reciprocal</xs:documentation>
+                    <xs:documentation>SIL Open Font License 1.0 with Reserved Font Name</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-1.0">
+            <xs:enumeration value="OFL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 1.0 Generic</xs:documentation>
+                    <xs:documentation>SIL Open Font License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NTP">
+            <xs:enumeration value="OFL-1.1-no-RFN">
                 <xs:annotation>
-                    <xs:documentation>NTP License</xs:documentation>
+                    <xs:documentation>SIL Open Font License 1.1 with no Reserved Font Name</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="PHP-3.01">
+            <xs:enumeration value="OFL-1.1-RFN">
                 <xs:annotation>
-                    <xs:documentation>PHP License v3.01</xs:documentation>
+                    <xs:documentation>SIL Open Font License 1.1 with Reserved Font Name</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OCLC-2.0">
+            <xs:enumeration value="OGC-1.0">
                 <xs:annotation>
-                    <xs:documentation>OCLC Research Public License 2.0</xs:documentation>
+                    <xs:documentation>OGC Software License, Version 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-3.0-DE">
+            <xs:enumeration value="OGDL-Taiwan-1.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 3.0 Germany</xs:documentation>
+                    <xs:documentation>Taiwan Open Government Data License, version 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-2.5">
+            <xs:enumeration value="OGL-Canada-2.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial 2.5 Generic</xs:documentation>
+                    <xs:documentation>Open Government Licence - Canada</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Zlib">
+            <xs:enumeration value="OGL-UK-1.0">
                 <xs:annotation>
-                    <xs:documentation>zlib License</xs:documentation>
+                    <xs:documentation>Open Government Licence v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CATOSL-1.1">
+            <xs:enumeration value="OGL-UK-2.0">
                 <xs:annotation>
-                    <xs:documentation>Computer Associates Trusted Open Source License 1.1</xs:documentation>
+                    <xs:documentation>Open Government Licence v2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-3.0+">
+            <xs:enumeration value="OGL-UK-3.0">
                 <xs:annotation>
-                    <xs:documentation>GNU Lesser General Public License v3.0 or later</xs:documentation>
+                    <xs:documentation>Open Government Licence v3.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CAL-1.0">
+            <xs:enumeration value="OGTSL">
                 <xs:annotation>
-                    <xs:documentation>Cryptographic Autonomy License 1.0</xs:documentation>
+                    <xs:documentation>Open Group Test Suite License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NPL-1.0">
+            <xs:enumeration value="OLDAP-1.1">
                 <xs:annotation>
-                    <xs:documentation>Netscape Public License v1.0</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SMLNJ">
+            <xs:enumeration value="OLDAP-1.2">
                 <xs:annotation>
-                    <xs:documentation>Standard ML of New Jersey License</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v1.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0+">
+            <xs:enumeration value="OLDAP-1.3">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 or later</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v1.3</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.5">
+            <xs:enumeration value="OLDAP-1.4">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.5</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v1.4</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="JasPer-2.0">
+            <xs:enumeration value="OLDAP-2.0">
                 <xs:annotation>
-                    <xs:documentation>JasPer License</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0-or-later">
+            <xs:enumeration value="OLDAP-2.0.1">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 or later</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.0.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-2-Clause-Patent">
+            <xs:enumeration value="OLDAP-2.1">
                 <xs:annotation>
-                    <xs:documentation>BSD-2-Clause Plus Patent License</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MS-RL">
+            <xs:enumeration value="OLDAP-2.2">
                 <xs:annotation>
-                    <xs:documentation>Microsoft Reciprocal License</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CUA-OPL-1.0">
+            <xs:enumeration value="OLDAP-2.2.1">
                 <xs:annotation>
-                    <xs:documentation>CUA Office Public License v1.0</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.2.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="IPA">
+            <xs:enumeration value="OLDAP-2.2.2">
                 <xs:annotation>
-                    <xs:documentation>IPA Font License</xs:documentation>
+                    <xs:documentation>Open LDAP Public License 2.2.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NLPL">
+            <xs:enumeration value="OLDAP-2.3">
                 <xs:annotation>
-                    <xs:documentation>No Limit Public License</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.3</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="O-UDA-1.0">
+            <xs:enumeration value="OLDAP-2.4">
                 <xs:annotation>
-                    <xs:documentation>Open Use of Data Agreement v1.0</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.4</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MIT-Modern-Variant">
+            <xs:enumeration value="OLDAP-2.5">
                 <xs:annotation>
-                    <xs:documentation>MIT License Modern Variant</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.5</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-1.2">
+            <xs:enumeration value="OLDAP-2.6">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v1.2</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.6</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-2-Clause-FreeBSD">
+            <xs:enumeration value="OLDAP-2.7">
                 <xs:annotation>
-                    <xs:documentation>BSD 2-Clause FreeBSD License</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.7</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Info-ZIP">
+            <xs:enumeration value="OLDAP-2.8">
                 <xs:annotation>
-                    <xs:documentation>Info-ZIP License</xs:documentation>
+                    <xs:documentation>Open LDAP Public License v2.8</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-2.0-FR">
+            <xs:enumeration value="OLFL-1.3">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution-NonCommercial-ShareAlike 2.0 France</xs:documentation>
+                    <xs:documentation>Open Logistics Foundation License Version 1.3</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="0BSD">
+            <xs:enumeration value="OML">
                 <xs:annotation>
-                    <xs:documentation>BSD Zero Clause License</xs:documentation>
+                    <xs:documentation>Open Market License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Unicode-DFS-2016">
+            <xs:enumeration value="OpenPBS-2.3">
                 <xs:annotation>
-                    <xs:documentation>Unicode License Agreement - Data Files and Software (2016)</xs:documentation>
+                    <xs:documentation>OpenPBS v2.3 Software License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OFL-1.0-RFN">
+            <xs:enumeration value="OpenSSL">
                 <xs:annotation>
-                    <xs:documentation>SIL Open Font License 1.0 with Reserved Font Name</xs:documentation>
+                    <xs:documentation>OpenSSL License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Intel">
+            <xs:enumeration value="OPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Intel Open Source License</xs:documentation>
+                    <xs:documentation>Open Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AFL-2.0">
+            <xs:enumeration value="OPL-UK-3.0">
                 <xs:annotation>
-                    <xs:documentation>Academic Free License v2.0</xs:documentation>
+                    <xs:documentation>United    Kingdom Open Parliament Licence v3.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GL2PS">
+            <xs:enumeration value="OPUBL-1.0">
                 <xs:annotation>
-                    <xs:documentation>GL2PS License</xs:documentation>
+                    <xs:documentation>Open Publication License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="TAPR-OHL-1.0">
+            <xs:enumeration value="OSET-PL-2.1">
                 <xs:annotation>
-                    <xs:documentation>TAPR Open Hardware License v1.0</xs:documentation>
+                    <xs:documentation>OSET Public License version 2.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Apache-1.0">
+            <xs:enumeration value="OSL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Apache License 1.0</xs:documentation>
+                    <xs:documentation>Open Software License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MTLL">
+            <xs:enumeration value="OSL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Matrix Template Library License</xs:documentation>
+                    <xs:documentation>Open Software License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Motosoto">
+            <xs:enumeration value="OSL-2.0">
                 <xs:annotation>
-                    <xs:documentation>Motosoto License</xs:documentation>
+                    <xs:documentation>Open Software License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="RSA-MD">
+            <xs:enumeration value="OSL-2.1">
                 <xs:annotation>
-                    <xs:documentation>RSA Message-Digest License</xs:documentation>
+                    <xs:documentation>Open Software License 2.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Community-Spec-1.0">
+            <xs:enumeration value="OSL-3.0">
                 <xs:annotation>
-                    <xs:documentation>Community Specification License 1.0</xs:documentation>
+                    <xs:documentation>Open Software License 3.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ODC-By-1.0">
+            <xs:enumeration value="Parity-6.0.0">
                 <xs:annotation>
-                    <xs:documentation>Open Data Commons Attribution License v1.0</xs:documentation>
+                    <xs:documentation>The Parity Public License 6.0.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="zlib-acknowledgement">
+            <xs:enumeration value="Parity-7.0.0">
                 <xs:annotation>
-                    <xs:documentation>zlib/libpng License with Acknowledgement</xs:documentation>
+                    <xs:documentation>The Parity Public License 7.0.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="DL-DE-BY-2.0">
+            <xs:enumeration value="PDDL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Data licence Germany – attribution – version 2.0</xs:documentation>
+                    <xs:documentation>Open Data Commons Public Domain Dedication &amp; License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="VSL-1.0">
+            <xs:enumeration value="PHP-3.0">
                 <xs:annotation>
-                    <xs:documentation>Vovida Software License v1.0</xs:documentation>
+                    <xs:documentation>PHP License v3.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LiLiQ-R-1.1">
+            <xs:enumeration value="PHP-3.01">
                 <xs:annotation>
-                    <xs:documentation>Licence Libre du Québec – Réciprocité version 1.1</xs:documentation>
+                    <xs:documentation>PHP License v3.01</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OPL-1.0">
+            <xs:enumeration value="Plexus">
                 <xs:annotation>
-                    <xs:documentation>Open Public License v1.0</xs:documentation>
+                    <xs:documentation>Plexus Classworlds License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-3.0+">
+            <xs:enumeration value="PolyForm-Noncommercial-1.0.0">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v3.0 or later</xs:documentation>
+                    <xs:documentation>PolyForm Noncommercial License 1.0.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MulanPSL-2.0">
+            <xs:enumeration value="PolyForm-Small-Business-1.0.0">
                 <xs:annotation>
-                    <xs:documentation>Mulan Permissive Software License, Version 2</xs:documentation>
+                    <xs:documentation>PolyForm Small Business License 1.0.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="APSL-1.2">
+            <xs:enumeration value="PostgreSQL">
                 <xs:annotation>
-                    <xs:documentation>Apple Public Source License 1.2</xs:documentation>
+                    <xs:documentation>PostgreSQL License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OGDL-Taiwan-1.0">
+            <xs:enumeration value="PSF-2.0">
                 <xs:annotation>
-                    <xs:documentation>Taiwan Open Government Data License, version 1.0</xs:documentation>
+                    <xs:documentation>Python Software Foundation License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="RSCPL">
+            <xs:enumeration value="psfrag">
                 <xs:annotation>
-                    <xs:documentation>Ricoh Source Code Public License</xs:documentation>
+                    <xs:documentation>psfrag License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OGC-1.0">
+            <xs:enumeration value="psutils">
                 <xs:annotation>
-                    <xs:documentation>OGC Software License, Version 1.0</xs:documentation>
+                    <xs:documentation>psutils License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EFL-2.0">
+            <xs:enumeration value="Python-2.0">
                 <xs:annotation>
-                    <xs:documentation>Eiffel Forum License v2.0</xs:documentation>
+                    <xs:documentation>Python License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CAL-1.0-Combined-Work-Exception">
+            <xs:enumeration value="Python-2.0.1">
                 <xs:annotation>
-                    <xs:documentation>Cryptographic Autonomy License 1.0 (Combined Work Exception)</xs:documentation>
+                    <xs:documentation>Python License 2.0.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MS-PL">
+            <xs:enumeration value="Qhull">
                 <xs:annotation>
-                    <xs:documentation>Microsoft Public License</xs:documentation>
+                    <xs:documentation>Qhull License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Plexus">
+            <xs:enumeration value="QPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Plexus Classworlds License</xs:documentation>
+                    <xs:documentation>Q Public License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Sendmail-8.23">
+            <xs:enumeration value="QPL-1.0-INRIA-2004">
                 <xs:annotation>
-                    <xs:documentation>Sendmail License 8.23</xs:documentation>
+                    <xs:documentation>Q Public License 1.0 - INRIA 2004 variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Cube">
+            <xs:enumeration value="Rdisc">
                 <xs:annotation>
-                    <xs:documentation>Cube License</xs:documentation>
+                    <xs:documentation>Rdisc License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="JSON">
+            <xs:enumeration value="RHeCos-1.1">
                 <xs:annotation>
-                    <xs:documentation>JSON License</xs:documentation>
+                    <xs:documentation>Red Hat eCos Public License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EUPL-1.2">
+            <xs:enumeration value="RPL-1.1">
                 <xs:annotation>
-                    <xs:documentation>European Union Public License 1.2</xs:documentation>
+                    <xs:documentation>Reciprocal Public License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Adobe-Glyph">
+            <xs:enumeration value="RPL-1.5">
                 <xs:annotation>
-                    <xs:documentation>Adobe Glyph List License</xs:documentation>
+                    <xs:documentation>Reciprocal Public License 1.5</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="FreeImage">
+            <xs:enumeration value="RPSL-1.0">
                 <xs:annotation>
-                    <xs:documentation>FreeImage Public License v1.0</xs:documentation>
+                    <xs:documentation>RealNetworks Public Source License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Watcom-1.0">
+            <xs:enumeration value="RSA-MD">
                 <xs:annotation>
-                    <xs:documentation>Sybase Open Watcom Public License 1.0</xs:documentation>
+                    <xs:documentation>RSA Message-Digest License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Jam">
+            <xs:enumeration value="RSCPL">
                 <xs:annotation>
-                    <xs:documentation>Jam License</xs:documentation>
+                    <xs:documentation>Ricoh Source Code Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Hippocratic-2.1">
+            <xs:enumeration value="Ruby">
                 <xs:annotation>
-                    <xs:documentation>Hippocratic License 2.1</xs:documentation>
+                    <xs:documentation>Ruby License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.0.1">
+            <xs:enumeration value="SAX-PD">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.0.1</xs:documentation>
+                    <xs:documentation>Sax Public Domain Notice</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-SA-2.0">
+            <xs:enumeration value="Saxpath">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial Share Alike 2.0 Generic</xs:documentation>
+                    <xs:documentation>Saxpath License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Nokia">
+            <xs:enumeration value="SCEA">
                 <xs:annotation>
-                    <xs:documentation>Nokia Open Source License</xs:documentation>
+                    <xs:documentation>SCEA Shared Source License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OCCT-PL">
+            <xs:enumeration value="SchemeReport">
                 <xs:annotation>
-                    <xs:documentation>Open CASCADE Technology Public License</xs:documentation>
+                    <xs:documentation>Scheme Language Report License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ErlPL-1.1">
+            <xs:enumeration value="Sendmail">
                 <xs:annotation>
-                    <xs:documentation>Erlang Public License v1.1</xs:documentation>
+                    <xs:documentation>Sendmail License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="TOSL">
+            <xs:enumeration value="Sendmail-8.23">
                 <xs:annotation>
-                    <xs:documentation>Trusster Open Source License</xs:documentation>
+                    <xs:documentation>Sendmail License 8.23</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OSL-2.1">
+            <xs:enumeration value="SGI-B-1.0">
                 <xs:annotation>
-                    <xs:documentation>Open Software License 2.1</xs:documentation>
+                    <xs:documentation>SGI Free Software License B v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ClArtistic">
+            <xs:enumeration value="SGI-B-1.1">
                 <xs:annotation>
-                    <xs:documentation>Clarified Artistic License</xs:documentation>
+                    <xs:documentation>SGI Free Software License B v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="xinetd">
+            <xs:enumeration value="SGI-B-2.0">
                 <xs:annotation>
-                    <xs:documentation>xinetd License</xs:documentation>
+                    <xs:documentation>SGI Free Software License B v2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-3.0-with-GCC-exception">
+            <xs:enumeration value="SGP4">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v3.0 w/GCC Runtime Library exception</xs:documentation>
+                    <xs:documentation>SGP4 Permission Notice</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ODbL-1.0">
+            <xs:enumeration value="SHL-0.5">
                 <xs:annotation>
-                    <xs:documentation>Open Data Commons Open Database License v1.0</xs:documentation>
+                    <xs:documentation>Solderpad Hardware License v0.5</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MIT">
+            <xs:enumeration value="SHL-0.51">
                 <xs:annotation>
-                    <xs:documentation>MIT License</xs:documentation>
+                    <xs:documentation>Solderpad Hardware License, Version 0.51</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-2.1+">
+            <xs:enumeration value="SimPL-2.0">
                 <xs:annotation>
-                    <xs:documentation>GNU Library General Public License v2.1 or later</xs:documentation>
+                    <xs:documentation>Simple Public License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-2.1-only">
+            <xs:enumeration value="SISSL">
                 <xs:annotation>
-                    <xs:documentation>GNU Lesser General Public License v2.1 only</xs:documentation>
+                    <xs:documentation>Sun Industry Standards Source License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CrystalStacker">
+            <xs:enumeration value="SISSL-1.2">
                 <xs:annotation>
-                    <xs:documentation>CrystalStacker License</xs:documentation>
+                    <xs:documentation>Sun Industry Standards Source License v1.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ECL-2.0">
+            <xs:enumeration value="Sleepycat">
                 <xs:annotation>
-                    <xs:documentation>Educational Community License v2.0</xs:documentation>
+                    <xs:documentation>Sleepycat License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LPPL-1.0">
+            <xs:enumeration value="SMLNJ">
                 <xs:annotation>
-                    <xs:documentation>LaTeX Project Public License v1.0</xs:documentation>
+                    <xs:documentation>Standard ML of New Jersey License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="iMatix">
+            <xs:enumeration value="SMPPL">
                 <xs:annotation>
-                    <xs:documentation>iMatix Standard Function Library Agreement</xs:documentation>
+                    <xs:documentation>Secure Messaging Protocol Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-ND-3.0-IGO">
+            <xs:enumeration value="SNIA">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO</xs:documentation>
+                    <xs:documentation>SNIA Public License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-Source-Code">
+            <xs:enumeration value="snprintf">
                 <xs:annotation>
-                    <xs:documentation>BSD Source Code Attribution</xs:documentation>
+                    <xs:documentation>snprintf License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Parity-6.0.0">
+            <xs:enumeration value="Spencer-86">
                 <xs:annotation>
-                    <xs:documentation>The Parity Public License 6.0.0</xs:documentation>
+                    <xs:documentation>Spencer License 86</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="TCL">
+            <xs:enumeration value="Spencer-94">
                 <xs:annotation>
-                    <xs:documentation>TCL/TK License</xs:documentation>
+                    <xs:documentation>Spencer License 94</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Arphic-1999">
+            <xs:enumeration value="Spencer-99">
                 <xs:annotation>
-                    <xs:documentation>Arphic Public License</xs:documentation>
+                    <xs:documentation>Spencer License 99</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-SA-3.0">
+            <xs:enumeration value="SPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Share Alike 3.0 Unported</xs:documentation>
+                    <xs:documentation>Sun Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Caldera">
+            <xs:enumeration value="SSH-OpenSSH">
                 <xs:annotation>
-                    <xs:documentation>Caldera License</xs:documentation>
+                    <xs:documentation>SSH OpenSSH license</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AGPL-1.0">
+            <xs:enumeration value="SSH-short">
                 <xs:annotation>
-                    <xs:documentation>Affero General Public License v1.0</xs:documentation>
+                    <xs:documentation>SSH short notice</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="IPL-1.0">
+            <xs:enumeration value="SSPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>IBM Public License v1.0</xs:documentation>
+                    <xs:documentation>Server Side Public License, v 1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LAL-1.3">
+            <xs:enumeration value="StandardML-NJ">
                 <xs:annotation>
-                    <xs:documentation>Licence Art Libre 1.3</xs:documentation>
+                    <xs:documentation>Standard ML of New Jersey License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EPICS">
+            <xs:enumeration value="SugarCRM-1.1.3">
                 <xs:annotation>
-                    <xs:documentation>EPICS Open License</xs:documentation>
+                    <xs:documentation>SugarCRM Public License v1.1.3</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NGPL">
+            <xs:enumeration value="SunPro">
                 <xs:annotation>
-                    <xs:documentation>Nethack General Public License</xs:documentation>
+                    <xs:documentation>SunPro License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="DRL-1.0">
+            <xs:enumeration value="SWL">
                 <xs:annotation>
-                    <xs:documentation>Detection Rule License 1.0</xs:documentation>
+                    <xs:documentation>Scheme Widget Library (SWL) Software License Agreement</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-2-Clause-NetBSD">
+            <xs:enumeration value="Symlinks">
                 <xs:annotation>
-                    <xs:documentation>BSD 2-Clause NetBSD License</xs:documentation>
+                    <xs:documentation>Symlinks License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ZPL-1.1">
+            <xs:enumeration value="TAPR-OHL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Zope Public License 1.1</xs:documentation>
+                    <xs:documentation>TAPR Open Hardware License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GD">
+            <xs:enumeration value="TCL">
                 <xs:annotation>
-                    <xs:documentation>GD License</xs:documentation>
+                    <xs:documentation>TCL/TK License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LPPL-1.2">
+            <xs:enumeration value="TCP-wrappers">
                 <xs:annotation>
-                    <xs:documentation>LaTeX Project Public License v1.2</xs:documentation>
+                    <xs:documentation>TCP Wrappers License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Dotseqn">
+            <xs:enumeration value="TermReadKey">
                 <xs:annotation>
-                    <xs:documentation>Dotseqn License</xs:documentation>
+                    <xs:documentation>TermReadKey License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Spencer-99">
+            <xs:enumeration value="TMate">
                 <xs:annotation>
-                    <xs:documentation>Spencer License 99</xs:documentation>
+                    <xs:documentation>TMate Open Source License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.3">
+            <xs:enumeration value="TORQUE-1.1">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.3</xs:documentation>
+                    <xs:documentation>TORQUE v2.5+ Software License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="YPL-1.1">
+            <xs:enumeration value="TOSL">
                 <xs:annotation>
-                    <xs:documentation>Yahoo! Public License v1.1</xs:documentation>
+                    <xs:documentation>Trusster Open Source License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Fair">
+            <xs:enumeration value="TPDL">
                 <xs:annotation>
-                    <xs:documentation>Fair License</xs:documentation>
+                    <xs:documentation>Time::ParseDate License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Qhull">
+            <xs:enumeration value="TPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Qhull License</xs:documentation>
+                    <xs:documentation>THOR Public License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.1-no-invariants-or-later">
+            <xs:enumeration value="TTWL">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.1 or later - no invariants</xs:documentation>
+                    <xs:documentation>Text-Tabs+Wrap License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CECILL-C">
+            <xs:enumeration value="TU-Berlin-1.0">
                 <xs:annotation>
-                    <xs:documentation>CeCILL-C Free Software License Agreement</xs:documentation>
+                    <xs:documentation>Technische Universitaet Berlin License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MulanPSL-1.0">
+            <xs:enumeration value="TU-Berlin-2.0">
                 <xs:annotation>
-                    <xs:documentation>Mulan Permissive Software License, Version 1</xs:documentation>
+                    <xs:documentation>Technische Universitaet Berlin License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-1.1">
+            <xs:enumeration value="UCAR">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v1.1</xs:documentation>
+                    <xs:documentation>UCAR License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.1">
+            <xs:enumeration value="UCL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License v2.1</xs:documentation>
+                    <xs:documentation>Upstream Compatibility License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LPL-1.02">
+            <xs:enumeration value="Unicode-DFS-2015">
                 <xs:annotation>
-                    <xs:documentation>Lucent Public License v1.02</xs:documentation>
+                    <xs:documentation>Unicode License Agreement - Data Files and Software (2015)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="UPL-1.0">
+            <xs:enumeration value="Unicode-DFS-2016">
                 <xs:annotation>
-                    <xs:documentation>Universal Permissive License v1.0</xs:documentation>
+                    <xs:documentation>Unicode License Agreement - Data Files and Software (2016)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Abstyles">
+            <xs:enumeration value="Unicode-TOU">
                 <xs:annotation>
-                    <xs:documentation>Abstyles License</xs:documentation>
+                    <xs:documentation>Unicode Terms of Use</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ZPL-2.0">
+            <xs:enumeration value="UnixCrypt">
                 <xs:annotation>
-                    <xs:documentation>Zope Public License 2.0</xs:documentation>
+                    <xs:documentation>UnixCrypt License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MIT-0">
+            <xs:enumeration value="Unlicense">
                 <xs:annotation>
-                    <xs:documentation>MIT No Attribution</xs:documentation>
+                    <xs:documentation>The Unlicense</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-2.0-only">
+            <xs:enumeration value="UPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>GNU Library General Public License v2 only</xs:documentation>
+                    <xs:documentation>Universal Permissive License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.3-no-invariants-only">
+            <xs:enumeration value="Vim">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.3 only - no invariants</xs:documentation>
+                    <xs:documentation>Vim License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AGPL-3.0">
+            <xs:enumeration value="VOSTROM">
                 <xs:annotation>
-                    <xs:documentation>GNU Affero General Public License v3.0</xs:documentation>
+                    <xs:documentation>VOSTROM Public License for Open Source</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="EPL-2.0">
+            <xs:enumeration value="VSL-1.0">
                 <xs:annotation>
-                    <xs:documentation>Eclipse Public License 2.0</xs:documentation>
+                    <xs:documentation>Vovida Software License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="AFL-3.0">
+            <xs:enumeration value="W3C">
                 <xs:annotation>
-                    <xs:documentation>Academic Free License v3.0</xs:documentation>
+                    <xs:documentation>W3C Software Notice and License (2002-12-31)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CDLA-Permissive-1.0">
+            <xs:enumeration value="W3C-19980720">
                 <xs:annotation>
-                    <xs:documentation>Community Data License Agreement Permissive 1.0</xs:documentation>
+                    <xs:documentation>W3C Software Notice and License (1998-07-20)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Artistic-1.0">
+            <xs:enumeration value="W3C-20150513">
                 <xs:annotation>
-                    <xs:documentation>Artistic License 1.0</xs:documentation>
+                    <xs:documentation>W3C Software Notice and Document License (2015-05-13)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-NC-ND-4.0">
+            <xs:enumeration value="w3m">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution Non Commercial No Derivatives 4.0 International</xs:documentation>
+                    <xs:documentation>w3m License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="HTMLTIDY">
+            <xs:enumeration value="Watcom-1.0">
                 <xs:annotation>
-                    <xs:documentation>HTML Tidy License</xs:documentation>
+                    <xs:documentation>Sybase Open Watcom Public License 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Glide">
+            <xs:enumeration value="Widget-Workshop">
                 <xs:annotation>
-                    <xs:documentation>3dfx Glide License</xs:documentation>
+                    <xs:documentation>Widget Workshop License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="FSFAP">
+            <xs:enumeration value="Wsuipa">
                 <xs:annotation>
-                    <xs:documentation>FSF All Permissive License</xs:documentation>
+                    <xs:documentation>Wsuipa License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPLLR">
+            <xs:enumeration value="WTFPL">
                 <xs:annotation>
-                    <xs:documentation>Lesser General Public License For Linguistic Resources</xs:documentation>
+                    <xs:documentation>Do What The F*ck You Want To Public License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OGL-UK-3.0">
+            <xs:enumeration value="wxWindows">
                 <xs:annotation>
-                    <xs:documentation>Open Government Licence v3.0</xs:documentation>
+                    <xs:documentation>wxWindows Library License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.2">
+            <xs:enumeration value="X11">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.2</xs:documentation>
+                    <xs:documentation>X11 License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SSH-OpenSSH">
+            <xs:enumeration value="X11-distribute-modifications-variant">
                 <xs:annotation>
-                    <xs:documentation>SSH OpenSSH license</xs:documentation>
+                    <xs:documentation>X11 License Distribution Modification Variant</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.1-only">
+            <xs:enumeration value="Xdebug-1.03">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.1 only</xs:documentation>
+                    <xs:documentation>Xdebug License v 1.03</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MIT-feh">
+            <xs:enumeration value="Xerox">
                 <xs:annotation>
-                    <xs:documentation>feh License</xs:documentation>
+                    <xs:documentation>Xerox License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="MPL-1.0">
+            <xs:enumeration value="Xfig">
                 <xs:annotation>
-                    <xs:documentation>Mozilla Public License 1.0</xs:documentation>
+                    <xs:documentation>Xfig License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="PostgreSQL">
+            <xs:enumeration value="XFree86-1.1">
                 <xs:annotation>
-                    <xs:documentation>PostgreSQL License</xs:documentation>
+                    <xs:documentation>XFree86 License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OLDAP-2.2.2">
+            <xs:enumeration value="xinetd">
                 <xs:annotation>
-                    <xs:documentation>Open LDAP Public License 2.2.2</xs:documentation>
+                    <xs:documentation>xinetd License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SMPPL">
+            <xs:enumeration value="xlock">
                 <xs:annotation>
-                    <xs:documentation>Secure Messaging Protocol Public License</xs:documentation>
+                    <xs:documentation>xlock License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OFL-1.1">
+            <xs:enumeration value="Xnet">
                 <xs:annotation>
-                    <xs:documentation>SIL Open Font License 1.1</xs:documentation>
+                    <xs:documentation>X.Net License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Leptonica">
+            <xs:enumeration value="xpp">
                 <xs:annotation>
-                    <xs:documentation>Leptonica License</xs:documentation>
+                    <xs:documentation>XPP License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CERN-OHL-1.1">
+            <xs:enumeration value="XSkat">
                 <xs:annotation>
-                    <xs:documentation>CERN Open Hardware Licence v1.1</xs:documentation>
+                    <xs:documentation>XSkat License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause-No-Nuclear-Warranty">
+            <xs:enumeration value="YPL-1.0">
                 <xs:annotation>
-                    <xs:documentation>BSD 3-Clause No Nuclear Warranty</xs:documentation>
+                    <xs:documentation>Yahoo! Public License v1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-ND-2.5">
+            <xs:enumeration value="YPL-1.1">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution No Derivatives 2.5 Generic</xs:documentation>
+                    <xs:documentation>Yahoo! Public License v1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CC-BY-1.0">
+            <xs:enumeration value="Zed">
                 <xs:annotation>
-                    <xs:documentation>Creative Commons Attribution 1.0 Generic</xs:documentation>
+                    <xs:documentation>Zed License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GFDL-1.2-only">
+            <xs:enumeration value="Zend-2.0">
                 <xs:annotation>
-                    <xs:documentation>GNU Free Documentation License v1.2 only</xs:documentation>
+                    <xs:documentation>Zend License v2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OPUBL-1.0">
+            <xs:enumeration value="Zimbra-1.3">
                 <xs:annotation>
-                    <xs:documentation>Open Publication License v1.0</xs:documentation>
+                    <xs:documentation>Zimbra Public License v1.3</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="libselinux-1.0">
+            <xs:enumeration value="Zimbra-1.4">
                 <xs:annotation>
-                    <xs:documentation>libselinux public domain notice</xs:documentation>
+                    <xs:documentation>Zimbra Public License v1.4</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-3-Clause">
+            <xs:enumeration value="Zlib">
                 <xs:annotation>
-                    <xs:documentation>BSD 3-Clause &quot;New&quot; or &quot;Revised&quot; License</xs:documentation>
+                    <xs:documentation>zlib License</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="ANTLR-PD-fallback">
+            <xs:enumeration value="zlib-acknowledgement">
                 <xs:annotation>
-                    <xs:documentation>ANTLR Software Rights Notice with license fallback</xs:documentation>
+                    <xs:documentation>zlib/libpng License with Acknowledgement</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="copyleft-next-0.3.1">
+            <xs:enumeration value="ZPL-1.1">
                 <xs:annotation>
-                    <xs:documentation>copyleft-next 0.3.1</xs:documentation>
+                    <xs:documentation>Zope Public License 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-1.0+">
+            <xs:enumeration value="ZPL-2.0">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v1.0 or later</xs:documentation>
+                    <xs:documentation>Zope Public License 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="wxWindows">
+            <xs:enumeration value="ZPL-2.1">
                 <xs:annotation>
-                    <xs:documentation>wxWindows Library License</xs:documentation>
+                    <xs:documentation>Zope Public License 2.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-3.0">
+            <!-- Exceptions -->
+            <xs:enumeration value="389-exception">
                 <xs:annotation>
-                    <xs:documentation>GNU Lesser General Public License v3.0 only</xs:documentation>
+                    <xs:documentation>389 Directory Server Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-2.1">
+            <xs:enumeration value="Asterisk-exception">
                 <xs:annotation>
-                    <xs:documentation>GNU Lesser General Public License v2.1 only</xs:documentation>
+                    <xs:documentation>Asterisk exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="StandardML-NJ">
+            <xs:enumeration value="Autoconf-exception-2.0">
                 <xs:annotation>
-                    <xs:documentation>Standard ML of New Jersey License</xs:documentation>
+                    <xs:documentation>Autoconf exception 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-4-Clause">
+            <xs:enumeration value="Autoconf-exception-3.0">
                 <xs:annotation>
-                    <xs:documentation>BSD 4-Clause &quot;Original&quot; or &quot;Old&quot; License</xs:documentation>
+                    <xs:documentation>Autoconf exception 3.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0-with-bison-exception">
+            <xs:enumeration value="Autoconf-exception-generic">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 w/Bison exception</xs:documentation>
+                    <xs:documentation>Autoconf generic exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Apache-2.0">
+            <xs:enumeration value="Autoconf-exception-macro">
                 <xs:annotation>
-                    <xs:documentation>Apache License 2.0</xs:documentation>
+                    <xs:documentation>Autoconf macro exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Artistic-1.0-cl8">
+            <xs:enumeration value="Bison-exception-2.2">
                 <xs:annotation>
-                    <xs:documentation>Artistic License 1.0 w/clause 8</xs:documentation>
+                    <xs:documentation>Bison exception 2.2</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-2.0">
+            <xs:enumeration value="Bootloader-exception">
                 <xs:annotation>
-                    <xs:documentation>GNU General Public License v2.0 only</xs:documentation>
+                    <xs:documentation>Bootloader Distribution Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Intel-ACPI">
+            <xs:enumeration value="Classpath-exception-2.0">
                 <xs:annotation>
-                    <xs:documentation>Intel ACPI Software License Agreement</xs:documentation>
+                    <xs:documentation>Classpath exception 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSL-1.0">
+            <xs:enumeration value="CLISP-exception-2.0">
                 <xs:annotation>
-                    <xs:documentation>Boost Software License 1.0</xs:documentation>
+                    <xs:documentation>CLISP exception 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Artistic-1.0-Perl">
+            <xs:enumeration value="cryptsetup-OpenSSL-exception">
                 <xs:annotation>
-                    <xs:documentation>Artistic License 1.0 (Perl)</xs:documentation>
+                    <xs:documentation>cryptsetup OpenSSL exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="BSD-2-Clause-Views">
+            <xs:enumeration value="DigiRule-FOSS-exception">
                 <xs:annotation>
-                    <xs:documentation>BSD 2-Clause with views sentence</xs:documentation>
+                    <xs:documentation>DigiRule FOSS License Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Interbase-1.0">
+            <xs:enumeration value="eCos-exception-2.0">
                 <xs:annotation>
-                    <xs:documentation>Interbase Public License v1.0</xs:documentation>
+                    <xs:documentation>eCos exception 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="NPOSL-3.0">
+            <xs:enumeration value="Fawkes-Runtime-exception">
                 <xs:annotation>
-                    <xs:documentation>Non-Profit Open Software License 3.0</xs:documentation>
+                    <xs:documentation>Fawkes Runtime Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <!-- Exceptions -->
             <xs:enumeration value="FLTK-exception">
                 <xs:annotation>
                     <xs:documentation>FLTK exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Bootloader-exception">
+            <xs:enumeration value="Font-exception-2.0">
                 <xs:annotation>
-                    <xs:documentation>Bootloader Distribution Exception</xs:documentation>
+                    <xs:documentation>Font exception 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="WxWindows-exception-3.1">
+            <xs:enumeration value="freertos-exception-2.0">
                 <xs:annotation>
-                    <xs:documentation>WxWindows Library Exception 3.1</xs:documentation>
+                    <xs:documentation>FreeRTOS Exception 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Linux-syscall-note">
+            <xs:enumeration value="GCC-exception-2.0">
                 <xs:annotation>
-                    <xs:documentation>Linux Syscall Note</xs:documentation>
+                    <xs:documentation>GCC Runtime Library exception 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Qt-LGPL-exception-1.1">
+            <xs:enumeration value="GCC-exception-3.1">
                 <xs:annotation>
-                    <xs:documentation>Qt LGPL exception 1.1</xs:documentation>
+                    <xs:documentation>GCC Runtime Library exception 3.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LLVM-exception">
+            <xs:enumeration value="GNAT-exception">
                 <xs:annotation>
-                    <xs:documentation>LLVM Exception</xs:documentation>
+                    <xs:documentation>GNAT exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="PS-or-PDF-font-exception-20170817">
+            <xs:enumeration value="gnu-javamail-exception">
                 <xs:annotation>
-                    <xs:documentation>PS/PDF font exception (2017-08-17)</xs:documentation>
+                    <xs:documentation>GNU JavaMail exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GCC-exception-3.1">
+            <xs:enumeration value="GPL-3.0-interface-exception">
                 <xs:annotation>
-                    <xs:documentation>GCC Runtime Library exception 3.1</xs:documentation>
+                    <xs:documentation>GPL-3.0 Interface Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Autoconf-exception-3.0">
+            <xs:enumeration value="GPL-3.0-linking-exception">
                 <xs:annotation>
-                    <xs:documentation>Autoconf exception 3.0</xs:documentation>
+                    <xs:documentation>GPL-3.0 Linking Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LGPL-3.0-linking-exception">
+            <xs:enumeration value="GPL-3.0-linking-source-exception">
                 <xs:annotation>
-                    <xs:documentation>LGPL-3.0 Linking Exception</xs:documentation>
+                    <xs:documentation>GPL-3.0 Linking Exception (with Corresponding Source)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GCC-exception-2.0">
+            <xs:enumeration value="GPL-CC-1.0">
                 <xs:annotation>
-                    <xs:documentation>GCC Runtime Library exception 2.0</xs:documentation>
+                    <xs:documentation>GPL Cooperation Commitment 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Bison-exception-2.2">
+            <xs:enumeration value="GStreamer-exception-2005">
                 <xs:annotation>
-                    <xs:documentation>Bison exception 2.2</xs:documentation>
+                    <xs:documentation>GStreamer Exception (2005)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="openvpn-openssl-exception">
+            <xs:enumeration value="GStreamer-exception-2008">
                 <xs:annotation>
-                    <xs:documentation>OpenVPN OpenSSL Exception</xs:documentation>
+                    <xs:documentation>GStreamer Exception (2008)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Libtool-exception">
+            <xs:enumeration value="i2p-gpl-java-exception">
                 <xs:annotation>
-                    <xs:documentation>Libtool Exception</xs:documentation>
+                    <xs:documentation>i2p GPL+Java Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Autoconf-exception-2.0">
+            <xs:enumeration value="KiCad-libraries-exception">
                 <xs:annotation>
-                    <xs:documentation>Autoconf exception 2.0</xs:documentation>
+                    <xs:documentation>KiCad Libraries Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-3.0-linking-source-exception">
+            <xs:enumeration value="LGPL-3.0-linking-exception">
                 <xs:annotation>
-                    <xs:documentation>GPL-3.0 Linking Exception (with Corresponding Source)</xs:documentation>
+                    <xs:documentation>LGPL-3.0 Linking Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-CC-1.0">
+            <xs:enumeration value="libpri-OpenH323-exception">
                 <xs:annotation>
-                    <xs:documentation>GPL Cooperation Commitment 1.0</xs:documentation>
+                    <xs:documentation>libpri OpenH323 exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OCaml-LGPL-linking-exception">
+            <xs:enumeration value="Libtool-exception">
                 <xs:annotation>
-                    <xs:documentation>OCaml LGPL Linking Exception</xs:documentation>
+                    <xs:documentation>Libtool Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Universal-FOSS-exception-1.0">
+            <xs:enumeration value="Linux-syscall-note">
                 <xs:annotation>
-                    <xs:documentation>Universal FOSS Exception, Version 1.0</xs:documentation>
+                    <xs:documentation>Linux Syscall Note</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="i2p-gpl-java-exception">
+            <xs:enumeration value="LLGPL">
                 <xs:annotation>
-                    <xs:documentation>i2p GPL+Java Exception</xs:documentation>
+                    <xs:documentation>LLGPL Preamble</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="CLISP-exception-2.0">
+            <xs:enumeration value="LLVM-exception">
                 <xs:annotation>
-                    <xs:documentation>CLISP exception 2.0</xs:documentation>
+                    <xs:documentation>LLVM Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OCCT-exception-1.0">
+            <xs:enumeration value="LZMA-exception">
                 <xs:annotation>
-                    <xs:documentation>Open CASCADE Exception 1.0</xs:documentation>
+                    <xs:documentation>LZMA exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Qwt-exception-1.0">
+            <xs:enumeration value="mif-exception">
                 <xs:annotation>
-                    <xs:documentation>Qwt exception 1.0</xs:documentation>
+                    <xs:documentation>Macros and Inline Functions Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="gnu-javamail-exception">
+            <xs:enumeration value="Nokia-Qt-exception-1.1">
                 <xs:annotation>
-                    <xs:documentation>GNU JavaMail exception</xs:documentation>
+                    <xs:documentation>Nokia Qt LGPL exception 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="u-boot-exception-2.0">
+            <xs:enumeration value="OCaml-LGPL-linking-exception">
                 <xs:annotation>
-                    <xs:documentation>U-Boot exception 2.0</xs:documentation>
+                    <xs:documentation>OCaml LGPL Linking Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="freertos-exception-2.0">
+            <xs:enumeration value="OCCT-exception-1.0">
                 <xs:annotation>
-                    <xs:documentation>FreeRTOS Exception 2.0</xs:documentation>
+                    <xs:documentation>Open CASCADE Exception 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Qt-GPL-exception-1.0">
+            <xs:enumeration value="OpenJDK-assembly-exception-1.0">
                 <xs:annotation>
-                    <xs:documentation>Qt GPL exception 1.0</xs:documentation>
+                    <xs:documentation>OpenJDK Assembly exception 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="OpenJDK-assembly-exception-1.0">
+            <xs:enumeration value="openvpn-openssl-exception">
                 <xs:annotation>
-                    <xs:documentation>OpenJDK Assembly exception 1.0</xs:documentation>
+                    <xs:documentation>OpenVPN OpenSSL Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="SHL-2.1">
+            <xs:enumeration value="PS-or-PDF-font-exception-20170817">
                 <xs:annotation>
-                    <xs:documentation>Solderpad Hardware License v2.1</xs:documentation>
+                    <xs:documentation>PS/PDF font exception (2017-08-17)</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="mif-exception">
+            <xs:enumeration value="QPL-1.0-INRIA-2004-exception">
                 <xs:annotation>
-                    <xs:documentation>Macros and Inline Functions Exception</xs:documentation>
+                    <xs:documentation>INRIA QPL 1.0 2004 variant exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Fawkes-Runtime-exception">
+            <xs:enumeration value="Qt-GPL-exception-1.0">
                 <xs:annotation>
-                    <xs:documentation>Fawkes Runtime Exception</xs:documentation>
+                    <xs:documentation>Qt GPL exception 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Swift-exception">
+            <xs:enumeration value="Qt-LGPL-exception-1.1">
                 <xs:annotation>
-                    <xs:documentation>Swift Exception</xs:documentation>
+                    <xs:documentation>Qt LGPL exception 1.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="GPL-3.0-linking-exception">
+            <xs:enumeration value="Qwt-exception-1.0">
                 <xs:annotation>
-                    <xs:documentation>GPL-3.0 Linking Exception</xs:documentation>
+                    <xs:documentation>Qwt exception 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
             <xs:enumeration value="SHL-2.0">
@@ -2623,39 +3033,44 @@
                     <xs:documentation>Solderpad Hardware License v2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Classpath-exception-2.0">
+            <xs:enumeration value="SHL-2.1">
                 <xs:annotation>
-                    <xs:documentation>Classpath exception 2.0</xs:documentation>
+                    <xs:documentation>Solderpad Hardware License v2.1</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="LZMA-exception">
+            <xs:enumeration value="SWI-exception">
                 <xs:annotation>
-                    <xs:documentation>LZMA exception</xs:documentation>
+                    <xs:documentation>SWI exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Font-exception-2.0">
+            <xs:enumeration value="Swift-exception">
                 <xs:annotation>
-                    <xs:documentation>Font exception 2.0</xs:documentation>
+                    <xs:documentation>Swift Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="Nokia-Qt-exception-1.1">
+            <xs:enumeration value="u-boot-exception-2.0">
                 <xs:annotation>
-                    <xs:documentation>Nokia Qt LGPL exception 1.1</xs:documentation>
+                    <xs:documentation>U-Boot exception 2.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="DigiRule-FOSS-exception">
+            <xs:enumeration value="Universal-FOSS-exception-1.0">
                 <xs:annotation>
-                    <xs:documentation>DigiRule FOSS License Exception</xs:documentation>
+                    <xs:documentation>Universal FOSS Exception, Version 1.0</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="eCos-exception-2.0">
+            <xs:enumeration value="vsftpd-openssl-exception">
                 <xs:annotation>
-                    <xs:documentation>eCos exception 2.0</xs:documentation>
+                    <xs:documentation>vsftpd OpenSSL exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
-            <xs:enumeration value="389-exception">
+            <xs:enumeration value="WxWindows-exception-3.1">
                 <xs:annotation>
-                    <xs:documentation>389 Directory Server Exception</xs:documentation>
+                    <xs:documentation>WxWindows Library Exception 3.1</xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+            <xs:enumeration value="x11vnc-openssl-exception">
+                <xs:annotation>
+                    <xs:documentation>x11vnc OpenSSL Exception</xs:documentation>
                 </xs:annotation>
             </xs:enumeration>
         </xs:restriction>
diff --git a/cyclonedx/schema/bom-1.2-strict.schema.json b/cyclonedx/schema/bom-1.2-strict.schema.json
deleted file mode 100644
index 30dad527e..000000000
--- a/cyclonedx/schema/bom-1.2-strict.schema.json
+++ /dev/null
@@ -1,1020 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-07/schema#",
-  "$id": "http://cyclonedx.org/schema/bom-1.2a.schema.json",
-  "type": "object",
-  "title": "CycloneDX Software Bill-of-Material Specification",
-  "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
-  "required": [
-    "bomFormat",
-    "specVersion",
-    "version"
-  ],
-  "additionalProperties": false,
-  "properties": {
-    "bomFormat": {
-      "$id": "#/properties/bomFormat",
-      "type": "string",
-      "title": "BOM Format",
-      "description": "Specifies the format of the BOM. This helps to identify the file as CycloneDX since BOMs do not have a filename convention nor does JSON schema support namespaces.",
-      "enum": [
-        "CycloneDX"
-      ]
-    },
-    "specVersion": {
-      "$id": "#/properties/specVersion",
-      "type": "string",
-      "title": "CycloneDX Specification Version",
-      "description": "The version of the CycloneDX specification a BOM is written to (starting at version 1.2)",
-      "examples": ["1.2"]
-    },
-    "serialNumber": {
-      "$id": "#/properties/serialNumber",
-      "type": "string",
-      "title": "BOM Serial Number",
-      "description": "Every BOM generated should have a unique serial number, even if the contents of the BOM being generated have not changed over time. The process or tool responsible for creating the BOM should create random UUID's for every BOM generated.",
-      "default": "",
-      "examples": ["urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"],
-      "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
-    },
-    "version": {
-      "$id": "#/properties/version",
-      "type": "integer",
-      "title": "BOM Version",
-      "description": "The version allows component publishers/authors to make changes to existing BOMs to update various aspects of the document such as description or licenses. When a system is presented with multiple BOMs for the same component, the system should use the most recent version of the BOM. The default version is '1' and should be incremented for each version of the BOM that is published. Each version of a component should have a unique BOM and if no changes are made to the BOMs, then each BOM will have a version of '1'.",
-      "default": 1,
-      "examples": [1]
-    },
-    "metadata": {
-      "$id": "#/properties/metadata",
-      "$ref": "#/definitions/metadata",
-      "title": "BOM Metadata",
-      "description": "Provides additional information about a BOM."
-    },
-    "components": {
-      "$id": "#/properties/components",
-      "type": "array",
-      "items": {"$ref": "#/definitions/component"},
-      "uniqueItems": true,
-      "title": "Components"
-    },
-    "services": {
-      "$id": "#/properties/services",
-      "type": "array",
-      "items": {"$ref": "#/definitions/service"},
-      "uniqueItems": true,
-      "title": "Services"
-    },
-    "externalReferences": {
-      "$id": "#/properties/externalReferences",
-      "type": "array",
-      "items": {"$ref": "#/definitions/externalReference"},
-      "title": "External References",
-      "description": "External references provide a way to document systems, sites, and information that may be relevant but which are not included with the BOM."
-    },
-    "dependencies": {
-      "$id": "#/properties/dependencies",
-      "type": "array",
-      "items": {"$ref": "#/definitions/dependency"},
-      "uniqueItems": true,
-      "title": "Dependencies",
-      "description": "Provides the ability to document dependency relationships."
-    }
-  },
-  "definitions": {
-    "metadata": {
-      "type": "object",
-      "title": "BOM Metadata Object",
-      "additionalProperties": false,
-      "properties": {
-        "timestamp": {
-          "type": "string",
-          "format": "date-time",
-          "title": "Timestamp",
-          "description": "The date and time (timestamp) when the document was created."
-        },
-        "tools": {
-          "type": "array",
-          "title": "Creation Tools",
-          "description": "The tool(s) used in the creation of the BOM.",
-          "items": {"$ref": "#/definitions/tool"}
-        },
-        "authors" :{
-          "type": "array",
-          "title": "Authors",
-          "description": "The person(s) who created the BOM. Authors are common in BOMs created through manual processes. BOMs created through automated means may not have authors.",
-          "items": {"$ref": "#/definitions/organizationalContact"}
-        },
-        "component": {
-          "title": "Component",
-          "description": "The component that the BOM describes.",
-          "$ref": "#/definitions/component"
-        },
-        "manufacture": {
-          "title": "Manufacture",
-          "description": "The organization that manufactured the component that the BOM describes.",
-          "$ref": "#/definitions/organizationalEntity"
-        },
-        "supplier": {
-          "title": "Supplier",
-          "description": " The organization that supplied the component that the BOM describes. The supplier may often be the manufacture, but may also be a distributor or repackager.",
-          "$ref": "#/definitions/organizationalEntity"
-        }
-      }
-    },
-    "tool": {
-      "type": "object",
-      "title": "Tool",
-      "description": "The tool used to create the BOM.",
-      "additionalProperties": false,
-      "properties": {
-        "vendor": {
-          "type": "string",
-          "format": "string",
-          "title": "Tool Vendor",
-          "description": "The date and time (timestamp) when the document was created."
-        },
-        "name": {
-          "type": "string",
-          "format": "string",
-          "title": "Tool Name",
-          "description": "The date and time (timestamp) when the document was created."
-        },
-        "version": {
-          "type": "string",
-          "format": "string",
-          "title": "Tool Version",
-          "description": "The date and time (timestamp) when the document was created."
-        },
-        "hashes": {
-          "$id": "#/properties/hashes",
-          "type": "array",
-          "items": {"$ref": "#/definitions/hash"},
-          "title": "Hashes",
-          "description": "The hashes of the tool (if applicable)."
-        }
-      }
-    },
-    "organizationalEntity": {
-      "type": "object",
-      "title": "Organizational Entity Object",
-      "description": "",
-      "additionalProperties": false,
-      "properties": {
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of the organization",
-          "default": "",
-          "examples": [
-            "Example Inc."
-          ],
-          "pattern": "^(.*)$"
-        },
-        "url": {
-          "type": "array",
-          "title": "URL",
-          "description": "The URL of the organization. Multiple URLs are allowed.",
-          "default": "",
-          "examples": ["https://example.com"],
-          "pattern": "^(.*)$"
-        },
-        "contact": {
-          "type": "array",
-          "title": "Contact",
-          "description": "A contact at the organization. Multiple contacts are allowed.",
-          "items": {"$ref": "#/definitions/organizationalContact"}
-        }
-      }
-    },
-    "organizationalContact": {
-      "type": "object",
-      "title": "Organizational Contact Object",
-      "description": "",
-      "additionalProperties": false,
-      "properties": {
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of a contact",
-          "default": "",
-          "examples": ["Contact name"],
-          "pattern": "^(.*)$"
-        },
-        "email": {
-          "type": "string",
-          "title": "Email Address",
-          "description": "The email address of the contact. Multiple email addresses are allowed.",
-          "default": "",
-          "examples": ["firstname.lastname@example.com"],
-          "pattern": "^(.*)$"
-        },
-        "phone": {
-          "type": "string",
-          "title": "Phone",
-          "description": "The phone number of the contact. Multiple phone numbers are allowed.",
-          "default": "",
-          "examples": ["800-555-1212"],
-          "pattern": "^(.*)$"
-        }
-      }
-    },
-    "component": {
-      "type": "object",
-      "title": "Component Object",
-      "required": [
-        "type",
-        "name",
-        "version"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "type": {
-          "type": "string",
-          "enum": [
-            "application",
-            "framework",
-            "library",
-            "container",
-            "operating-system",
-            "device",
-            "firmware",
-            "file"
-          ],
-          "title": "Component Type",
-          "description": "Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component.",
-          "default": "",
-          "examples": ["library"],
-          "pattern": "^(.*)$"
-        },
-        "mime-type": {
-          "type": "string",
-          "title": "Mime-Type",
-          "description": "The optional mime-type of the component. When used on file components, the mime-type can provide additional context about the kind of file being represented such as an image, font, or executable. Some library or framework components may also have an associated mime-type.",
-          "default": "",
-          "examples": ["image/jpeg"],
-          "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
-        },
-        "bom-ref": {
-          "type": "string",
-          "title": "BOM Reference",
-          "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique.",
-          "default": "",
-          "pattern": "^(.*)$"
-        },
-        "supplier": {
-          "title": "Component Supplier",
-          "description": " The organization that supplied the component. The supplier may often be the manufacture, but may also be a distributor or repackager.",
-          "$ref": "#/definitions/organizationalEntity"
-        },
-        "author": {
-          "type": "string",
-          "title": "Component Author",
-          "description": "The person(s) or organization(s) that authored the component",
-          "default": "",
-          "examples": ["Acme Inc"],
-          "pattern": "^(.*)$"
-        },
-        "publisher": {
-          "type": "string",
-          "title": "Component Publisher",
-          "description": "The person(s) or organization(s) that published the component",
-          "default": "",
-          "examples": ["Acme Inc"],
-          "pattern": "^(.*)$"
-        },
-        "group": {
-          "type": "string",
-          "title": "Component Group",
-          "description": "The grouping name or identifier. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. Whitespace and special characters should be avoided. Examples include: apache, org.apache.commons, and apache.org.",
-          "default": "",
-          "examples": ["com.acme"],
-          "pattern": "^(.*)$"
-        },
-        "name": {
-          "type": "string",
-          "title": "Component Name",
-          "description": "The name of the component. This will often be a shortened, single name of the component. Examples: commons-lang3 and jquery",
-          "default": "",
-          "examples": ["tomcat-catalina"],
-          "pattern": "^(.*)$"
-        },
-        "version": {
-          "type": "string",
-          "title": "Component Version",
-          "description": "The component version. The version should ideally comply with semantic versioning but is not enforced.",
-          "default": "",
-          "examples": ["9.0.14"],
-          "pattern": "^(.*)$"
-        },
-        "description": {
-          "type": "string",
-          "title": "Component Description",
-          "description": "Specifies a description for the component",
-          "default": "",
-          "pattern": "^(.*)$"
-        },
-        "scope": {
-          "type": "string",
-          "enum": [
-            "required",
-            "optional",
-            "excluded"
-          ],
-          "title": "Component Scope",
-          "description": "Specifies the scope of the component. If scope is not specified, 'required' scope should be assumed by the consumer of the BOM",
-          "default": "required",
-          "pattern": "^(.*)$"
-        },
-        "hashes": {
-          "type": "array",
-          "title": "Component Hashes",
-          "items": {"$ref": "#/definitions/hash"}
-        },
-        "licenses": {
-          "type": "array",
-          "title": "Component License(s)",
-          "items": {
-            "additionalProperties": false,
-            "properties": {
-              "license": {
-                "$ref": "#/definitions/license"
-              },
-              "expression": {
-                "type": "string",
-                "title": "SPDX License Expression",
-                "examples": [
-                  "Apache-2.0 AND (MIT OR GPL-2.0-only)",
-                  "GPL-3.0-only WITH Classpath-exception-2.0"
-                ],
-                "pattern": "^(.*)$"
-              }
-            },
-            "oneOf":[
-              {
-                "required": ["license"]
-              },
-              {
-                "required": ["expression"]
-              }
-            ]
-          }
-        },
-        "copyright": {
-          "type": "string",
-          "title": "Component Copyright",
-          "description": "An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.",
-          "examples": ["Acme Inc"],
-          "pattern": "^(.*)$"
-        },
-        "cpe": {
-          "type": "string",
-          "title": "Component Common Platform Enumeration (CPE)",
-          "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe",
-          "examples": ["cpe:2.3:a:acme:component_framework:-:*:*:*:*:*:*:*"],
-          "pattern": "^(.*)$"
-        },
-        "purl": {
-          "type": "string",
-          "title": "Component Package URL (purl)",
-          "default": "",
-          "examples": ["pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar"],
-          "pattern": "^(.*)$"
-        },
-        "swid": {
-          "$ref": "#/definitions/swid",
-          "title": "SWID Tag",
-          "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags."
-        },
-        "modified": {
-          "type": "boolean",
-          "title": "Component Modified From Original",
-          "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree element instead to supply information on exactly how the component was modified. A boolean value indicating is the component has been modified from the original. A value of true indicates the component is a derivative of the original. A value of false indicates the component has not been modified from the original."
-        },
-        "pedigree": {
-          "type": "object",
-          "title": "Component Pedigree",
-          "description": "Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to document variants where the exact relation may not be known.",
-          "additionalProperties": false,
-          "properties": {
-            "ancestors": {
-              "type": "array",
-              "title": "Ancestors",
-              "description": "Describes zero or more components in which a component is derived from. This is commonly used to describe forks from existing projects where the forked version contains a ancestor node containing the original component it was forked from. For example, Component A is the original component. Component B is the component being used and documented in the BOM. However, Component B contains a pedigree node with a single ancestor documenting Component A - the original component from which Component B is derived from.",
-              "items": {"$ref": "#/definitions/component"}
-            },
-            "descendants": {
-              "type": "array",
-              "title": "Descendants",
-              "description": "Descendants are the exact opposite of ancestors. This provides a way to document all forks (and their forks) of an original or root component.",
-              "items": {"$ref": "#/definitions/component"}
-            },
-            "variants": {
-              "type": "array",
-              "title": "Variants",
-              "description": "Variants describe relations where the relationship between the components are not known. For example, if Component A contains nearly identical code to Component B. They are both related, but it is unclear if one is derived from the other, or if they share a common ancestor.",
-              "items": {"$ref": "#/definitions/component"}
-            },
-            "commits": {
-              "type": "array",
-              "title": "Commits",
-              "description": "A list of zero or more commits which provide a trail describing how the component deviates from an ancestor, descendant, or variant.",
-              "items": {"$ref": "#/definitions/commit"}
-            },
-            "patches": {
-              "type": "array",
-              "title": "Patches",
-              "description": ">A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits or may be used in place of commits.",
-              "items": {"$ref": "#/definitions/patch"}
-            },
-            "notes": {
-              "type": "string",
-              "title": "Notes",
-              "description": "Notes, observations, and other non-structured commentary describing the components pedigree.",
-              "pattern": "^(.*)$"
-            }
-          }
-        },
-        "externalReferences": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/externalReference"},
-          "title": "External References"
-        },
-        "components": {
-          "$id": "#/properties/components",
-          "type": "array",
-          "items": {"$ref": "#/definitions/component"},
-          "uniqueItems": true,
-          "title": "Components"
-        }
-      }
-    },
-    "swid": {
-      "type": "object",
-      "title": "SWID Tag",
-      "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.",
-      "required": [
-        "tagId",
-        "name"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "tagId": {
-          "type": "string",
-          "title": "Tag ID",
-          "description": "Maps to the tagId of a SoftwareIdentity."
-        },
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "Maps to the name of a SoftwareIdentity."
-        },
-        "version": {
-          "type": "string",
-          "title": "Version",
-          "default": "0.0",
-          "description": "Maps to the version of a SoftwareIdentity."
-        },
-        "tagVersion": {
-          "type": "integer",
-          "title": "Tag Version",
-          "default": 0,
-          "description": "Maps to the tagVersion of a SoftwareIdentity."
-        },
-        "patch": {
-          "type": "boolean",
-          "title": "Patch",
-          "default": false,
-          "description": "Maps to the patch of a SoftwareIdentity."
-        },
-        "text": {
-          "title": "Attachment text",
-          "description": "Specifies the metadata and content of the SWID tag.",
-          "$ref": "#/definitions/attachment"
-        },
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "default": "The URL to the SWID file.",
-          "pattern": "^(.*)$"
-        }
-      }
-    },
-    "attachment": {
-      "type": "object",
-      "title": "Attachment",
-      "description": "Specifies the metadata and content for an attachment.",
-      "required": [
-        "content"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "contentType": {
-          "type": "string",
-          "title": "Content-Type",
-          "description": "Specifies the content type of the text. Defaults to text/plain if not specified.",
-          "default": "text/plain"
-        },
-        "encoding": {
-          "type": "string",
-          "title": "Encoding",
-          "description": "Specifies the optional encoding the text is represented in.",
-          "enum": [
-            "base64"
-          ],
-          "default": "",
-          "pattern": "^(.*)$"
-        },
-        "content": {
-          "type": "string",
-          "title": "Attachment Text",
-          "description": "The attachment data"
-        }
-      }
-    },
-    "hash": {
-      "type": "object",
-      "title": "Hash Objects",
-      "required": [
-        "alg",
-        "content"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "alg": {
-          "$ref": "#/definitions/hash-alg"
-        },
-        "content": {
-          "$ref": "#/definitions/hash-content"
-        }
-      }
-    },
-    "hash-alg": {
-      "type": "string",
-      "enum": [
-        "MD5",
-        "SHA-1",
-        "SHA-256",
-        "SHA-384",
-        "SHA-512",
-        "SHA3-256",
-        "SHA3-384",
-        "SHA3-512",
-        "BLAKE2b-256",
-        "BLAKE2b-384",
-        "BLAKE2b-512",
-        "BLAKE3"
-      ],
-      "title": "Hash Algorithm",
-      "default": "",
-      "pattern": "^(.*)$"
-    },
-    "hash-content": {
-      "type": "string",
-      "title": "Hash Content (value)",
-      "default": "",
-      "examples": ["3942447fac867ae5cdb3229b658f4d48"],
-      "pattern": "^([a-fA-F0-9]{32}|[a-fA-F0-9]{40}|[a-fA-F0-9]{64}|[a-fA-F0-9]{96}|[a-fA-F0-9]{128})$"
-    },
-    "license": {
-      "type": "object",
-      "title": "License Object",
-      "oneOf": [
-        {
-          "required": ["id"]
-        },
-        {
-          "required": ["name"]
-        }
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "id": {
-          "$ref": "spdx.schema.json",
-          "title": "License ID (SPDX)",
-          "description": "A valid SPDX license ID",
-          "examples": ["Apache-2.0"]
-        },
-        "name": {
-          "type": "string",
-          "title": "License Name",
-          "description": "If SPDX does not define the license used, this field may be used to provide the license name",
-          "default": "",
-          "examples": ["Acme Software License"],
-          "pattern": "^(.*)$"
-        },
-        "text": {
-          "title": "License text",
-          "description": "An optional way to include the textual content of a license.",
-          "$ref": "#/definitions/attachment"
-        },
-        "url": {
-          "type": "string",
-          "title": "License URL",
-          "description": "The URL to the license file. If specified, a 'license' externalReference should also be specified for completeness",
-          "examples": ["https://www.apache.org/licenses/LICENSE-2.0.txt"],
-          "pattern": "^(.*)$"
-        }
-      }
-    },
-    "commit": {
-      "type": "object",
-      "title": "Commit",
-      "description": "Specifies an individual commit",
-      "additionalProperties": false,
-      "properties": {
-        "uid": {
-          "type": "string",
-          "title": "UID",
-          "description": "A unique identifier of the commit. This may be version control specific. For example, Subversion uses revision numbers whereas git uses commit hashes.",
-          "pattern": "^(.*)$"
-        },
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "description": "The URL to the commit. This URL will typically point to a commit in a version control system.",
-          "format": "iri-reference"
-        },
-        "author": {
-          "title": "Author",
-          "description": "The author who created the changes in the commit",
-          "$ref": "#/definitions/identifiableAction"
-        },
-        "committer": {
-          "title": "Committer",
-          "description": "The person who committed or pushed the commit",
-          "$ref": "#/definitions/identifiableAction"
-        },
-        "message": {
-          "type": "string",
-          "title": "Message",
-          "description": "The text description of the contents of the commit",
-          "pattern": "^(.*)$"
-        }
-      }
-    },
-    "patch": {
-      "type": "object",
-      "title": "Patch",
-      "description": "Specifies an individual patch",
-      "required": [
-        "type"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "type": {
-          "type": "string",
-          "enum": [
-            "unofficial",
-            "monkey",
-            "backport",
-            "cherry-pick"
-          ],
-          "title": "Type",
-          "description": "Specifies the purpose for the patch including the resolution of defects, security issues, or new behavior or functionality"
-        },
-        "diff": {
-          "title": "Diff",
-          "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
-          "$ref": "#/definitions/diff"
-        },
-        "resolves": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/issue"},
-          "title": "Resolves",
-          "description": "A collection of issues the patch resolves"
-        }
-      }
-    },
-    "diff": {
-      "type": "object",
-      "title": "Diff",
-      "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
-      "additionalProperties": false,
-      "properties": {
-        "text": {
-          "title": "Diff text",
-          "description": "Specifies the optional text of the diff",
-          "$ref": "#/definitions/attachment"
-        },
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "description": "Specifies the URL to the diff",
-          "pattern": "^(.*)$"
-        }
-      }
-    },
-    "issue": {
-      "type": "object",
-      "title": "Diff",
-      "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
-      "required": [
-        "type"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "type": {
-          "type": "string",
-          "enum": [
-            "defect",
-            "enhancement",
-            "security"
-          ],
-          "title": "Type",
-          "description": "Specifies the type of issue"
-        },
-        "id": {
-          "type": "string",
-          "title": "ID",
-          "description": "The identifier of the issue assigned by the source of the issue",
-          "pattern": "^(.*)$"
-        },
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of the issue",
-          "pattern": "^(.*)$"
-        },
-        "description": {
-          "type": "string",
-          "title": "Description",
-          "description": "A description of the issue",
-          "pattern": "^(.*)$"
-        },
-        "source": {
-          "type": "object",
-          "title": "Source",
-          "description": "The source of the issue where it is documented",
-          "additionalProperties": false,
-          "properties": {
-            "name": {
-              "type": "string",
-              "title": "Name",
-              "description": "The name of the source. For example 'National Vulnerability Database', 'NVD', and 'Apache'",
-              "pattern": "^(.*)$"
-            },
-            "url": {
-              "type": "string",
-              "title": "URL",
-              "description": "The url of the issue documentation as provided by the source",
-              "pattern": "^(.*)$"
-            }
-          }
-        },
-        "references": {
-          "type": "array",
-          "title": "References",
-          "description": "A collection of URL's for reference. Multiple URLs are allowed.",
-          "default": "",
-          "examples": ["https://example.com"],
-          "pattern": "^(.*)$"
-        }
-      }
-    },
-    "identifiableAction": {
-      "type": "object",
-      "title": "Identifiable Action",
-      "description": "Specifies an individual commit",
-      "additionalProperties": false,
-      "properties": {
-        "timestamp": {
-          "type": "string",
-          "format": "date-time",
-          "title": "Timestamp",
-          "description": "The timestamp in which the action occurred"
-        },
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of the individual who performed the action",
-          "pattern": "^(.*)$"
-        },
-        "email": {
-          "type": "string",
-          "format": "idn-email",
-          "title": "E-mail",
-          "description": "The email address of the individual who performed the action"
-        }
-      }
-    },
-    "externalReference": {
-      "type": "object",
-      "title": "External Reference",
-      "description": "Specifies an individual external reference",
-      "required": [
-        "url",
-        "type"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "description": "The URL to the external reference",
-          "pattern": "^(.*)$"
-        },
-        "comment": {
-          "type": "string",
-          "title": "Comment",
-          "description": "An optional comment describing the external reference",
-          "pattern": "^(.*)$"
-        },
-        "type": {
-          "type": "string",
-          "title": "Type",
-          "description": "Specifies the type of external reference. There are built-in types to describe common references. If a type does not exist for the reference being referred to, use the \"other\" type.",
-          "enum": [
-            "vcs",
-            "issue-tracker",
-            "website",
-            "advisories",
-            "bom",
-            "mailing-list",
-            "social",
-            "chat",
-            "documentation",
-            "support",
-            "distribution",
-            "license",
-            "build-meta",
-            "build-system",
-            "other"
-          ]
-        }
-      }
-    },
-    "dependency": {
-      "type": "object",
-      "title": "Dependency",
-      "description": "Defines the direct dependencies of a component. Components that do not have their own dependencies MUST be declared as empty elements within the graph. Components that are not represented in the dependency graph MAY have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque and not an indicator of a component being dependency-free.",
-      "required": [
-        "ref"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "ref": {
-          "type": "string",
-          "format": "string",
-          "title": "Reference",
-          "description": "References a component by the components bom-ref attribute"
-        },
-        "dependsOn": {
-          "type": "array",
-          "uniqueItems": true,
-          "items": {
-            "type": "string"
-          },
-          "title": "Depends On",
-          "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
-        }
-      }
-    },
-    "service": {
-      "type": "object",
-      "title": "Service Object",
-      "required": [
-        "name"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "bom-ref": {
-          "type": "string",
-          "title": "BOM Reference",
-          "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique.",
-          "default": "",
-          "pattern": "^(.*)$"
-        },
-        "provider": {
-          "title": "Provider",
-          "description": "The organization that provides the service.",
-          "$ref": "#/definitions/organizationalEntity"
-        },
-        "group": {
-          "type": "string",
-          "title": "Service Group",
-          "description": "The grouping name, namespace, or identifier. This will often be a shortened, single name of the company or project that produced the service or domain name. Whitespace and special characters should be avoided.",
-          "default": "",
-          "examples": ["com.acme"],
-          "pattern": "^(.*)$"
-        },
-        "name": {
-          "type": "string",
-          "title": "Service Name",
-          "description": "The name of the service. This will often be a shortened, single name of the service.",
-          "default": "",
-          "examples": ["ticker-service"],
-          "pattern": "^(.*)$"
-        },
-        "version": {
-          "type": "string",
-          "title": "Service Version",
-          "description": "The service version.",
-          "default": "",
-          "examples": ["1.0.0"],
-          "pattern": "^(.*)$"
-        },
-        "description": {
-          "type": "string",
-          "title": "Service Description",
-          "description": "Specifies a description for the service",
-          "default": "",
-          "pattern": "^(.*)$"
-        },
-        "endpoints": {
-          "type": "array",
-          "title": "Endpoints",
-          "description": "The endpoint URIs of the service. Multiple endpoints are allowed.",
-          "default": "",
-          "examples": ["https://example.com/api/v1/ticker"],
-          "pattern": "^(.*)$"
-        },
-        "authenticated": {
-          "type": "boolean",
-          "title": "Authentication Required",
-          "description": "A boolean value indicating if the service requires authentication. A value of true indicates the service requires authentication prior to use. A value of false indicates the service does not require authentication."
-        },
-        "x-trust-boundary": {
-          "type": "boolean",
-          "title": "Crosses Trust Boundary",
-          "description": "A boolean value indicating if use of the service crosses a trust zone or boundary. A value of true indicates that by using the service, a trust boundary is crossed. A value of false indicates that by using the service, a trust boundary is not crossed."
-        },
-        "data": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/dataClassification"},
-          "title": "Data Classification",
-          "description": "Specifies the data classification."
-        },
-        "licenses": {
-          "type": "array",
-          "title": "Component License(s)",
-          "items": {
-            "additionalProperties": false,
-            "properties": {
-              "license": {
-                "$ref": "#/definitions/license"
-              },
-              "expression": {
-                "type": "string",
-                "title": "SPDX License Expression",
-                "examples": [
-                  "Apache-2.0 AND (MIT OR GPL-2.0-only)",
-                  "GPL-3.0-only WITH Classpath-exception-2.0"
-                ],
-                "pattern": "^(.*)$"
-              }
-            },
-            "oneOf":[
-              {
-                "required": ["license"]
-              },
-              {
-                "required": ["expression"]
-              }
-            ]
-          }
-        },
-        "externalReferences": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/externalReference"},
-          "title": "External References"
-        },
-        "services": {
-          "$id": "#/properties/services",
-          "type": "array",
-          "items": {"$ref": "#/definitions/service"},
-          "uniqueItems": true,
-          "title": "Services"
-        }
-      }
-    },
-    "dataClassification": {
-      "type": "object",
-      "title": "Hash Objects",
-      "required": [
-        "flow",
-        "classification"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "flow": {
-          "$ref": "#/definitions/dataFlow"
-        },
-        "classification": {
-          "type": "string"
-        }
-      }
-    },
-    "dataFlow": {
-      "type": "string",
-      "enum": [
-        "inbound",
-        "outbound",
-        "bi-directional",
-        "unknown"
-      ],
-      "title": "Data flow direction",
-      "default": "",
-      "pattern": "^(.*)$"
-    }
-  }
-}
diff --git a/cyclonedx/schema/bom-1.3-strict.schema.json b/cyclonedx/schema/bom-1.3-strict.schema.json
deleted file mode 100644
index 35c8c2e5e..000000000
--- a/cyclonedx/schema/bom-1.3-strict.schema.json
+++ /dev/null
@@ -1,1085 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-07/schema#",
-  "$id": "http://cyclonedx.org/schema/bom-1.3.schema.json",
-  "type": "object",
-  "title": "CycloneDX Software Bill-of-Material Specification",
-  "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
-  "required": [
-    "bomFormat",
-    "specVersion",
-    "version"
-  ],
-  "additionalProperties": false,
-  "properties": {
-    "$schema": {
-      "type": "string",
-      "enum": [
-        "http://cyclonedx.org/schema/bom-1.3.schema.json"
-      ]
-    },
-    "bomFormat": {
-      "$id": "#/properties/bomFormat",
-      "type": "string",
-      "title": "BOM Format",
-      "description": "Specifies the format of the BOM. This helps to identify the file as CycloneDX since BOMs do not have a filename convention nor does JSON schema support namespaces.",
-      "enum": [
-        "CycloneDX"
-      ]
-    },
-    "specVersion": {
-      "$id": "#/properties/specVersion",
-      "type": "string",
-      "title": "CycloneDX Specification Version",
-      "description": "The version of the CycloneDX specification a BOM is written to (starting at version 1.2)",
-      "examples": ["1.3"]
-    },
-    "serialNumber": {
-      "$id": "#/properties/serialNumber",
-      "type": "string",
-      "title": "BOM Serial Number",
-      "description": "Every BOM generated should have a unique serial number, even if the contents of the BOM being generated have not changed over time. The process or tool responsible for creating the BOM should create random UUID's for every BOM generated.",
-      "examples": ["urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"],
-      "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
-    },
-    "version": {
-      "$id": "#/properties/version",
-      "type": "integer",
-      "title": "BOM Version",
-      "description": "The version allows component publishers/authors to make changes to existing BOMs to update various aspects of the document such as description or licenses. When a system is presented with multiple BOMs for the same component, the system should use the most recent version of the BOM. The default version is '1' and should be incremented for each version of the BOM that is published. Each version of a component should have a unique BOM and if no changes are made to the BOMs, then each BOM will have a version of '1'.",
-      "default": 1,
-      "examples": [1]
-    },
-    "metadata": {
-      "$id": "#/properties/metadata",
-      "$ref": "#/definitions/metadata",
-      "title": "BOM Metadata",
-      "description": "Provides additional information about a BOM."
-    },
-    "components": {
-      "$id": "#/properties/components",
-      "type": "array",
-      "items": {"$ref": "#/definitions/component"},
-      "uniqueItems": true,
-      "title": "Components"
-    },
-    "services": {
-      "$id": "#/properties/services",
-      "type": "array",
-      "items": {"$ref": "#/definitions/service"},
-      "uniqueItems": true,
-      "title": "Services"
-    },
-    "externalReferences": {
-      "$id": "#/properties/externalReferences",
-      "type": "array",
-      "items": {"$ref": "#/definitions/externalReference"},
-      "title": "External References",
-      "description": "External references provide a way to document systems, sites, and information that may be relevant but which are not included with the BOM."
-    },
-    "dependencies": {
-      "$id": "#/properties/dependencies",
-      "type": "array",
-      "items": {"$ref": "#/definitions/dependency"},
-      "uniqueItems": true,
-      "title": "Dependencies",
-      "description": "Provides the ability to document dependency relationships."
-    },
-    "compositions": {
-      "$id": "#/properties/compositions",
-      "type": "array",
-      "items": {"$ref": "#/definitions/compositions"},
-      "uniqueItems": true,
-      "title": "Compositions",
-      "description": "Compositions describe constituent parts (including components, services, and dependency relationships) and their completeness."
-    }
-  },
-  "definitions": {
-    "metadata": {
-      "type": "object",
-      "title": "BOM Metadata Object",
-      "additionalProperties": false,
-      "properties": {
-        "timestamp": {
-          "type": "string",
-          "format": "date-time",
-          "title": "Timestamp",
-          "description": "The date and time (timestamp) when the document was created."
-        },
-        "tools": {
-          "type": "array",
-          "title": "Creation Tools",
-          "description": "The tool(s) used in the creation of the BOM.",
-          "items": {"$ref": "#/definitions/tool"}
-        },
-        "authors" :{
-          "type": "array",
-          "title": "Authors",
-          "description": "The person(s) who created the BOM. Authors are common in BOMs created through manual processes. BOMs created through automated means may not have authors.",
-          "items": {"$ref": "#/definitions/organizationalContact"}
-        },
-        "component": {
-          "title": "Component",
-          "description": "The component that the BOM describes.",
-          "$ref": "#/definitions/component"
-        },
-        "manufacture": {
-          "title": "Manufacture",
-          "description": "The organization that manufactured the component that the BOM describes.",
-          "$ref": "#/definitions/organizationalEntity"
-        },
-        "supplier": {
-          "title": "Supplier",
-          "description": " The organization that supplied the component that the BOM describes. The supplier may often be the manufacturer, but may also be a distributor or repackager.",
-          "$ref": "#/definitions/organizationalEntity"
-        },
-        "licenses": {
-          "type": "array",
-          "title": "BOM License(s)",
-          "items": {"$ref": "#/definitions/licenseChoice"}
-        },
-        "properties": {
-          "type": "array",
-          "title": "Properties",
-          "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
-          "items": {"$ref": "#/definitions/property"}
-        }
-      }
-    },
-    "tool": {
-      "type": "object",
-      "title": "Tool",
-      "description": "The tool used to create the BOM.",
-      "additionalProperties": false,
-      "properties": {
-        "vendor": {
-          "type": "string",
-          "title": "Tool Vendor",
-          "description": "The date and time (timestamp) when the document was created."
-        },
-        "name": {
-          "type": "string",
-          "title": "Tool Name",
-          "description": "The date and time (timestamp) when the document was created."
-        },
-        "version": {
-          "type": "string",
-          "title": "Tool Version",
-          "description": "The date and time (timestamp) when the document was created."
-        },
-        "hashes": {
-          "$id": "#/properties/hashes",
-          "type": "array",
-          "items": {"$ref": "#/definitions/hash"},
-          "title": "Hashes",
-          "description": "The hashes of the tool (if applicable)."
-        }
-      }
-    },
-    "organizationalEntity": {
-      "type": "object",
-      "title": "Organizational Entity Object",
-      "description": "",
-      "additionalProperties": false,
-      "properties": {
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of the organization",
-          "examples": [
-            "Example Inc."
-          ]
-        },
-        "url": {
-          "type": "array",
-          "items": {
-            "type": "string",
-            "format": "iri-reference"
-          },
-          "title": "URL",
-          "description": "The URL of the organization. Multiple URLs are allowed.",
-          "examples": ["https://example.com"]
-        },
-        "contact": {
-          "type": "array",
-          "title": "Contact",
-          "description": "A contact at the organization. Multiple contacts are allowed.",
-          "items": {"$ref": "#/definitions/organizationalContact"}
-        }
-      }
-    },
-    "organizationalContact": {
-      "type": "object",
-      "title": "Organizational Contact Object",
-      "description": "",
-      "additionalProperties": false,
-      "properties": {
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of a contact",
-          "examples": ["Contact name"]
-        },
-        "email": {
-          "type": "string",
-          "title": "Email Address",
-          "description": "The email address of the contact.",
-          "examples": ["firstname.lastname@example.com"]
-        },
-        "phone": {
-          "type": "string",
-          "title": "Phone",
-          "description": "The phone number of the contact.",
-          "examples": ["800-555-1212"]
-        }
-      }
-    },
-    "component": {
-      "type": "object",
-      "title": "Component Object",
-      "required": [
-        "type",
-        "name",
-        "version"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "type": {
-          "type": "string",
-          "enum": [
-            "application",
-            "framework",
-            "library",
-            "container",
-            "operating-system",
-            "device",
-            "firmware",
-            "file"
-          ],
-          "title": "Component Type",
-          "description": "Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component.",
-          "examples": ["library"]
-        },
-        "mime-type": {
-          "type": "string",
-          "title": "Mime-Type",
-          "description": "The optional mime-type of the component. When used on file components, the mime-type can provide additional context about the kind of file being represented such as an image, font, or executable. Some library or framework components may also have an associated mime-type.",
-          "examples": ["image/jpeg"],
-          "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
-        },
-        "bom-ref": {
-          "type": "string",
-          "title": "BOM Reference",
-          "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique."
-        },
-        "supplier": {
-          "title": "Component Supplier",
-          "description": " The organization that supplied the component. The supplier may often be the manufacturer, but may also be a distributor or repackager.",
-          "$ref": "#/definitions/organizationalEntity"
-        },
-        "author": {
-          "type": "string",
-          "title": "Component Author",
-          "description": "The person(s) or organization(s) that authored the component",
-          "examples": ["Acme Inc"]
-        },
-        "publisher": {
-          "type": "string",
-          "title": "Component Publisher",
-          "description": "The person(s) or organization(s) that published the component",
-          "examples": ["Acme Inc"]
-        },
-        "group": {
-          "type": "string",
-          "title": "Component Group",
-          "description": "The grouping name or identifier. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. Whitespace and special characters should be avoided. Examples include: apache, org.apache.commons, and apache.org.",
-          "examples": ["com.acme"]
-        },
-        "name": {
-          "type": "string",
-          "title": "Component Name",
-          "description": "The name of the component. This will often be a shortened, single name of the component. Examples: commons-lang3 and jquery",
-          "examples": ["tomcat-catalina"]
-        },
-        "version": {
-          "type": "string",
-          "title": "Component Version",
-          "description": "The component version. The version should ideally comply with semantic versioning but is not enforced.",
-          "examples": ["9.0.14"]
-        },
-        "description": {
-          "type": "string",
-          "title": "Component Description",
-          "description": "Specifies a description for the component"
-        },
-        "scope": {
-          "type": "string",
-          "enum": [
-            "required",
-            "optional",
-            "excluded"
-          ],
-          "title": "Component Scope",
-          "description": "Specifies the scope of the component. If scope is not specified, 'required' scope should be assumed by the consumer of the BOM",
-          "default": "required"
-        },
-        "hashes": {
-          "type": "array",
-          "title": "Component Hashes",
-          "items": {"$ref": "#/definitions/hash"}
-        },
-        "licenses": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/licenseChoice"},
-          "title": "Component License(s)"
-        },
-        "copyright": {
-          "type": "string",
-          "title": "Component Copyright",
-          "description": "An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.",
-          "examples": ["Acme Inc"]
-        },
-        "cpe": {
-          "type": "string",
-          "title": "Component Common Platform Enumeration (CPE)",
-          "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe",
-          "examples": ["cpe:2.3:a:acme:component_framework:-:*:*:*:*:*:*:*"]
-        },
-        "purl": {
-          "type": "string",
-          "title": "Component Package URL (purl)",
-          "examples": ["pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar"]
-        },
-        "swid": {
-          "$ref": "#/definitions/swid",
-          "title": "SWID Tag",
-          "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags."
-        },
-        "modified": {
-          "type": "boolean",
-          "title": "Component Modified From Original",
-          "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree element instead to supply information on exactly how the component was modified. A boolean value indicating is the component has been modified from the original. A value of true indicates the component is a derivative of the original. A value of false indicates the component has not been modified from the original."
-        },
-        "pedigree": {
-          "type": "object",
-          "title": "Component Pedigree",
-          "description": "Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to document variants where the exact relation may not be known.",
-          "additionalProperties": false,
-          "properties": {
-            "ancestors": {
-              "type": "array",
-              "title": "Ancestors",
-              "description": "Describes zero or more components in which a component is derived from. This is commonly used to describe forks from existing projects where the forked version contains a ancestor node containing the original component it was forked from. For example, Component A is the original component. Component B is the component being used and documented in the BOM. However, Component B contains a pedigree node with a single ancestor documenting Component A - the original component from which Component B is derived from.",
-              "items": {"$ref": "#/definitions/component"}
-            },
-            "descendants": {
-              "type": "array",
-              "title": "Descendants",
-              "description": "Descendants are the exact opposite of ancestors. This provides a way to document all forks (and their forks) of an original or root component.",
-              "items": {"$ref": "#/definitions/component"}
-            },
-            "variants": {
-              "type": "array",
-              "title": "Variants",
-              "description": "Variants describe relations where the relationship between the components are not known. For example, if Component A contains nearly identical code to Component B. They are both related, but it is unclear if one is derived from the other, or if they share a common ancestor.",
-              "items": {"$ref": "#/definitions/component"}
-            },
-            "commits": {
-              "type": "array",
-              "title": "Commits",
-              "description": "A list of zero or more commits which provide a trail describing how the component deviates from an ancestor, descendant, or variant.",
-              "items": {"$ref": "#/definitions/commit"}
-            },
-            "patches": {
-              "type": "array",
-              "title": "Patches",
-              "description": ">A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits or may be used in place of commits.",
-              "items": {"$ref": "#/definitions/patch"}
-            },
-            "notes": {
-              "type": "string",
-              "title": "Notes",
-              "description": "Notes, observations, and other non-structured commentary describing the components pedigree."
-            }
-          }
-        },
-        "externalReferences": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/externalReference"},
-          "title": "External References"
-        },
-        "components": {
-          "$id": "#/properties/components",
-          "type": "array",
-          "items": {"$ref": "#/definitions/component"},
-          "uniqueItems": true,
-          "title": "Components"
-        },
-        "evidence": {
-          "$ref": "#/definitions/componentEvidence",
-          "title": "Evidence",
-          "description": "Provides the ability to document evidence collected through various forms of extraction or analysis."
-        },
-        "properties": {
-          "type": "array",
-          "title": "Properties",
-          "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
-          "items": {"$ref": "#/definitions/property"}
-        }
-      }
-    },
-    "swid": {
-      "type": "object",
-      "title": "SWID Tag",
-      "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.",
-      "required": [
-        "tagId",
-        "name"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "tagId": {
-          "type": "string",
-          "title": "Tag ID",
-          "description": "Maps to the tagId of a SoftwareIdentity."
-        },
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "Maps to the name of a SoftwareIdentity."
-        },
-        "version": {
-          "type": "string",
-          "title": "Version",
-          "default": "0.0",
-          "description": "Maps to the version of a SoftwareIdentity."
-        },
-        "tagVersion": {
-          "type": "integer",
-          "title": "Tag Version",
-          "default": 0,
-          "description": "Maps to the tagVersion of a SoftwareIdentity."
-        },
-        "patch": {
-          "type": "boolean",
-          "title": "Patch",
-          "default": false,
-          "description": "Maps to the patch of a SoftwareIdentity."
-        },
-        "text": {
-          "title": "Attachment text",
-          "description": "Specifies the metadata and content of the SWID tag.",
-          "$ref": "#/definitions/attachment"
-        },
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "description": "The URL to the SWID file.",
-          "format": "iri-reference"
-        }
-      }
-    },
-    "attachment": {
-      "type": "object",
-      "title": "Attachment",
-      "description": "Specifies the metadata and content for an attachment.",
-      "required": [
-        "content"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "contentType": {
-          "type": "string",
-          "title": "Content-Type",
-          "description": "Specifies the content type of the text. Defaults to text/plain if not specified.",
-          "default": "text/plain"
-        },
-        "encoding": {
-          "type": "string",
-          "title": "Encoding",
-          "description": "Specifies the optional encoding the text is represented in.",
-          "enum": [
-            "base64"
-          ]
-        },
-        "content": {
-          "type": "string",
-          "title": "Attachment Text",
-          "description": "The attachment data"
-        }
-      }
-    },
-    "hash": {
-      "type": "object",
-      "title": "Hash Objects",
-      "required": [
-        "alg",
-        "content"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "alg": {
-          "$ref": "#/definitions/hash-alg"
-        },
-        "content": {
-          "$ref": "#/definitions/hash-content"
-        }
-      }
-    },
-    "hash-alg": {
-      "type": "string",
-      "enum": [
-        "MD5",
-        "SHA-1",
-        "SHA-256",
-        "SHA-384",
-        "SHA-512",
-        "SHA3-256",
-        "SHA3-384",
-        "SHA3-512",
-        "BLAKE2b-256",
-        "BLAKE2b-384",
-        "BLAKE2b-512",
-        "BLAKE3"
-      ],
-      "title": "Hash Algorithm"
-    },
-    "hash-content": {
-      "type": "string",
-      "title": "Hash Content (value)",
-      "examples": ["3942447fac867ae5cdb3229b658f4d48"],
-      "pattern": "^([a-fA-F0-9]{32}|[a-fA-F0-9]{40}|[a-fA-F0-9]{64}|[a-fA-F0-9]{96}|[a-fA-F0-9]{128})$"
-    },
-    "license": {
-      "type": "object",
-      "title": "License Object",
-      "oneOf": [
-        {
-          "required": ["id"]
-        },
-        {
-          "required": ["name"]
-        }
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "id": {
-          "$ref": "spdx.schema.json",
-          "title": "License ID (SPDX)",
-          "description": "A valid SPDX license ID",
-          "examples": ["Apache-2.0"]
-        },
-        "name": {
-          "type": "string",
-          "title": "License Name",
-          "description": "If SPDX does not define the license used, this field may be used to provide the license name",
-          "examples": ["Acme Software License"]
-        },
-        "text": {
-          "title": "License text",
-          "description": "An optional way to include the textual content of a license.",
-          "$ref": "#/definitions/attachment"
-        },
-        "url": {
-          "type": "string",
-          "title": "License URL",
-          "description": "The URL to the license file. If specified, a 'license' externalReference should also be specified for completeness",
-          "examples": ["https://www.apache.org/licenses/LICENSE-2.0.txt"],
-          "format": "iri-reference"
-        }
-      }
-    },
-    "licenseChoice": {
-      "type": "object",
-      "title": "License(s)",
-      "additionalProperties": false,
-      "properties": {
-        "license": {
-          "$ref": "#/definitions/license"
-        },
-        "expression": {
-          "type": "string",
-          "title": "SPDX License Expression",
-          "examples": [
-            "Apache-2.0 AND (MIT OR GPL-2.0-only)",
-            "GPL-3.0-only WITH Classpath-exception-2.0"
-          ]
-        }
-      },
-      "oneOf":[
-        {
-          "required": ["license"]
-        },
-        {
-          "required": ["expression"]
-        }
-      ]
-    },
-    "commit": {
-      "type": "object",
-      "title": "Commit",
-      "description": "Specifies an individual commit",
-      "additionalProperties": false,
-      "properties": {
-        "uid": {
-          "type": "string",
-          "title": "UID",
-          "description": "A unique identifier of the commit. This may be version control specific. For example, Subversion uses revision numbers whereas git uses commit hashes."
-        },
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "description": "The URL to the commit. This URL will typically point to a commit in a version control system.",
-          "format": "iri-reference"
-        },
-        "author": {
-          "title": "Author",
-          "description": "The author who created the changes in the commit",
-          "$ref": "#/definitions/identifiableAction"
-        },
-        "committer": {
-          "title": "Committer",
-          "description": "The person who committed or pushed the commit",
-          "$ref": "#/definitions/identifiableAction"
-        },
-        "message": {
-          "type": "string",
-          "title": "Message",
-          "description": "The text description of the contents of the commit"
-        }
-      }
-    },
-    "patch": {
-      "type": "object",
-      "title": "Patch",
-      "description": "Specifies an individual patch",
-      "required": [
-        "type"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "type": {
-          "type": "string",
-          "enum": [
-            "unofficial",
-            "monkey",
-            "backport",
-            "cherry-pick"
-          ],
-          "title": "Type",
-          "description": "Specifies the purpose for the patch including the resolution of defects, security issues, or new behavior or functionality"
-        },
-        "diff": {
-          "title": "Diff",
-          "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
-          "$ref": "#/definitions/diff"
-        },
-        "resolves": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/issue"},
-          "title": "Resolves",
-          "description": "A collection of issues the patch resolves"
-        }
-      }
-    },
-    "diff": {
-      "type": "object",
-      "title": "Diff",
-      "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
-      "additionalProperties": false,
-      "properties": {
-        "text": {
-          "title": "Diff text",
-          "description": "Specifies the optional text of the diff",
-          "$ref": "#/definitions/attachment"
-        },
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "description": "Specifies the URL to the diff",
-          "format": "iri-reference"
-        }
-      }
-    },
-    "issue": {
-      "type": "object",
-      "title": "Diff",
-      "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
-      "required": [
-        "type"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "type": {
-          "type": "string",
-          "enum": [
-            "defect",
-            "enhancement",
-            "security"
-          ],
-          "title": "Type",
-          "description": "Specifies the type of issue"
-        },
-        "id": {
-          "type": "string",
-          "title": "ID",
-          "description": "The identifier of the issue assigned by the source of the issue"
-        },
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of the issue"
-        },
-        "description": {
-          "type": "string",
-          "title": "Description",
-          "description": "A description of the issue"
-        },
-        "source": {
-          "type": "object",
-          "title": "Source",
-          "description": "The source of the issue where it is documented",
-          "additionalProperties": false,
-          "properties": {
-            "name": {
-              "type": "string",
-              "title": "Name",
-              "description": "The name of the source. For example 'National Vulnerability Database', 'NVD', and 'Apache'"
-            },
-            "url": {
-              "type": "string",
-              "title": "URL",
-              "description": "The url of the issue documentation as provided by the source",
-              "format": "iri-reference"
-            }
-          }
-        },
-        "references": {
-          "type": "array",
-          "items": {
-            "type": "string",
-            "format": "iri-reference"
-          },
-          "title": "References",
-          "description": "A collection of URL's for reference. Multiple URLs are allowed.",
-          "examples": ["https://example.com"]
-        }
-      }
-    },
-    "identifiableAction": {
-      "type": "object",
-      "title": "Identifiable Action",
-      "description": "Specifies an individual commit",
-      "additionalProperties": false,
-      "properties": {
-        "timestamp": {
-          "type": "string",
-          "format": "date-time",
-          "title": "Timestamp",
-          "description": "The timestamp in which the action occurred"
-        },
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of the individual who performed the action"
-        },
-        "email": {
-          "type": "string",
-          "format": "idn-email",
-          "title": "E-mail",
-          "description": "The email address of the individual who performed the action"
-        }
-      }
-    },
-    "externalReference": {
-      "type": "object",
-      "title": "External Reference",
-      "description": "Specifies an individual external reference",
-      "required": [
-        "url",
-        "type"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "description": "The URL to the external reference",
-          "format": "iri-reference"
-        },
-        "comment": {
-          "type": "string",
-          "title": "Comment",
-          "description": "An optional comment describing the external reference"
-        },
-        "type": {
-          "type": "string",
-          "title": "Type",
-          "description": "Specifies the type of external reference. There are built-in types to describe common references. If a type does not exist for the reference being referred to, use the \"other\" type.",
-          "enum": [
-            "vcs",
-            "issue-tracker",
-            "website",
-            "advisories",
-            "bom",
-            "mailing-list",
-            "social",
-            "chat",
-            "documentation",
-            "support",
-            "distribution",
-            "license",
-            "build-meta",
-            "build-system",
-            "other"
-          ]
-        },
-        "hashes": {
-          "$id": "#/properties/hashes",
-          "type": "array",
-          "items": {"$ref": "#/definitions/hash"},
-          "title": "Hashes",
-          "description": "The hashes of the external reference (if applicable)."
-        }
-      }
-    },
-    "dependency": {
-      "type": "object",
-      "title": "Dependency",
-      "description": "Defines the direct dependencies of a component. Components that do not have their own dependencies MUST be declared as empty elements within the graph. Components that are not represented in the dependency graph MAY have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque and not an indicator of a component being dependency-free.",
-      "required": [
-        "ref"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "ref": {
-          "type": "string",
-          "title": "Reference",
-          "description": "References a component by the components bom-ref attribute"
-        },
-        "dependsOn": {
-          "type": "array",
-          "uniqueItems": true,
-          "items": {
-            "type": "string"
-          },
-          "title": "Depends On",
-          "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
-        }
-      }
-    },
-    "service": {
-      "type": "object",
-      "title": "Service Object",
-      "required": [
-        "name"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "bom-ref": {
-          "type": "string",
-          "title": "BOM Reference",
-          "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique."
-        },
-        "provider": {
-          "title": "Provider",
-          "description": "The organization that provides the service.",
-          "$ref": "#/definitions/organizationalEntity"
-        },
-        "group": {
-          "type": "string",
-          "title": "Service Group",
-          "description": "The grouping name, namespace, or identifier. This will often be a shortened, single name of the company or project that produced the service or domain name. Whitespace and special characters should be avoided.",
-          "examples": ["com.acme"]
-        },
-        "name": {
-          "type": "string",
-          "title": "Service Name",
-          "description": "The name of the service. This will often be a shortened, single name of the service.",
-          "examples": ["ticker-service"]
-        },
-        "version": {
-          "type": "string",
-          "title": "Service Version",
-          "description": "The service version.",
-          "examples": ["1.0.0"]
-        },
-        "description": {
-          "type": "string",
-          "title": "Service Description",
-          "description": "Specifies a description for the service"
-        },
-        "endpoints": {
-          "type": "array",
-          "items": {
-            "type": "string",
-            "format": "iri-reference"
-          },
-          "title": "Endpoints",
-          "description": "The endpoint URIs of the service. Multiple endpoints are allowed.",
-          "examples": ["https://example.com/api/v1/ticker"]
-        },
-        "authenticated": {
-          "type": "boolean",
-          "title": "Authentication Required",
-          "description": "A boolean value indicating if the service requires authentication. A value of true indicates the service requires authentication prior to use. A value of false indicates the service does not require authentication."
-        },
-        "x-trust-boundary": {
-          "type": "boolean",
-          "title": "Crosses Trust Boundary",
-          "description": "A boolean value indicating if use of the service crosses a trust zone or boundary. A value of true indicates that by using the service, a trust boundary is crossed. A value of false indicates that by using the service, a trust boundary is not crossed."
-        },
-        "data": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/dataClassification"},
-          "title": "Data Classification",
-          "description": "Specifies the data classification."
-        },
-        "licenses": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/licenseChoice"},
-          "title": "Component License(s)"
-        },
-        "externalReferences": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/externalReference"},
-          "title": "External References"
-        },
-        "services": {
-          "$id": "#/properties/services",
-          "type": "array",
-          "items": {"$ref": "#/definitions/service"},
-          "uniqueItems": true,
-          "title": "Services"
-        },
-        "properties": {
-          "type": "array",
-          "title": "Properties",
-          "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
-          "items": {"$ref": "#/definitions/property"}
-        }
-      }
-    },
-    "dataClassification": {
-      "type": "object",
-      "title": "Hash Objects",
-      "required": [
-        "flow",
-        "classification"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "flow": {
-          "$ref": "#/definitions/dataFlow"
-        },
-        "classification": {
-          "type": "string"
-        }
-      }
-    },
-    "dataFlow": {
-      "type": "string",
-      "enum": [
-        "inbound",
-        "outbound",
-        "bi-directional",
-        "unknown"
-      ],
-      "title": "Data flow direction"
-    },
-
-    "copyright": {
-      "type": "object",
-      "title": "Copyright",
-      "required": [
-        "text"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "text": {
-          "type": "string",
-          "title": "Copyright Text"
-        }
-      }
-    },
-
-    "componentEvidence": {
-      "type": "object",
-      "title": "Evidence",
-      "description": "Provides the ability to document evidence collected through various forms of extraction or analysis.",
-      "additionalProperties": false,
-      "properties": {
-        "licenses": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/licenseChoice"},
-          "title": "Component License(s)"
-        },
-        "copyright": {
-          "type": "array",
-          "items": {"$ref": "#/definitions/copyright"},
-          "title": "Copyright"
-        }
-      }
-    },
-    "compositions": {
-      "type": "object",
-      "title": "Compositions",
-      "required": [
-        "aggregate"
-      ],
-      "additionalProperties": false,
-      "properties": {
-        "aggregate": {
-          "$ref": "#/definitions/aggregateType",
-          "title": "Aggregate",
-          "description": "Specifies an aggregate type that describe how complete a relationship is."
-        },
-        "assemblies": {
-          "type": "array",
-          "uniqueItems": true,
-          "items": {
-            "type": "string"
-          },
-          "title": "BOM references",
-          "description": "The bom-ref identifiers of the components or services being described. Assemblies refer to nested relationships whereby a constituent part may include other constituent parts. References do not cascade to child parts. References are explicit for the specified constituent part only."
-        },
-        "dependencies": {
-          "type": "array",
-          "uniqueItems": true,
-          "items": {
-            "type": "string"
-          },
-          "title": "BOM references",
-          "description": "The bom-ref identifiers of the components or services being described. Dependencies refer to a relationship whereby an independent constituent part requires another independent constituent part. References do not cascade to transitive dependencies. References are explicit for the specified dependency only."
-        }
-      }
-    },
-    "aggregateType": {
-      "type": "string",
-      "default": "not_specified",
-      "enum": [
-        "complete",
-        "incomplete",
-        "incomplete_first_party_only",
-        "incomplete_third_party_only",
-        "unknown",
-        "not_specified"
-      ]
-    },
-    "property": {
-      "type": "object",
-      "title": "Lightweight name-value pair",
-      "properties": {
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of the property. Duplicate names are allowed, each potentially having a different value."
-        },
-        "value": {
-          "type": "string",
-          "title": "Value",
-          "description": "The value of the property."
-        }
-      }
-    }
-  }
-}
\ No newline at end of file
diff --git a/cyclonedx/schema/bom-1.3.proto b/cyclonedx/schema/bom-1.3.proto
deleted file mode 100644
index 5c9926b20..000000000
--- a/cyclonedx/schema/bom-1.3.proto
+++ /dev/null
@@ -1,452 +0,0 @@
-syntax = "proto3";
-package cyclonedx.v1_3;
-import "google/protobuf/timestamp.proto";
-
-// Specifies attributes of the text
-message AttachedText {
-  // Specifies the content type of the text. Defaults to text/plain if not specified.
-  optional string content_type = 1;
-  // Specifies the optional encoding the text is represented in
-  optional string encoding = 2;
-  // SimpleContent value of element
-  string value = 3;
-}
-
-message Bom {
-  // The version of the CycloneDX specification a BOM is written to (starting at version 1.3)
-  string spec_version = 1;
-  // The version allows component publishers/authors to make changes to existing BOMs to update various aspects of the document such as description or licenses. When a system is presented with multiple BOMs for the same component, the system should use the most recent version of the BOM. The default version is '1' and should be incremented for each version of the BOM that is published. Each version of a component should have a unique BOM and if no changes are made to the BOMs, then each BOM will have a version of '1'.
-  optional int32 version = 2;
-  // Every BOM generated should have a unique serial number, even if the contents of the BOM being generated have not changed over time. The process or tool responsible for creating the BOM should create random UUID's for every BOM generated.
-  optional string serial_number = 3;
-  // Provides additional information about a BOM.
-  optional Metadata metadata = 4;
-  // Provides the ability to document a list of components.
-  repeated Component components = 5;
-  // Provides the ability to document a list of external services.
-  repeated Service services = 6;
-  // Provides the ability to document external references related to the BOM or to the project the BOM describes.
-  repeated ExternalReference external_references = 7;
-  // Provides the ability to document dependency relationships.
-  repeated Dependency dependencies = 8;
-  // Provides the ability to document aggregate completeness
-  repeated Composition compositions = 9;
-}
-
-enum Classification {
-  CLASSIFICATION_NULL = 0;
-  // A software application. Refer to https://en.wikipedia.org/wiki/Application_software for information about applications.
-  CLASSIFICATION_APPLICATION = 1;
-  // A software framework. Refer to https://en.wikipedia.org/wiki/Software_framework for information on how frameworks vary slightly from libraries.
-  CLASSIFICATION_FRAMEWORK = 2;
-  // A software library. Refer to https://en.wikipedia.org/wiki/Library_(computing) for information about libraries. All third-party and open source reusable components will likely be a library. If the library also has key features of a framework, then it should be classified as a framework. If not, or is unknown, then specifying library is recommended.
-  CLASSIFICATION_LIBRARY = 3;
-  // A software operating system without regard to deployment model (i.e. installed on physical hardware, virtual machine, image, etc) Refer to https://en.wikipedia.org/wiki/Operating_system
-  CLASSIFICATION_OPERATING_SYSTEM = 4;
-  // A hardware device such as a processor, or chip-set. A hardware device containing firmware should include a component for the physical hardware itself, and another component of type 'firmware' or 'operating-system' (whichever is relevant), describing information about the software running on the device.
-  CLASSIFICATION_DEVICE = 5;
-  // A computer file. Refer to https://en.wikipedia.org/wiki/Computer_file for information about files.
-  CLASSIFICATION_FILE = 6;
-  // A packaging and/or runtime format, not specific to any particular technology, which isolates software inside the container from software outside of a container through virtualization technology. Refer to https://en.wikipedia.org/wiki/OS-level_virtualization
-  CLASSIFICATION_CONTAINER = 7;
-  // A special type of software that provides low-level control over a devices hardware. Refer to https://en.wikipedia.org/wiki/Firmware
-  CLASSIFICATION_FIRMWARE = 8;
-}
-
-message Commit {
-  // A unique identifier of the commit. This may be version control specific. For example, Subversion uses revision numbers whereas git uses commit hashes.
-  optional string uid = 1;
-  // The URL to the commit. This URL will typically point to a commit in a version control system.
-  optional string url = 2;
-  // The author who created the changes in the commit
-  optional IdentifiableAction author = 3;
-  // The person who committed or pushed the commit
-  optional IdentifiableAction committer = 4;
-  // The text description of the contents of the commit
-  optional string message = 5;
-}
-
-message Component {
-  // Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component.
-  Classification type = 1;
-  // The optional mime-type of the component. When used on file components, the mime-type can provide additional context about the kind of file being represented such as an image, font, or executable. Some library or framework components may also have an associated mime-type.
-  optional string mime_type = 2;
-  // An optional identifier which can be used to reference the component elsewhere in the BOM. Uniqueness is enforced within all elements and children of the root-level bom element.
-  optional string bom_ref = 3;
-  // The organization that supplied the component. The supplier may often be the manufacture, but may also be a distributor or repackager.
-  optional OrganizationalEntity supplier = 4;
-  // The person(s) or organization(s) that authored the component
-  optional string author = 5;
-  // The person(s) or organization(s) that published the component
-  optional string publisher = 6;
-  // The grouping name or identifier. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. Whitespace and special characters should be avoided. Examples include: apache, org.apache.commons, and apache.org.
-  optional string group = 7;
-  // The name of the component. This will often be a shortened, single name of the component. Examples: commons-lang3 and jquery
-  string name = 8;
-  // The component version. The version should ideally comply with semantic versioning but is not enforced.
-  string version = 9;
-  // Specifies a description for the component
-  optional string description = 10;
-  // Specifies the scope of the component. If scope is not specified, 'runtime' scope should be assumed by the consumer of the BOM
-  optional Scope scope = 11;
-  repeated Hash hashes = 12;
-  repeated LicenseChoice licenses = 13;
-  // An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.
-  optional string copyright = 14;
-  // DEPRECATED - DO NOT USE. This will be removed in a future version. Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe
-  optional string cpe = 15;
-  // Specifies the package-url (PURL). The purl, if specified, must be valid and conform to the specification defined at: https://github.com/package-url/purl-spec
-  optional string purl = 16;
-  // Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.
-  optional Swid swid = 17;
-  // DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree element instead to supply information on exactly how the component was modified. A boolean value indicating is the component has been modified from the original. A value of true indicates the component is a derivative of the original. A value of false indicates the component has not been modified from the original.
-  optional bool modified = 18;
-  // Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc.
-  optional Pedigree pedigree = 19;
-  // Provides the ability to document external references related to the component or to the project the component describes.
-  repeated ExternalReference external_references = 20;
-  // Specifies optional sub-components. This is not a dependency tree. It provides a way to specify a hierarchical representation of component assemblies, similar to system -> subsystem -> parts assembly in physical supply chains.
-  repeated Component components = 21;
-  // Specifies optional, custom, properties
-  repeated Property properties = 22;
-  // Specifies optional license and copyright evidence
-  repeated Evidence evidence = 23;
-}
-
-// Specifies the data classification.
-message DataClassification {
-  // Specifies the flow direction of the data.
-  DataFlow flow = 1;
-  // SimpleContent value of element
-  string value = 2;
-}
-
-// Specifies the flow direction of the data. Valid values are: inbound, outbound, bi-directional, and unknown. Direction is relative to the service. Inbound flow states that data enters the service. Outbound flow states that data leaves the service. Bi-directional states that data flows both ways, and unknown states that the direction is not known.
-enum DataFlow {
-  DATA_FLOW_NULL = 0;
-  DATA_FLOW_INBOUND = 1;
-  DATA_FLOW_OUTBOUND = 2;
-  DATA_FLOW_BI_DIRECTIONAL = 3;
-  DATA_FLOW_UNKNOWN = 4;
-}
-
-message Dependency {
-  // References a component or service by the its bom-ref attribute
-  string ref = 1;
-  repeated Dependency dependencies = 2;
-}
-
-message Diff {
-  // Specifies the optional text of the diff
-  optional AttachedText text = 1;
-  // Specifies the URL to the diff
-  optional string url = 2;
-}
-
-message ExternalReference {
-  // Specifies the type of external reference. There are built-in types to describe common references. If a type does not exist for the reference being referred to, use the "other" type.
-  ExternalReferenceType type = 1;
-  // The URL to the external reference
-  string url = 2;
-  // An optional comment describing the external reference
-  optional string comment = 3;
-  // Optional integrity hashes for the external resource content
-  repeated Hash hashes = 4;
-}
-
-enum ExternalReferenceType {
-  // Use this if no other types accurately describe the purpose of the external reference
-  EXTERNAL_REFERENCE_TYPE_OTHER = 0;
-  // Version Control System
-  EXTERNAL_REFERENCE_TYPE_VCS = 1;
-  // Issue or defect tracking system, or an Application Lifecycle Management (ALM) system
-  EXTERNAL_REFERENCE_TYPE_ISSUE_TRACKER = 2;
-  // Website
-  EXTERNAL_REFERENCE_TYPE_WEBSITE = 3;
-  // Security advisories
-  EXTERNAL_REFERENCE_TYPE_ADVISORIES = 4;
-  // Bill-of-material document (CycloneDX, SPDX, SWID, etc)
-  EXTERNAL_REFERENCE_TYPE_BOM = 5;
-  // Mailing list or discussion group
-  EXTERNAL_REFERENCE_TYPE_MAILING_LIST = 6;
-  // Social media account
-  EXTERNAL_REFERENCE_TYPE_SOCIAL = 7;
-  // Real-time chat platform
-  EXTERNAL_REFERENCE_TYPE_CHAT = 8;
-  // Documentation, guides, or how-to instructions
-  EXTERNAL_REFERENCE_TYPE_DOCUMENTATION = 9;
-  // Community or commercial support
-  EXTERNAL_REFERENCE_TYPE_SUPPORT = 10;
-  // Direct or repository download location
-  EXTERNAL_REFERENCE_TYPE_DISTRIBUTION = 11;
-  // The URL to the license file. If a license URL has been defined in the license node, it should also be defined as an external reference for completeness
-  EXTERNAL_REFERENCE_TYPE_LICENSE = 12;
-  // Build-system specific meta file (i.e. pom.xml, package.json, .nuspec, etc)
-  EXTERNAL_REFERENCE_TYPE_BUILD_META = 13;
-  // URL to an automated build system
-  EXTERNAL_REFERENCE_TYPE_BUILD_SYSTEM = 14;
-}
-
-enum HashAlg {
-  HASH_ALG_NULL = 0;
-  HASH_ALG_MD_5 = 1;
-  HASH_ALG_SHA_1 = 2;
-  HASH_ALG_SHA_256 = 3;
-  HASH_ALG_SHA_384 = 4;
-  HASH_ALG_SHA_512 = 5;
-  HASH_ALG_SHA_3_256 = 6;
-  HASH_ALG_SHA_3_384 = 7;
-  HASH_ALG_SHA_3_512 = 8;
-  HASH_ALG_BLAKE_2_B_256 = 9;
-  HASH_ALG_BLAKE_2_B_384 = 10;
-  HASH_ALG_BLAKE_2_B_512 = 11;
-  HASH_ALG_BLAKE_3 = 12;
-}
-
-// Specifies the file hash of the component
-message Hash {
-  // Specifies the algorithm used to create the hash
-  HashAlg alg = 1;
-  // SimpleContent value of element
-  string value = 2;
-}
-
-message IdentifiableAction {
-  // The timestamp in which the action occurred
-  optional google.protobuf.Timestamp timestamp = 1;
-  // The name of the individual who performed the action
-  optional string name = 2;
-  // The email address of the individual who performed the action
-  optional string email = 3;
-}
-
-enum IssueClassification {
-  ISSUE_CLASSIFICATION_NULL = 0;
-  // A fault, flaw, or bug in software
-  ISSUE_CLASSIFICATION_DEFECT = 1;
-  // A new feature or behavior in software
-  ISSUE_CLASSIFICATION_ENHANCEMENT = 2;
-  // A special type of defect which impacts security
-  ISSUE_CLASSIFICATION_SECURITY = 3;
-}
-
-message Issue {
-  // Specifies the type of issue
-  IssueClassification type = 1;
-  // The identifier of the issue assigned by the source of the issue
-  optional string id = 2;
-  // The name of the issue
-  optional string name = 3;
-  // A description of the issue
-  optional string description = 4;
-  optional Source source = 5;
-  repeated string references = 6;
-}
-
-// The source of the issue where it is documented.
-message Source {
-  // The name of the source. For example "National Vulnerability Database", "NVD", and "Apache"
-  optional string name = 1;
-  // The url of the issue documentation as provided by the source
-  optional string url = 2;
-}
-
-message LicenseChoice {
-  oneof choice {
-    License license = 1;
-    string expression = 2;
-  }
-}
-
-message License {
-  oneof license {
-    // A valid SPDX license ID
-    string id = 1;
-    // If SPDX does not define the license used, this field may be used to provide the license name
-    string name = 2;
-  }
-  // Specifies the optional full text of the attachment
-  optional AttachedText text = 3;
-  // The URL to the attachment file. If the attachment is a license or BOM, an externalReference should also be specified for completeness.
-  optional string url = 4;
-}
-
-message Metadata {
-  // The date and time (timestamp) when the document was created.
-  optional google.protobuf.Timestamp timestamp = 1;
-  // The tool(s) used in the creation of the BOM.
-  repeated Tool tools = 2;
-  // The person(s) who created the BOM. Authors are common in BOMs created through manual processes. BOMs created through automated means may not have authors.
-  repeated OrganizationalContact authors = 3;
-  // The component that the BOM describes.
-  optional Component component = 4;
-  // The organization that manufactured the component that the BOM describes.
-  optional OrganizationalEntity manufacture = 5;
-  // The organization that supplied the component that the BOM describes. The supplier may often be the manufacture, but may also be a distributor or repackager.
-  optional OrganizationalEntity supplier = 6;
-  // The license information for the BOM document
-  optional LicenseChoice licenses = 7;
-  // Specifies optional, custom, properties
-  repeated Property properties = 8;
-}
-
-message OrganizationalContact {
-  // The name of the contact
-  optional string name = 1;
-  // The email address of the contact.
-  optional string email = 2;
-  // The phone number of the contact.
-  optional string phone = 3;
-}
-
-message OrganizationalEntity {
-  // The name of the organization
-  optional string name = 1;
-  // The URL of the organization. Multiple URLs are allowed.
-  repeated string url = 2;
-  // A contact person at the organization. Multiple contacts are allowed.
-  repeated OrganizationalContact contact = 3;
-}
-
-enum PatchClassification {
-  PATCH_CLASSIFICATION_NULL = 0;
-  // A patch which is not developed by the creators or maintainers of the software being patched. Refer to https://en.wikipedia.org/wiki/Unofficial_patch
-  PATCH_CLASSIFICATION_UNOFFICIAL = 1;
-  // A patch which dynamically modifies runtime behavior. Refer to https://en.wikipedia.org/wiki/Monkey_patch
-  PATCH_CLASSIFICATION_MONKEY = 2;
-  // A patch which takes code from a newer version of software and applies it to older versions of the same software. Refer to https://en.wikipedia.org/wiki/Backporting
-  PATCH_CLASSIFICATION_BACKPORT = 3;
-  // A patch created by selectively applying commits from other versions or branches of the same software.
-  PATCH_CLASSIFICATION_CHERRY_PICK = 4;
-}
-
-message Patch {
-  // Specifies the purpose for the patch including the resolution of defects, security issues, or new behavior or functionality
-  PatchClassification type = 1;
-  // The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff
-  optional Diff diff = 2;
-  repeated Issue resolves = 3;
-}
-
-// Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to document variants where the exact relation may not be known.
-message Pedigree {
-  // Describes zero or more components in which a component is derived from. This is commonly used to describe forks from existing projects where the forked version contains a ancestor node containing the original component it was forked from. For example, Component A is the original component. Component B is the component being used and documented in the BOM. However, Component B contains a pedigree node with a single ancestor documenting Component A - the original component from which Component B is derived from.
-  repeated Component ancestors = 1;
-  // Descendants are the exact opposite of ancestors. This provides a way to document all forks (and their forks) of an original or root component.
-  repeated Component descendants = 2;
-  // Variants describe relations where the relationship between the components are not known. For example, if Component A contains nearly identical code to Component B. They are both related, but it is unclear if one is derived from the other, or if they share a common ancestor.
-  repeated Component variants = 3;
-  // A list of zero or more commits which provide a trail describing how the component deviates from an ancestor, descendant, or variant.
-  repeated Commit commits = 4;
-  // A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits or may be used in place of commits.
-  repeated Patch patches = 5;
-  // Notes, observations, and other non-structured commentary describing the components pedigree.
-  optional string notes = 6;
-}
-
-enum Scope {
-  // Default
-  SCOPE_UNSPECIFIED = 0;
-  // The component is required for runtime
-  SCOPE_REQUIRED = 1;
-  // The component is optional at runtime. Optional components are components that are not capable of being called due to them not be installed or otherwise accessible by any means. Components that are installed but due to configuration or other restrictions are prohibited from being called must be scoped as 'required'.
-  SCOPE_OPTIONAL = 2;
-  // Components that are excluded provide the ability to document component usage for test and other non-runtime purposes. Excluded components are not reachable within a call graph at runtime.
-  SCOPE_EXCLUDED = 3;
-}
-
-message Service {
-  // An optional identifier which can be used to reference the service elsewhere in the BOM. Uniqueness is enforced within all elements and children of the root-level bom element.
-  optional string bom_ref = 1;
-  // The organization that provides the service.
-  optional OrganizationalEntity provider = 2;
-  // The grouping name, namespace, or identifier. This will often be a shortened, single name of the company or project that produced the service or domain name. Whitespace and special characters should be avoided.
-  optional string group = 3;
-  // The name of the service. This will often be a shortened, single name of the service.
-  string name = 4;
-  // The service version.
-  optional string version = 5;
-  // Specifies a description for the service.
-  optional string description = 6;
-  repeated string endpoints = 7;
-  // A boolean value indicating if the service requires authentication. A value of true indicates the service requires authentication prior to use. A value of false indicates the service does not require authentication.
-  optional bool authenticated = 8;
-  // A boolean value indicating if use of the service crosses a trust zone or boundary. A value of true indicates that by using the service, a trust boundary is crossed. A value of false indicates that by using the service, a trust boundary is not crossed.
-  optional bool x_trust_boundary = 9;
-  repeated DataClassification data = 10;
-  repeated LicenseChoice licenses = 11;
-  // Provides the ability to document external references related to the service.
-  repeated ExternalReference external_references = 12;
-  // Specifies optional sub-service. This is not a dependency tree. It provides a way to specify a hierarchical representation of service assemblies, similar to system -> subsystem -> parts assembly in physical supply chains.
-  repeated Service services = 13;
-  // Specifies optional, custom, properties
-  repeated Property properties = 14;
-}
-
-message Swid {
-  // Maps to the tagId of a SoftwareIdentity.
-  string tag_id = 1;
-  // Maps to the name of a SoftwareIdentity.
-  string name = 2;
-  // Maps to the version of a SoftwareIdentity.
-  optional string version = 3;
-  // Maps to the tagVersion of a SoftwareIdentity.
-  optional int32 tag_version = 4;
-  // Maps to the patch of a SoftwareIdentity.
-  optional bool patch = 5;
-  // Specifies the full content of the SWID tag.
-  optional AttachedText text = 6;
-  // The URL to the SWID file.
-  optional string url = 7;
-}
-
-// Specifies a tool (manual or automated).
-message Tool {
-  // The vendor of the tool used to create the BOM.
-  optional string vendor = 1;
-  // The name of the tool used to create the BOM.
-  optional string name = 2;
-  // The version of the tool used to create the BOM.
-  optional string version = 3;
-  repeated Hash hashes = 4;
-}
-
-// Specifies a property
-message Property {
-  string name = 1;
-  optional string value = 2;
-}
-
-enum Aggregate {
-  // Default, no statement about the aggregate completeness is being made
-  AGGREGATE_NOT_SPECIFIED = 0;
-  // The aggregate composition is complete
-  AGGREGATE_COMPLETE = 1;
-  // The aggregate composition is incomplete
-  AGGREGATE_INCOMPLETE = 2;
-  // The aggregate composition is incomplete for first party components, complete for third party components
-  AGGREGATE_INCOMPLETE_FIRST_PARTY_ONLY = 3;
-  // The aggregate composition is incomplete for third party components, complete for first party components
-  AGGREGATE_INCOMPLETE_THIRD_PARTY_ONLY = 4;
-  // The aggregate composition completeness is unknown
-  AGGREGATE_UNKNOWN = 5;
-}
-
-message Composition {
-  // Indicates the aggregate completeness
-  Aggregate aggregate = 1;
-  // The assemblies the aggregate completeness applies to
-  repeated string assemblies = 2;
-  // The dependencies the aggregate completeness applies to
-  repeated string dependencies = 3;
-}
-
-message EvidenceCopyright {
-  // Copyright text
-  string text = 1;
-}
-
-message Evidence {
-  repeated LicenseChoice licenses = 1;
-  repeated EvidenceCopyright copyright = 2;
-}
diff --git a/cyclonedx/schema/ext/bom-descriptor-0.9.xsd b/cyclonedx/schema/ext/bom-descriptor-0.9.xsd
deleted file mode 100644
index 605df12f7..000000000
--- a/cyclonedx/schema/ext/bom-descriptor-0.9.xsd
+++ /dev/null
@@ -1,175 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-CycloneDX BOM Descriptor Extension
-
-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.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
-           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
-           xmlns:bom="http://cyclonedx.org/schema/bom/1.1"
-           xmlns:desc="http://cyclonedx.org/schema/ext/bom-descriptor/0.9"
-           elementFormDefault="qualified"
-           targetNamespace="http://cyclonedx.org/schema/ext/bom-descriptor/0.9"
-           vc:minVersion="1.0"
-           vc:maxVersion="1.1"
-           version="0.9">
-
-    <xs:annotation>
-        <xs:documentation>
-            <name>CycloneDX BOM Descriptor Extension</name>
-            <url>https://cyclonedx.org/ext/bom-descriptor</url>
-            <license uri="http://www.apache.org/licenses/LICENSE-2.0"
-                     version="2.0">Apache License, Version 2.0</license>
-            <authors>
-                <author>Steve Springett</author>
-            </authors>
-        </xs:documentation>
-    </xs:annotation>
-
-    <xs:complexType name="metadata">
-        <xs:sequence minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="softwareName" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>Specifies the name of the software the BOM describes.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="softwareVersion" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>Specifies the version of the software the BOM describes.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="softwareEdition" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>Specifies the edition of the software the BOM describes.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="hashes" minOccurs="0" maxOccurs="1">
-                <xs:complexType>
-                    <xs:sequence minOccurs="0" maxOccurs="unbounded">
-                        <xs:element name="hash" type="bom:hashType"/>
-                    </xs:sequence>
-                </xs:complexType>
-            </xs:element>
-            <xs:element name="licenses" minOccurs="0" maxOccurs="1">
-                <xs:complexType>
-                    <xs:choice>
-                        <xs:element name="license" type="bom:licenseType" minOccurs="0" maxOccurs="unbounded"/>
-                        <xs:element name="expression" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-                            <xs:annotation>
-                                <xs:documentation>A valid SPDX license expression.
-                                    Refer to https://spdx.org/specifications for syntax requirements</xs:documentation>
-                            </xs:annotation>
-                        </xs:element>
-                    </xs:choice>
-                </xs:complexType>
-            </xs:element>
-            <xs:element name="copyright" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>An optional copyright notice informing users of the underlying claims to
-                        copyright ownership in a published work.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="cpe" type="bom:cpe" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>
-                        Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="purl" type="xs:anyURI" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>
-                        Specifies the package-url (PURL). The purl, if specified, must be valid and conform
-                        to the specification defined at: https://github.com/package-url/purl-spec
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="manufacture" type="desc:organizationalEntity" minOccurs="0" maxOccurs="unbounded">
-                <xs:annotation>
-                    <xs:documentation>The organization that manufactured the software for which the BOM describes.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="supplier" type="desc:organizationalEntity" minOccurs="0" maxOccurs="unbounded">
-                <xs:annotation>
-                    <xs:documentation>The organization that supplied the software for which the BOM describes. The
-                    supplier may often be the manufacture, but may also be a distributor or repackager.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:sequence>
-        <xs:anyAttribute namespace="##other" processContents="lax">
-            <xs:annotation>
-                <xs:documentation>User-defined attributes may be used on this element as long as they
-                    do not have the same name as an existing attribute used by the schema.</xs:documentation>
-            </xs:annotation>
-        </xs:anyAttribute>
-    </xs:complexType>
-
-    <xs:complexType name="organizationalEntity">
-        <xs:sequence minOccurs="0" maxOccurs="1">
-            <xs:element name="name" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>The name of the organization</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="url" type="xs:anyURI" minOccurs="0" maxOccurs="unbounded">
-                <xs:annotation>
-                    <xs:documentation>The URL of the organization. Multiple URLs are allowed.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="contact" type="desc:organizationalPerson" minOccurs="0" maxOccurs="unbounded">
-                <xs:annotation>
-                    <xs:documentation>A contact person at the organization. Multiple contacts are allowed.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:sequence>
-        <xs:anyAttribute namespace="##other" processContents="lax">
-            <xs:annotation>
-                <xs:documentation>User-defined attributes may be used on this element as long as they
-                    do not have the same name as an existing attribute used by the schema.</xs:documentation>
-            </xs:annotation>
-        </xs:anyAttribute>
-    </xs:complexType>
-
-    <xs:complexType name="organizationalPerson">
-        <xs:sequence minOccurs="0" maxOccurs="1">
-            <xs:element name="name" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>The name of the person</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="email" type="xs:normalizedString" minOccurs="0" maxOccurs="unbounded">
-                <xs:annotation>
-                    <xs:documentation>The email address of the person. Multiple email addresses are allowed.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="phone" type="xs:normalizedString" minOccurs="0" maxOccurs="unbounded">
-                <xs:annotation>
-                    <xs:documentation>The phone number of the person. Multiple phone numbers are allowed.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:sequence>
-        <xs:anyAttribute namespace="##other" processContents="lax">
-            <xs:annotation>
-                <xs:documentation>User-defined attributes may be used on this element as long as they
-                    do not have the same name as an existing attribute used by the schema.</xs:documentation>
-            </xs:annotation>
-        </xs:anyAttribute>
-    </xs:complexType>
-
-    <xs:element name="metadata" type="desc:metadata">
-        <xs:annotation>
-            <xs:documentation>Provides additional information about a BOM.</xs:documentation>
-        </xs:annotation>
-    </xs:element>
-
-</xs:schema>
diff --git a/cyclonedx/schema/ext/bom-descriptor-1.0.xsd b/cyclonedx/schema/ext/bom-descriptor-1.0.xsd
deleted file mode 100644
index 013f550eb..000000000
--- a/cyclonedx/schema/ext/bom-descriptor-1.0.xsd
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-CycloneDX BOM Descriptor Extension
-
-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.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
-           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
-           xmlns:bom="http://cyclonedx.org/schema/bom/1.1"
-           xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0"
-           elementFormDefault="qualified"
-           targetNamespace="http://cyclonedx.org/schema/ext/bom-descriptor/1.0"
-           vc:minVersion="1.0"
-           vc:maxVersion="1.1"
-           version="1.0">
-
-  <xs:annotation>
-    <xs:documentation>
-      <name>CycloneDX BOM Descriptor Extension</name>
-      <url>https://cyclonedx.org/ext/bom-descriptor</url>
-      <license uri="http://www.apache.org/licenses/LICENSE-2.0"
-               version="2.0">Apache License, Version 2.0</license>
-      <authors>
-        <author>Steve Springett</author>
-      </authors>
-    </xs:documentation>
-  </xs:annotation>
-
-  <xs:import namespace="http://cyclonedx.org/schema/bom/1.1" schemaLocation="http://cyclonedx.org/schema/bom/1.1"/>
-
-  <xs:complexType name="metadata">
-    <xs:sequence minOccurs="0" maxOccurs="1">
-      <xs:element name="timestamp" type="xs:dateTime" minOccurs="0">
-        <xs:annotation>
-          <xs:documentation>The date and time (timestamp) when the document was created.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="tool" minOccurs="0" type="bd:toolType">
-        <xs:annotation>
-          <xs:documentation>The tool used to create the BOM.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="authors" minOccurs="0" maxOccurs="1">
-        <xs:annotation>
-          <xs:documentation>The person(s) who created the BOM. Authors are common in BOMs created through
-            manual processes. BOMs created through automated means may not have authors.</xs:documentation>
-        </xs:annotation>
-        <xs:complexType>
-          <xs:sequence minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="author" type="bd:organizationalPerson"/>
-          </xs:sequence>
-        </xs:complexType>
-      </xs:element>
-      <xs:element name="component" type="bom:component" minOccurs="0">
-        <xs:annotation>
-          <xs:documentation>The component that the BOM describes.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="manufacture" type="bd:organizationalEntity" minOccurs="0" maxOccurs="unbounded">
-        <xs:annotation>
-          <xs:documentation>The organization that manufactured the component that the BOM describes.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="supplier" type="bd:organizationalEntity" minOccurs="0" maxOccurs="unbounded">
-        <xs:annotation>
-          <xs:documentation>The organization that supplied the component that the BOM describes. The
-            supplier may often be the manufacture, but may also be a distributor or repackager.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-    </xs:sequence>
-    <xs:anyAttribute namespace="##other" processContents="lax">
-      <xs:annotation>
-        <xs:documentation>User-defined attributes may be used on this element as long as they
-          do not have the same name as an existing attribute used by the schema.</xs:documentation>
-      </xs:annotation>
-    </xs:anyAttribute>
-  </xs:complexType>
-
-  <xs:complexType name="organizationalEntity">
-    <xs:sequence minOccurs="0" maxOccurs="1">
-      <xs:element name="name" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-        <xs:annotation>
-          <xs:documentation>The name of the organization</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="url" type="xs:anyURI" minOccurs="0" maxOccurs="unbounded">
-        <xs:annotation>
-          <xs:documentation>The URL of the organization. Multiple URLs are allowed.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="contact" type="bd:organizationalPerson" minOccurs="0" maxOccurs="unbounded">
-        <xs:annotation>
-          <xs:documentation>A contact person at the organization. Multiple contacts are allowed.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-    </xs:sequence>
-    <xs:anyAttribute namespace="##other" processContents="lax">
-      <xs:annotation>
-        <xs:documentation>User-defined attributes may be used on this element as long as they
-          do not have the same name as an existing attribute used by the schema.</xs:documentation>
-      </xs:annotation>
-    </xs:anyAttribute>
-  </xs:complexType>
-
-  <xs:complexType name="toolType">
-    <xs:annotation>
-      <xs:documentation>Specifies a tool (manual or automated).</xs:documentation>
-    </xs:annotation>
-    <xs:sequence minOccurs="0" maxOccurs="1">
-      <xs:element name="vendor" minOccurs="0" maxOccurs="1" type="xs:normalizedString">
-        <xs:annotation>
-          <xs:documentation>The vendor of the tool used to create the BOM.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:normalizedString">
-        <xs:annotation>
-          <xs:documentation>The name of the tool used to create the BOM.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="version" minOccurs="0" maxOccurs="1" type="xs:normalizedString">
-        <xs:annotation>
-          <xs:documentation>The version of the tool used to create the BOM.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="hashes" minOccurs="0" maxOccurs="1">
-        <xs:complexType>
-          <xs:sequence minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="hash" type="bom:hashType"/>
-          </xs:sequence>
-        </xs:complexType>
-      </xs:element>
-    </xs:sequence>
-    <xs:anyAttribute namespace="##other" processContents="lax">
-      <xs:annotation>
-        <xs:documentation>User-defined attributes may be used on this element as long as they
-          do not have the same name as an existing attribute used by the schema.</xs:documentation>
-      </xs:annotation>
-    </xs:anyAttribute>
-  </xs:complexType>
-
-  <xs:complexType name="organizationalPerson">
-    <xs:sequence minOccurs="0" maxOccurs="1">
-      <xs:element name="name" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
-        <xs:annotation>
-          <xs:documentation>The name of the person</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="email" type="xs:normalizedString" minOccurs="0" maxOccurs="unbounded">
-        <xs:annotation>
-          <xs:documentation>The email address of the person. Multiple email addresses are allowed.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-      <xs:element name="phone" type="xs:normalizedString" minOccurs="0" maxOccurs="unbounded">
-        <xs:annotation>
-          <xs:documentation>The phone number of the person. Multiple phone numbers are allowed.</xs:documentation>
-        </xs:annotation>
-      </xs:element>
-    </xs:sequence>
-    <xs:anyAttribute namespace="##other" processContents="lax">
-      <xs:annotation>
-        <xs:documentation>User-defined attributes may be used on this element as long as they
-          do not have the same name as an existing attribute used by the schema.</xs:documentation>
-      </xs:annotation>
-    </xs:anyAttribute>
-  </xs:complexType>
-
-  <xs:element name="metadata" type="bd:metadata">
-    <xs:annotation>
-      <xs:documentation>Provides additional information about a BOM.</xs:documentation>
-    </xs:annotation>
-  </xs:element>
-
-</xs:schema>
diff --git a/cyclonedx/schema/ext/dependency-graph-1.0.xsd b/cyclonedx/schema/ext/dependency-graph-1.0.xsd
deleted file mode 100644
index ddcb53656..000000000
--- a/cyclonedx/schema/ext/dependency-graph-1.0.xsd
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-CycloneDX Dependency Graph Extension
-
-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.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
-           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
-           xmlns:dg="http://cyclonedx.org/schema/ext/dependency-graph/1.0"
-           elementFormDefault="qualified"
-           targetNamespace="http://cyclonedx.org/schema/ext/dependency-graph/1.0"
-           vc:minVersion="1.0"
-           vc:maxVersion="1.1"
-           version="1.0">
-
-    <xs:annotation>
-        <xs:documentation>
-            <name>CycloneDX Dependency Graph Extension</name>
-            <url>https://cyclonedx.org/ext/dependency-graph</url>
-            <license uri="http://www.apache.org/licenses/LICENSE-2.0"
-                version="2.0">Apache License, Version 2.0</license>
-            <authors>
-                <author>Steve Springett</author>
-            </authors>
-        </xs:documentation>
-    </xs:annotation>
-
-    <xs:complexType name="dependency">
-        <xs:sequence minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="dependency" type="dg:dependency"/>
-        </xs:sequence>
-        <xs:attribute name="ref" type="xs:string" use="required">
-            <xs:annotation>
-                <xs:documentation>References a component by the components bom-ref attribute</xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:anyAttribute namespace="##other" processContents="lax">
-            <xs:annotation>
-                <xs:documentation>User-defined attributes may be used on this element as long as they
-                    do not have the same name as an existing attribute used by the schema.</xs:documentation>
-            </xs:annotation>
-        </xs:anyAttribute>
-    </xs:complexType>
-
-    <xs:element name="dependencies">
-        <xs:complexType>
-            <xs:sequence minOccurs="0" maxOccurs="unbounded">
-                <xs:element name="dependency" type="dg:dependency">
-                    <xs:annotation>
-                        <xs:documentation>Components that do not have their own dependencies MUST be declared as empty
-                            elements within the graph. Components that are not represented in the dependency graph MAY
-                            have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque
-                            and not an indicator of a component being dependency-free.</xs:documentation>
-                    </xs:annotation>
-                </xs:element>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
-
-</xs:schema>
diff --git a/cyclonedx/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json b/cyclonedx/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json
deleted file mode 100644
index 378bd498c..000000000
--- a/cyclonedx/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json
+++ /dev/null
@@ -1,182 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-07/schema#",
-  "$id": "http://cyclonedx.org/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json",
-  "type": "object",
-  "title": "CycloneDX Vulnerability Extension",
-  "$comment" : "CycloneDX Vulnerability Extension for JSON Schema is published under the terms of the Apache License 2.0.",
-  "properties": {
-    "vulnerabilities": {
-      "$id": "#/properties/vulnerabilities",
-      "type": "array",
-      "items": {"$ref": "#/definitions/vulnerability"},
-      "title": "Vulnerabilities",
-      "description": "Defines a list of vulnerabilities."
-    }
-  },
-  "definitions": {
-    "cwe": {
-      "type": "integer",
-      "minimum": 1,
-      "title": "CWE",
-      "description": "Integer representation of a Common Weaknesses Enumerations (CWE). For example 399 (of https://cwe.mitre.org/data/definitions/399.html)"
-    },
-    "severity": {
-      "type": "string",
-      "title": "Severity",
-      "description": "Textual representation of the severity of the vulnerability adopted by the risk analysis method. If an other risk analysis method is used other than whats defined in scoreSourceType, the user is expected to translate appropriately to match with an element value below.",
-      "enum": [
-        "None",
-        "Low",
-        "Medium",
-        "High",
-        "Critical",
-        "Unknown"
-      ]
-    },
-    "scoreValue": {
-      "type": "number",
-      "title": "Score",
-      "description": "Numerical representation of the vulnerability score. Must be a number between 0 - 10 (maps to lowest severity - highest severity)",
-      "multipleOf": 0.1,
-      "examples": [7.9, 10.0]
-    },
-    "scoreSource": {
-      "type": "string",
-      "title": "Source",
-      "description": "Specifies the risk scoring methodology/standard used.",
-      "enum": [
-        "CVSSv2",
-        "CVSSv3",
-        "OWASP Risk",
-        "Open FAIR",
-        "Other"
-      ]
-    },
-    "score": {
-      "type": "object",
-      "title": "Score",
-      "description": "Defines the numerical risk score of a vulnerability",
-      "properties": {
-        "base": {
-          "type": "number",
-          "title": "Base Score",
-          "description": "The base score of the security vulnerability (Refer CVSS standard for example)",
-          "multipleOf": 0.1,
-          "examples": [2.9, 7.2]
-        },
-        "impact": {
-          "type": "number",
-          "title": "Impact Score",
-          "description": "The impact subscore of the security vulnerability (Refer CVSS standard for example)",
-          "multipleOf": 0.1,
-          "examples": [2.9, 7.2]
-        },
-        "exploitability": {
-          "type": "number",
-          "title": "Exploitability Score",
-          "description": "The exploitability subscore of the security vulnerability (Refer CVSS standard for example)",
-          "multipleOf": 0.1,
-          "examples": [2.9, 7.2]
-        }
-      }
-    },
-    "rating": {
-      "type": "object",
-      "title": "Rating",
-      "description": "Defines the risk rating of a vulnerability.",
-      "properties": {
-        "score": {
-          "$ref": "#/definitions/score"
-        },
-        "severity": {
-          "$ref": "#/definitions/severity"
-        },
-        "method": {
-          "$ref": "#/definitions/scoreSource"
-        },
-        "vector": {
-          "type": "string",
-          "title": "Vector",
-          "description": "Textual representation of the metric values used to score the vulnerability see attack vector in https://www.first.org/cvss/v3.1/specification-document"
-        }
-      }
-    },
-    "source": {
-      "type": "object",
-      "title": "Source",
-      "description": "The source of the vulnerability where it is documented. Usually the name of the organization publishing vulnerability information",
-      "properties": {
-        "url": {
-          "type": "string",
-          "title": "URL",
-          "description": "The url of the vulnerability documentation as provided by the source.",
-          "examples": [
-            "https://nvd.nist.gov/vuln/detail/CVE-2019-15842"
-          ]
-        },
-        "name": {
-          "type": "string",
-          "title": "Name",
-          "description": "The name of the source.",
-          "examples": [
-            "NVD", "National Vulnerability Database", "OSS Index", "VulnDB", "NPM Advisories"
-          ]
-        }
-      }
-    },
-    "vulnerability": {
-      "type": "object",
-      "title": "Vulnerability",
-      "description": "Defines the structure of a vulnerability.",
-      "properties": {
-        "ref": {
-          "type": "string",
-          "format": "string",
-          "title": "Reference",
-          "description": "References a component by the components bom-ref attribute"
-        },
-        "id": {
-          "type": "string",
-          "title": "ID",
-          "description": "The id of the vulnerability as defined by the risk scoring methodology. For example CVE-2019-15842 (of https://nvd.nist.gov/vuln/detail/CVE-2019-15842)"
-        },
-        "source": {
-          "$ref": "#/definitions/source"
-        },
-        "ratings": {
-          "type": "array",
-          "title": "Ratings",
-          "description": "List of the vulnerability ratings as defined by various risk rating methodologies.",
-          "items": {"$ref": "#/definitions/rating"}
-        },
-        "cwes": {
-          "type": "array",
-          "title": "CWEs",
-          "description": "List of Common Weaknesses Enumerations (CWEs) codes that describes this vulnerability. For example 399 (of https://cwe.mitre.org/data/definitions/399.html)",
-          "items": {"$ref": "#/definitions/cwe"}
-        },
-        "description": {
-          "type": "string",
-          "title": "Description",
-          "description": "Description of the vulnerability as provided by the source organization"
-        },
-        "recommendations": {
-          "type": "array",
-          "title": "Recommendations",
-          "description": "List of recommendations of how the particular vulnerability can be avoided/mitigated.",
-          "items": {
-            "type": "string"
-          }
-        },
-        "advisories": {
-          "type": "array",
-          "title": "Advisories",
-          "description": "Published advisories of the vulnerability if provided.",
-          "items": {
-            "type": "string"
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/cyclonedx/schema/ext/vulnerability-1.0.xsd b/cyclonedx/schema/ext/vulnerability-1.0.xsd
deleted file mode 100644
index 2d6847458..000000000
--- a/cyclonedx/schema/ext/vulnerability-1.0.xsd
+++ /dev/null
@@ -1,291 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-CycloneDX Vulnerability Extension
-
-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.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
-           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
-           xmlns:vuln="http://cyclonedx.org/schema/ext/vulnerability/1.0"
-           elementFormDefault="qualified"
-           targetNamespace="http://cyclonedx.org/schema/ext/vulnerability/1.0"
-           vc:minVersion="1.0"
-           vc:maxVersion="1.1"
-           version="1.0.0">
-
-    <xs:annotation>
-        <xs:documentation>
-            <name>CycloneDX Vulnerability Extension</name>
-            <url>https://cyclonedx.org/ext/vulnerability</url>
-            <license uri="http://www.apache.org/licenses/LICENSE-2.0"
-                     version="2.0">Apache License, Version 2.0</license>
-        </xs:documentation>
-    </xs:annotation>
-
-    <xs:simpleType name="severityType" final="restriction">
-        <xs:annotation>
-            <xs:documentation xml:lang="en">
-                Textual representation of the severity of the vulnerability adopted by the risk analysis method.
-                If an other risk analysis method is used other than whats defined in scoreSourceType,
-                the user is expected to translate appropriately to match with an element value below.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="None"/>
-            <xs:enumeration value="Low"/>
-            <xs:enumeration value="Medium"/>
-            <xs:enumeration value="High"/>
-            <xs:enumeration value="Critical"/>
-            <xs:enumeration value="Unknown"/>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="scoreValueType">
-        <xs:annotation>
-            <xs:documentation xml:lang="en">
-                Numerical representation of the vulnerability score.
-                Must be a number between 0 - 10 (maps to lowest severity - highest severity)
-            </xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:decimal">
-            <xs:minInclusive value="0"/>
-            <xs:fractionDigits value="1"/>
-            <xs:maxInclusive value="10"/>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="scoreSourceType" final="restriction">
-        <xs:annotation>
-            <xs:documentation xml:lang="en">
-                Specifies the risk scoring methodology/standard used.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="CVSSv2">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        The rating is based on CVSS v2 standard
-                        https://www.first.org/cvss/v2/guide
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:enumeration>
-            <xs:enumeration value="CVSSv3">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        The rating is based on CVSS v3 standard
-                        https://www.first.org/cvss/v3.1/specification-document
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:enumeration>
-            <xs:enumeration value="OWASP Risk">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        The rating is based on OWASP Risk Rating
-                        https://www.owasp.org/index.php/OWASP_Risk_Rating_Methodology
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:enumeration>
-            <xs:enumeration value="Open FAIR">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        The rating is based on Open FAIR specification
-                        http://www.opengroup.org/subjectareas/security/risk
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:enumeration>
-            <xs:enumeration value="Other">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        Use this if the risk scoring methodology is not based on any of the options above
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:complexType name="scoreType">
-        <xs:annotation>
-            <xs:documentation xml:lang="en">
-                Defines the numerical risk score of a vulnerability
-            </xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="score" minOccurs="0" maxOccurs="1">
-                <xs:complexType>
-                    <xs:sequence>
-                        <xs:element name="base" type="vuln:scoreValueType" minOccurs="0" maxOccurs="1">
-                            <xs:annotation>
-                                <xs:documentation xml:lang="en">
-                                    The base score of the security vulnerability (Refer CVSS standard for example)
-                                </xs:documentation>
-                            </xs:annotation>
-                        </xs:element>
-                        <xs:element name="impact" type="vuln:scoreValueType" minOccurs="0" maxOccurs="1">
-                            <xs:annotation>
-                                <xs:documentation xml:lang="en">
-                                    The impact subscore of the security vulnerability (Refer CVSS standard for example)
-                                </xs:documentation>
-                            </xs:annotation>
-                        </xs:element>
-                        <xs:element name="exploitability" type="vuln:scoreValueType" minOccurs="0" maxOccurs="1">
-                            <xs:annotation>
-                                <xs:documentation xml:lang="en">
-                                    The exploitability subscore of the security vulnerability (Refer CVSS standard for
-                                    example)
-                                </xs:documentation>
-                            </xs:annotation>
-                        </xs:element>
-                    </xs:sequence>
-                </xs:complexType>
-            </xs:element>
-            <xs:element name="severity" type="vuln:severityType" minOccurs="0" maxOccurs="1"/>
-            <xs:element name="method" type="vuln:scoreSourceType" minOccurs="0" maxOccurs="1"/>
-            <xs:element name="vector" type="xs:string" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        Textual representation of the metric values used to score the vulnerability
-                        see attack vector in https://www.first.org/cvss/v3.1/specification-document
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="vulnerability">
-        <xs:annotation>
-            <xs:documentation xml:lang="en">
-                Defines the structure of a vulnerability.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="id" type="xs:normalizedString" minOccurs="1" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        The id of the vulnerability as defined by the risk scoring methodology
-                        For example CVE-2019-15842 (of https://nvd.nist.gov/vuln/detail/CVE-2019-15842)
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="source" minOccurs="0" maxOccurs="1">
-                <xs:complexType>
-                    <xs:annotation>
-                        <xs:documentation xml:lang="en">
-                            The source of the vulnerability where it is documented.
-                            Usually the name of the organization publishing vulnerability information
-                        </xs:documentation>
-                    </xs:annotation>
-                    <xs:sequence>
-                        <xs:element name="url" minOccurs="0" type="xs:anyURI" maxOccurs="1">
-                            <xs:annotation>
-                                <xs:documentation xml:lang="en">
-                                    The url of the vulnerability documentation as provided by the source
-                                    For example https://nvd.nist.gov/vuln/detail/CVE-2019-15842
-                                </xs:documentation>
-                            </xs:annotation>
-                        </xs:element>
-                    </xs:sequence>
-                    <xs:attribute name="name" type="xs:normalizedString" use="required">
-                        <xs:annotation>
-                            <xs:documentation xml:lang="en">
-                                The name of the source. For example "National Vulnerability Database"
-                            </xs:documentation>
-                        </xs:annotation>
-                    </xs:attribute>
-                </xs:complexType>
-            </xs:element>
-            <xs:element name="ratings" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        List of the vulnerability ratings as defined by various risk rating methodologies.
-                    </xs:documentation>
-                </xs:annotation>
-                <xs:complexType>
-                    <xs:sequence>
-                        <xs:element name="rating" type="vuln:scoreType" minOccurs="0" maxOccurs="unbounded"/>
-                    </xs:sequence>
-                </xs:complexType>
-            </xs:element>
-            <xs:element name="cwes" minOccurs="0" maxOccurs="1">
-                <xs:complexType>
-                    <xs:annotation>
-                        <xs:documentation xml:lang="en">
-                            List of Common Weaknesses Enumerations (CWEs) codes that describes this vulnerability.
-                            For example 399 (of https://cwe.mitre.org/data/definitions/399.html)
-                        </xs:documentation>
-                    </xs:annotation>
-                    <xs:sequence minOccurs="0" maxOccurs="unbounded">
-                        <xs:element name="cwe" type="xs:integer" minOccurs="0" maxOccurs="1"/>
-                    </xs:sequence>
-                </xs:complexType>
-            </xs:element>
-            <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation xml:lang="en">
-                        Description of the vulnerability as provided by the source organization
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="recommendations" minOccurs="0" maxOccurs="1">
-                <xs:complexType>
-                    <xs:annotation>
-                        <xs:documentation xml:lang="en">
-                            The remediation options for the vulnerability if available
-                        </xs:documentation>
-                    </xs:annotation>
-                    <xs:sequence minOccurs="0" maxOccurs="unbounded">
-                        <xs:element name="recommendation" type="xs:string">
-                            <xs:annotation>
-                                <xs:documentation xml:lang="en">
-                                    A recommendation of how the particular vulnerability can be avoided/mitigated.
-                                </xs:documentation>
-                            </xs:annotation>
-                        </xs:element>
-                    </xs:sequence>
-                </xs:complexType>
-            </xs:element>
-            <xs:element name="advisories" minOccurs="0" maxOccurs="1">
-                <xs:complexType>
-                    <xs:annotation>
-                        <xs:documentation xml:lang="en">
-                            Published advisories of the vulnerability if provided
-                        </xs:documentation>
-                    </xs:annotation>
-                    <xs:sequence minOccurs="0" maxOccurs="unbounded">
-                        <xs:element name="advisory" type="xs:string"/>
-                    </xs:sequence>
-                </xs:complexType>
-            </xs:element>
-        </xs:sequence>
-        <xs:attribute name="ref" type="xs:string" use="required">
-            <xs:annotation>
-                <xs:documentation>References a component by the components bom-ref attribute</xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:complexType>
-
-    <xs:element name="vulnerabilities">
-        <xs:annotation>
-            <xs:documentation xml:lang="en">
-                Defines a list of vulnerabilities.
-                Vulnerabilities are intended to be used inside the BOM component element.
-                Extending a component ability to declare associated vulnerability information.
-                Each component element optionally can add a vulnerabilities element.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:complexType>
-            <xs:sequence minOccurs="0" maxOccurs="unbounded">
-                <xs:element name="vulnerability" type="vuln:vulnerability"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
-</xs:schema>
diff --git a/cyclonedx/spdx.py b/cyclonedx/spdx.py
index 8e59f376e..6a684f978 100644
--- a/cyclonedx/spdx.py
+++ b/cyclonedx/spdx.py
@@ -20,11 +20,12 @@
 ]
 
 from json import load as json_load
-from os.path import dirname, join as path_join
 from typing import TYPE_CHECKING, Dict, Optional, Set
 
 from license_expression import get_spdx_licensing  # type: ignore
 
+from .schema._res import SPDX_JSON as __SPDX_JSON_SCHEMA
+
 if TYPE_CHECKING:
     from license_expression import Licensing
 
@@ -32,7 +33,7 @@
 # python's internal module loader will assure that this init-part runs only once.
 
 # !!! this requires to ship the actual schema data with the package.
-with open(path_join(dirname(__file__), 'schema', 'spdx.schema.json')) as schema:
+with open(__SPDX_JSON_SCHEMA) as schema:
     __IDS: Set[str] = set(json_load(schema).get('enum', []))
 assert len(__IDS) > 0, 'known SPDX-IDs should be non-empty set'
 
diff --git a/cyclonedx/validation/__init__.py b/cyclonedx/validation/__init__.py
new file mode 100644
index 000000000..c6eada0ab
--- /dev/null
+++ b/cyclonedx/validation/__init__.py
@@ -0,0 +1,73 @@
+# encoding: utf-8
+
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING, Any, Optional, Protocol
+
+if TYPE_CHECKING:
+    from ..schema import SchemaVersion
+
+
+class ValidationError:
+    """Validation failed with this specific error.
+
+    Use :attr:`~data` to access the content.
+    """
+
+    data: Any
+
+    def __init__(self, data: Any) -> None:
+        self.data = data
+
+    def __repr__(self) -> str:
+        return repr(self.data)
+
+    def __str__(self) -> str:
+        return str(self.data)
+
+
+class Validator(Protocol):
+    """Validator protocol"""
+
+    def validate_str(self, data: str) -> Optional[ValidationError]:
+        """Validate a string
+
+        :param data: the data string to validate
+        :return: validation error
+        :retval None: if `data` is valid
+        :retval ValidationError:  if `data` is invalid
+        """
+        ...
+
+
+class BaseValidator(ABC, Validator):
+    """BaseValidator"""
+
+    def __init__(self, schema_version: 'SchemaVersion') -> None:
+        self.__schema_version = schema_version
+        if not self._schema_file:
+            raise ValueError(f'unsupported schema: {schema_version}')
+
+    @property
+    def schema_version(self) -> 'SchemaVersion':
+        """get the schema version."""
+        return self.__schema_version
+
+    @property
+    @abstractmethod
+    def _schema_file(self) -> Optional[str]:
+        """get the schema file according to schema version."""
+        ...
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
new file mode 100644
index 000000000..34c1aca63
--- /dev/null
+++ b/cyclonedx/validation/json.py
@@ -0,0 +1,112 @@
+# encoding: utf-8
+
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+__all__ = ['JsonValidator', 'JsonStrictValidator']
+
+from abc import ABC
+from json import loads as json_loads
+from typing import TYPE_CHECKING, Any, Optional, Tuple
+
+if TYPE_CHECKING:
+    from ..schema import SchemaVersion
+
+from ..exception import MissingOptionalDependencyException
+from ..schema._res import BOM_JSON as _S_BOM, BOM_JSON_STRICT as _S_BOM_STRICT, JSF as _S_JSF, SPDX_JSON as _S_SPDX
+from . import BaseValidator, ValidationError, Validator
+
+_missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
+try:
+    from jsonschema.exceptions import ValidationError as JsonValidationError  # type: ignore[import]
+    from jsonschema.validators import Draft7Validator  # type: ignore[import]
+    from referencing import Registry
+    from referencing.jsonschema import DRAFT7
+
+    if TYPE_CHECKING:
+        from jsonschema.protocols import Validator as JsonSchemaValidator  # type: ignore[import]
+except ImportError as err:
+    _missing_deps_error = MissingOptionalDependencyException(
+        'This functionality requires optional dependencies.\n'
+        'Please install `cyclonedx-python-lib` with the extra "json-validation".\n'
+    ), err
+
+
+class _BaseJsonValidator(BaseValidator, ABC):
+
+    def __init__(self, schema_version: 'SchemaVersion') -> None:
+        # this is the def that is used for generating the documentation
+        super().__init__(schema_version)
+
+    if _missing_deps_error:
+        __MDERROR = _missing_deps_error
+
+        def validate_str(self, data: str) -> Optional[ValidationError]:
+            raise self.__MDERROR[0]  # from functionality_not_implemented_error[1]
+
+    else:
+        def validate_str(self, data: str) -> Optional[ValidationError]:
+            return self._validata_data(
+                json_loads(data))
+
+        def _validata_data(self, data: Any) -> Optional[ValidationError]:
+            validator = self._validator  # may throw on error that MUST NOT be caught
+            try:
+                validator.validate(data)
+            except JsonValidationError as error:
+                return ValidationError(error)
+            return None
+
+        __validator: Optional['JsonSchemaValidator'] = None
+
+        @property
+        def _validator(self) -> 'JsonSchemaValidator':
+            if not self.__validator:
+                schema_file = self._schema_file
+                if schema_file is None:
+                    raise NotImplementedError('missing schema file')
+                with open(schema_file) as sf:
+                    self.__validator = Draft7Validator(
+                        json_loads(sf.read()),
+                        registry=self.__make_validator_registry(),
+                        format_checker=Draft7Validator.FORMAT_CHECKER)
+            return self.__validator
+
+        @staticmethod
+        def __make_validator_registry() -> Registry[Any]:
+            schema_prefix = 'http://cyclonedx.org/schema/'
+            with open(_S_SPDX) as spdx, open(_S_JSF) as jsf:
+                return Registry().with_resources([
+                    (f'{schema_prefix}spdx.SNAPSHOT.schema.json', DRAFT7.create_resource(json_loads(spdx.read()))),
+                    (f'{schema_prefix}jsf-0.82.SNAPSHOT.schema.json', DRAFT7.create_resource(json_loads(jsf.read()))),
+                ])
+
+
+class JsonValidator(_BaseJsonValidator, Validator):
+    """Validator for CycloneDX documents in JSON format."""
+
+    @property
+    def _schema_file(self) -> Optional[str]:
+        return _S_BOM.get(self.schema_version)
+
+
+class JsonStrictValidator(_BaseJsonValidator, Validator):
+    """Strict validator for CycloneDX documents in JSON format.
+
+    In contrast to :class:`~JsonValidator`,
+    the document must not have additional or unknown JSON properties.
+    """
+    @property
+    def _schema_file(self) -> Optional[str]:
+        return _S_BOM_STRICT.get(self.schema_version)
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
new file mode 100644
index 000000000..f49a75f46
--- /dev/null
+++ b/cyclonedx/validation/xml.py
@@ -0,0 +1,84 @@
+# encoding: utf-8
+
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+__all__ = ['XmlValidator']
+
+from abc import ABC
+from typing import TYPE_CHECKING, Any, Optional, Tuple
+
+from ..exception import MissingOptionalDependencyException
+from ..schema._res import BOM_XML as _S_BOM
+from . import BaseValidator, ValidationError, Validator
+
+if TYPE_CHECKING:
+    from ..schema import SchemaVersion
+
+_missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
+try:
+    from lxml.etree import XMLParser, XMLSchema, fromstring as xml_fromstring  # type: ignore[import]
+except ImportError as err:
+    _missing_deps_error = MissingOptionalDependencyException(
+        'This functionality requires optional dependencies.\n'
+        'Please install `cyclonedx-python-lib` with the extra "json-validation".\n'
+    ), err
+
+
+class _BaseXmlValidator(BaseValidator, ABC):
+
+    def __init__(self, schema_version: 'SchemaVersion') -> None:
+        # this is the def that is used for generating the documentation
+        super().__init__(schema_version)
+
+    if _missing_deps_error:
+        __MDERROR = _missing_deps_error
+
+        def validate_str(self, data: str) -> Optional[ValidationError]:
+            raise self.__MDERROR[0]  # from functionality_not_implemented_error[1]
+    else:
+        def validate_str(self, data: str) -> Optional[ValidationError]:
+            return self._validata_data(
+                xml_fromstring(bytes(data, encoding='utf8'), parser=self.__xml_parser))
+
+        def _validata_data(self, data: Any) -> Optional[ValidationError]:
+            validator = self._validator  # may throw on error that MUST NOT be caught
+            if not validator.validate(data):
+                return ValidationError(validator.error_log.last_error)
+            return None
+
+        __validator: Optional['XMLSchema'] = None
+
+        __xml_parser = XMLParser(
+            resolve_entities=False,
+            no_network=True,
+            huge_tree=True,
+            compact=True)
+
+        @property
+        def _validator(self) -> 'XMLSchema':
+            if not self.__validator:
+                schema_file = self._schema_file
+                if schema_file is None:
+                    raise NotImplementedError('missing schema file')
+                self.__validator = XMLSchema(file=schema_file)
+            return self.__validator
+
+
+class XmlValidator(_BaseXmlValidator, Validator):
+    """Validator for CycloneDX documents in XML format."""
+
+    @property
+    def _schema_file(self) -> Optional[str]:
+        return _S_BOM.get(self.schema_version)
diff --git a/deps.lowest.r b/deps.lowest.r
deleted file mode 100644
index 70b35aaa9..000000000
--- a/deps.lowest.r
+++ /dev/null
@@ -1,7 +0,0 @@
-# exactly pinned dependencies to the lowest version regardless of python_version
-# see pyptoject file for ranges
-
-packageurl-python == 0.11.1
-py-serializable == 0.11.1
-
-# file name is a untypical one, so dependabot does not bump this file
diff --git a/docs/conf.py b/docs/conf.py
index 9faa5c7ae..5abdefc51 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -31,15 +31,18 @@
 # ones.
 extensions = [
     "sphinx.ext.autodoc",
-    "sphinx.ext.viewcode",
+    # "sphinx.ext.viewcode",
     "autoapi.extension",
     "sphinx_rtd_theme",
     "m2r2"
 ]
 
+
 # Document Python Code
 autoapi_type = 'python'
 autoapi_dirs = ['../cyclonedx']
+# see https://sphinx-autoapi.readthedocs.io/en/latest/reference/config.html#confval-autoapi_options
+autoapi_options = ['show-module-summary', 'members', 'undoc-members', 'inherited-members', 'show-inheritance']
 
 source_suffix = ['.rst', '.md']
 
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 5a7f88a0a..4fc50161c 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -1,83 +1 @@
-Contributing
-====================================================
-
-Pull requests are welcome, but please read these contributing guidelines first.
-
-Setup
-----------------------------------------------------
-
-This project uses `poetry`_. Have it installed and setup first.
-
-To install dev-dependencies and tools:
-
-.. code-block::
-
-   poetry install
-
-Code style
-----------------------------------------------------
-
-This project uses `PEP8`_ Style Guide for Python Code. This project loves sorted imports. Get it all applied via:
-
-.. code-block::
-
-    poetry run isort .
-    poetry run flake8 cyclonedx/ tests/ typings/
-
-
-Documentation
-----------------------------------------------------
-
-This project uses `Sphinx`_ to generate documentation which is automatically published to `readthedocs.io`_.
-
-Source for documentation is stored in the ``docs`` folder in `RST`_ format.
-
-You can generate the documentation locally by running:
-
-.. code-block::
-
-    cd docs
-    pip install -r requirements.txt
-    make html
-
-
-Testing
-----------------------------------------------------
-
-Run all tests in dedicated environments, via:
-
-.. code-block::
-
-    poetry run tox
-
-
-Sign your commits
-----------------------------------------------------
-
-Please sign your commits, to show that you agree to publish your changes under the current terms and licenses of the
-project. We can't accept contributions, however great, if you do not sign your commits.
-
-.. code-block::
-
-    git commit --signed-off ...
-
-
-Pre-commit hooks
-----------------------------------------------------
-
-If you like to take advantage of `pre-commit hooks`_, you can do so to cover most of the topics on this page when
-contributing.
-
-.. code-block::
-
-    pre-commit install
-
-All our pre-commit checks will run locally before you can commit!
-
-
-.. _poetry: https://python-poetry.org
-.. _PEP8: https://www.python.org/dev/peps/pep-0008
-.. _Sphinx: https://www.sphinx-doc.org/
-.. _readthedocs.io: https://cyclonedx-python-library.readthedocs.io/
-.. _RST: https://en.wikipedia.org/wiki/ReStructuredText
-.. _pre-commit hooks: https://pre-commit.com
+.. mdinclude:: ../CONTRIBUTING.md
diff --git a/docs/examples.rst b/docs/examples.rst
index 0df9d8d11..a2b9c97b6 100644
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -15,9 +15,9 @@
 Examples
 ========
 
-Build & Serialize
------------------
+Complex
+-------
 
-.. literalinclude:: ../examples/build_and_serialize.py
+.. literalinclude:: ../examples/complex.py
   :language: python
   :linenos:
diff --git a/docs/install.rst b/docs/install.rst
index 43123c612..62bbb625b 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -25,3 +25,21 @@ Install from `pypi.org`_ as you would any other Python module using your preferr
 
 .. _pypi.org: https://pypi.org/project/cyclonedx-python-lib/
 .. _conda-forge: https://anaconda.org/conda-forge/cyclonedx-python-lib
+
+Extras
+------
+
+The following extras are available when installing this package:
+
+`json-validation`
+    Install the optional dependencies needed for JSON validation.
+`xml-validation`
+    Install the optional dependencies needed for XML validation.
+`validation`
+    Install the optional dependencies needed for all supported validations.
+
+They can be used when installing in order to include additional dependencies, e.g.:
+
+.. code-block:: bash
+
+    pip install 'cyclonedx-python-lib[validation]'
diff --git a/docs/requirements.txt b/docs/requirements.txt
index db0c3d0f7..dfba7e147 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,4 +1,4 @@
 m2r2>=0.3.2
-Sphinx>=4.3.2
-sphinx-autoapi>=1.8.4
-sphinx-rtd-theme>=1.0.0
\ No newline at end of file
+Sphinx>=7.2.6,<8
+sphinx-autoapi>=2.1.1,<3
+sphinx-rtd-theme>=1.3.0,<2
diff --git a/examples/build_and_serialize.py b/examples/complex.py
similarity index 56%
rename from examples/build_and_serialize.py
rename to examples/complex.py
index 52567e667..f64b1652a 100644
--- a/examples/build_and_serialize.py
+++ b/examples/complex.py
@@ -1,10 +1,17 @@
+import sys
+
+from packageurl import PackageURL
+
+from cyclonedx.exception import MissingOptionalDependencyException
 from cyclonedx.factory.license import LicenseChoiceFactory, LicenseFactory
 from cyclonedx.model import OrganizationalEntity, XsUri
 from cyclonedx.model.bom import Bom
 from cyclonedx.model.component import Component, ComponentType
 from cyclonedx.output.json import JsonV1Dot4
 from cyclonedx.output.xml import XmlV1Dot4
-from packageurl import PackageURL
+from cyclonedx.schema import SchemaVersion
+from cyclonedx.validation.json import JsonValidator
+from cyclonedx.validation.xml import XmlValidator
 
 lc_factory = LicenseChoiceFactory(license_factory=LicenseFactory())
 
@@ -44,8 +51,25 @@
 
 # endregion build the BOM
 
-serializedJSON = JsonV1Dot4(bom).output_as_string()
-print(serializedJSON)
 
-serializedXML = XmlV1Dot4(bom).output_as_string()
-print(serializedXML)
+serialized_json = JsonV1Dot4(bom).output_as_string()
+print(serialized_json)
+try:
+    validation_errors = JsonValidator(SchemaVersion.V1_4).validate_str(serialized_json)
+    if validation_errors:
+        print('', 'JSON ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
+        sys.exit(2)
+    print('JSON valid')
+except MissingOptionalDependencyException as error:
+    print('JSON-validation was skipped due to', error)
+
+serialized_xml = XmlV1Dot4(bom).output_as_string()
+print(serialized_xml)
+try:
+    validation_errors = XmlValidator(SchemaVersion.V1_4).validate_str(serialized_xml)
+    if validation_errors:
+        print('', 'JSON ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
+        sys.exit(2)
+    print('JSON valid')
+except MissingOptionalDependencyException as error:
+    print('XML-validation was skipped due to', error)
diff --git a/pyproject.toml b/pyproject.toml
index 8f889159c..d0bc7f55b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,7 +7,10 @@ name = "cyclonedx-python-lib"
 # !! version is managed by semantic_release
 version = "5.0.0-alpha.1"
 description = "A library for producing CycloneDX SBOM (Software Bill of Materials) files."
-authors = ["Paul Horton <phorton@sonatype.com>"]
+authors = [
+  "Paul Horton <phorton@sonatype.com>",
+  "Jan Kowalleck <jan.kowalleck@gmail.com>",
+]
 maintainers = [
   "Paul Horton <phorton@sonatype.com>",
   "Jan Kowalleck <jan.kowalleck@gmail.com>",
@@ -24,6 +27,10 @@ include = [
   "README.md", "LICENSE", "NOTICE",
   { path = "tests", format = "sdist" },
 ]
+exclude = [
+  # exclude dotfiles
+  "**/.*"
+]
 classifiers = [
   # Trove classifiers - https://packaging.python.org/specifications/core-metadata/#metadata-classifier
   # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
@@ -56,6 +63,13 @@ packageurl-python = ">= 0.11"
 py-serializable = "^0.11.1"
 sortedcontainers = "^2.4.0"
 license-expression = "^30"
+jsonschema = { version = "^4.18", extras=['format'], optional=true, python="^3.8" }
+lxml = { version="^4", optional=true }
+
+[tool.poetry.extras]
+validation = ["jsonschema", "lxml"]
+json-validation = ["jsonschema"]
+xml-validation = ["lxml"]
 
 [tool.poetry.dev-dependencies]
 ddt = "1.6.0"
@@ -66,9 +80,7 @@ flake8-bugbear = { version="23.9.16", python=">=3.8.1" }
 flake8-isort = "6.1.0 "
 isort = "5.12.0"
 autopep8 = "2.0.4"
-jsonschema = "4.17.3"
 mypy = "1.5.1"
-lxml = "4.9.3"
 tox = "4.11.3"
 xmldiff = "2.6.3"
 
diff --git a/tests/__init__.py b/tests/__init__.py
index 4c9653000..0b497f9e5 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -19,11 +19,7 @@
 
 from os import getenv, path
 
-import cyclonedx
-
-CDX_SCHEMA_DIRECTORY = path.join(path.dirname(cyclonedx.__file__), 'schema')
-
-FIXTURES_DIRECTORY = path.join(path.dirname(__file__), 'fixtures')
+TESTDATA_DIRECTORY = path.join(path.dirname(__file__), '_data')
 
 RECREATE_SNAPSHOTS = bool(getenv('CDX_TEST_RECREATE_SNAPSHOTS'))
 if RECREATE_SNAPSHOTS:
diff --git a/tests/_data/own/.gitattributes b/tests/_data/own/.gitattributes
new file mode 100644
index 000000000..6558d375e
--- /dev/null
+++ b/tests/_data/own/.gitattributes
@@ -0,0 +1,2 @@
+xml/*/*.xml     linguist-generated
+json/*/*.josn   linguist-generated
diff --git a/tests/fixtures/README.md b/tests/_data/own/README.md
similarity index 100%
rename from tests/fixtures/README.md
rename to tests/_data/own/README.md
diff --git a/tests/fixtures/json/1.2/bom_dependencies.json b/tests/_data/own/json/1.2/bom_dependencies.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_dependencies.json
rename to tests/_data/own/json/1.2/bom_dependencies.json
diff --git a/tests/fixtures/json/1.2/bom_dependencies_component.json b/tests/_data/own/json/1.2/bom_dependencies_component.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_dependencies_component.json
rename to tests/_data/own/json/1.2/bom_dependencies_component.json
diff --git a/tests/fixtures/json/1.2/bom_external_references.json b/tests/_data/own/json/1.2/bom_external_references.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_external_references.json
rename to tests/_data/own/json/1.2/bom_external_references.json
diff --git a/tests/fixtures/json/1.2/bom_issue_275_components.json b/tests/_data/own/json/1.2/bom_issue_275_components.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_issue_275_components.json
rename to tests/_data/own/json/1.2/bom_issue_275_components.json
diff --git a/tests/fixtures/json/1.2/bom_issue_328_components.json b/tests/_data/own/json/1.2/bom_issue_328_components.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_issue_328_components.json
rename to tests/_data/own/json/1.2/bom_issue_328_components.json
diff --git a/tests/fixtures/json/1.2/bom_services_complex.json b/tests/_data/own/json/1.2/bom_services_complex.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_services_complex.json
rename to tests/_data/own/json/1.2/bom_services_complex.json
diff --git a/tests/fixtures/json/1.2/bom_services_nested.json b/tests/_data/own/json/1.2/bom_services_nested.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_services_nested.json
rename to tests/_data/own/json/1.2/bom_services_nested.json
diff --git a/tests/fixtures/json/1.2/bom_services_simple.json b/tests/_data/own/json/1.2/bom_services_simple.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_services_simple.json
rename to tests/_data/own/json/1.2/bom_services_simple.json
diff --git a/tests/fixtures/json/1.2/bom_setuptools.json b/tests/_data/own/json/1.2/bom_setuptools.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_setuptools.json
rename to tests/_data/own/json/1.2/bom_setuptools.json
diff --git a/tests/fixtures/json/1.2/bom_setuptools_complete.json b/tests/_data/own/json/1.2/bom_setuptools_complete.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_setuptools_complete.json
rename to tests/_data/own/json/1.2/bom_setuptools_complete.json
diff --git a/tests/fixtures/json/1.2/bom_setuptools_no_version.json b/tests/_data/own/json/1.2/bom_setuptools_no_version.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_setuptools_no_version.json
rename to tests/_data/own/json/1.2/bom_setuptools_no_version.json
diff --git a/tests/fixtures/json/1.2/bom_setuptools_with_cpe.json b/tests/_data/own/json/1.2/bom_setuptools_with_cpe.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_setuptools_with_cpe.json
rename to tests/_data/own/json/1.2/bom_setuptools_with_cpe.json
diff --git a/tests/fixtures/json/1.2/bom_toml_1.json b/tests/_data/own/json/1.2/bom_toml_1.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_toml_1.json
rename to tests/_data/own/json/1.2/bom_toml_1.json
diff --git a/tests/fixtures/json/1.2/bom_with_full_metadata.json b/tests/_data/own/json/1.2/bom_with_full_metadata.json
similarity index 100%
rename from tests/fixtures/json/1.2/bom_with_full_metadata.json
rename to tests/_data/own/json/1.2/bom_with_full_metadata.json
diff --git a/tests/fixtures/json/1.3/bom_dependencies.json b/tests/_data/own/json/1.3/bom_dependencies.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_dependencies.json
rename to tests/_data/own/json/1.3/bom_dependencies.json
diff --git a/tests/fixtures/json/1.3/bom_dependencies_component.json b/tests/_data/own/json/1.3/bom_dependencies_component.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_dependencies_component.json
rename to tests/_data/own/json/1.3/bom_dependencies_component.json
diff --git a/tests/fixtures/json/1.3/bom_external_references.json b/tests/_data/own/json/1.3/bom_external_references.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_external_references.json
rename to tests/_data/own/json/1.3/bom_external_references.json
diff --git a/tests/fixtures/json/1.3/bom_issue_275_components.json b/tests/_data/own/json/1.3/bom_issue_275_components.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_issue_275_components.json
rename to tests/_data/own/json/1.3/bom_issue_275_components.json
diff --git a/tests/fixtures/json/1.3/bom_issue_328_components.json b/tests/_data/own/json/1.3/bom_issue_328_components.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_issue_328_components.json
rename to tests/_data/own/json/1.3/bom_issue_328_components.json
diff --git a/tests/fixtures/json/1.3/bom_services_complex.json b/tests/_data/own/json/1.3/bom_services_complex.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_services_complex.json
rename to tests/_data/own/json/1.3/bom_services_complex.json
diff --git a/tests/fixtures/json/1.3/bom_services_nested.json b/tests/_data/own/json/1.3/bom_services_nested.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_services_nested.json
rename to tests/_data/own/json/1.3/bom_services_nested.json
diff --git a/tests/fixtures/json/1.3/bom_services_simple.json b/tests/_data/own/json/1.3/bom_services_simple.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_services_simple.json
rename to tests/_data/own/json/1.3/bom_services_simple.json
diff --git a/tests/fixtures/json/1.3/bom_setuptools.json b/tests/_data/own/json/1.3/bom_setuptools.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_setuptools.json
rename to tests/_data/own/json/1.3/bom_setuptools.json
diff --git a/tests/fixtures/json/1.3/bom_setuptools_complete.json b/tests/_data/own/json/1.3/bom_setuptools_complete.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_setuptools_complete.json
rename to tests/_data/own/json/1.3/bom_setuptools_complete.json
diff --git a/tests/fixtures/json/1.3/bom_setuptools_no_version.json b/tests/_data/own/json/1.3/bom_setuptools_no_version.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_setuptools_no_version.json
rename to tests/_data/own/json/1.3/bom_setuptools_no_version.json
diff --git a/tests/fixtures/json/1.3/bom_setuptools_with_cpe.json b/tests/_data/own/json/1.3/bom_setuptools_with_cpe.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_setuptools_with_cpe.json
rename to tests/_data/own/json/1.3/bom_setuptools_with_cpe.json
diff --git a/tests/fixtures/json/1.3/bom_toml_1.json b/tests/_data/own/json/1.3/bom_toml_1.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_toml_1.json
rename to tests/_data/own/json/1.3/bom_toml_1.json
diff --git a/tests/fixtures/json/1.3/bom_with_full_metadata.json b/tests/_data/own/json/1.3/bom_with_full_metadata.json
similarity index 100%
rename from tests/fixtures/json/1.3/bom_with_full_metadata.json
rename to tests/_data/own/json/1.3/bom_with_full_metadata.json
diff --git a/tests/fixtures/json/1.4/bom_dependencies.json b/tests/_data/own/json/1.4/bom_dependencies.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_dependencies.json
rename to tests/_data/own/json/1.4/bom_dependencies.json
diff --git a/tests/fixtures/json/1.4/bom_dependencies_component.json b/tests/_data/own/json/1.4/bom_dependencies_component.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_dependencies_component.json
rename to tests/_data/own/json/1.4/bom_dependencies_component.json
diff --git a/tests/fixtures/json/1.4/bom_external_references.json b/tests/_data/own/json/1.4/bom_external_references.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_external_references.json
rename to tests/_data/own/json/1.4/bom_external_references.json
diff --git a/tests/fixtures/json/1.4/bom_issue_275_components.json b/tests/_data/own/json/1.4/bom_issue_275_components.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_issue_275_components.json
rename to tests/_data/own/json/1.4/bom_issue_275_components.json
diff --git a/tests/fixtures/json/1.4/bom_issue_328_components.json b/tests/_data/own/json/1.4/bom_issue_328_components.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_issue_328_components.json
rename to tests/_data/own/json/1.4/bom_issue_328_components.json
diff --git a/tests/fixtures/json/1.4/bom_services_complex.json b/tests/_data/own/json/1.4/bom_services_complex.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_services_complex.json
rename to tests/_data/own/json/1.4/bom_services_complex.json
diff --git a/tests/fixtures/json/1.4/bom_services_nested.json b/tests/_data/own/json/1.4/bom_services_nested.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_services_nested.json
rename to tests/_data/own/json/1.4/bom_services_nested.json
diff --git a/tests/fixtures/json/1.4/bom_services_simple.json b/tests/_data/own/json/1.4/bom_services_simple.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_services_simple.json
rename to tests/_data/own/json/1.4/bom_services_simple.json
diff --git a/tests/fixtures/json/1.4/bom_setuptools.json b/tests/_data/own/json/1.4/bom_setuptools.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_setuptools.json
rename to tests/_data/own/json/1.4/bom_setuptools.json
diff --git a/tests/fixtures/json/1.4/bom_setuptools_complete.json b/tests/_data/own/json/1.4/bom_setuptools_complete.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_setuptools_complete.json
rename to tests/_data/own/json/1.4/bom_setuptools_complete.json
diff --git a/tests/fixtures/json/1.4/bom_setuptools_no_version.json b/tests/_data/own/json/1.4/bom_setuptools_no_version.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_setuptools_no_version.json
rename to tests/_data/own/json/1.4/bom_setuptools_no_version.json
diff --git a/tests/fixtures/json/1.4/bom_setuptools_with_cpe.json b/tests/_data/own/json/1.4/bom_setuptools_with_cpe.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_setuptools_with_cpe.json
rename to tests/_data/own/json/1.4/bom_setuptools_with_cpe.json
diff --git a/tests/fixtures/json/1.4/bom_setuptools_with_release_notes.json b/tests/_data/own/json/1.4/bom_setuptools_with_release_notes.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_setuptools_with_release_notes.json
rename to tests/_data/own/json/1.4/bom_setuptools_with_release_notes.json
diff --git a/tests/fixtures/json/1.4/bom_setuptools_with_vulnerabilities.json b/tests/_data/own/json/1.4/bom_setuptools_with_vulnerabilities.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_setuptools_with_vulnerabilities.json
rename to tests/_data/own/json/1.4/bom_setuptools_with_vulnerabilities.json
diff --git a/tests/fixtures/json/1.4/bom_toml_1.json b/tests/_data/own/json/1.4/bom_toml_1.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_toml_1.json
rename to tests/_data/own/json/1.4/bom_toml_1.json
diff --git a/tests/fixtures/json/1.4/bom_with_dependencies_hanging.json b/tests/_data/own/json/1.4/bom_with_dependencies_hanging.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_with_dependencies_hanging.json
rename to tests/_data/own/json/1.4/bom_with_dependencies_hanging.json
diff --git a/tests/fixtures/json/1.4/bom_with_full_metadata.json b/tests/_data/own/json/1.4/bom_with_full_metadata.json
similarity index 100%
rename from tests/fixtures/json/1.4/bom_with_full_metadata.json
rename to tests/_data/own/json/1.4/bom_with_full_metadata.json
diff --git a/tests/fixtures/xml/1.0/bom_empty.xml b/tests/_data/own/xml/1.0/bom_empty.xml
similarity index 100%
rename from tests/fixtures/xml/1.0/bom_empty.xml
rename to tests/_data/own/xml/1.0/bom_empty.xml
diff --git a/tests/fixtures/xml/1.0/bom_issue_275_components.xml b/tests/_data/own/xml/1.0/bom_issue_275_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.0/bom_issue_275_components.xml
rename to tests/_data/own/xml/1.0/bom_issue_275_components.xml
diff --git a/tests/fixtures/xml/1.0/bom_issue_328_components.xml b/tests/_data/own/xml/1.0/bom_issue_328_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.0/bom_issue_328_components.xml
rename to tests/_data/own/xml/1.0/bom_issue_328_components.xml
diff --git a/tests/fixtures/xml/1.0/bom_setuptools.xml b/tests/_data/own/xml/1.0/bom_setuptools.xml
similarity index 100%
rename from tests/fixtures/xml/1.0/bom_setuptools.xml
rename to tests/_data/own/xml/1.0/bom_setuptools.xml
diff --git a/tests/fixtures/xml/1.0/bom_setuptools_complete.xml b/tests/_data/own/xml/1.0/bom_setuptools_complete.xml
similarity index 100%
rename from tests/fixtures/xml/1.0/bom_setuptools_complete.xml
rename to tests/_data/own/xml/1.0/bom_setuptools_complete.xml
diff --git a/tests/fixtures/xml/1.0/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.0/bom_setuptools_no_version.xml
similarity index 100%
rename from tests/fixtures/xml/1.0/bom_setuptools_no_version.xml
rename to tests/_data/own/xml/1.0/bom_setuptools_no_version.xml
diff --git a/tests/fixtures/xml/1.0/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.0/bom_setuptools_with_cpe.xml
similarity index 100%
rename from tests/fixtures/xml/1.0/bom_setuptools_with_cpe.xml
rename to tests/_data/own/xml/1.0/bom_setuptools_with_cpe.xml
diff --git a/tests/fixtures/xml/1.0/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.0/bom_toml_hashes_and_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.0/bom_toml_hashes_and_references.xml
rename to tests/_data/own/xml/1.0/bom_toml_hashes_and_references.xml
diff --git a/tests/fixtures/xml/1.1/bom_dependencies.xml b/tests/_data/own/xml/1.1/bom_dependencies.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_dependencies.xml
rename to tests/_data/own/xml/1.1/bom_dependencies.xml
diff --git a/tests/fixtures/xml/1.1/bom_empty.xml b/tests/_data/own/xml/1.1/bom_empty.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_empty.xml
rename to tests/_data/own/xml/1.1/bom_empty.xml
diff --git a/tests/fixtures/xml/1.1/bom_external_references.xml b/tests/_data/own/xml/1.1/bom_external_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_external_references.xml
rename to tests/_data/own/xml/1.1/bom_external_references.xml
diff --git a/tests/fixtures/xml/1.1/bom_issue_275_components.xml b/tests/_data/own/xml/1.1/bom_issue_275_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_issue_275_components.xml
rename to tests/_data/own/xml/1.1/bom_issue_275_components.xml
diff --git a/tests/fixtures/xml/1.1/bom_issue_328_components.xml b/tests/_data/own/xml/1.1/bom_issue_328_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_issue_328_components.xml
rename to tests/_data/own/xml/1.1/bom_issue_328_components.xml
diff --git a/tests/fixtures/xml/1.1/bom_setuptools.xml b/tests/_data/own/xml/1.1/bom_setuptools.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_setuptools.xml
rename to tests/_data/own/xml/1.1/bom_setuptools.xml
diff --git a/tests/fixtures/xml/1.1/bom_setuptools_complete.xml b/tests/_data/own/xml/1.1/bom_setuptools_complete.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_setuptools_complete.xml
rename to tests/_data/own/xml/1.1/bom_setuptools_complete.xml
diff --git a/tests/fixtures/xml/1.1/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.1/bom_setuptools_no_version.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_setuptools_no_version.xml
rename to tests/_data/own/xml/1.1/bom_setuptools_no_version.xml
diff --git a/tests/fixtures/xml/1.1/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.1/bom_setuptools_with_cpe.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_setuptools_with_cpe.xml
rename to tests/_data/own/xml/1.1/bom_setuptools_with_cpe.xml
diff --git a/tests/fixtures/xml/1.1/bom_setuptools_with_vulnerabilities.xml b/tests/_data/own/xml/1.1/bom_setuptools_with_vulnerabilities.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_setuptools_with_vulnerabilities.xml
rename to tests/_data/own/xml/1.1/bom_setuptools_with_vulnerabilities.xml
diff --git a/tests/fixtures/xml/1.1/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.1/bom_toml_hashes_and_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.1/bom_toml_hashes_and_references.xml
rename to tests/_data/own/xml/1.1/bom_toml_hashes_and_references.xml
diff --git a/tests/fixtures/xml/1.2/bom_dependencies.xml b/tests/_data/own/xml/1.2/bom_dependencies.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_dependencies.xml
rename to tests/_data/own/xml/1.2/bom_dependencies.xml
diff --git a/tests/fixtures/xml/1.2/bom_dependencies_component.xml b/tests/_data/own/xml/1.2/bom_dependencies_component.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_dependencies_component.xml
rename to tests/_data/own/xml/1.2/bom_dependencies_component.xml
diff --git a/tests/fixtures/xml/1.2/bom_external_references.xml b/tests/_data/own/xml/1.2/bom_external_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_external_references.xml
rename to tests/_data/own/xml/1.2/bom_external_references.xml
diff --git a/tests/fixtures/xml/1.2/bom_issue_275_components.xml b/tests/_data/own/xml/1.2/bom_issue_275_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_issue_275_components.xml
rename to tests/_data/own/xml/1.2/bom_issue_275_components.xml
diff --git a/tests/fixtures/xml/1.2/bom_issue_328_components.xml b/tests/_data/own/xml/1.2/bom_issue_328_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_issue_328_components.xml
rename to tests/_data/own/xml/1.2/bom_issue_328_components.xml
diff --git a/tests/fixtures/xml/1.2/bom_services_complex.xml b/tests/_data/own/xml/1.2/bom_services_complex.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_services_complex.xml
rename to tests/_data/own/xml/1.2/bom_services_complex.xml
diff --git a/tests/fixtures/xml/1.2/bom_services_nested.xml b/tests/_data/own/xml/1.2/bom_services_nested.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_services_nested.xml
rename to tests/_data/own/xml/1.2/bom_services_nested.xml
diff --git a/tests/fixtures/xml/1.2/bom_services_simple.xml b/tests/_data/own/xml/1.2/bom_services_simple.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_services_simple.xml
rename to tests/_data/own/xml/1.2/bom_services_simple.xml
diff --git a/tests/fixtures/xml/1.2/bom_setuptools.xml b/tests/_data/own/xml/1.2/bom_setuptools.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_setuptools.xml
rename to tests/_data/own/xml/1.2/bom_setuptools.xml
diff --git a/tests/fixtures/xml/1.2/bom_setuptools_complete.xml b/tests/_data/own/xml/1.2/bom_setuptools_complete.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_setuptools_complete.xml
rename to tests/_data/own/xml/1.2/bom_setuptools_complete.xml
diff --git a/tests/fixtures/xml/1.2/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.2/bom_setuptools_no_version.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_setuptools_no_version.xml
rename to tests/_data/own/xml/1.2/bom_setuptools_no_version.xml
diff --git a/tests/fixtures/xml/1.2/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.2/bom_setuptools_with_cpe.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_setuptools_with_cpe.xml
rename to tests/_data/own/xml/1.2/bom_setuptools_with_cpe.xml
diff --git a/tests/fixtures/xml/1.2/bom_setuptools_with_vulnerabilities.xml b/tests/_data/own/xml/1.2/bom_setuptools_with_vulnerabilities.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_setuptools_with_vulnerabilities.xml
rename to tests/_data/own/xml/1.2/bom_setuptools_with_vulnerabilities.xml
diff --git a/tests/fixtures/xml/1.2/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.2/bom_toml_hashes_and_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_toml_hashes_and_references.xml
rename to tests/_data/own/xml/1.2/bom_toml_hashes_and_references.xml
diff --git a/tests/fixtures/xml/1.2/bom_with_full_metadata.xml b/tests/_data/own/xml/1.2/bom_with_full_metadata.xml
similarity index 100%
rename from tests/fixtures/xml/1.2/bom_with_full_metadata.xml
rename to tests/_data/own/xml/1.2/bom_with_full_metadata.xml
diff --git a/tests/fixtures/xml/1.3/bom_dependencies.xml b/tests/_data/own/xml/1.3/bom_dependencies.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_dependencies.xml
rename to tests/_data/own/xml/1.3/bom_dependencies.xml
diff --git a/tests/fixtures/xml/1.3/bom_dependencies_component.xml b/tests/_data/own/xml/1.3/bom_dependencies_component.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_dependencies_component.xml
rename to tests/_data/own/xml/1.3/bom_dependencies_component.xml
diff --git a/tests/fixtures/xml/1.3/bom_external_references.xml b/tests/_data/own/xml/1.3/bom_external_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_external_references.xml
rename to tests/_data/own/xml/1.3/bom_external_references.xml
diff --git a/tests/fixtures/xml/1.3/bom_issue_275_components.xml b/tests/_data/own/xml/1.3/bom_issue_275_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_issue_275_components.xml
rename to tests/_data/own/xml/1.3/bom_issue_275_components.xml
diff --git a/tests/fixtures/xml/1.3/bom_issue_328_components.xml b/tests/_data/own/xml/1.3/bom_issue_328_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_issue_328_components.xml
rename to tests/_data/own/xml/1.3/bom_issue_328_components.xml
diff --git a/tests/fixtures/xml/1.3/bom_services_complex.xml b/tests/_data/own/xml/1.3/bom_services_complex.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_services_complex.xml
rename to tests/_data/own/xml/1.3/bom_services_complex.xml
diff --git a/tests/fixtures/xml/1.3/bom_services_nested.xml b/tests/_data/own/xml/1.3/bom_services_nested.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_services_nested.xml
rename to tests/_data/own/xml/1.3/bom_services_nested.xml
diff --git a/tests/fixtures/xml/1.3/bom_services_simple.xml b/tests/_data/own/xml/1.3/bom_services_simple.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_services_simple.xml
rename to tests/_data/own/xml/1.3/bom_services_simple.xml
diff --git a/tests/fixtures/xml/1.3/bom_setuptools.xml b/tests/_data/own/xml/1.3/bom_setuptools.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_setuptools.xml
rename to tests/_data/own/xml/1.3/bom_setuptools.xml
diff --git a/tests/fixtures/xml/1.3/bom_setuptools_complete.xml b/tests/_data/own/xml/1.3/bom_setuptools_complete.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_setuptools_complete.xml
rename to tests/_data/own/xml/1.3/bom_setuptools_complete.xml
diff --git a/tests/fixtures/xml/1.3/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.3/bom_setuptools_no_version.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_setuptools_no_version.xml
rename to tests/_data/own/xml/1.3/bom_setuptools_no_version.xml
diff --git a/tests/fixtures/xml/1.3/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.3/bom_setuptools_with_cpe.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_setuptools_with_cpe.xml
rename to tests/_data/own/xml/1.3/bom_setuptools_with_cpe.xml
diff --git a/tests/fixtures/xml/1.3/bom_setuptools_with_vulnerabilities.xml b/tests/_data/own/xml/1.3/bom_setuptools_with_vulnerabilities.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_setuptools_with_vulnerabilities.xml
rename to tests/_data/own/xml/1.3/bom_setuptools_with_vulnerabilities.xml
diff --git a/tests/fixtures/xml/1.3/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.3/bom_toml_hashes_and_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_toml_hashes_and_references.xml
rename to tests/_data/own/xml/1.3/bom_toml_hashes_and_references.xml
diff --git a/tests/fixtures/xml/1.3/bom_with_full_metadata.xml b/tests/_data/own/xml/1.3/bom_with_full_metadata.xml
similarity index 100%
rename from tests/fixtures/xml/1.3/bom_with_full_metadata.xml
rename to tests/_data/own/xml/1.3/bom_with_full_metadata.xml
diff --git a/tests/fixtures/xml/1.4/bom_dependencies.xml b/tests/_data/own/xml/1.4/bom_dependencies.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_dependencies.xml
rename to tests/_data/own/xml/1.4/bom_dependencies.xml
diff --git a/tests/fixtures/xml/1.4/bom_dependencies_component.xml b/tests/_data/own/xml/1.4/bom_dependencies_component.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_dependencies_component.xml
rename to tests/_data/own/xml/1.4/bom_dependencies_component.xml
diff --git a/tests/fixtures/xml/1.4/bom_external_references.xml b/tests/_data/own/xml/1.4/bom_external_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_external_references.xml
rename to tests/_data/own/xml/1.4/bom_external_references.xml
diff --git a/tests/fixtures/xml/1.4/bom_issue_275_components.xml b/tests/_data/own/xml/1.4/bom_issue_275_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_issue_275_components.xml
rename to tests/_data/own/xml/1.4/bom_issue_275_components.xml
diff --git a/tests/fixtures/xml/1.4/bom_issue_328_components.xml b/tests/_data/own/xml/1.4/bom_issue_328_components.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_issue_328_components.xml
rename to tests/_data/own/xml/1.4/bom_issue_328_components.xml
diff --git a/tests/fixtures/xml/1.4/bom_services_complex.xml b/tests/_data/own/xml/1.4/bom_services_complex.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_services_complex.xml
rename to tests/_data/own/xml/1.4/bom_services_complex.xml
diff --git a/tests/fixtures/xml/1.4/bom_services_nested.xml b/tests/_data/own/xml/1.4/bom_services_nested.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_services_nested.xml
rename to tests/_data/own/xml/1.4/bom_services_nested.xml
diff --git a/tests/fixtures/xml/1.4/bom_services_simple.xml b/tests/_data/own/xml/1.4/bom_services_simple.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_services_simple.xml
rename to tests/_data/own/xml/1.4/bom_services_simple.xml
diff --git a/tests/fixtures/xml/1.4/bom_setuptools.xml b/tests/_data/own/xml/1.4/bom_setuptools.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_setuptools.xml
rename to tests/_data/own/xml/1.4/bom_setuptools.xml
diff --git a/tests/fixtures/xml/1.4/bom_setuptools_complete.xml b/tests/_data/own/xml/1.4/bom_setuptools_complete.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_setuptools_complete.xml
rename to tests/_data/own/xml/1.4/bom_setuptools_complete.xml
diff --git a/tests/fixtures/xml/1.4/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.4/bom_setuptools_no_version.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_setuptools_no_version.xml
rename to tests/_data/own/xml/1.4/bom_setuptools_no_version.xml
diff --git a/tests/fixtures/xml/1.4/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.4/bom_setuptools_with_cpe.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_setuptools_with_cpe.xml
rename to tests/_data/own/xml/1.4/bom_setuptools_with_cpe.xml
diff --git a/tests/fixtures/xml/1.4/bom_setuptools_with_release_notes.xml b/tests/_data/own/xml/1.4/bom_setuptools_with_release_notes.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_setuptools_with_release_notes.xml
rename to tests/_data/own/xml/1.4/bom_setuptools_with_release_notes.xml
diff --git a/tests/fixtures/xml/1.4/bom_setuptools_with_vulnerabilities.xml b/tests/_data/own/xml/1.4/bom_setuptools_with_vulnerabilities.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_setuptools_with_vulnerabilities.xml
rename to tests/_data/own/xml/1.4/bom_setuptools_with_vulnerabilities.xml
diff --git a/tests/fixtures/xml/1.4/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.4/bom_toml_hashes_and_references.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_toml_hashes_and_references.xml
rename to tests/_data/own/xml/1.4/bom_toml_hashes_and_references.xml
diff --git a/tests/fixtures/xml/1.4/bom_with_dependencies_hanging.xml b/tests/_data/own/xml/1.4/bom_with_dependencies_hanging.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_with_dependencies_hanging.xml
rename to tests/_data/own/xml/1.4/bom_with_dependencies_hanging.xml
diff --git a/tests/fixtures/xml/1.4/bom_with_full_metadata.xml b/tests/_data/own/xml/1.4/bom_with_full_metadata.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/bom_with_full_metadata.xml
rename to tests/_data/own/xml/1.4/bom_with_full_metadata.xml
diff --git a/tests/fixtures/xml/1.4/webgoat-6.1.xml b/tests/_data/own/xml/1.4/webgoat-6.1.xml
similarity index 100%
rename from tests/fixtures/xml/1.4/webgoat-6.1.xml
rename to tests/_data/own/xml/1.4/webgoat-6.1.xml
diff --git a/tests/_data/schemaTestData/.gitattributes b/tests/_data/schemaTestData/.gitattributes
new file mode 100644
index 000000000..bcf7bae75
--- /dev/null
+++ b/tests/_data/schemaTestData/.gitattributes
@@ -0,0 +1,2 @@
+*/*.json    linguist-vendored
+*/*.xml     linguist-vendored
diff --git a/tests/_data/schemaTestData/1.0/valid-bom-1.0.xml b/tests/_data/schemaTestData/1.0/valid-bom-1.0.xml
new file mode 100644
index 000000000..f0bfba221
--- /dev/null
+++ b/tests/_data/schemaTestData/1.0/valid-bom-1.0.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+    <components>
+        <component type="application">
+            <group>org.example</group>
+            <name>myapplication</name>
+            <version>1.0.0</version>
+            <description>An example application</description>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+
+            <!-- The application includes the following components -->
+            <components>
+                <component type="framework">
+                    <group>twitter</group>
+                    <name>bootstrap</name>
+                    <version>3.3.7</version>
+                    <description>The most popular front-end framework for developing responsive, mobile first projects on the web.</description>
+                    <hashes>
+                        <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                        <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                        <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                        <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+                    </hashes>
+                    <licenses>
+                        <license>
+                            <id>MIT</id>
+                        </license>
+                    </licenses>
+                    <purl>pkg:npm/bootstrap@3.3.7</purl>
+                    <modified>false</modified>
+                </component>
+                <component type="framework">
+                    <group>com.example</group>
+                    <name>myframework</name>
+                    <version>1.0.0</version>
+                    <description>Example Inc, enterprise framework</description>
+                    <hashes>
+                        <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                        <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                        <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                        <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+                    </hashes>
+                    <licenses>
+                        <license>
+                            <id>Apache-2.0</id>
+                        </license>
+                    </licenses>
+                    <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+                    <modified>false</modified>
+                </component>
+                <!-- continue adding additional components -->
+            </components>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.0/valid-component-hashes-1.0.xml b/tests/_data/schemaTestData/1.0/valid-component-hashes-1.0.xml
new file mode 100644
index 000000000..5e0286599
--- /dev/null
+++ b/tests/_data/schemaTestData/1.0/valid-component-hashes-1.0.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<bom version="1" xmlns="http://cyclonedx.org/schema/bom/1.0">
+    <components>
+        <component type="library">
+            <name>acme-example</name>
+            <version>1.0.0</version>
+            <hashes>
+                <hash alg="MD5">641b6e166f8b33c5e959e2adcc18b1c7</hash>
+                <hash alg="SHA-1">9188560f22e0b73070d2efce670c74af2bdf30af</hash>
+                <hash alg="SHA-256">d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964</hash>
+                <hash alg="SHA-384">d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad</hash>
+                <hash alg="SHA-512">74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6</hash>
+                <hash alg="SHA3-256">7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa</hash>
+                <hash alg="SHA3-512">7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20</hash>
+            </hashes>
+            <modified>false</modified>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.1/invalid-component-ref-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-component-ref-1.1.xml
new file mode 100644
index 000000000..2eaaf7895
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-component-ref-1.1.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library" bom-ref="123">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library" bom-ref="123">
+                    <name>acme-library</name>
+                    <version>1.0.0</version>
+                </component>
+            </components>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-component-type-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-component-type-1.1.xml
new file mode 100644
index 000000000..125cf0962
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-component-type-1.1.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="foo">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-empty-component-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-empty-component-1.1.xml
new file mode 100644
index 000000000..20d8ef394
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-empty-component-1.1.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-hash-alg-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-hash-alg-1.1.xml
new file mode 100644
index 000000000..e7c28b8e5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-hash-alg-1.1.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="FOO">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-hash-md5-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-hash-md5-1.1.xml
new file mode 100644
index 000000000..64473513f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-hash-md5-1.1.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">foo</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-hash-sha1-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-hash-sha1-1.1.xml
new file mode 100644
index 000000000..f13b5696d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-hash-sha1-1.1.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">foo</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-hash-sha256-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-hash-sha256-1.1.xml
new file mode 100644
index 000000000..a1815e43a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-hash-sha256-1.1.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">foo</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-hash-sha512-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-hash-sha512-1.1.xml
new file mode 100644
index 000000000..53d2bdd48
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-hash-sha512-1.1.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">foo</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-license-choice-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-license-choice-1.1.xml
new file mode 100644
index 000000000..d217aa5e2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-license-choice-1.1.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-license-encoding-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-license-encoding-1.1.xml
new file mode 100644
index 000000000..a7d73d177
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-license-encoding-1.1.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base85">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-license-id-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-license-id-1.1.xml
new file mode 100644
index 000000000..f9b083a43
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-license-id-1.1.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-license-id-count-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-license-id-count-1.1.xml
new file mode 100644
index 000000000..7f89adf32
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-license-id-count-1.1.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>MIT</id>
+                    <!-- This was a defect in schema 1.0 and is no longer permitted -->
+                    <id>MIT</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-license-name-count-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-license-name-count-1.1.xml
new file mode 100644
index 000000000..70470cb14
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-license-name-count-1.1.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Apache License 2.0</name>
+                    <!-- This was a defect in schema 1.0 and is no longer permitted -->
+                    <name>Apache License 2.0</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-missing-component-type-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-missing-component-type-1.1.xml
new file mode 100644
index 000000000..8825945b1
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-missing-component-type-1.1.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component>
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-namespace-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-namespace-1.1.xml
new file mode 100644
index 000000000..2e83863c9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-namespace-1.1.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/11">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-scope-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-scope-1.1.xml
new file mode 100644
index 000000000..f093dc144
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-scope-1.1.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>foo</scope>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/invalid-serialnumber-1.1.xml b/tests/_data/schemaTestData/1.1/invalid-serialnumber-1.1.xml
new file mode 100644
index 000000000..5149a031b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/invalid-serialnumber-1.1.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-bom-1.1.xml b/tests/_data/schemaTestData/1.1/valid-bom-1.1.xml
new file mode 100644
index 000000000..06fc5e870
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-bom-1.1.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-component-hashes-1.1.xml b/tests/_data/schemaTestData/1.1/valid-component-hashes-1.1.xml
new file mode 100644
index 000000000..0ee0e69b9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-component-hashes-1.1.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library">
+            <name>acme-example</name>
+            <version>1.0.0</version>
+            <hashes>
+                <hash alg="MD5">641b6e166f8b33c5e959e2adcc18b1c7</hash>
+                <hash alg="SHA-1">9188560f22e0b73070d2efce670c74af2bdf30af</hash>
+                <hash alg="SHA-256">d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964</hash>
+                <hash alg="SHA-384">d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad</hash>
+                <hash alg="SHA-512">74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6</hash>
+                <hash alg="SHA3-256">7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa</hash>
+                <hash alg="SHA3-512">7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.1/valid-component-ref-1.1.xml b/tests/_data/schemaTestData/1.1/valid-component-ref-1.1.xml
new file mode 100644
index 000000000..6712fb5a1
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-component-ref-1.1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library" bom-ref="123">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library" bom-ref="456">
+                    <name>acme-library</name>
+                    <version>1.0.0</version>
+                </component>
+            </components>
+        </component>
+        <component type="library" bom-ref="789">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-component-types-1.1.xml b/tests/_data/schemaTestData/1.1/valid-component-types-1.1.xml
new file mode 100644
index 000000000..714f6c716
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-component-types-1.1.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <name>application-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="library">
+            <name>library-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="framework">
+            <name>framework-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="operating-system">
+            <name>operating-system-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="device">
+            <name>device-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="file">
+            <name>file-a</name>
+            <version>1.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.1/valid-empty-components-1.1.xml b/tests/_data/schemaTestData/1.1/valid-empty-components-1.1.xml
new file mode 100644
index 000000000..9763b2c43
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-empty-components-1.1.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-external-elements-1.1.xml b/tests/_data/schemaTestData/1.1/valid-external-elements-1.1.xml
new file mode 100644
index 000000000..6fab6f352
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-external-elements-1.1.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                                <foo:fruit xmlns:foo="foo">
+                                    <foo:name>Banana</foo:name>
+                                </foo:fruit>
+                                <foo:fruit xmlns:foo="foo">
+                                    <foo:name>Banana</foo:name>
+                                </foo:fruit>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </ancestors>
+                <descendants>
+                    <component type="library">
+                        <name>foo</name>
+                        <version>1.0</version>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </descendants>
+                <variants>
+                    <component type="library">
+                        <name>bar</name>
+                        <version>1.0</version>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </variants>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                        </committer>
+                        <message>Initial commit</message>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                    </commit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </commits>
+                <notes>Commentary here</notes>
+                <foo:fruit xmlns:foo="foo">
+                    <foo:name>Banana</foo:name>
+                </foo:fruit>
+                <foo:fruit xmlns:foo="foo">
+                    <foo:name>Banana</foo:name>
+                </foo:fruit>
+            </pedigree>
+            <foo:fruit xmlns:foo="foo">
+                <foo:name>Banana</foo:name>
+            </foo:fruit>
+            <foo:fruit xmlns:foo="foo">
+                <foo:name>Banana</foo:name>
+            </foo:fruit>
+        </component>
+        <foo:fruit xmlns:foo="foo">
+            <foo:name>Banana</foo:name>
+        </foo:fruit>
+        <foo:fruit xmlns:foo="foo">
+            <foo:name>Banana</foo:name>
+        </foo:fruit>
+    </components>
+    <foo:fruit xmlns:foo="foo">
+        <foo:name>Banana</foo:name>
+    </foo:fruit>
+    <foo:fruit xmlns:foo="foo">
+        <foo:name>Banana</foo:name>
+    </foo:fruit>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-license-expression-1.1.xml b/tests/_data/schemaTestData/1.1/valid-license-expression-1.1.xml
new file mode 100644
index 000000000..436c09a19
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-license-expression-1.1.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-license-id-1.1.xml b/tests/_data/schemaTestData/1.1/valid-license-id-1.1.xml
new file mode 100644
index 000000000..fdd25ac6f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-license-id-1.1.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-license-name-1.1.xml b/tests/_data/schemaTestData/1.1/valid-license-name-1.1.xml
new file mode 100644
index 000000000..d3a72f137
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-license-name-1.1.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Apache License 2.0</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-minimal-viable-1.1.xml b/tests/_data/schemaTestData/1.1/valid-minimal-viable-1.1.xml
new file mode 100644
index 000000000..6d681aabc
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-minimal-viable-1.1.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-random-attributes-1.1.xml b/tests/_data/schemaTestData/1.1/valid-random-attributes-1.1.xml
new file mode 100644
index 000000000..15525e880
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-random-attributes-1.1.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom foo="bar" bar="foo" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components foo="bar" bar="foo" >
+        <component foo="bar" bar="foo"  type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors foo="bar" bar="foo">
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.1/valid-xml-signature-1.1.xml b/tests/_data/schemaTestData/1.1/valid-xml-signature-1.1.xml
new file mode 100644
index 000000000..b3a7ccaa9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.1/valid-xml-signature-1.1.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.1">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                        
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>jdoe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>jdoe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/xml" encoding="base64">blah</text>
+                    <url>fdaf</url>
+                </license>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+<ds:Reference URI="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+<ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+</ds:Transforms>
+<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+<ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">PrB8/rofGs34XwIX5OIdYSjV2aKSe5VaztJKBvsgjIk=</ds:DigestValue>
+</ds:Reference>
+</ds:SignedInfo>
+<ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ePGNg30Zl9CW7RZdcRn8gFCp1AlWncjudA9pQDXyqZOvyj9RC2YtkI688WdfDOdVRZs6mflJFXr7
+IKA9wY6jVrEqZmlef55Qp/8iGwOjOjWbwYsm2AhrdkUi9gaFSWEd8uITYHOpWbiPFSsnimiK9+ft
+56dkg/oJMLdXzlaukzq9iGkRcafRkW433OQcZIXwD2K8lg4cdD0pNNNqBa+PgIvzbxA5H84TyQDB
+HBcQiw/j1edRBJgPOwlqzZDUawOJaFhAPUQ+GGKMetIJH2FqqrHXGuV1NIwnbWTCg40RdOcBdCrl
+PDtDVjFh34uZ4dYBpJBIlM4daD2N4B6WPB5iHRyuZTczF2q03ObabuTgkpK6EeadFVqFNsEOOPPt
+MDDyda+Lwff5KjvUHvRRtUDIOm2rNIQKzaseulwYcA9UWQHAFcupJmWcLLM4zzY7F/uOdZuSurzh
+U6h5kdb76Juepof6ee4Q5YpwNOGNL5JfB4C3sc/Dbbv8dZ8OuXFYSZN7reUGZzCNksByqERPEbAe
+n1ldJu1HnRXRQpwaon8Asy9CuNmPfFCfDwOs2B4p4tb+tLNIKFHdRlpd19Zr9vCMCbltXeqq0Cpq
+OejSyLYGqSWzzzUh449dJrg6KTevrTNEln5GAlLBFSdjM5JA7KV2u/GyDVFwSEW7UKooGN4CtgU=
+</ds:SignatureValue>
+<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+<ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+<ds:X509SubjectName xmlns:ds="http://www.w3.org/2000/09/xmldsig#">CN=bomsigner,OU=development,O=cyclonedx</ds:X509SubjectName>
+<ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+MIIE+DCCAuCgAwIBAgIEXGzayTANBgkqhkiG9w0BAQsFADA+MRIwEAYDVQQKDAljeWNsb25lZHgx
+FDASBgNVBAsMC2RldmVsb3BtZW50MRIwEAYDVQQDDAlib21zaWduZXIwHhcNMTkwMjIwMDQ0MjQ5
+WhcNNDkwMjIwMDQ0MjQ5WjA+MRIwEAYDVQQKDAljeWNsb25lZHgxFDASBgNVBAsMC2RldmVsb3Bt
+ZW50MRIwEAYDVQQDDAlib21zaWduZXIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo
+5JZsM4ZLfWW/dpRlU6CpnItWspddF+bEVDETKVwVj9tGpqR5jURgKS/BOQP2TGUsR3/ZJJBhYRll
+ONhrUQrVKV/I6wp3Z40qPEa1RJLE+QlG9iL8qBV52CnXkLmnUSax3dspSzmSct5vDiTnvpHG9jr0
+AKFeTjy7U9rv8GJybz0ijwlpBoO9JRdYPX2PrrzoSeJLoxKq+GwuyCZ5LhXRN0p1a+NAirTAmY+c
+G1ZTLkMmfeCUy1t6H/bG4RnYOSSPOvk7Rb68lQpUqb+pbbNuB2o/b9cDwtLLCtGVlu+5Wj8mrytY
+3FGFQM20j3yVeRInmGqTTDBelQa/CO4JKqBlmaeYEIvNYbFs9+AlqadivwDO51RpdPo9fPSpsBpy
+ZMv6S2bXNuUML+Rk99WyKJTPM0PTZhRLZ64ZXEhlz3kQWVoSlrcwwim6sj6LRUb5IRqA3lxRFUI6
+NXKyiQLamQp+t3/9OGW9L1rLCcw7yFo0s8LhMTPMiv4ol9/hQViT+8ICzDsr0OM9ZiF4/UagFRlt
+IClV70cjh1DpsZjzQIRVGaj8uQ/JdtfRz4E43Ki7U0a2Vpho/t6poLVndv46tkX5nYGtMW4WfMoD
+ZflQ9pajvvKtr2jB1wob6nsU+VTmAcWZy4BCPH+XyfDw/0SFBdUceJJJtPWIeYFDUY7onptf+wID
+AQABMA0GCSqGSIb3DQEBCwUAA4ICAQCOVariNgK+9OF/5T9ZaSvZbkk45RTmzgQNXtFc5xfRvqwP
+s+pu/DFXm1R+ltjyS5j3w6NBZUFUI5MqLQr6JEEDrbu8BvfBO57wJNAEATj1JIHEfDfh7BxnBF8f
+oYFOwbrh4jOt0wz0FW2obsSVmF4GSvS7tTlWqTcsxjdZVmwP40RWu18B9jzv7M61adrWD3ksDA5O
+amSOsZi3Nt0aacDkyGRdCIEFi0fplxQInXMtD1z3RhXu2JSTAIr54Cei49Bh71kAXSWHMCog/f8a
+lSrZyqZBty/ACfU9DqlPIM+giHePKm4z2bcdpUdKZk6wcKDn4CvuBOqsMBMg7L05UEyyqTPD/4dk
+2GwJ8Nv0E5gsYHCIXF2cZ3OUVsw0mB/ozleEJVDE02uZZN/1wW1Xq028LsMdgN0Wk1WvWyF5MEdh
+nPWuhqp6tNaDI/kK6XQF+LjYJUzua3AQFOHfYNLKhO6d+bJ4rr0833v4v3cLW34kbXkKb6U3Yv8X
+SK3jBGCACiPgnc0N6awkh1kDlrZQ7GMsl14c+2+vpl9Lf0sL0mRUIyICfSC8MjlsP/BZH3emyfsk
+iWivPALomycKqP+PSkt1WaWApGENZWk1wNN99FYSYlt6LViW2p6T97fRx4jPRlHu+wecfD2k9RP4
+bt5W2HWfOP0zNAS7SnAVLEl2QZxXKw==
+</ds:X509Certificate>
+</ds:X509Data>
+<ds:KeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+<ds:RSAKeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+<ds:Modulus xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+qOSWbDOGS31lv3aUZVOgqZyLVrKXXRfmxFQxEylcFY/bRqakeY1EYCkvwTkD9kxlLEd/2SSQYWEZ
+ZTjYa1EK1SlfyOsKd2eNKjxGtUSSxPkJRvYi/KgVedgp15C5p1Emsd3bKUs5knLebw4k576RxvY6
+9AChXk48u1Pa7/Bicm89Io8JaQaDvSUXWD19j6686EniS6MSqvhsLsgmeS4V0TdKdWvjQIq0wJmP
+nBtWUy5DJn3glMtbeh/2xuEZ2Dkkjzr5O0W+vJUKVKm/qW2zbgdqP2/XA8LSywrRlZbvuVo/Jq8r
+WNxRhUDNtI98lXkSJ5hqk0wwXpUGvwjuCSqgZZmnmBCLzWGxbPfgJamnYr8AzudUaXT6PXz0qbAa
+cmTL+ktm1zblDC/kZPfVsiiUzzND02YUS2euGVxIZc95EFlaEpa3MMIpurI+i0VG+SEagN5cURVC
+OjVysokC2pkKfrd//ThlvS9aywnMO8haNLPC4TEzzIr+KJff4UFYk/vCAsw7K9DjPWYheP1GoBUZ
+bSApVe9HI4dQ6bGY80CEVRmo/LkPyXbX0c+BONyou1NGtlaYaP7eqaC1Z3b+OrZF+Z2BrTFuFnzK
+A2X5UPaWo77yra9owdcKG+p7FPlU5gHFmcuAQjx/l8nw8P9EhQXVHHiSSbT1iHmBQ1GO6J6bX/s=
+</ds:Modulus>
+<ds:Exponent xmlns:ds="http://www.w3.org/2000/09/xmldsig#">AQAB</ds:Exponent>
+</ds:RSAKeyValue>
+</ds:KeyValue>
+</ds:KeyInfo>
+</ds:Signature></bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.2/invalid-bomformat-1.2.json b/tests/_data/schemaTestData/1.2/invalid-bomformat-1.2.json
new file mode 100644
index 000000000..ab493ea09
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-bomformat-1.2.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "AnotherFormat",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-component-ref-1.2.json b/tests/_data/schemaTestData/1.2/invalid-component-ref-1.2.json
new file mode 100644
index 000000000..570520d4a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-component-ref-1.2.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    },
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-component-ref-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-component-ref-1.2.xml
new file mode 100644
index 000000000..7ddef820b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-component-ref-1.2.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library" bom-ref="123">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library" bom-ref="123">
+                    <name>acme-library</name>
+                    <version>1.0.0</version>
+                </component>
+            </components>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-component-swid-1.2.json b/tests/_data/schemaTestData/1.2/invalid-component-swid-1.2.json
new file mode 100644
index 000000000..e93d6ed15
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-component-swid-1.2.json
@@ -0,0 +1,18 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "name": "Acme Application",
+        "version": "9.1.1"
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-component-swid-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-component-swid-1.2.xml
new file mode 100644
index 000000000..4aac9cbed
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-component-swid-1.2.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid name="Acme Application" version="9.1.1" />
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-component-type-1.2.json b/tests/_data/schemaTestData/1.2/invalid-component-type-1.2.json
new file mode 100644
index 000000000..a34b26e31
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-component-type-1.2.json
@@ -0,0 +1,13 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "foo",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-component-type-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-component-type-1.2.xml
new file mode 100644
index 000000000..881350ab2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-component-type-1.2.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="foo">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-dependency-1.2.json b/tests/_data/schemaTestData/1.2/invalid-dependency-1.2.json
new file mode 100644
index 000000000..248d4f8f8
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-dependency-1.2.json
@@ -0,0 +1,37 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "library-a",
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-b",
+      "type": "library",
+      "name": "library-b",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-c",
+      "type": "library",
+      "name": "library-c",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "dependsOn": []
+    },
+    {
+      "ref": "library-b",
+      "dependsOn": [
+        "library-c"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-dependency-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-dependency-1.2.xml
new file mode 100644
index 000000000..b954f29d4
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-dependency-1.2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library" bom-ref="library-a">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-b">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-c">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+    <dependencies>
+        <dependency />
+        <dependency ref="library-b">
+            <dependency ref="library-c"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-empty-component-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-empty-component-1.2.xml
new file mode 100644
index 000000000..af24c96ad
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-empty-component-1.2.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-alg-1.2.json b/tests/_data/schemaTestData/1.2/invalid-hash-alg-1.2.json
new file mode 100644
index 000000000..9a4a50472
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-alg-1.2.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "FOO",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-alg-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-hash-alg-1.2.xml
new file mode 100644
index 000000000..7f4f077f5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-alg-1.2.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="FOO">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-md5-1.2.json b/tests/_data/schemaTestData/1.2/invalid-hash-md5-1.2.json
new file mode 100644
index 000000000..9edb2eb4f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-md5-1.2.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-md5-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-hash-md5-1.2.xml
new file mode 100644
index 000000000..1f12a35b1
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-md5-1.2.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">foo</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-sha1-1.2.json b/tests/_data/schemaTestData/1.2/invalid-hash-sha1-1.2.json
new file mode 100644
index 000000000..7cfa1e04d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-sha1-1.2.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-sha1-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-hash-sha1-1.2.xml
new file mode 100644
index 000000000..8c660bda5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-sha1-1.2.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">foo</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-sha256-1.2.json b/tests/_data/schemaTestData/1.2/invalid-hash-sha256-1.2.json
new file mode 100644
index 000000000..3ec0bdd5f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-sha256-1.2.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-sha256-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-hash-sha256-1.2.xml
new file mode 100644
index 000000000..13954ca39
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-sha256-1.2.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">foo</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-sha512-1.2.json b/tests/_data/schemaTestData/1.2/invalid-hash-sha512-1.2.json
new file mode 100644
index 000000000..a80fb9c86
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-sha512-1.2.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "foo"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-hash-sha512-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-hash-sha512-1.2.xml
new file mode 100644
index 000000000..36bd80937
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-hash-sha512-1.2.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">foo</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-issue-type-1.2.json b/tests/_data/schemaTestData/1.2/invalid-issue-type-1.2.json
new file mode 100644
index 000000000..ce04bd3f5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-issue-type-1.2.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "unofficial",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "foo",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-issue-type-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-issue-type-1.2.xml
new file mode 100644
index 000000000..611fc2eba
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-issue-type-1.2.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="unofficial">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="foo">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-license-choice-1.2.json b/tests/_data/schemaTestData/1.2/invalid-license-choice-1.2.json
new file mode 100644
index 000000000..2084a1977
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-license-choice-1.2.json
@@ -0,0 +1,23 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "expression": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0",
+          "license": {
+            "name": "Apache License 2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-license-choice-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-license-choice-1.2.xml
new file mode 100644
index 000000000..02396c08b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-license-choice-1.2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-license-encoding-1.2.json b/tests/_data/schemaTestData/1.2/invalid-license-encoding-1.2.json
new file mode 100644
index 000000000..c46dbce8e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-license-encoding-1.2.json
@@ -0,0 +1,28 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0",
+            "text": {
+              "contentType": "text/plain",
+              "encoding": "base85",
+              "content": "CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4="
+            },
+            "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-license-encoding-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-license-encoding-1.2.xml
new file mode 100644
index 000000000..e003ce04e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-license-encoding-1.2.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base85">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-license-id-1.2.json b/tests/_data/schemaTestData/1.2/invalid-license-id-1.2.json
new file mode 100644
index 000000000..3e16a5c6d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-license-id-1.2.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-license-id-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-license-id-1.2.xml
new file mode 100644
index 000000000..f85430021
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-license-id-1.2.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-license-id-count-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-license-id-count-1.2.xml
new file mode 100644
index 000000000..cca7e050e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-license-id-count-1.2.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>MIT</id>
+                    <!-- This was a defect in schema 1.0 and is no longer permitted -->
+                    <id>MIT</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-license-name-count-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-license-name-count-1.2.xml
new file mode 100644
index 000000000..0d335e165
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-license-name-count-1.2.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Apache License 2.0</name>
+                    <!-- This was a defect in schema 1.0 and is no longer permitted -->
+                    <name>Apache License 2.0</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-metadata-timestamp-1.2.json b/tests/_data/schemaTestData/1.2/invalid-metadata-timestamp-1.2.json
new file mode 100644
index 000000000..b1dcfa8de
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-metadata-timestamp-1.2.json
@@ -0,0 +1,10 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13"
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-metadata-timestamp-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-metadata-timestamp-1.2.xml
new file mode 100644
index 000000000..b34b81e7f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-metadata-timestamp-1.2.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <metadata>
+        <timestamp>2020-04-07</timestamp>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-missing-component-type-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-missing-component-type-1.2.xml
new file mode 100644
index 000000000..91dd27755
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-missing-component-type-1.2.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component>
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-namespace-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-namespace-1.2.xml
new file mode 100644
index 000000000..9e42be401
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-namespace-1.2.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/12">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-patch-type-1.2.json b/tests/_data/schemaTestData/1.2/invalid-patch-type-1.2.json
new file mode 100644
index 000000000..4a1eb80aa
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-patch-type-1.2.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "foo",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "enhancement",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-patch-type-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-patch-type-1.2.xml
new file mode 100644
index 000000000..8a5ba4609
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-patch-type-1.2.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="foo">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="enhancement">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-scope-1.2.json b/tests/_data/schemaTestData/1.2/invalid-scope-1.2.json
new file mode 100644
index 000000000..987481fce
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-scope-1.2.json
@@ -0,0 +1,14 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "foo"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-scope-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-scope-1.2.xml
new file mode 100644
index 000000000..b1e610126
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-scope-1.2.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>foo</scope>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-serialnumber-1.2.json b/tests/_data/schemaTestData/1.2/invalid-serialnumber-1.2.json
new file mode 100644
index 000000000..691956ad3
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-serialnumber-1.2.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-serialnumber-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-serialnumber-1.2.xml
new file mode 100644
index 000000000..1fabd2436
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-serialnumber-1.2.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/invalid-service-data-1.2.json b/tests/_data/schemaTestData/1.2/invalid-service-data-1.2.json
new file mode 100644
index 000000000..b341c481f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-service-data-1.2.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "name": "Stock ticker service",
+      "authenticated": true,
+      "x-trust-boundary": true,
+      "data": [
+        {
+          "classification": "foo",
+          "flow": "bar"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/invalid-service-data-1.2.xml b/tests/_data/schemaTestData/1.2/invalid-service-data-1.2.xml
new file mode 100644
index 000000000..5ef788902
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/invalid-service-data-1.2.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <name>Stock ticker service</name>
+            <data>
+                <classification flow="foo">bar</classification>
+            </data>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/skip_invalid-empty-component-1.2.json b/tests/_data/schemaTestData/1.2/skip_invalid-empty-component-1.2.json
new file mode 100644
index 000000000..fa916a9e1
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/skip_invalid-empty-component-1.2.json
@@ -0,0 +1,12 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "$comment": "expected to fail, since `name` and `version` are missing. But in fact `name` and `version` are optional as they have a default value in CDX-v1.2"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/skip_invalid-missing-component-type-1.2.json b/tests/_data/schemaTestData/1.2/skip_invalid-missing-component-type-1.2.json
new file mode 100644
index 000000000..141da0727
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/skip_invalid-missing-component-type-1.2.json
@@ -0,0 +1,13 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "name": "acme-library",
+      "version": "1.0.0",
+      "$comment": "expected to fail, since `type` is missing. But in fact `type` is optional as it has a default value in CDX-v1.2"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-assembly-1.2.json b/tests/_data/schemaTestData/1.2/valid-assembly-1.2.json
new file mode 100644
index 000000000..2516922c6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-assembly-1.2.json
@@ -0,0 +1,30 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library-a",
+      "version": "1.0.0",
+      "components": [
+        {
+          "type": "library",
+          "name": "acme-library-b",
+          "version": "2.0.0"
+        }
+      ]
+    }
+  ],
+  "services": [
+    {
+      "name": "acme-service-a",
+      "services": [
+        {
+          "name": "acme-service-b"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-assembly-1.2.xml b/tests/_data/schemaTestData/1.2/valid-assembly-1.2.xml
new file mode 100644
index 000000000..c58ef4d2a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-assembly-1.2.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library">
+                    <name>acme-library-b</name>
+                    <version>2.0.0</version>
+                </component>
+            </components>
+        </component>
+    </components>
+    <services>
+        <service>
+            <name>acme-service-a</name>
+            <services>
+                <service>
+                    <name>acme-service-b</name>
+                </service>
+            </services>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-bom-1.2.json b/tests/_data/schemaTestData/1.2/valid-bom-1.2.json
new file mode 100644
index 000000000..629793568
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-bom-1.2.json
@@ -0,0 +1,177 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13T20:20:39+00:00",
+    "tools": [
+      {
+        "vendor": "Awesome Vendor",
+        "name": "Awesome Tool",
+        "version": "9.1.2",
+        "hashes": [
+          {
+            "alg": "SHA-1",
+            "content": "25ed8e31b995bb927966616df2a42b979a2717f0"
+          },
+          {
+            "alg": "SHA-256",
+            "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df"
+          }
+        ]
+      }
+    ],
+    "authors": [
+      {
+        "name": "Samantha Wright",
+        "email": "samantha.wright@example.com",
+        "phone": "800-555-1212"
+      }
+    ],
+    "component": {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1",
+        "text": {
+          "contentType": "text/xml",
+          "encoding": "base64",
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
+        }
+      }
+    },
+    "manufacture": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Professional Services",
+          "email": "professional.services@example.com"
+        }
+      ]
+    },
+    "supplier": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Distribution",
+          "email": "distribution@example.com"
+        }
+      ]
+    }
+  },
+  "components": [
+    {
+      "bom-ref": "pkg:npm/acme/component@1.0.0",
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0",
+            "text": {
+              "contentType": "text/plain",
+              "encoding": "base64",
+              "content": "CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4="
+            },
+            "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
+          }
+        }
+      ],
+      "purl": "pkg:npm/acme/component@1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "publisher": "Acme Inc",
+            "group": "com.acme",
+            "name": "tomcat-catalina",
+            "version": "9.0.14"
+          },
+          {
+            "type": "library",
+            "publisher": "Acme Inc",
+            "group": "com.acme",
+            "name": "tomcat-catalina",
+            "version": "9.0.14"
+          }
+        ],
+        "commits": [
+          {
+            "uid": "7638417db6d59f3c431d3e1f261cc637155684cd",
+            "url": "https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd",
+            "author": {
+              "timestamp": "2018-11-13T20:20:39+00:00",
+              "name": "me",
+              "email": "me@acme.org"
+            }
+          }
+        ]
+      }
+    },
+    {
+      "type": "library",
+      "supplier": {
+        "name": "Example, Inc.",
+        "url": [
+          "https://example.com",
+          "https://example.net"
+        ],
+        "contact": [
+          {
+            "name": "Example Support AMER Distribution",
+            "email": "support@example.com",
+            "phone": "800-555-1212"
+          },
+          {
+            "name": "Example Support APAC",
+            "email": "support@apac.example.com"
+          }
+        ]
+      },
+      "author": "Example Super Heros",
+      "group": "org.example",
+      "name": "mylibrary",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:npm/acme/component@1.0.0",
+      "dependsOn": [
+        "pkg:npm/acme/component@1.0.0"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-bom-1.2.xml b/tests/_data/schemaTestData/1.2/valid-bom-1.2.xml
new file mode 100644
index 000000000..6be1b4f06
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-bom-1.2.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <metadata>
+        <timestamp>2020-04-07T07:01:00Z</timestamp>
+        <tools>
+            <tool>
+                <vendor>Awesome Vendor</vendor>
+                <name>Awesome Tool</name>
+                <version>9.1.2</version>
+                <hashes>
+                    <hash alg="SHA-1">25ed8e31b995bb927966616df2a42b979a2717f0</hash>
+                    <hash alg="SHA-256">a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df</hash>
+                </hashes>
+            </tool>
+        </tools>
+        <authors>
+            <author>
+                <name>Samantha Wright</name>
+                <email>samantha.wright@example.com</email>
+                <phone>800-555-1212</phone>
+            </author>
+        </authors>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1">
+                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+            </swid>
+        </component>
+        <manufacture>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Professional Services</name>
+                <email>professional.services@example.com</email>
+            </contact>
+        </manufacture>
+        <supplier>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Distribution</name>
+                <email>distribution@example.com</email>
+            </contact>
+        </supplier>
+    </metadata>
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <author>Apache Super Heros</author>
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <supplier>
+                <name>Example Inc.</name>
+                <url>https://example.com</url>
+                <url>https://example.net</url>
+                <contact>
+                    <name>Example Support AMER</name>
+                    <email>support@example.com</email>
+                    <phone>800-555-1212</phone>
+                </contact>
+                <contact>
+                    <name>Example Support APAC</name>
+                    <email>support@apac.example.com</email>
+                </contact>
+            </supplier>
+            <author>Example Super Heros</author>
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0-with-classpath-exception</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <author>Example Super Heros</author>
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-component-hashes-1.2.json b/tests/_data/schemaTestData/1.2/valid-component-hashes-1.2.json
new file mode 100644
index 000000000..98d4285e5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-hashes-1.2.json
@@ -0,0 +1,63 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-example",
+      "version": "1.0.0",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "641b6e166f8b33c5e959e2adcc18b1c7"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "9188560f22e0b73070d2efce670c74af2bdf30af"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964"
+        },
+        {
+          "alg": "SHA-384",
+          "content": "d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6"
+        },
+        {
+          "alg": "SHA3-256",
+          "content": "7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa"
+        },
+        {
+          "alg": "SHA3-384",
+          "content": "a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5"
+        },
+        {
+          "alg": "SHA3-512",
+          "content": "7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20"
+        },
+        {
+          "alg": "BLAKE2b-256",
+          "content": "d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237"
+        },
+        {
+          "alg": "BLAKE2b-384",
+          "content": "e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a"
+        },
+        {
+          "alg": "BLAKE2b-512",
+          "content": "f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d"
+        },
+        {
+          "alg": "BLAKE3",
+          "content": "26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-component-hashes-1.2.xml b/tests/_data/schemaTestData/1.2/valid-component-hashes-1.2.xml
new file mode 100644
index 000000000..309e0ee23
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-hashes-1.2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-example</name>
+            <version>1.0.0</version>
+            <hashes>
+                <hash alg="MD5">641b6e166f8b33c5e959e2adcc18b1c7</hash>
+                <hash alg="SHA-1">9188560f22e0b73070d2efce670c74af2bdf30af</hash>
+                <hash alg="SHA-256">d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964</hash>
+                <hash alg="SHA-384">d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad</hash>
+                <hash alg="SHA-512">74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6</hash>
+                <hash alg="SHA3-256">7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa</hash>
+                <hash alg="SHA3-384">a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5</hash>
+                <hash alg="SHA3-512">7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20</hash>
+                <hash alg="BLAKE2b-256">d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237</hash>
+                <hash alg="BLAKE2b-384">e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a</hash>
+                <hash alg="BLAKE2b-512">f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d</hash>
+                <hash alg="BLAKE3">26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-component-ref-1.2.json b/tests/_data/schemaTestData/1.2/valid-component-ref-1.2.json
new file mode 100644
index 000000000..131af1d78
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-ref-1.2.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    },
+    {
+      "type": "library",
+      "bom-ref": "456",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-component-ref-1.2.xml b/tests/_data/schemaTestData/1.2/valid-component-ref-1.2.xml
new file mode 100644
index 000000000..46d33c470
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-ref-1.2.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library" bom-ref="123">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library" bom-ref="456">
+                    <name>acme-library</name>
+                    <version>1.0.0</version>
+                </component>
+            </components>
+        </component>
+        <component type="library" bom-ref="789">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-component-swid-1.2.json b/tests/_data/schemaTestData/1.2/valid-component-swid-1.2.json
new file mode 100644
index 000000000..96a0ae1c0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-swid-1.2.json
@@ -0,0 +1,19 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1"
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-component-swid-1.2.xml b/tests/_data/schemaTestData/1.2/valid-component-swid-1.2.xml
new file mode 100644
index 000000000..4e1fe5391
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-swid-1.2.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1" />
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-component-swid-full-1.2.json b/tests/_data/schemaTestData/1.2/valid-component-swid-full-1.2.json
new file mode 100644
index 000000000..02b935e38
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-swid-full-1.2.json
@@ -0,0 +1,24 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1",
+        "text": {
+          "contentType": "text/xml",
+          "encoding": "base64",
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-component-swid-full-1.2.xml b/tests/_data/schemaTestData/1.2/valid-component-swid-full-1.2.xml
new file mode 100644
index 000000000..d7bba6bce
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-swid-full-1.2.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1">
+                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+            </swid>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-component-types-1.2.json b/tests/_data/schemaTestData/1.2/valid-component-types-1.2.json
new file mode 100644
index 000000000..5ffcbd71d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-types-1.2.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "name": "application-a",
+      "version": "1.0"
+    },
+    {
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0"
+    },
+    {
+      "type": "framework",
+      "name": "framework-a",
+      "version": "1.0"
+    },
+    {
+      "type": "container",
+      "name": "container-a",
+      "version": "1.0"
+    },
+    {
+      "type": "operating-system",
+      "name": "operating-system-a",
+      "version": "1.0"
+    },
+    {
+      "type": "firmware",
+      "name": "firmware-a",
+      "version": "1.0"
+    },
+    {
+      "type": "device",
+      "name": "device-a",
+      "version": "1.0"
+    },
+    {
+      "type": "file",
+      "name": "file-a",
+      "version": "1.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-component-types-1.2.xml b/tests/_data/schemaTestData/1.2/valid-component-types-1.2.xml
new file mode 100644
index 000000000..0349a1a45
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-component-types-1.2.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <name>application-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="library">
+            <name>library-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="framework">
+            <name>framework-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="container">
+            <name>container-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="operating-system">
+            <name>operating-system-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="firmware">
+            <name>firmware-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="device">
+            <name>device-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="file">
+            <name>file-a</name>
+            <version>1.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-dependency-1.2.json b/tests/_data/schemaTestData/1.2/valid-dependency-1.2.json
new file mode 100644
index 000000000..bf3a26494
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-dependency-1.2.json
@@ -0,0 +1,38 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "library-a",
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-b",
+      "type": "library",
+      "name": "library-b",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-c",
+      "type": "library",
+      "name": "library-c",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "library-a",
+      "dependsOn": []
+    },
+    {
+      "ref": "library-b",
+      "dependsOn": [
+        "library-c"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-dependency-1.2.xml b/tests/_data/schemaTestData/1.2/valid-dependency-1.2.xml
new file mode 100644
index 000000000..e245766ce
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-dependency-1.2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library" bom-ref="library-a">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-b">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-c">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+    <dependencies>
+        <dependency ref="library-a"/>
+        <dependency ref="library-b">
+            <dependency ref="library-c"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-empty-components-1.2.json b/tests/_data/schemaTestData/1.2/valid-empty-components-1.2.json
new file mode 100644
index 000000000..c3878bf6c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-empty-components-1.2.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-empty-components-1.2.xml b/tests/_data/schemaTestData/1.2/valid-empty-components-1.2.xml
new file mode 100644
index 000000000..cacbb9dfc
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-empty-components-1.2.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-external-elements-1.2.xml b/tests/_data/schemaTestData/1.2/valid-external-elements-1.2.xml
new file mode 100644
index 000000000..3231b7038
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-external-elements-1.2.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                                <foo:fruit xmlns:foo="foo">
+                                    <foo:name>Banana</foo:name>
+                                </foo:fruit>
+                                <foo:fruit xmlns:foo="foo">
+                                    <foo:name>Banana</foo:name>
+                                </foo:fruit>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </ancestors>
+                <descendants>
+                    <component type="library">
+                        <name>foo</name>
+                        <version>1.0</version>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </descendants>
+                <variants>
+                    <component type="library">
+                        <name>bar</name>
+                        <version>1.0</version>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </variants>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                        </committer>
+                        <message>Initial commit</message>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                    </commit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </commits>
+                <notes>Commentary here</notes>
+                <foo:fruit xmlns:foo="foo">
+                    <foo:name>Banana</foo:name>
+                </foo:fruit>
+                <foo:fruit xmlns:foo="foo">
+                    <foo:name>Banana</foo:name>
+                </foo:fruit>
+            </pedigree>
+            <foo:fruit xmlns:foo="foo">
+                <foo:name>Banana</foo:name>
+            </foo:fruit>
+            <foo:fruit xmlns:foo="foo">
+                <foo:name>Banana</foo:name>
+            </foo:fruit>
+        </component>
+        <foo:fruit xmlns:foo="foo">
+            <foo:name>Banana</foo:name>
+        </foo:fruit>
+        <foo:fruit xmlns:foo="foo">
+            <foo:name>Banana</foo:name>
+        </foo:fruit>
+    </components>
+    <foo:fruit xmlns:foo="foo">
+        <foo:name>Banana</foo:name>
+    </foo:fruit>
+    <foo:fruit xmlns:foo="foo">
+        <foo:name>Banana</foo:name>
+    </foo:fruit>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-license-expression-1.2.json b/tests/_data/schemaTestData/1.2/valid-license-expression-1.2.json
new file mode 100644
index 000000000..89c06c1ca
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-license-expression-1.2.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "expression": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-license-expression-1.2.xml b/tests/_data/schemaTestData/1.2/valid-license-expression-1.2.xml
new file mode 100644
index 000000000..53f5c1ca5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-license-expression-1.2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-license-id-1.2.json b/tests/_data/schemaTestData/1.2/valid-license-id-1.2.json
new file mode 100644
index 000000000..0b3ff68b1
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-license-id-1.2.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-license-id-1.2.xml b/tests/_data/schemaTestData/1.2/valid-license-id-1.2.xml
new file mode 100644
index 000000000..2cf536cd2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-license-id-1.2.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-license-name-1.2.json b/tests/_data/schemaTestData/1.2/valid-license-name-1.2.json
new file mode 100644
index 000000000..4dabe805b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-license-name-1.2.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "name": "Apache License 2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-license-name-1.2.xml b/tests/_data/schemaTestData/1.2/valid-license-name-1.2.xml
new file mode 100644
index 000000000..11cb08a6b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-license-name-1.2.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Apache License 2.0</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-author-1.2.json b/tests/_data/schemaTestData/1.2/valid-metadata-author-1.2.json
new file mode 100644
index 000000000..e0c0b45ac
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-author-1.2.json
@@ -0,0 +1,16 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "authors": [
+      {
+        "name": "Samantha Wright",
+        "email": "samantha.wright@example.com",
+        "phone": "800-555-1212"
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-author-1.2.xml b/tests/_data/schemaTestData/1.2/valid-metadata-author-1.2.xml
new file mode 100644
index 000000000..e37ac51d9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-author-1.2.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <metadata>
+        <authors>
+            <author>
+                <name>Samantha Wright</name>
+                <email>samantha.wright@example.com</email>
+                <phone>800-555-1212</phone>
+            </author>
+        </authors>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-manufacture-1.2.json b/tests/_data/schemaTestData/1.2/valid-metadata-manufacture-1.2.json
new file mode 100644
index 000000000..fb92230a6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-manufacture-1.2.json
@@ -0,0 +1,21 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "manufacture": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Professional Services",
+          "email": "professional.services@example.com"
+        }
+      ]
+    }
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-manufacture-1.2.xml b/tests/_data/schemaTestData/1.2/valid-metadata-manufacture-1.2.xml
new file mode 100644
index 000000000..b6773a54e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-manufacture-1.2.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <metadata>
+        <manufacture>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Professional Services</name>
+                <email>professional.services@example.com</email>
+            </contact>
+        </manufacture>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-supplier-1.2.json b/tests/_data/schemaTestData/1.2/valid-metadata-supplier-1.2.json
new file mode 100644
index 000000000..5a241c788
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-supplier-1.2.json
@@ -0,0 +1,21 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "supplier": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Distribution",
+          "email": "distribution@example.com"
+        }
+      ]
+    }
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-supplier-1.2.xml b/tests/_data/schemaTestData/1.2/valid-metadata-supplier-1.2.xml
new file mode 100644
index 000000000..8a980b254
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-supplier-1.2.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <metadata>
+        <supplier>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Distribution</name>
+                <email>distribution@example.com</email>
+            </contact>
+        </supplier>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-timestamp-1.2.json b/tests/_data/schemaTestData/1.2/valid-metadata-timestamp-1.2.json
new file mode 100644
index 000000000..cf242cca2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-timestamp-1.2.json
@@ -0,0 +1,10 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13T20:20:39+00:00"
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-timestamp-1.2.xml b/tests/_data/schemaTestData/1.2/valid-metadata-timestamp-1.2.xml
new file mode 100644
index 000000000..4891b1a50
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-timestamp-1.2.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <metadata>
+        <timestamp>2020-04-07T07:01:00Z</timestamp>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-tool-1.2.json b/tests/_data/schemaTestData/1.2/valid-metadata-tool-1.2.json
new file mode 100644
index 000000000..7adade0db
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-tool-1.2.json
@@ -0,0 +1,26 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "tools": [
+      {
+        "vendor": "Awesome Vendor",
+        "name": "Awesome Tool",
+        "version": "9.1.2",
+        "hashes": [
+          {
+            "alg": "SHA-1",
+            "content": "25ed8e31b995bb927966616df2a42b979a2717f0"
+          },
+          {
+            "alg": "SHA-256",
+            "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df"
+          }
+        ]
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-metadata-tool-1.2.xml b/tests/_data/schemaTestData/1.2/valid-metadata-tool-1.2.xml
new file mode 100644
index 000000000..ebfc4085c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-metadata-tool-1.2.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <metadata>
+        <tools>
+            <tool>
+                <vendor>Awesome Vendor</vendor>
+                <name>Awesome Tool</name>
+                <version>9.1.2</version>
+                <hashes>
+                    <hash alg="SHA-1">25ed8e31b995bb927966616df2a42b979a2717f0</hash>
+                    <hash alg="SHA-256">a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df</hash>
+                </hashes>
+            </tool>
+        </tools>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-minimal-viable-1.2.json b/tests/_data/schemaTestData/1.2/valid-minimal-viable-1.2.json
new file mode 100644
index 000000000..5c9795c2e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-minimal-viable-1.2.json
@@ -0,0 +1,13 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-minimal-viable-1.2.xml b/tests/_data/schemaTestData/1.2/valid-minimal-viable-1.2.xml
new file mode 100644
index 000000000..7088bb511
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-minimal-viable-1.2.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-patch-1.2.json b/tests/_data/schemaTestData/1.2/valid-patch-1.2.json
new file mode 100644
index 000000000..2b53cf4c5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-patch-1.2.json
@@ -0,0 +1,88 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "unofficial",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "enhancement",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          },
+          {
+            "type": "backport",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "security",
+                "id": "CVE-2019-9997",
+                "name": "CVE-2019-9997",
+                "description": "blah blah",
+                "source": {
+                  "name": "NVD",
+                  "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9997"
+                },
+                "references": [
+                  "http://some/other/site-1",
+                  "http://some/other/site-2"
+                ]
+              },
+              {
+                "type": "defect",
+                "id": "JIRA-874319",
+                "description": "Enable to do something",
+                "source": {
+                  "name": "Example Org",
+                  "url": "https://issues.example.org/874319"
+                },
+                "references": [
+                  "http://some/other/site-1",
+                  "http://some/other/site-2"
+                ]
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-patch-1.2.xml b/tests/_data/schemaTestData/1.2/valid-patch-1.2.xml
new file mode 100644
index 000000000..80f9984b2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-patch-1.2.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="unofficial">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="enhancement">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                    <patch type="backport">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="security">
+                                <id>CVE-2019-9997</id>
+                                <name>CVE-2019-9997</name>
+                                <description>blah blah</description>
+                                <source>
+                                    <name>NVD</name>
+                                    <url>https://nvd.nist.gov/vuln/detail/CVE-2019-9997</url>
+                                </source>
+                                <references>
+                                    <url>http://some/other/site-1</url>
+                                    <url>http://some/other/site-2</url>
+                                </references>
+                            </issue>
+                            <issue type="defect">
+                                <id>JIRA-874319</id>
+                                <description>Enable to do something</description>
+                                <source>
+                                    <name>Example Org</name>
+                                    <url>https://issues.example.org/874319</url>
+                                </source>
+                                <references>
+                                    <url>http://some/other/site-1</url>
+                                    <url>http://some/other/site-2</url>
+                                </references>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-random-attributes-1.2.xml b/tests/_data/schemaTestData/1.2/valid-random-attributes-1.2.xml
new file mode 100644
index 000000000..a76db616b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-random-attributes-1.2.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom foo="bar" bar="foo" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components foo="bar" bar="foo" >
+        <component foo="bar" bar="foo"  type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors foo="bar" bar="foo">
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-service-1.2.json b/tests/_data/schemaTestData/1.2/valid-service-1.2.json
new file mode 100644
index 000000000..2b75c68ba
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-service-1.2.json
@@ -0,0 +1,101 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:maven/com.acme/stock-java-client@1.0.12",
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "stock-java-client",
+      "version": "1.0.12",
+      "hashes": [
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "purl": "pkg:maven/com.acme/stock-java-client@1.0.12"
+    }
+  ],
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "provider": {
+        "name": "Partner Org",
+        "url": [
+          "https://partner.org"
+        ],
+        "contact": [
+          {
+            "name": "Support",
+            "email": "support@partner",
+            "phone": "800-555-1212"
+          }
+        ]
+      },
+      "group": "org.partner",
+      "name": "Stock ticker service",
+      "version": "2020-Q2",
+      "description": "Provides real-time stock information",
+      "endpoints": [
+        "https://partner.org/api/v1/lookup",
+        "https://partner.org/api/v1/stock"
+      ],
+      "authenticated": true,
+      "x-trust-boundary": true,
+      "data": [
+        {
+          "classification": "PII",
+          "flow": "inbound"
+        },
+        {
+          "classification": "PIFI",
+          "flow": "outbound"
+        },
+        {
+          "classification": "pubic",
+          "flow": "bi-directional"
+        },
+        {
+          "classification": "partner-data",
+          "flow": "unknown"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "name": "Partner license"
+          }
+        }
+      ],
+      "externalReferences": [
+        {
+          "type": "website",
+          "url": "http://partner.org"
+        },
+        {
+          "type": "documentation",
+          "url": "http://api.partner.org/swagger"
+        }
+      ]
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:maven/com.acme/stock-java-client@1.0.12",
+      "dependsOn": [
+        "b2a46a4b-8367-4bae-9820-95557cfe03a8"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-service-1.2.xml b/tests/_data/schemaTestData/1.2/valid-service-1.2.xml
new file mode 100644
index 000000000..48ee7af2a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-service-1.2.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="library" bom-ref="pkg:maven/com.acme/stock-java-client@1.0.12">
+            <group>com.acme</group>
+            <name>stock-java-client</name>
+            <version>1.0.12</version>
+            <hashes>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/stock-java-client@1.0.12</purl>
+        </component>
+    </components>
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <provider>
+                <name>Partner Org</name>
+                <url>https://partner.org</url>
+                <contact>
+                    <name>Support</name>
+                    <email>support@partner</email>
+                    <phone>800-555-1212</phone>
+                </contact>
+            </provider>
+            <group>org.partner</group>
+            <name>Stock ticker service</name>
+            <version>2020-Q2</version>
+            <description>Provides real-time stock information</description>
+            <endpoints>
+                <endpoint>https://partner.org/api/v1/lookup</endpoint>
+                <endpoint>https://partner.org/api/v1/stock</endpoint>
+            </endpoints>
+            <authenticated>true</authenticated>
+            <x-trust-boundary>true</x-trust-boundary>
+            <data>
+                <classification flow="inbound">PII</classification>
+                <classification flow="outbound">PIFI</classification>
+                <classification flow="bi-directional">pubic</classification>
+                <classification flow="unknown">partner-data</classification>
+            </data>
+            <licenses>
+                <license>
+                    <name>Partner license</name>
+                </license>
+            </licenses>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://partner.org</url>
+                </reference>
+                <reference type="documentation">
+                    <url>http://api.partner.org/swagger</url>
+                </reference>
+            </externalReferences>
+        </service>
+    </services>
+    <dependencies>
+        <dependency ref="pkg:maven/com.acme/stock-java-client@1.0.12">
+            <dependency ref="b2a46a4b-8367-4bae-9820-95557cfe03a8"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-service-empty-objects-1.2.json b/tests/_data/schemaTestData/1.2/valid-service-empty-objects-1.2.json
new file mode 100644
index 000000000..ece3a65f2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-service-empty-objects-1.2.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "provider": {
+        "contact": [
+        ]
+      },
+      "name": "Stock ticker service",
+      "endpoints": [
+      ],
+      "data": [
+      ],
+      "externalReferences": [
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.2/valid-service-empty-objects-1.2.xml b/tests/_data/schemaTestData/1.2/valid-service-empty-objects-1.2.xml
new file mode 100644
index 000000000..b1ecb31ed
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-service-empty-objects-1.2.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <provider>
+            </provider>
+            <name>Stock ticker service</name>
+            <endpoints>
+            </endpoints>
+            <data>
+            </data>
+            <licenses>
+            </licenses>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.2/valid-xml-signature-1.2.xml b/tests/_data/schemaTestData/1.2/valid-xml-signature-1.2.xml
new file mode 100644
index 000000000..96051448d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.2/valid-xml-signature-1.2.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.2">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>jdoe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>jdoe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/xml" encoding="base64">blah</text>
+                    <url>fdaf</url>
+                </license>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+        <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+            <ds:Reference URI="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+                </ds:Transforms>
+                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+                <ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">PrB8/rofGs34XwIX5OIdYSjV2aKSe5VaztJKBvsgjIk=</ds:DigestValue>
+            </ds:Reference>
+        </ds:SignedInfo>
+        <ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            ePGNg30Zl9CW7RZdcRn8gFCp1AlWncjudA9pQDXyqZOvyj9RC2YtkI688WdfDOdVRZs6mflJFXr7
+            IKA9wY6jVrEqZmlef55Qp/8iGwOjOjWbwYsm2AhrdkUi9gaFSWEd8uITYHOpWbiPFSsnimiK9+ft
+            56dkg/oJMLdXzlaukzq9iGkRcafRkW433OQcZIXwD2K8lg4cdD0pNNNqBa+PgIvzbxA5H84TyQDB
+            HBcQiw/j1edRBJgPOwlqzZDUawOJaFhAPUQ+GGKMetIJH2FqqrHXGuV1NIwnbWTCg40RdOcBdCrl
+            PDtDVjFh34uZ4dYBpJBIlM4daD2N4B6WPB5iHRyuZTczF2q03ObabuTgkpK6EeadFVqFNsEOOPPt
+            MDDyda+Lwff5KjvUHvRRtUDIOm2rNIQKzaseulwYcA9UWQHAFcupJmWcLLM4zzY7F/uOdZuSurzh
+            U6h5kdb76Juepof6ee4Q5YpwNOGNL5JfB4C3sc/Dbbv8dZ8OuXFYSZN7reUGZzCNksByqERPEbAe
+            n1ldJu1HnRXRQpwaon8Asy9CuNmPfFCfDwOs2B4p4tb+tLNIKFHdRlpd19Zr9vCMCbltXeqq0Cpq
+            OejSyLYGqSWzzzUh449dJrg6KTevrTNEln5GAlLBFSdjM5JA7KV2u/GyDVFwSEW7UKooGN4CtgU=
+        </ds:SignatureValue>
+        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            <ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:X509SubjectName xmlns:ds="http://www.w3.org/2000/09/xmldsig#">CN=bomsigner,OU=development,O=cyclonedx</ds:X509SubjectName>
+                <ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    MIIE+DCCAuCgAwIBAgIEXGzayTANBgkqhkiG9w0BAQsFADA+MRIwEAYDVQQKDAljeWNsb25lZHgx
+                    FDASBgNVBAsMC2RldmVsb3BtZW50MRIwEAYDVQQDDAlib21zaWduZXIwHhcNMTkwMjIwMDQ0MjQ5
+                    WhcNNDkwMjIwMDQ0MjQ5WjA+MRIwEAYDVQQKDAljeWNsb25lZHgxFDASBgNVBAsMC2RldmVsb3Bt
+                    ZW50MRIwEAYDVQQDDAlib21zaWduZXIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo
+                    5JZsM4ZLfWW/dpRlU6CpnItWspddF+bEVDETKVwVj9tGpqR5jURgKS/BOQP2TGUsR3/ZJJBhYRll
+                    ONhrUQrVKV/I6wp3Z40qPEa1RJLE+QlG9iL8qBV52CnXkLmnUSax3dspSzmSct5vDiTnvpHG9jr0
+                    AKFeTjy7U9rv8GJybz0ijwlpBoO9JRdYPX2PrrzoSeJLoxKq+GwuyCZ5LhXRN0p1a+NAirTAmY+c
+                    G1ZTLkMmfeCUy1t6H/bG4RnYOSSPOvk7Rb68lQpUqb+pbbNuB2o/b9cDwtLLCtGVlu+5Wj8mrytY
+                    3FGFQM20j3yVeRInmGqTTDBelQa/CO4JKqBlmaeYEIvNYbFs9+AlqadivwDO51RpdPo9fPSpsBpy
+                    ZMv6S2bXNuUML+Rk99WyKJTPM0PTZhRLZ64ZXEhlz3kQWVoSlrcwwim6sj6LRUb5IRqA3lxRFUI6
+                    NXKyiQLamQp+t3/9OGW9L1rLCcw7yFo0s8LhMTPMiv4ol9/hQViT+8ICzDsr0OM9ZiF4/UagFRlt
+                    IClV70cjh1DpsZjzQIRVGaj8uQ/JdtfRz4E43Ki7U0a2Vpho/t6poLVndv46tkX5nYGtMW4WfMoD
+                    ZflQ9pajvvKtr2jB1wob6nsU+VTmAcWZy4BCPH+XyfDw/0SFBdUceJJJtPWIeYFDUY7onptf+wID
+                    AQABMA0GCSqGSIb3DQEBCwUAA4ICAQCOVariNgK+9OF/5T9ZaSvZbkk45RTmzgQNXtFc5xfRvqwP
+                    s+pu/DFXm1R+ltjyS5j3w6NBZUFUI5MqLQr6JEEDrbu8BvfBO57wJNAEATj1JIHEfDfh7BxnBF8f
+                    oYFOwbrh4jOt0wz0FW2obsSVmF4GSvS7tTlWqTcsxjdZVmwP40RWu18B9jzv7M61adrWD3ksDA5O
+                    amSOsZi3Nt0aacDkyGRdCIEFi0fplxQInXMtD1z3RhXu2JSTAIr54Cei49Bh71kAXSWHMCog/f8a
+                    lSrZyqZBty/ACfU9DqlPIM+giHePKm4z2bcdpUdKZk6wcKDn4CvuBOqsMBMg7L05UEyyqTPD/4dk
+                    2GwJ8Nv0E5gsYHCIXF2cZ3OUVsw0mB/ozleEJVDE02uZZN/1wW1Xq028LsMdgN0Wk1WvWyF5MEdh
+                    nPWuhqp6tNaDI/kK6XQF+LjYJUzua3AQFOHfYNLKhO6d+bJ4rr0833v4v3cLW34kbXkKb6U3Yv8X
+                    SK3jBGCACiPgnc0N6awkh1kDlrZQ7GMsl14c+2+vpl9Lf0sL0mRUIyICfSC8MjlsP/BZH3emyfsk
+                    iWivPALomycKqP+PSkt1WaWApGENZWk1wNN99FYSYlt6LViW2p6T97fRx4jPRlHu+wecfD2k9RP4
+                    bt5W2HWfOP0zNAS7SnAVLEl2QZxXKw==
+                </ds:X509Certificate>
+            </ds:X509Data>
+            <ds:KeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:RSAKeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:Modulus xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                        qOSWbDOGS31lv3aUZVOgqZyLVrKXXRfmxFQxEylcFY/bRqakeY1EYCkvwTkD9kxlLEd/2SSQYWEZ
+                        ZTjYa1EK1SlfyOsKd2eNKjxGtUSSxPkJRvYi/KgVedgp15C5p1Emsd3bKUs5knLebw4k576RxvY6
+                        9AChXk48u1Pa7/Bicm89Io8JaQaDvSUXWD19j6686EniS6MSqvhsLsgmeS4V0TdKdWvjQIq0wJmP
+                        nBtWUy5DJn3glMtbeh/2xuEZ2Dkkjzr5O0W+vJUKVKm/qW2zbgdqP2/XA8LSywrRlZbvuVo/Jq8r
+                        WNxRhUDNtI98lXkSJ5hqk0wwXpUGvwjuCSqgZZmnmBCLzWGxbPfgJamnYr8AzudUaXT6PXz0qbAa
+                        cmTL+ktm1zblDC/kZPfVsiiUzzND02YUS2euGVxIZc95EFlaEpa3MMIpurI+i0VG+SEagN5cURVC
+                        OjVysokC2pkKfrd//ThlvS9aywnMO8haNLPC4TEzzIr+KJff4UFYk/vCAsw7K9DjPWYheP1GoBUZ
+                        bSApVe9HI4dQ6bGY80CEVRmo/LkPyXbX0c+BONyou1NGtlaYaP7eqaC1Z3b+OrZF+Z2BrTFuFnzK
+                        A2X5UPaWo77yra9owdcKG+p7FPlU5gHFmcuAQjx/l8nw8P9EhQXVHHiSSbT1iHmBQ1GO6J6bX/s=
+                    </ds:Modulus>
+                    <ds:Exponent xmlns:ds="http://www.w3.org/2000/09/xmldsig#">AQAB</ds:Exponent>
+                </ds:RSAKeyValue>
+            </ds:KeyValue>
+        </ds:KeyInfo>
+    </ds:Signature></bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-bomformat-1.3.json b/tests/_data/schemaTestData/1.3/invalid-bomformat-1.3.json
new file mode 100644
index 000000000..7df3cac2f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-bomformat-1.3.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "AnotherFormat",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-component-ref-1.3.json b/tests/_data/schemaTestData/1.3/invalid-component-ref-1.3.json
new file mode 100644
index 000000000..ba06096b8
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-component-ref-1.3.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    },
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-component-ref-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-component-ref-1.3.xml
new file mode 100644
index 000000000..4b5976dd3
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-component-ref-1.3.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library" bom-ref="123">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library" bom-ref="123">
+                    <name>acme-library</name>
+                    <version>1.0.0</version>
+                </component>
+            </components>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-component-swid-1.3.json b/tests/_data/schemaTestData/1.3/invalid-component-swid-1.3.json
new file mode 100644
index 000000000..455f2f33f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-component-swid-1.3.json
@@ -0,0 +1,18 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "name": "Acme Application",
+        "version": "9.1.1"
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-component-swid-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-component-swid-1.3.xml
new file mode 100644
index 000000000..868072da8
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-component-swid-1.3.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid name="Acme Application" version="9.1.1" />
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-component-type-1.3.json b/tests/_data/schemaTestData/1.3/invalid-component-type-1.3.json
new file mode 100644
index 000000000..a22bf3888
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-component-type-1.3.json
@@ -0,0 +1,13 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "foo",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-component-type-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-component-type-1.3.xml
new file mode 100644
index 000000000..2a9da0fbd
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-component-type-1.3.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="foo">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-dependency-1.3.json b/tests/_data/schemaTestData/1.3/invalid-dependency-1.3.json
new file mode 100644
index 000000000..988a04501
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-dependency-1.3.json
@@ -0,0 +1,37 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "library-a",
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-b",
+      "type": "library",
+      "name": "library-b",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-c",
+      "type": "library",
+      "name": "library-c",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "dependsOn": []
+    },
+    {
+      "ref": "library-b",
+      "dependsOn": [
+        "library-c"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-dependency-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-dependency-1.3.xml
new file mode 100644
index 000000000..d3c1567bc
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-dependency-1.3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library" bom-ref="library-a">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-b">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-c">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+    <dependencies>
+        <dependency />
+        <dependency ref="library-b">
+            <dependency ref="library-c"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-empty-component-1.3.json b/tests/_data/schemaTestData/1.3/invalid-empty-component-1.3.json
new file mode 100644
index 000000000..31537b2ca
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-empty-component-1.3.json
@@ -0,0 +1,11 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-empty-component-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-empty-component-1.3.xml
new file mode 100644
index 000000000..c47376c04
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-empty-component-1.3.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-alg-1.3.json b/tests/_data/schemaTestData/1.3/invalid-hash-alg-1.3.json
new file mode 100644
index 000000000..625094c34
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-alg-1.3.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "FOO",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-alg-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-hash-alg-1.3.xml
new file mode 100644
index 000000000..541b2ed21
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-alg-1.3.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="FOO">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-md5-1.3.json b/tests/_data/schemaTestData/1.3/invalid-hash-md5-1.3.json
new file mode 100644
index 000000000..408128193
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-md5-1.3.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-md5-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-hash-md5-1.3.xml
new file mode 100644
index 000000000..9e63b8fde
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-md5-1.3.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">foo</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-sha1-1.3.json b/tests/_data/schemaTestData/1.3/invalid-hash-sha1-1.3.json
new file mode 100644
index 000000000..7b1e0036c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-sha1-1.3.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-sha1-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-hash-sha1-1.3.xml
new file mode 100644
index 000000000..082a82672
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-sha1-1.3.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">foo</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-sha256-1.3.json b/tests/_data/schemaTestData/1.3/invalid-hash-sha256-1.3.json
new file mode 100644
index 000000000..49f747e0c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-sha256-1.3.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-sha256-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-hash-sha256-1.3.xml
new file mode 100644
index 000000000..e29c2b22c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-sha256-1.3.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">foo</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-sha512-1.3.json b/tests/_data/schemaTestData/1.3/invalid-hash-sha512-1.3.json
new file mode 100644
index 000000000..5e83aae6e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-sha512-1.3.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "foo"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-hash-sha512-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-hash-sha512-1.3.xml
new file mode 100644
index 000000000..463035235
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-hash-sha512-1.3.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">foo</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-issue-type-1.3.json b/tests/_data/schemaTestData/1.3/invalid-issue-type-1.3.json
new file mode 100644
index 000000000..cea6add44
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-issue-type-1.3.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "unofficial",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "foo",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-issue-type-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-issue-type-1.3.xml
new file mode 100644
index 000000000..f3b80ba8a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-issue-type-1.3.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="unofficial">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="foo">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-license-choice-1.3.json b/tests/_data/schemaTestData/1.3/invalid-license-choice-1.3.json
new file mode 100644
index 000000000..1218f847a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-license-choice-1.3.json
@@ -0,0 +1,23 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "expression": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0",
+          "license": {
+            "name": "Apache License 2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-license-choice-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-license-choice-1.3.xml
new file mode 100644
index 000000000..0a89d0247
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-license-choice-1.3.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-license-encoding-1.3.json b/tests/_data/schemaTestData/1.3/invalid-license-encoding-1.3.json
new file mode 100644
index 000000000..b61550ee0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-license-encoding-1.3.json
@@ -0,0 +1,28 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0",
+            "text": {
+              "contentType": "text/plain",
+              "encoding": "base85",
+              "content": "CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4="
+            },
+            "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-license-encoding-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-license-encoding-1.3.xml
new file mode 100644
index 000000000..1518cb716
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-license-encoding-1.3.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base85">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-license-id-1.3.json b/tests/_data/schemaTestData/1.3/invalid-license-id-1.3.json
new file mode 100644
index 000000000..0d275dd0e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-license-id-1.3.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-license-id-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-license-id-1.3.xml
new file mode 100644
index 000000000..9adb85cee
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-license-id-1.3.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-license-id-count-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-license-id-count-1.3.xml
new file mode 100644
index 000000000..ce13178da
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-license-id-count-1.3.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>MIT</id>
+                    <!-- This was a defect in schema 1.0 and is no longer permitted -->
+                    <id>MIT</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-license-name-count-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-license-name-count-1.3.xml
new file mode 100644
index 000000000..85d87e5a6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-license-name-count-1.3.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Apache License 2.0</name>
+                    <!-- This was a defect in schema 1.0 and is no longer permitted -->
+                    <name>Apache License 2.0</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-metadata-license-1.3.json b/tests/_data/schemaTestData/1.3/invalid-metadata-license-1.3.json
new file mode 100644
index 000000000..82a79226c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-metadata-license-1.3.json
@@ -0,0 +1,16 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "licenses": [
+      {
+        "license": {
+          "id": "Apache-2"
+        }
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-metadata-license-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-metadata-license-1.3.xml
new file mode 100644
index 000000000..07d4f9cbe
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-metadata-license-1.3.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <licenses>
+            <license>
+                <id>Apache-2</id>
+            </license>
+        </licenses>
+    </metadata>
+    <components />
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.3/invalid-metadata-timestamp-1.3.json b/tests/_data/schemaTestData/1.3/invalid-metadata-timestamp-1.3.json
new file mode 100644
index 000000000..a021eb672
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-metadata-timestamp-1.3.json
@@ -0,0 +1,10 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13"
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-metadata-timestamp-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-metadata-timestamp-1.3.xml
new file mode 100644
index 000000000..4154eed97
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-metadata-timestamp-1.3.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <timestamp>2020-04-07</timestamp>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-missing-component-type-1.3.json b/tests/_data/schemaTestData/1.3/invalid-missing-component-type-1.3.json
new file mode 100644
index 000000000..f11a51ef7
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-missing-component-type-1.3.json
@@ -0,0 +1,12 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-missing-component-type-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-missing-component-type-1.3.xml
new file mode 100644
index 000000000..ee10a82c9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-missing-component-type-1.3.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component>
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-namespace-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-namespace-1.3.xml
new file mode 100644
index 000000000..9e42be401
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-namespace-1.3.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/12">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-patch-type-1.3.json b/tests/_data/schemaTestData/1.3/invalid-patch-type-1.3.json
new file mode 100644
index 000000000..a8897abd2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-patch-type-1.3.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "foo",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "enhancement",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-patch-type-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-patch-type-1.3.xml
new file mode 100644
index 000000000..c6d591e98
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-patch-type-1.3.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="foo">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="enhancement">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-scope-1.3.json b/tests/_data/schemaTestData/1.3/invalid-scope-1.3.json
new file mode 100644
index 000000000..38e5bb102
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-scope-1.3.json
@@ -0,0 +1,14 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "foo"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-scope-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-scope-1.3.xml
new file mode 100644
index 000000000..6d25da49c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-scope-1.3.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>foo</scope>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-serialnumber-1.3.json b/tests/_data/schemaTestData/1.3/invalid-serialnumber-1.3.json
new file mode 100644
index 000000000..70d3112a0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-serialnumber-1.3.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-serialnumber-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-serialnumber-1.3.xml
new file mode 100644
index 000000000..b5578dc97
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-serialnumber-1.3.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/invalid-service-data-1.3.json b/tests/_data/schemaTestData/1.3/invalid-service-data-1.3.json
new file mode 100644
index 000000000..510684135
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-service-data-1.3.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "name": "Stock ticker service",
+      "authenticated": true,
+      "x-trust-boundary": true,
+      "data": [
+        {
+          "classification": "foo",
+          "flow": "bar"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/invalid-service-data-1.3.xml b/tests/_data/schemaTestData/1.3/invalid-service-data-1.3.xml
new file mode 100644
index 000000000..af9ed8b34
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/invalid-service-data-1.3.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <name>Stock ticker service</name>
+            <data>
+                <classification flow="foo">bar</classification>
+            </data>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-assembly-1.3.json b/tests/_data/schemaTestData/1.3/valid-assembly-1.3.json
new file mode 100644
index 000000000..78720ccb5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-assembly-1.3.json
@@ -0,0 +1,30 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library-a",
+      "version": "1.0.0",
+      "components": [
+        {
+          "type": "library",
+          "name": "acme-library-b",
+          "version": "2.0.0"
+        }
+      ]
+    }
+  ],
+  "services": [
+    {
+      "name": "acme-service-a",
+      "services": [
+        {
+          "name": "acme-service-b"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-assembly-1.3.xml b/tests/_data/schemaTestData/1.3/valid-assembly-1.3.xml
new file mode 100644
index 000000000..b53f3eb7d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-assembly-1.3.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library">
+                    <name>acme-library-b</name>
+                    <version>2.0.0</version>
+                </component>
+            </components>
+        </component>
+    </components>
+    <services>
+        <service>
+            <name>acme-service-a</name>
+            <services>
+                <service>
+                    <name>acme-service-b</name>
+                </service>
+            </services>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-bom-1.3.json b/tests/_data/schemaTestData/1.3/valid-bom-1.3.json
new file mode 100644
index 000000000..75550db71
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-bom-1.3.json
@@ -0,0 +1,177 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13T20:20:39+00:00",
+    "tools": [
+      {
+        "vendor": "Awesome Vendor",
+        "name": "Awesome Tool",
+        "version": "9.1.2",
+        "hashes": [
+          {
+            "alg": "SHA-1",
+            "content": "25ed8e31b995bb927966616df2a42b979a2717f0"
+          },
+          {
+            "alg": "SHA-256",
+            "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df"
+          }
+        ]
+      }
+    ],
+    "authors": [
+      {
+        "name": "Samantha Wright",
+        "email": "samantha.wright@example.com",
+        "phone": "800-555-1212"
+      }
+    ],
+    "component": {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1",
+        "text": {
+          "contentType": "text/xml",
+          "encoding": "base64",
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
+        }
+      }
+    },
+    "manufacture": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Professional Services",
+          "email": "professional.services@example.com"
+        }
+      ]
+    },
+    "supplier": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Distribution",
+          "email": "distribution@example.com"
+        }
+      ]
+    }
+  },
+  "components": [
+    {
+      "bom-ref": "pkg:npm/acme/component@1.0.0",
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0",
+            "text": {
+              "contentType": "text/plain",
+              "encoding": "base64",
+              "content": "CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4="
+            },
+            "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
+          }
+        }
+      ],
+      "purl": "pkg:npm/acme/component@1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "publisher": "Acme Inc",
+            "group": "com.acme",
+            "name": "tomcat-catalina",
+            "version": "9.0.14"
+          },
+          {
+            "type": "library",
+            "publisher": "Acme Inc",
+            "group": "com.acme",
+            "name": "tomcat-catalina",
+            "version": "9.0.14"
+          }
+        ],
+        "commits": [
+          {
+            "uid": "7638417db6d59f3c431d3e1f261cc637155684cd",
+            "url": "https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd",
+            "author": {
+              "timestamp": "2018-11-13T20:20:39+00:00",
+              "name": "me",
+              "email": "me@acme.org"
+            }
+          }
+        ]
+      }
+    },
+    {
+      "type": "library",
+      "supplier": {
+        "name": "Example, Inc.",
+        "url": [
+          "https://example.com",
+          "https://example.net"
+        ],
+        "contact": [
+          {
+            "name": "Example Support AMER Distribution",
+            "email": "support@example.com",
+            "phone": "800-555-1212"
+          },
+          {
+            "name": "Example Support APAC",
+            "email": "support@apac.example.com"
+          }
+        ]
+      },
+      "author": "Example Super Heros",
+      "group": "org.example",
+      "name": "mylibrary",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:npm/acme/component@1.0.0",
+      "dependsOn": [
+        "pkg:npm/acme/component@1.0.0"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-bom-1.3.xml b/tests/_data/schemaTestData/1.3/valid-bom-1.3.xml
new file mode 100644
index 000000000..c9cda0c6d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-bom-1.3.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <timestamp>2020-04-07T07:01:00Z</timestamp>
+        <tools>
+            <tool>
+                <vendor>Awesome Vendor</vendor>
+                <name>Awesome Tool</name>
+                <version>9.1.2</version>
+                <hashes>
+                    <hash alg="SHA-1">25ed8e31b995bb927966616df2a42b979a2717f0</hash>
+                    <hash alg="SHA-256">a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df</hash>
+                </hashes>
+            </tool>
+        </tools>
+        <authors>
+            <author>
+                <name>Samantha Wright</name>
+                <email>samantha.wright@example.com</email>
+                <phone>800-555-1212</phone>
+            </author>
+        </authors>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1">
+                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+            </swid>
+        </component>
+        <manufacture>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Professional Services</name>
+                <email>professional.services@example.com</email>
+            </contact>
+        </manufacture>
+        <supplier>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Distribution</name>
+                <email>distribution@example.com</email>
+            </contact>
+        </supplier>
+    </metadata>
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <author>Apache Super Heros</author>
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <supplier>
+                <name>Example Inc.</name>
+                <url>https://example.com</url>
+                <url>https://example.net</url>
+                <contact>
+                    <name>Example Support AMER</name>
+                    <email>support@example.com</email>
+                    <phone>800-555-1212</phone>
+                </contact>
+                <contact>
+                    <name>Example Support APAC</name>
+                    <email>support@apac.example.com</email>
+                </contact>
+            </supplier>
+            <author>Example Super Heros</author>
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0-with-classpath-exception</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <author>Example Super Heros</author>
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-component-hashes-1.3.json b/tests/_data/schemaTestData/1.3/valid-component-hashes-1.3.json
new file mode 100644
index 000000000..77be66513
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-hashes-1.3.json
@@ -0,0 +1,63 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-example",
+      "version": "1.0.0",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "641b6e166f8b33c5e959e2adcc18b1c7"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "9188560f22e0b73070d2efce670c74af2bdf30af"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964"
+        },
+        {
+          "alg": "SHA-384",
+          "content": "d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6"
+        },
+        {
+          "alg": "SHA3-256",
+          "content": "7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa"
+        },
+        {
+          "alg": "SHA3-384",
+          "content": "a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5"
+        },
+        {
+          "alg": "SHA3-512",
+          "content": "7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20"
+        },
+        {
+          "alg": "BLAKE2b-256",
+          "content": "d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237"
+        },
+        {
+          "alg": "BLAKE2b-384",
+          "content": "e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a"
+        },
+        {
+          "alg": "BLAKE2b-512",
+          "content": "f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d"
+        },
+        {
+          "alg": "BLAKE3",
+          "content": "26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-component-hashes-1.3.xml b/tests/_data/schemaTestData/1.3/valid-component-hashes-1.3.xml
new file mode 100644
index 000000000..53df1b7c7
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-hashes-1.3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-example</name>
+            <version>1.0.0</version>
+            <hashes>
+                <hash alg="MD5">641b6e166f8b33c5e959e2adcc18b1c7</hash>
+                <hash alg="SHA-1">9188560f22e0b73070d2efce670c74af2bdf30af</hash>
+                <hash alg="SHA-256">d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964</hash>
+                <hash alg="SHA-384">d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad</hash>
+                <hash alg="SHA-512">74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6</hash>
+                <hash alg="SHA3-256">7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa</hash>
+                <hash alg="SHA3-384">a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5</hash>
+                <hash alg="SHA3-512">7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20</hash>
+                <hash alg="BLAKE2b-256">d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237</hash>
+                <hash alg="BLAKE2b-384">e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a</hash>
+                <hash alg="BLAKE2b-512">f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d</hash>
+                <hash alg="BLAKE3">26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-component-ref-1.3.json b/tests/_data/schemaTestData/1.3/valid-component-ref-1.3.json
new file mode 100644
index 000000000..b7e2bb386
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-ref-1.3.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    },
+    {
+      "type": "library",
+      "bom-ref": "456",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-component-ref-1.3.xml b/tests/_data/schemaTestData/1.3/valid-component-ref-1.3.xml
new file mode 100644
index 000000000..89cdb8800
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-ref-1.3.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library" bom-ref="123">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library" bom-ref="456">
+                    <name>acme-library</name>
+                    <version>1.0.0</version>
+                </component>
+            </components>
+        </component>
+        <component type="library" bom-ref="789">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-component-swid-1.3.json b/tests/_data/schemaTestData/1.3/valid-component-swid-1.3.json
new file mode 100644
index 000000000..4dbad442c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-swid-1.3.json
@@ -0,0 +1,19 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1"
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-component-swid-1.3.xml b/tests/_data/schemaTestData/1.3/valid-component-swid-1.3.xml
new file mode 100644
index 000000000..859c11d67
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-swid-1.3.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1" />
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-component-swid-full-1.3.json b/tests/_data/schemaTestData/1.3/valid-component-swid-full-1.3.json
new file mode 100644
index 000000000..074dd07ec
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-swid-full-1.3.json
@@ -0,0 +1,24 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1",
+        "text": {
+          "contentType": "text/xml",
+          "encoding": "base64",
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-component-swid-full-1.3.xml b/tests/_data/schemaTestData/1.3/valid-component-swid-full-1.3.xml
new file mode 100644
index 000000000..0896c06df
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-swid-full-1.3.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1">
+                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+            </swid>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-component-types-1.3.json b/tests/_data/schemaTestData/1.3/valid-component-types-1.3.json
new file mode 100644
index 000000000..591dd3bf9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-types-1.3.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "name": "application-a",
+      "version": "1.0"
+    },
+    {
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0"
+    },
+    {
+      "type": "framework",
+      "name": "framework-a",
+      "version": "1.0"
+    },
+    {
+      "type": "container",
+      "name": "container-a",
+      "version": "1.0"
+    },
+    {
+      "type": "operating-system",
+      "name": "operating-system-a",
+      "version": "1.0"
+    },
+    {
+      "type": "firmware",
+      "name": "firmware-a",
+      "version": "1.0"
+    },
+    {
+      "type": "device",
+      "name": "device-a",
+      "version": "1.0"
+    },
+    {
+      "type": "file",
+      "name": "file-a",
+      "version": "1.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-component-types-1.3.xml b/tests/_data/schemaTestData/1.3/valid-component-types-1.3.xml
new file mode 100644
index 000000000..34676a638
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-component-types-1.3.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <name>application-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="library">
+            <name>library-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="framework">
+            <name>framework-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="container">
+            <name>container-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="operating-system">
+            <name>operating-system-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="firmware">
+            <name>firmware-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="device">
+            <name>device-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="file">
+            <name>file-a</name>
+            <version>1.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-compositions-1.3.json b/tests/_data/schemaTestData/1.3/valid-compositions-1.3.json
new file mode 100644
index 000000000..eeb6e48f6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-compositions-1.3.json
@@ -0,0 +1,65 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "component": {
+      "bom-ref": "acme-application-1.0",
+      "type": "application",
+      "name": "Acme Application",
+      "version": "1.0"
+    }
+  },
+  "components": [
+    {
+      "bom-ref": "pkg:maven/partner/shaded-library@1.0",
+      "type": "library",
+      "name": "Partner Shaded Library",
+      "version": "1.0",
+      "purl": "pkg:maven/partner/shaded-library@1.0",
+      "components": [
+        {
+          "bom-ref": "pkg:maven/ossproject/library@2.0",
+          "type": "library",
+          "name": "Some Opensource Library",
+          "version": "2.0",
+          "purl": "pkg:maven/ossproject/library@2.0"
+        }
+      ]
+    },
+    {
+      "bom-ref": "pkg:maven/acme/library@3.0",
+      "type": "library",
+      "name": "Acme Library",
+      "version": "3.0",
+      "purl": "pkg:maven/acme/library@3.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "acme-application-1.0",
+      "dependsOn": [
+        "pkg:maven/partner/shaded-library@1.0",
+        "pkg:maven/acme/library@3.0"
+      ]
+    }
+  ],
+  "compositions": [
+    {
+      "aggregate": "complete",
+      "assemblies": [
+        "pkg:maven/partner/shaded-library@1.0"
+      ],
+      "dependencies": [
+        "acme-application-1.0"
+      ]
+    },
+    {
+      "aggregate": "unknown",
+      "assemblies": [
+        "pkg:maven/acme/library@3.0"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-compositions-1.3.xml b/tests/_data/schemaTestData/1.3/valid-compositions-1.3.xml
new file mode 100644
index 000000000..2b2d78478
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-compositions-1.3.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <component type="application" bom-ref="acme-application-1.0">
+            <name>Acme Application</name>
+            <version>1.0</version>
+        </component>
+    </metadata>
+    <components>
+        <component type="library" bom-ref="pkg:maven/partner/shaded-library@1.0">
+            <name>Partner Shaded Library</name>
+            <version>1.0</version>
+            <purl>pkg:maven/partner/shaded-library@1.0</purl>
+            <components>
+                <component type="library" bom-ref="pkg:maven/ossproject/library@2.0">
+                    <name>Some Opensource Library</name>
+                    <version>2.0</version>
+                    <purl>pkg:maven/ossproject/library@2.0</purl>
+                </component>
+            </components>
+        </component>
+        <component type="library" bom-ref="pkg:maven/acme/library@3.0">
+            <name>Acme Library</name>
+            <version>2.0</version>
+            <purl>pkg:maven/acme/library@3.0</purl>
+        </component>
+    </components>
+    <dependencies>
+        <dependency ref="acme-application-1.0">
+            <dependency ref="pkg:maven/partner/shaded-library@1.0"/>
+            <dependency ref="pkg:maven/acme/library@3.0"/>
+        </dependency>
+    </dependencies>
+    <compositions>
+        <composition>
+            <aggregate>complete</aggregate>
+            <assemblies>
+                <assembly ref="pkg:maven/partner/shaded-library@1.0"/>
+            </assemblies>
+            <dependencies>
+                <dependency ref="acme-application-1.0"/>
+            </dependencies>
+        </composition>
+        <composition>
+            <aggregate>unknown</aggregate>
+            <assemblies>
+                <assembly ref="pkg:maven/acme/library@3.0"/>
+            </assemblies>
+        </composition>
+    </compositions>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-dependency-1.3.json b/tests/_data/schemaTestData/1.3/valid-dependency-1.3.json
new file mode 100644
index 000000000..87f70743d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-dependency-1.3.json
@@ -0,0 +1,38 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "library-a",
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-b",
+      "type": "library",
+      "name": "library-b",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-c",
+      "type": "library",
+      "name": "library-c",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "library-a",
+      "dependsOn": []
+    },
+    {
+      "ref": "library-b",
+      "dependsOn": [
+        "library-c"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-dependency-1.3.xml b/tests/_data/schemaTestData/1.3/valid-dependency-1.3.xml
new file mode 100644
index 000000000..d02773b43
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-dependency-1.3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library" bom-ref="library-a">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-b">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-c">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+    <dependencies>
+        <dependency ref="library-a"/>
+        <dependency ref="library-b">
+            <dependency ref="library-c"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-empty-components-1.3.json b/tests/_data/schemaTestData/1.3/valid-empty-components-1.3.json
new file mode 100644
index 000000000..ba708657a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-empty-components-1.3.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-empty-components-1.3.xml b/tests/_data/schemaTestData/1.3/valid-empty-components-1.3.xml
new file mode 100644
index 000000000..0c37d3f30
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-empty-components-1.3.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-evidence-1.3.json b/tests/_data/schemaTestData/1.3/valid-evidence-1.3.json
new file mode 100644
index 000000000..4fc32ab8a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-evidence-1.3.json
@@ -0,0 +1,53 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "group": "com.google.code.findbugs",
+      "name": "findbugs-project",
+      "version": "3.0.0",
+      "licenses": [
+        {
+          "license": {
+            "id": "LGPL-3.0-or-later",
+            "url": "https://www.gnu.org/licenses/lgpl-3.0-standalone.html"
+          }
+        }
+      ],
+      "purl": "pkg:maven/com.google.code.findbugs/findbugs-project@3.0.0",
+      "evidence": {
+        "licenses": [
+          {
+            "license": {
+              "id": "Apache-2.0",
+              "url": "http://www.apache.org/licenses/LICENSE-2.0"
+            }
+          },
+          {
+            "license": {
+              "id": "LGPL-2.1-only",
+              "url": "https://opensource.org/licenses/LGPL-2.1"
+            }
+          }
+        ],
+        "copyright": [
+          {
+            "text": "Copyright 2012 Google Inc. All Rights Reserved."
+          },
+          {
+            "text": "Copyright (C) 2004,2005 Dave Brosius <dbrosius@users.sourceforge.net>"
+          },
+          {
+            "text": "Copyright (C) 2005 William Pugh"
+          },
+          {
+            "text": "Copyright (C) 2004,2005 University of Maryland"
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-evidence-1.3.xml b/tests/_data/schemaTestData/1.3/valid-evidence-1.3.xml
new file mode 100644
index 000000000..c2435a4ba
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-evidence-1.3.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <group>com.google.code.findbugs</group>
+            <name>findbugs-project</name>
+            <version>3.0.0</version>
+            <licenses>
+                <license>
+                    <id>LGPL-3.0-or-later</id>
+                    <url>https://www.gnu.org/licenses/lgpl-3.0-standalone.html</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.google.code.findbugs/findbugs-project@3.0.0</purl>
+            <evidence>
+                <licenses>
+                    <license>
+                        <id>Apache-2.0</id>
+                        <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+                    </license>
+                    <license>
+                        <id>LGPL-2.1-only</id>
+                        <url>https://opensource.org/licenses/LGPL-2.1</url>
+                    </license>
+                </licenses>
+                <copyright>
+                    <text><![CDATA[Copyright 2012 Google Inc. All Rights Reserved.]]></text>
+                    <text><![CDATA[Copyright (C) 2004,2005 Dave Brosius <dbrosius@users.sourceforge.net>]]></text>
+                    <text><![CDATA[Copyright (C) 2005 William Pugh]]></text>
+                    <text><![CDATA[Copyright (C) 2004,2005 University of Maryland]]></text>
+                </copyright>
+            </evidence>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-external-elements-1.3.xml b/tests/_data/schemaTestData/1.3/valid-external-elements-1.3.xml
new file mode 100644
index 000000000..4fe8ffdf5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-external-elements-1.3.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                                <foo:fruit xmlns:foo="foo">
+                                    <foo:name>Banana</foo:name>
+                                </foo:fruit>
+                                <foo:fruit xmlns:foo="foo">
+                                    <foo:name>Banana</foo:name>
+                                </foo:fruit>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </ancestors>
+                <descendants>
+                    <component type="library">
+                        <name>foo</name>
+                        <version>1.0</version>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </descendants>
+                <variants>
+                    <component type="library">
+                        <name>bar</name>
+                        <version>1.0</version>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </variants>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                        </committer>
+                        <message>Initial commit</message>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                    </commit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </commits>
+                <notes>Commentary here</notes>
+                <foo:fruit xmlns:foo="foo">
+                    <foo:name>Banana</foo:name>
+                </foo:fruit>
+                <foo:fruit xmlns:foo="foo">
+                    <foo:name>Banana</foo:name>
+                </foo:fruit>
+            </pedigree>
+            <foo:fruit xmlns:foo="foo">
+                <foo:name>Banana</foo:name>
+            </foo:fruit>
+            <foo:fruit xmlns:foo="foo">
+                <foo:name>Banana</foo:name>
+            </foo:fruit>
+        </component>
+        <foo:fruit xmlns:foo="foo">
+            <foo:name>Banana</foo:name>
+        </foo:fruit>
+        <foo:fruit xmlns:foo="foo">
+            <foo:name>Banana</foo:name>
+        </foo:fruit>
+    </components>
+    <foo:fruit xmlns:foo="foo">
+        <foo:name>Banana</foo:name>
+    </foo:fruit>
+    <foo:fruit xmlns:foo="foo">
+        <foo:name>Banana</foo:name>
+    </foo:fruit>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-external-reference-1.3.json b/tests/_data/schemaTestData/1.3/valid-external-reference-1.3.json
new file mode 100644
index 000000000..060770e12
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-external-reference-1.3.json
@@ -0,0 +1,38 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "org.example",
+      "name": "mylibrary",
+      "version": "1.0.0",
+      "externalReferences": [
+        {
+          "type": "advisories",
+          "url": "https://example.org/security/feed/csaf",
+          "comment": "Security advisories from the vendor"
+        },
+        {
+          "type": "bom",
+          "url": "https://example.org/support/sbom/portal-server/1.0.0",
+          "comment": "An external SBOM that describes what this component includes",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313"
+            }
+          ]
+        },
+        {
+          "type": "documentation",
+          "url": "https://example.org/support/documentation/portal-server/1.0.0",
+          "comment": "Vendor provided documentation for the product"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-external-reference-1.3.xml b/tests/_data/schemaTestData/1.3/valid-external-reference-1.3.xml
new file mode 100644
index 000000000..6a2888edb
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-external-reference-1.3.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <externalReferences>
+                <reference type="advisories">
+                    <url>https://example.org/security/feed/csaf</url>
+                    <comment>Security advisories from the vendor</comment>
+                </reference>
+                <reference type="bom">
+                    <url>https://example.org/support/sbom/portal-server/1.0.0</url>
+                    <comment>An external SBOM that describes what this component includes</comment>
+                    <hashes>
+                        <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                    </hashes>
+                </reference>
+                <reference type="documentation">
+                    <url>https://example.org/support/documentation/portal-server/1.0.0</url>
+                    <comment>Vendor provided documentation for the product</comment>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-license-expression-1.3.json b/tests/_data/schemaTestData/1.3/valid-license-expression-1.3.json
new file mode 100644
index 000000000..787a8cd61
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-license-expression-1.3.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "expression": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-license-expression-1.3.xml b/tests/_data/schemaTestData/1.3/valid-license-expression-1.3.xml
new file mode 100644
index 000000000..ae9099a24
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-license-expression-1.3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-license-id-1.3.json b/tests/_data/schemaTestData/1.3/valid-license-id-1.3.json
new file mode 100644
index 000000000..e227babce
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-license-id-1.3.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-license-id-1.3.xml b/tests/_data/schemaTestData/1.3/valid-license-id-1.3.xml
new file mode 100644
index 000000000..e25e92039
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-license-id-1.3.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-license-name-1.3.json b/tests/_data/schemaTestData/1.3/valid-license-name-1.3.json
new file mode 100644
index 000000000..9d865b992
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-license-name-1.3.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "name": "Apache License 2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-license-name-1.3.xml b/tests/_data/schemaTestData/1.3/valid-license-name-1.3.xml
new file mode 100644
index 000000000..9097df575
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-license-name-1.3.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Apache License 2.0</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-author-1.3.json b/tests/_data/schemaTestData/1.3/valid-metadata-author-1.3.json
new file mode 100644
index 000000000..9c78197a0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-author-1.3.json
@@ -0,0 +1,16 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "authors": [
+      {
+        "name": "Samantha Wright",
+        "email": "samantha.wright@example.com",
+        "phone": "800-555-1212"
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-author-1.3.xml b/tests/_data/schemaTestData/1.3/valid-metadata-author-1.3.xml
new file mode 100644
index 000000000..e9492df03
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-author-1.3.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <authors>
+            <author>
+                <name>Samantha Wright</name>
+                <email>samantha.wright@example.com</email>
+                <phone>800-555-1212</phone>
+            </author>
+        </authors>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-license-1.3.json b/tests/_data/schemaTestData/1.3/valid-metadata-license-1.3.json
new file mode 100644
index 000000000..8ab899620
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-license-1.3.json
@@ -0,0 +1,16 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "licenses": [
+      {
+        "license": {
+          "id": "Apache-2.0"
+        }
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-license-1.3.xml b/tests/_data/schemaTestData/1.3/valid-metadata-license-1.3.xml
new file mode 100644
index 000000000..3c9d10d67
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-license-1.3.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <licenses>
+            <license>
+                <id>Apache-2.0</id>
+            </license>
+        </licenses>
+    </metadata>
+    <components />
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-manufacture-1.3.json b/tests/_data/schemaTestData/1.3/valid-metadata-manufacture-1.3.json
new file mode 100644
index 000000000..e4c694983
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-manufacture-1.3.json
@@ -0,0 +1,21 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "manufacture": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Professional Services",
+          "email": "professional.services@example.com"
+        }
+      ]
+    }
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-manufacture-1.3.xml b/tests/_data/schemaTestData/1.3/valid-metadata-manufacture-1.3.xml
new file mode 100644
index 000000000..c94d01c92
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-manufacture-1.3.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <manufacture>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Professional Services</name>
+                <email>professional.services@example.com</email>
+            </contact>
+        </manufacture>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-supplier-1.3.json b/tests/_data/schemaTestData/1.3/valid-metadata-supplier-1.3.json
new file mode 100644
index 000000000..103882ca2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-supplier-1.3.json
@@ -0,0 +1,21 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "supplier": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Distribution",
+          "email": "distribution@example.com"
+        }
+      ]
+    }
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-supplier-1.3.xml b/tests/_data/schemaTestData/1.3/valid-metadata-supplier-1.3.xml
new file mode 100644
index 000000000..1235f4c23
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-supplier-1.3.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <supplier>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Distribution</name>
+                <email>distribution@example.com</email>
+            </contact>
+        </supplier>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-timestamp-1.3.json b/tests/_data/schemaTestData/1.3/valid-metadata-timestamp-1.3.json
new file mode 100644
index 000000000..8f47f110a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-timestamp-1.3.json
@@ -0,0 +1,10 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13T20:20:39+00:00"
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-timestamp-1.3.xml b/tests/_data/schemaTestData/1.3/valid-metadata-timestamp-1.3.xml
new file mode 100644
index 000000000..881349216
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-timestamp-1.3.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <timestamp>2020-04-07T07:01:00Z</timestamp>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-tool-1.3.json b/tests/_data/schemaTestData/1.3/valid-metadata-tool-1.3.json
new file mode 100644
index 000000000..61bcaec34
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-tool-1.3.json
@@ -0,0 +1,26 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "tools": [
+      {
+        "vendor": "Awesome Vendor",
+        "name": "Awesome Tool",
+        "version": "9.1.2",
+        "hashes": [
+          {
+            "alg": "SHA-1",
+            "content": "25ed8e31b995bb927966616df2a42b979a2717f0"
+          },
+          {
+            "alg": "SHA-256",
+            "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df"
+          }
+        ]
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-metadata-tool-1.3.xml b/tests/_data/schemaTestData/1.3/valid-metadata-tool-1.3.xml
new file mode 100644
index 000000000..8c2d17fea
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-metadata-tool-1.3.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <tools>
+            <tool>
+                <vendor>Awesome Vendor</vendor>
+                <name>Awesome Tool</name>
+                <version>9.1.2</version>
+                <hashes>
+                    <hash alg="SHA-1">25ed8e31b995bb927966616df2a42b979a2717f0</hash>
+                    <hash alg="SHA-256">a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df</hash>
+                </hashes>
+            </tool>
+        </tools>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-minimal-viable-1.3.json b/tests/_data/schemaTestData/1.3/valid-minimal-viable-1.3.json
new file mode 100644
index 000000000..6a9e646d0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-minimal-viable-1.3.json
@@ -0,0 +1,13 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-minimal-viable-1.3.xml b/tests/_data/schemaTestData/1.3/valid-minimal-viable-1.3.xml
new file mode 100644
index 000000000..6a9480298
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-minimal-viable-1.3.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-patch-1.3.json b/tests/_data/schemaTestData/1.3/valid-patch-1.3.json
new file mode 100644
index 000000000..eebdf67a1
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-patch-1.3.json
@@ -0,0 +1,88 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "unofficial",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "enhancement",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          },
+          {
+            "type": "backport",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "security",
+                "id": "CVE-2019-9997",
+                "name": "CVE-2019-9997",
+                "description": "blah blah",
+                "source": {
+                  "name": "NVD",
+                  "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9997"
+                },
+                "references": [
+                  "http://some/other/site-1",
+                  "http://some/other/site-2"
+                ]
+              },
+              {
+                "type": "defect",
+                "id": "JIRA-874319",
+                "description": "Enable to do something",
+                "source": {
+                  "name": "Example Org",
+                  "url": "https://issues.example.org/874319"
+                },
+                "references": [
+                  "http://some/other/site-1",
+                  "http://some/other/site-2"
+                ]
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-patch-1.3.xml b/tests/_data/schemaTestData/1.3/valid-patch-1.3.xml
new file mode 100644
index 000000000..d6e1f4426
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-patch-1.3.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="unofficial">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="enhancement">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                    <patch type="backport">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="security">
+                                <id>CVE-2019-9997</id>
+                                <name>CVE-2019-9997</name>
+                                <description>blah blah</description>
+                                <source>
+                                    <name>NVD</name>
+                                    <url>https://nvd.nist.gov/vuln/detail/CVE-2019-9997</url>
+                                </source>
+                                <references>
+                                    <url>http://some/other/site-1</url>
+                                    <url>http://some/other/site-2</url>
+                                </references>
+                            </issue>
+                            <issue type="defect">
+                                <id>JIRA-874319</id>
+                                <description>Enable to do something</description>
+                                <source>
+                                    <name>Example Org</name>
+                                    <url>https://issues.example.org/874319</url>
+                                </source>
+                                <references>
+                                    <url>http://some/other/site-1</url>
+                                    <url>http://some/other/site-2</url>
+                                </references>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-properties-1.3.json b/tests/_data/schemaTestData/1.3/valid-properties-1.3.json
new file mode 100644
index 000000000..f30e2dbe4
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-properties-1.3.json
@@ -0,0 +1,55 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "properties": [
+      {
+        "name": "Foo",
+        "value": "Bar"
+      },
+      {
+        "name": "Foo",
+        "value": "You"
+      },
+      {
+        "name": "Foo",
+        "value": "Two"
+      },
+      {
+        "name": "Bar",
+        "value": "Foo"
+      }
+    ]
+  },
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "properties": [
+        {
+          "name": "Foo",
+          "value": "Bar"
+        }
+      ]
+    }
+  ],
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "group": "org.partner",
+      "name": "Stock ticker service",
+      "endpoints": [
+        "https://partner.org/api/v1/stock"
+      ],
+      "properties": [
+        {
+          "name": "Foo",
+          "value": "Bar"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-properties-1.3.xml b/tests/_data/schemaTestData/1.3/valid-properties-1.3.xml
new file mode 100644
index 000000000..79d49c2e4
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-properties-1.3.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <metadata>
+        <properties>
+            <property name="Foo">Bar</property>
+            <property name="Foo">You</property>
+            <property name="Foo">Two</property>
+            <property name="Bar">Foo</property>
+        </properties>
+    </metadata>
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <properties>
+                <property name="Foo">Bar</property>
+                <property name="Bar">Foo</property>
+            </properties>
+        </component>
+    </components>
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <group>org.partner</group>
+            <name>Stock ticker service</name>
+            <endpoints>
+                <endpoint>https://partner.org/api/v1/stock</endpoint>
+            </endpoints>
+            <properties>
+                <property name="Foo">Bar</property>
+                <property name="Bar">Foo</property>
+            </properties>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-random-attributes-1.3.xml b/tests/_data/schemaTestData/1.3/valid-random-attributes-1.3.xml
new file mode 100644
index 000000000..b07d29db2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-random-attributes-1.3.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom foo="bar" bar="foo" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components foo="bar" bar="foo" >
+        <component foo="bar" bar="foo"  type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors foo="bar" bar="foo">
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-service-1.3.json b/tests/_data/schemaTestData/1.3/valid-service-1.3.json
new file mode 100644
index 000000000..1a627c4c3
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-service-1.3.json
@@ -0,0 +1,101 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:maven/com.acme/stock-java-client@1.0.12",
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "stock-java-client",
+      "version": "1.0.12",
+      "hashes": [
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "purl": "pkg:maven/com.acme/stock-java-client@1.0.12"
+    }
+  ],
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "provider": {
+        "name": "Partner Org",
+        "url": [
+          "https://partner.org"
+        ],
+        "contact": [
+          {
+            "name": "Support",
+            "email": "support@partner",
+            "phone": "800-555-1212"
+          }
+        ]
+      },
+      "group": "org.partner",
+      "name": "Stock ticker service",
+      "version": "2020-Q2",
+      "description": "Provides real-time stock information",
+      "endpoints": [
+        "https://partner.org/api/v1/lookup",
+        "https://partner.org/api/v1/stock"
+      ],
+      "authenticated": true,
+      "x-trust-boundary": true,
+      "data": [
+        {
+          "classification": "PII",
+          "flow": "inbound"
+        },
+        {
+          "classification": "PIFI",
+          "flow": "outbound"
+        },
+        {
+          "classification": "pubic",
+          "flow": "bi-directional"
+        },
+        {
+          "classification": "partner-data",
+          "flow": "unknown"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "name": "Partner license"
+          }
+        }
+      ],
+      "externalReferences": [
+        {
+          "type": "website",
+          "url": "http://partner.org"
+        },
+        {
+          "type": "documentation",
+          "url": "http://api.partner.org/swagger"
+        }
+      ]
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:maven/com.acme/stock-java-client@1.0.12",
+      "dependsOn": [
+        "b2a46a4b-8367-4bae-9820-95557cfe03a8"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-service-1.3.xml b/tests/_data/schemaTestData/1.3/valid-service-1.3.xml
new file mode 100644
index 000000000..5fe3aa5ee
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-service-1.3.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="library" bom-ref="pkg:maven/com.acme/stock-java-client@1.0.12">
+            <group>com.acme</group>
+            <name>stock-java-client</name>
+            <version>1.0.12</version>
+            <hashes>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/stock-java-client@1.0.12</purl>
+        </component>
+    </components>
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <provider>
+                <name>Partner Org</name>
+                <url>https://partner.org</url>
+                <contact>
+                    <name>Support</name>
+                    <email>support@partner</email>
+                    <phone>800-555-1212</phone>
+                </contact>
+            </provider>
+            <group>org.partner</group>
+            <name>Stock ticker service</name>
+            <version>2020-Q2</version>
+            <description>Provides real-time stock information</description>
+            <endpoints>
+                <endpoint>https://partner.org/api/v1/lookup</endpoint>
+                <endpoint>https://partner.org/api/v1/stock</endpoint>
+            </endpoints>
+            <authenticated>true</authenticated>
+            <x-trust-boundary>true</x-trust-boundary>
+            <data>
+                <classification flow="inbound">PII</classification>
+                <classification flow="outbound">PIFI</classification>
+                <classification flow="bi-directional">pubic</classification>
+                <classification flow="unknown">partner-data</classification>
+            </data>
+            <licenses>
+                <license>
+                    <name>Partner license</name>
+                </license>
+            </licenses>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://partner.org</url>
+                </reference>
+                <reference type="documentation">
+                    <url>http://api.partner.org/swagger</url>
+                </reference>
+            </externalReferences>
+        </service>
+    </services>
+    <dependencies>
+        <dependency ref="pkg:maven/com.acme/stock-java-client@1.0.12">
+            <dependency ref="b2a46a4b-8367-4bae-9820-95557cfe03a8"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-service-empty-objects-1.3.json b/tests/_data/schemaTestData/1.3/valid-service-empty-objects-1.3.json
new file mode 100644
index 000000000..72c9ceae0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-service-empty-objects-1.3.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "provider": {
+        "contact": [
+        ]
+      },
+      "name": "Stock ticker service",
+      "endpoints": [
+      ],
+      "data": [
+      ],
+      "externalReferences": [
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.3/valid-service-empty-objects-1.3.xml b/tests/_data/schemaTestData/1.3/valid-service-empty-objects-1.3.xml
new file mode 100644
index 000000000..c5cdb1fbd
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-service-empty-objects-1.3.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <provider>
+            </provider>
+            <name>Stock ticker service</name>
+            <endpoints>
+            </endpoints>
+            <data>
+            </data>
+            <licenses>
+            </licenses>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.3/valid-xml-signature-1.3.xml b/tests/_data/schemaTestData/1.3/valid-xml-signature-1.3.xml
new file mode 100644
index 000000000..248018125
--- /dev/null
+++ b/tests/_data/schemaTestData/1.3/valid-xml-signature-1.3.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.3">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>jdoe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>jdoe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/xml" encoding="base64">blah</text>
+                    <url>fdaf</url>
+                </license>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+        <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+            <ds:Reference URI="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+                </ds:Transforms>
+                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+                <ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">PrB8/rofGs34XwIX5OIdYSjV2aKSe5VaztJKBvsgjIk=</ds:DigestValue>
+            </ds:Reference>
+        </ds:SignedInfo>
+        <ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            ePGNg30Zl9CW7RZdcRn8gFCp1AlWncjudA9pQDXyqZOvyj9RC2YtkI688WdfDOdVRZs6mflJFXr7
+            IKA9wY6jVrEqZmlef55Qp/8iGwOjOjWbwYsm2AhrdkUi9gaFSWEd8uITYHOpWbiPFSsnimiK9+ft
+            56dkg/oJMLdXzlaukzq9iGkRcafRkW433OQcZIXwD2K8lg4cdD0pNNNqBa+PgIvzbxA5H84TyQDB
+            HBcQiw/j1edRBJgPOwlqzZDUawOJaFhAPUQ+GGKMetIJH2FqqrHXGuV1NIwnbWTCg40RdOcBdCrl
+            PDtDVjFh34uZ4dYBpJBIlM4daD2N4B6WPB5iHRyuZTczF2q03ObabuTgkpK6EeadFVqFNsEOOPPt
+            MDDyda+Lwff5KjvUHvRRtUDIOm2rNIQKzaseulwYcA9UWQHAFcupJmWcLLM4zzY7F/uOdZuSurzh
+            U6h5kdb76Juepof6ee4Q5YpwNOGNL5JfB4C3sc/Dbbv8dZ8OuXFYSZN7reUGZzCNksByqERPEbAe
+            n1ldJu1HnRXRQpwaon8Asy9CuNmPfFCfDwOs2B4p4tb+tLNIKFHdRlpd19Zr9vCMCbltXeqq0Cpq
+            OejSyLYGqSWzzzUh449dJrg6KTevrTNEln5GAlLBFSdjM5JA7KV2u/GyDVFwSEW7UKooGN4CtgU=
+        </ds:SignatureValue>
+        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            <ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:X509SubjectName xmlns:ds="http://www.w3.org/2000/09/xmldsig#">CN=bomsigner,OU=development,O=cyclonedx</ds:X509SubjectName>
+                <ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    MIIE+DCCAuCgAwIBAgIEXGzayTANBgkqhkiG9w0BAQsFADA+MRIwEAYDVQQKDAljeWNsb25lZHgx
+                    FDASBgNVBAsMC2RldmVsb3BtZW50MRIwEAYDVQQDDAlib21zaWduZXIwHhcNMTkwMjIwMDQ0MjQ5
+                    WhcNNDkwMjIwMDQ0MjQ5WjA+MRIwEAYDVQQKDAljeWNsb25lZHgxFDASBgNVBAsMC2RldmVsb3Bt
+                    ZW50MRIwEAYDVQQDDAlib21zaWduZXIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo
+                    5JZsM4ZLfWW/dpRlU6CpnItWspddF+bEVDETKVwVj9tGpqR5jURgKS/BOQP2TGUsR3/ZJJBhYRll
+                    ONhrUQrVKV/I6wp3Z40qPEa1RJLE+QlG9iL8qBV52CnXkLmnUSax3dspSzmSct5vDiTnvpHG9jr0
+                    AKFeTjy7U9rv8GJybz0ijwlpBoO9JRdYPX2PrrzoSeJLoxKq+GwuyCZ5LhXRN0p1a+NAirTAmY+c
+                    G1ZTLkMmfeCUy1t6H/bG4RnYOSSPOvk7Rb68lQpUqb+pbbNuB2o/b9cDwtLLCtGVlu+5Wj8mrytY
+                    3FGFQM20j3yVeRInmGqTTDBelQa/CO4JKqBlmaeYEIvNYbFs9+AlqadivwDO51RpdPo9fPSpsBpy
+                    ZMv6S2bXNuUML+Rk99WyKJTPM0PTZhRLZ64ZXEhlz3kQWVoSlrcwwim6sj6LRUb5IRqA3lxRFUI6
+                    NXKyiQLamQp+t3/9OGW9L1rLCcw7yFo0s8LhMTPMiv4ol9/hQViT+8ICzDsr0OM9ZiF4/UagFRlt
+                    IClV70cjh1DpsZjzQIRVGaj8uQ/JdtfRz4E43Ki7U0a2Vpho/t6poLVndv46tkX5nYGtMW4WfMoD
+                    ZflQ9pajvvKtr2jB1wob6nsU+VTmAcWZy4BCPH+XyfDw/0SFBdUceJJJtPWIeYFDUY7onptf+wID
+                    AQABMA0GCSqGSIb3DQEBCwUAA4ICAQCOVariNgK+9OF/5T9ZaSvZbkk45RTmzgQNXtFc5xfRvqwP
+                    s+pu/DFXm1R+ltjyS5j3w6NBZUFUI5MqLQr6JEEDrbu8BvfBO57wJNAEATj1JIHEfDfh7BxnBF8f
+                    oYFOwbrh4jOt0wz0FW2obsSVmF4GSvS7tTlWqTcsxjdZVmwP40RWu18B9jzv7M61adrWD3ksDA5O
+                    amSOsZi3Nt0aacDkyGRdCIEFi0fplxQInXMtD1z3RhXu2JSTAIr54Cei49Bh71kAXSWHMCog/f8a
+                    lSrZyqZBty/ACfU9DqlPIM+giHePKm4z2bcdpUdKZk6wcKDn4CvuBOqsMBMg7L05UEyyqTPD/4dk
+                    2GwJ8Nv0E5gsYHCIXF2cZ3OUVsw0mB/ozleEJVDE02uZZN/1wW1Xq028LsMdgN0Wk1WvWyF5MEdh
+                    nPWuhqp6tNaDI/kK6XQF+LjYJUzua3AQFOHfYNLKhO6d+bJ4rr0833v4v3cLW34kbXkKb6U3Yv8X
+                    SK3jBGCACiPgnc0N6awkh1kDlrZQ7GMsl14c+2+vpl9Lf0sL0mRUIyICfSC8MjlsP/BZH3emyfsk
+                    iWivPALomycKqP+PSkt1WaWApGENZWk1wNN99FYSYlt6LViW2p6T97fRx4jPRlHu+wecfD2k9RP4
+                    bt5W2HWfOP0zNAS7SnAVLEl2QZxXKw==
+                </ds:X509Certificate>
+            </ds:X509Data>
+            <ds:KeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:RSAKeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:Modulus xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                        qOSWbDOGS31lv3aUZVOgqZyLVrKXXRfmxFQxEylcFY/bRqakeY1EYCkvwTkD9kxlLEd/2SSQYWEZ
+                        ZTjYa1EK1SlfyOsKd2eNKjxGtUSSxPkJRvYi/KgVedgp15C5p1Emsd3bKUs5knLebw4k576RxvY6
+                        9AChXk48u1Pa7/Bicm89Io8JaQaDvSUXWD19j6686EniS6MSqvhsLsgmeS4V0TdKdWvjQIq0wJmP
+                        nBtWUy5DJn3glMtbeh/2xuEZ2Dkkjzr5O0W+vJUKVKm/qW2zbgdqP2/XA8LSywrRlZbvuVo/Jq8r
+                        WNxRhUDNtI98lXkSJ5hqk0wwXpUGvwjuCSqgZZmnmBCLzWGxbPfgJamnYr8AzudUaXT6PXz0qbAa
+                        cmTL+ktm1zblDC/kZPfVsiiUzzND02YUS2euGVxIZc95EFlaEpa3MMIpurI+i0VG+SEagN5cURVC
+                        OjVysokC2pkKfrd//ThlvS9aywnMO8haNLPC4TEzzIr+KJff4UFYk/vCAsw7K9DjPWYheP1GoBUZ
+                        bSApVe9HI4dQ6bGY80CEVRmo/LkPyXbX0c+BONyou1NGtlaYaP7eqaC1Z3b+OrZF+Z2BrTFuFnzK
+                        A2X5UPaWo77yra9owdcKG+p7FPlU5gHFmcuAQjx/l8nw8P9EhQXVHHiSSbT1iHmBQ1GO6J6bX/s=
+                    </ds:Modulus>
+                    <ds:Exponent xmlns:ds="http://www.w3.org/2000/09/xmldsig#">AQAB</ds:Exponent>
+                </ds:RSAKeyValue>
+            </ds:KeyValue>
+        </ds:KeyInfo>
+    </ds:Signature></bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-bomformat-1.4.json b/tests/_data/schemaTestData/1.4/invalid-bomformat-1.4.json
new file mode 100644
index 000000000..6959cab0c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-bomformat-1.4.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "AnotherFormat",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-component-ref-1.4.json b/tests/_data/schemaTestData/1.4/invalid-component-ref-1.4.json
new file mode 100644
index 000000000..3be019a3b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-component-ref-1.4.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    },
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-component-ref-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-component-ref-1.4.xml
new file mode 100644
index 000000000..d44179094
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-component-ref-1.4.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library" bom-ref="123">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library" bom-ref="123">
+                    <name>acme-library</name>
+                    <version>1.0.0</version>
+                </component>
+            </components>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-component-swid-1.4.json b/tests/_data/schemaTestData/1.4/invalid-component-swid-1.4.json
new file mode 100644
index 000000000..4ad023c59
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-component-swid-1.4.json
@@ -0,0 +1,18 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "name": "Acme Application",
+        "version": "9.1.1"
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-component-swid-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-component-swid-1.4.xml
new file mode 100644
index 000000000..5ba6401e7
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-component-swid-1.4.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid name="Acme Application" version="9.1.1" />
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-component-type-1.4.json b/tests/_data/schemaTestData/1.4/invalid-component-type-1.4.json
new file mode 100644
index 000000000..7c7bd8bb0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-component-type-1.4.json
@@ -0,0 +1,13 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "foo",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-component-type-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-component-type-1.4.xml
new file mode 100644
index 000000000..4f82adfec
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-component-type-1.4.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="foo">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-dependency-1.4.json b/tests/_data/schemaTestData/1.4/invalid-dependency-1.4.json
new file mode 100644
index 000000000..1e5f12a18
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-dependency-1.4.json
@@ -0,0 +1,37 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "library-a",
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-b",
+      "type": "library",
+      "name": "library-b",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-c",
+      "type": "library",
+      "name": "library-c",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "dependsOn": []
+    },
+    {
+      "ref": "library-b",
+      "dependsOn": [
+        "library-c"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-dependency-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-dependency-1.4.xml
new file mode 100644
index 000000000..3c9e00497
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-dependency-1.4.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library" bom-ref="library-a">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-b">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-c">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+    <dependencies>
+        <dependency />
+        <dependency ref="library-b">
+            <dependency ref="library-c"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-empty-component-1.4.json b/tests/_data/schemaTestData/1.4/invalid-empty-component-1.4.json
new file mode 100644
index 000000000..2bbf057b7
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-empty-component-1.4.json
@@ -0,0 +1,11 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-empty-component-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-empty-component-1.4.xml
new file mode 100644
index 000000000..8d82fe536
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-empty-component-1.4.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-alg-1.4.json b/tests/_data/schemaTestData/1.4/invalid-hash-alg-1.4.json
new file mode 100644
index 000000000..9cb10fb0c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-alg-1.4.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "FOO",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-alg-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-hash-alg-1.4.xml
new file mode 100644
index 000000000..51fd9fed0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-alg-1.4.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="FOO">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-md5-1.4.json b/tests/_data/schemaTestData/1.4/invalid-hash-md5-1.4.json
new file mode 100644
index 000000000..07d0ac03e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-md5-1.4.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-md5-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-hash-md5-1.4.xml
new file mode 100644
index 000000000..d964a5920
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-md5-1.4.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">foo</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-sha1-1.4.json b/tests/_data/schemaTestData/1.4/invalid-hash-sha1-1.4.json
new file mode 100644
index 000000000..9342157ae
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-sha1-1.4.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-sha1-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-hash-sha1-1.4.xml
new file mode 100644
index 000000000..0c6c28143
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-sha1-1.4.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">foo</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-sha256-1.4.json b/tests/_data/schemaTestData/1.4/invalid-hash-sha256-1.4.json
new file mode 100644
index 000000000..a3a9a9dc8
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-sha256-1.4.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "foo"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-sha256-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-hash-sha256-1.4.xml
new file mode 100644
index 000000000..e753128e0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-sha256-1.4.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">foo</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-sha512-1.4.json b/tests/_data/schemaTestData/1.4/invalid-hash-sha512-1.4.json
new file mode 100644
index 000000000..fdf1f5b88
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-sha512-1.4.json
@@ -0,0 +1,32 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "required",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "foo"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-hash-sha512-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-hash-sha512-1.4.xml
new file mode 100644
index 000000000..0339763df
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-hash-sha512-1.4.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">foo</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-issue-type-1.4.json b/tests/_data/schemaTestData/1.4/invalid-issue-type-1.4.json
new file mode 100644
index 000000000..e1f02ce8a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-issue-type-1.4.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "unofficial",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "foo",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-issue-type-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-issue-type-1.4.xml
new file mode 100644
index 000000000..0e005c280
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-issue-type-1.4.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="unofficial">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="foo">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-license-choice-1.4.json b/tests/_data/schemaTestData/1.4/invalid-license-choice-1.4.json
new file mode 100644
index 000000000..82fcfdba8
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-license-choice-1.4.json
@@ -0,0 +1,23 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "expression": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0",
+          "license": {
+            "name": "Apache License 2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-license-choice-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-license-choice-1.4.xml
new file mode 100644
index 000000000..83e4e3791
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-license-choice-1.4.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-license-encoding-1.4.json b/tests/_data/schemaTestData/1.4/invalid-license-encoding-1.4.json
new file mode 100644
index 000000000..ce76280fa
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-license-encoding-1.4.json
@@ -0,0 +1,28 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0",
+            "text": {
+              "contentType": "text/plain",
+              "encoding": "base85",
+              "content": "CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4="
+            },
+            "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-license-encoding-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-license-encoding-1.4.xml
new file mode 100644
index 000000000..95bd2bcb9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-license-encoding-1.4.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base85">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-license-id-1.4.json b/tests/_data/schemaTestData/1.4/invalid-license-id-1.4.json
new file mode 100644
index 000000000..ed317a5be
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-license-id-1.4.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-license-id-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-license-id-1.4.xml
new file mode 100644
index 000000000..68ca8efa7
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-license-id-1.4.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-license-id-count-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-license-id-count-1.4.xml
new file mode 100644
index 000000000..27f73e5d6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-license-id-count-1.4.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>MIT</id>
+                    <!-- This was a defect in schema 1.0 and is no longer permitted -->
+                    <id>MIT</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-license-name-count-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-license-name-count-1.4.xml
new file mode 100644
index 000000000..e986db569
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-license-name-count-1.4.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Apache License 2.0</name>
+                    <!-- This was a defect in schema 1.0 and is no longer permitted -->
+                    <name>Apache License 2.0</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-metadata-license-1.4.json b/tests/_data/schemaTestData/1.4/invalid-metadata-license-1.4.json
new file mode 100644
index 000000000..0ea6d35a6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-metadata-license-1.4.json
@@ -0,0 +1,16 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "licenses": [
+      {
+        "license": {
+          "id": "Apache-2"
+        }
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-metadata-license-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-metadata-license-1.4.xml
new file mode 100644
index 000000000..51cbe10e6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-metadata-license-1.4.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <licenses>
+            <license>
+                <id>Apache-2</id>
+            </license>
+        </licenses>
+    </metadata>
+    <components />
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.4/invalid-metadata-timestamp-1.4.json b/tests/_data/schemaTestData/1.4/invalid-metadata-timestamp-1.4.json
new file mode 100644
index 000000000..22ce0aa86
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-metadata-timestamp-1.4.json
@@ -0,0 +1,10 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13"
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-metadata-timestamp-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-metadata-timestamp-1.4.xml
new file mode 100644
index 000000000..544abc19c
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-metadata-timestamp-1.4.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <timestamp>2020-04-07</timestamp>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-missing-component-type-1.4.json b/tests/_data/schemaTestData/1.4/invalid-missing-component-type-1.4.json
new file mode 100644
index 000000000..eee0ac3a2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-missing-component-type-1.4.json
@@ -0,0 +1,12 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-missing-component-type-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-missing-component-type-1.4.xml
new file mode 100644
index 000000000..7200d4ad0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-missing-component-type-1.4.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component>
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-namespace-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-namespace-1.4.xml
new file mode 100644
index 000000000..9e42be401
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-namespace-1.4.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/12">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-patch-type-1.4.json b/tests/_data/schemaTestData/1.4/invalid-patch-type-1.4.json
new file mode 100644
index 000000000..1e35b0954
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-patch-type-1.4.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "foo",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "enhancement",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-patch-type-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-patch-type-1.4.xml
new file mode 100644
index 000000000..0e8a30d10
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-patch-type-1.4.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="foo">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="enhancement">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-scope-1.4.json b/tests/_data/schemaTestData/1.4/invalid-scope-1.4.json
new file mode 100644
index 000000000..7a9faeacd
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-scope-1.4.json
@@ -0,0 +1,14 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "scope": "foo"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-scope-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-scope-1.4.xml
new file mode 100644
index 000000000..9c34b135f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-scope-1.4.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <scope>foo</scope>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-serialnumber-1.4.json b/tests/_data/schemaTestData/1.4/invalid-serialnumber-1.4.json
new file mode 100644
index 000000000..42569ecd0
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-serialnumber-1.4.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-serialnumber-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-serialnumber-1.4.xml
new file mode 100644
index 000000000..c4637f265
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-serialnumber-1.4.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/invalid-service-data-1.4.json b/tests/_data/schemaTestData/1.4/invalid-service-data-1.4.json
new file mode 100644
index 000000000..3cc11be1f
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-service-data-1.4.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "name": "Stock ticker service",
+      "authenticated": true,
+      "x-trust-boundary": true,
+      "data": [
+        {
+          "classification": "foo",
+          "flow": "bar"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/invalid-service-data-1.4.xml b/tests/_data/schemaTestData/1.4/invalid-service-data-1.4.xml
new file mode 100644
index 000000000..d999dca90
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/invalid-service-data-1.4.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <name>Stock ticker service</name>
+            <data>
+                <classification flow="foo">bar</classification>
+            </data>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-assembly-1.4.json b/tests/_data/schemaTestData/1.4/valid-assembly-1.4.json
new file mode 100644
index 000000000..6d8f82271
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-assembly-1.4.json
@@ -0,0 +1,30 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library-a",
+      "version": "1.0.0",
+      "components": [
+        {
+          "type": "library",
+          "name": "acme-library-b",
+          "version": "2.0.0"
+        }
+      ]
+    }
+  ],
+  "services": [
+    {
+      "name": "acme-service-a",
+      "services": [
+        {
+          "name": "acme-service-b"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-assembly-1.4.xml b/tests/_data/schemaTestData/1.4/valid-assembly-1.4.xml
new file mode 100644
index 000000000..7aa65a3f7
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-assembly-1.4.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library">
+                    <name>acme-library-b</name>
+                    <version>2.0.0</version>
+                </component>
+            </components>
+        </component>
+    </components>
+    <services>
+        <service>
+            <name>acme-service-a</name>
+            <services>
+                <service>
+                    <name>acme-service-b</name>
+                </service>
+            </services>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-bom-1.4.json b/tests/_data/schemaTestData/1.4/valid-bom-1.4.json
new file mode 100644
index 000000000..a6494a7b6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-bom-1.4.json
@@ -0,0 +1,177 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13T20:20:39+00:00",
+    "tools": [
+      {
+        "vendor": "Awesome Vendor",
+        "name": "Awesome Tool",
+        "version": "9.1.2",
+        "hashes": [
+          {
+            "alg": "SHA-1",
+            "content": "25ed8e31b995bb927966616df2a42b979a2717f0"
+          },
+          {
+            "alg": "SHA-256",
+            "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df"
+          }
+        ]
+      }
+    ],
+    "authors": [
+      {
+        "name": "Samantha Wright",
+        "email": "samantha.wright@example.com",
+        "phone": "800-555-1212"
+      }
+    ],
+    "component": {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1",
+        "text": {
+          "contentType": "text/xml",
+          "encoding": "base64",
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
+        }
+      }
+    },
+    "manufacture": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Professional Services",
+          "email": "professional.services@example.com"
+        }
+      ]
+    },
+    "supplier": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Distribution",
+          "email": "distribution@example.com"
+        }
+      ]
+    }
+  },
+  "components": [
+    {
+      "bom-ref": "pkg:npm/acme/component@1.0.0",
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "3942447fac867ae5cdb3229b658f4d48"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0",
+            "text": {
+              "contentType": "text/plain",
+              "encoding": "base64",
+              "content": "CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4="
+            },
+            "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
+          }
+        }
+      ],
+      "purl": "pkg:npm/acme/component@1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "publisher": "Acme Inc",
+            "group": "com.acme",
+            "name": "tomcat-catalina",
+            "version": "9.0.14"
+          },
+          {
+            "type": "library",
+            "publisher": "Acme Inc",
+            "group": "com.acme",
+            "name": "tomcat-catalina",
+            "version": "9.0.14"
+          }
+        ],
+        "commits": [
+          {
+            "uid": "7638417db6d59f3c431d3e1f261cc637155684cd",
+            "url": "https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd",
+            "author": {
+              "timestamp": "2018-11-13T20:20:39+00:00",
+              "name": "me",
+              "email": "me@acme.org"
+            }
+          }
+        ]
+      }
+    },
+    {
+      "type": "library",
+      "supplier": {
+        "name": "Example, Inc.",
+        "url": [
+          "https://example.com",
+          "https://example.net"
+        ],
+        "contact": [
+          {
+            "name": "Example Support AMER Distribution",
+            "email": "support@example.com",
+            "phone": "800-555-1212"
+          },
+          {
+            "name": "Example Support APAC",
+            "email": "support@apac.example.com"
+          }
+        ]
+      },
+      "author": "Example Super Heros",
+      "group": "org.example",
+      "name": "mylibrary",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:npm/acme/component@1.0.0",
+      "dependsOn": [
+        "pkg:npm/acme/component@1.0.0"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-bom-1.4.xml b/tests/_data/schemaTestData/1.4/valid-bom-1.4.xml
new file mode 100644
index 000000000..a675a9676
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-bom-1.4.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <timestamp>2020-04-07T07:01:00Z</timestamp>
+        <tools>
+            <tool>
+                <vendor>Awesome Vendor</vendor>
+                <name>Awesome Tool</name>
+                <version>9.1.2</version>
+                <hashes>
+                    <hash alg="SHA-1">25ed8e31b995bb927966616df2a42b979a2717f0</hash>
+                    <hash alg="SHA-256">a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df</hash>
+                </hashes>
+            </tool>
+        </tools>
+        <authors>
+            <author>
+                <name>Samantha Wright</name>
+                <email>samantha.wright@example.com</email>
+                <phone>800-555-1212</phone>
+            </author>
+        </authors>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1">
+                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+            </swid>
+        </component>
+        <manufacture>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Professional Services</name>
+                <email>professional.services@example.com</email>
+            </contact>
+        </manufacture>
+        <supplier>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Distribution</name>
+                <email>distribution@example.com</email>
+            </contact>
+        </supplier>
+    </metadata>
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <author>Apache Super Heros</author>
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <supplier>
+                <name>Example Inc.</name>
+                <url>https://example.com</url>
+                <url>https://example.net</url>
+                <contact>
+                    <name>Example Support AMER</name>
+                    <email>support@example.com</email>
+                    <phone>800-555-1212</phone>
+                </contact>
+                <contact>
+                    <name>Example Support APAC</name>
+                    <email>support@apac.example.com</email>
+                </contact>
+            </supplier>
+            <author>Example Super Heros</author>
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0-with-classpath-exception</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <author>Example Super Heros</author>
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-component-hashes-1.4.json b/tests/_data/schemaTestData/1.4/valid-component-hashes-1.4.json
new file mode 100644
index 000000000..af90bd1f1
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-hashes-1.4.json
@@ -0,0 +1,63 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-example",
+      "version": "1.0.0",
+      "hashes": [
+        {
+          "alg": "MD5",
+          "content": "641b6e166f8b33c5e959e2adcc18b1c7"
+        },
+        {
+          "alg": "SHA-1",
+          "content": "9188560f22e0b73070d2efce670c74af2bdf30af"
+        },
+        {
+          "alg": "SHA-256",
+          "content": "d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964"
+        },
+        {
+          "alg": "SHA-384",
+          "content": "d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad"
+        },
+        {
+          "alg": "SHA-512",
+          "content": "74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6"
+        },
+        {
+          "alg": "SHA3-256",
+          "content": "7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa"
+        },
+        {
+          "alg": "SHA3-384",
+          "content": "a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5"
+        },
+        {
+          "alg": "SHA3-512",
+          "content": "7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20"
+        },
+        {
+          "alg": "BLAKE2b-256",
+          "content": "d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237"
+        },
+        {
+          "alg": "BLAKE2b-384",
+          "content": "e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a"
+        },
+        {
+          "alg": "BLAKE2b-512",
+          "content": "f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d"
+        },
+        {
+          "alg": "BLAKE3",
+          "content": "26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-component-hashes-1.4.xml b/tests/_data/schemaTestData/1.4/valid-component-hashes-1.4.xml
new file mode 100644
index 000000000..5def2ebd7
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-hashes-1.4.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-example</name>
+            <version>1.0.0</version>
+            <hashes>
+                <hash alg="MD5">641b6e166f8b33c5e959e2adcc18b1c7</hash>
+                <hash alg="SHA-1">9188560f22e0b73070d2efce670c74af2bdf30af</hash>
+                <hash alg="SHA-256">d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964</hash>
+                <hash alg="SHA-384">d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad</hash>
+                <hash alg="SHA-512">74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6</hash>
+                <hash alg="SHA3-256">7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa</hash>
+                <hash alg="SHA3-384">a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5</hash>
+                <hash alg="SHA3-512">7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20</hash>
+                <hash alg="BLAKE2b-256">d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237</hash>
+                <hash alg="BLAKE2b-384">e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a</hash>
+                <hash alg="BLAKE2b-512">f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d</hash>
+                <hash alg="BLAKE3">26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf</hash>
+            </hashes>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-component-ref-1.4.json b/tests/_data/schemaTestData/1.4/valid-component-ref-1.4.json
new file mode 100644
index 000000000..f21c7fb7a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-ref-1.4.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "bom-ref": "123",
+      "name": "acme-library",
+      "version": "1.0.0"
+    },
+    {
+      "type": "library",
+      "bom-ref": "456",
+      "name": "acme-library",
+      "version": "1.0.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-component-ref-1.4.xml b/tests/_data/schemaTestData/1.4/valid-component-ref-1.4.xml
new file mode 100644
index 000000000..9c66ef416
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-ref-1.4.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library" bom-ref="123">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <components>
+                <component type="library" bom-ref="456">
+                    <name>acme-library</name>
+                    <version>1.0.0</version>
+                </component>
+            </components>
+        </component>
+        <component type="library" bom-ref="789">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-component-swid-1.4.json b/tests/_data/schemaTestData/1.4/valid-component-swid-1.4.json
new file mode 100644
index 000000000..fd037a2f6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-swid-1.4.json
@@ -0,0 +1,19 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1"
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-component-swid-1.4.xml b/tests/_data/schemaTestData/1.4/valid-component-swid-1.4.xml
new file mode 100644
index 000000000..f651bab27
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-swid-1.4.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1" />
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-component-swid-full-1.4.json b/tests/_data/schemaTestData/1.4/valid-component-swid-full-1.4.json
new file mode 100644
index 000000000..fe6de2378
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-swid-full-1.4.json
@@ -0,0 +1,24 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "author": "Acme Super Heros",
+      "name": "Acme Application",
+      "version": "9.1.1",
+      "swid": {
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "name": "Acme Application",
+        "version": "9.1.1",
+        "text": {
+          "contentType": "text/xml",
+          "encoding": "base64",
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-component-swid-full-1.4.xml b/tests/_data/schemaTestData/1.4/valid-component-swid-full-1.4.xml
new file mode 100644
index 000000000..e0d968ddc
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-swid-full-1.4.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <author>Acme Super Heros</author>
+            <name>Acme Application</name>
+            <version>9.1.1</version>
+            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Acme Application" version="9.1.1">
+                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+            </swid>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-component-types-1.4.json b/tests/_data/schemaTestData/1.4/valid-component-types-1.4.json
new file mode 100644
index 000000000..dfcc9bcd3
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-types-1.4.json
@@ -0,0 +1,48 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "name": "application-a",
+      "version": "1.0"
+    },
+    {
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0"
+    },
+    {
+      "type": "framework",
+      "name": "framework-a",
+      "version": "1.0"
+    },
+    {
+      "type": "container",
+      "name": "container-a",
+      "version": "1.0"
+    },
+    {
+      "type": "operating-system",
+      "name": "operating-system-a",
+      "version": "1.0"
+    },
+    {
+      "type": "firmware",
+      "name": "firmware-a",
+      "version": "1.0"
+    },
+    {
+      "type": "device",
+      "name": "device-a",
+      "version": "1.0"
+    },
+    {
+      "type": "file",
+      "name": "file-a",
+      "version": "1.0"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-component-types-1.4.xml b/tests/_data/schemaTestData/1.4/valid-component-types-1.4.xml
new file mode 100644
index 000000000..2c41ad6ec
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-component-types-1.4.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <name>application-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="library">
+            <name>library-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="framework">
+            <name>framework-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="container">
+            <name>container-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="operating-system">
+            <name>operating-system-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="firmware">
+            <name>firmware-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="device">
+            <name>device-a</name>
+            <version>1.0</version>
+        </component>
+        <component type="file">
+            <name>file-a</name>
+            <version>1.0</version>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-compositions-1.4.json b/tests/_data/schemaTestData/1.4/valid-compositions-1.4.json
new file mode 100644
index 000000000..ed86e4901
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-compositions-1.4.json
@@ -0,0 +1,65 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "component": {
+      "bom-ref": "acme-application-1.0",
+      "type": "application",
+      "name": "Acme Application",
+      "version": "1.0"
+    }
+  },
+  "components": [
+    {
+      "bom-ref": "pkg:maven/partner/shaded-library@1.0",
+      "type": "library",
+      "name": "Partner Shaded Library",
+      "version": "1.0",
+      "purl": "pkg:maven/partner/shaded-library@1.0",
+      "components": [
+        {
+          "bom-ref": "pkg:maven/ossproject/library@2.0",
+          "type": "library",
+          "name": "Some Opensource Library",
+          "version": "2.0",
+          "purl": "pkg:maven/ossproject/library@2.0"
+        }
+      ]
+    },
+    {
+      "bom-ref": "pkg:maven/acme/library@3.0",
+      "type": "library",
+      "name": "Acme Library",
+      "version": "3.0",
+      "purl": "pkg:maven/acme/library@3.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "acme-application-1.0",
+      "dependsOn": [
+        "pkg:maven/partner/shaded-library@1.0",
+        "pkg:maven/acme/library@3.0"
+      ]
+    }
+  ],
+  "compositions": [
+    {
+      "aggregate": "complete",
+      "assemblies": [
+        "pkg:maven/partner/shaded-library@1.0"
+      ],
+      "dependencies": [
+        "acme-application-1.0"
+      ]
+    },
+    {
+      "aggregate": "unknown",
+      "assemblies": [
+        "pkg:maven/acme/library@3.0"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-compositions-1.4.xml b/tests/_data/schemaTestData/1.4/valid-compositions-1.4.xml
new file mode 100644
index 000000000..ae0b0ef80
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-compositions-1.4.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <component type="application" bom-ref="acme-application-1.0">
+            <name>Acme Application</name>
+            <version>1.0</version>
+        </component>
+    </metadata>
+    <components>
+        <component type="library" bom-ref="pkg:maven/partner/shaded-library@1.0">
+            <name>Partner Shaded Library</name>
+            <version>1.0</version>
+            <purl>pkg:maven/partner/shaded-library@1.0</purl>
+            <components>
+                <component type="library" bom-ref="pkg:maven/ossproject/library@2.0">
+                    <name>Some Opensource Library</name>
+                    <version>2.0</version>
+                    <purl>pkg:maven/ossproject/library@2.0</purl>
+                </component>
+            </components>
+        </component>
+        <component type="library" bom-ref="pkg:maven/acme/library@3.0">
+            <name>Acme Library</name>
+            <version>2.0</version>
+            <purl>pkg:maven/acme/library@3.0</purl>
+        </component>
+    </components>
+    <dependencies>
+        <dependency ref="acme-application-1.0">
+            <dependency ref="pkg:maven/partner/shaded-library@1.0"/>
+            <dependency ref="pkg:maven/acme/library@3.0"/>
+        </dependency>
+    </dependencies>
+    <compositions>
+        <composition>
+            <aggregate>complete</aggregate>
+            <assemblies>
+                <assembly ref="pkg:maven/partner/shaded-library@1.0"/>
+            </assemblies>
+            <dependencies>
+                <dependency ref="acme-application-1.0"/>
+            </dependencies>
+        </composition>
+        <composition>
+            <aggregate>unknown</aggregate>
+            <assemblies>
+                <assembly ref="pkg:maven/acme/library@3.0"/>
+            </assemblies>
+        </composition>
+    </compositions>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-dependency-1.4.json b/tests/_data/schemaTestData/1.4/valid-dependency-1.4.json
new file mode 100644
index 000000000..b15c6b92e
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-dependency-1.4.json
@@ -0,0 +1,38 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "library-a",
+      "type": "library",
+      "name": "library-a",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-b",
+      "type": "library",
+      "name": "library-b",
+      "version": "1.0.0"
+    },
+    {
+      "bom-ref": "library-c",
+      "type": "library",
+      "name": "library-c",
+      "version": "1.0.0"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "library-a",
+      "dependsOn": []
+    },
+    {
+      "ref": "library-b",
+      "dependsOn": [
+        "library-c"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-dependency-1.4.xml b/tests/_data/schemaTestData/1.4/valid-dependency-1.4.xml
new file mode 100644
index 000000000..7e4bc15f7
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-dependency-1.4.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library" bom-ref="library-a">
+            <name>acme-library-a</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-b">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+        <component type="library" bom-ref="library-c">
+            <name>acme-library-b</name>
+            <version>1.0.0</version>
+        </component>
+    </components>
+    <dependencies>
+        <dependency ref="library-a"/>
+        <dependency ref="library-b">
+            <dependency ref="library-c"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-empty-components-1.4.json b/tests/_data/schemaTestData/1.4/valid-empty-components-1.4.json
new file mode 100644
index 000000000..0cc93e13b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-empty-components-1.4.json
@@ -0,0 +1,8 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-empty-components-1.4.xml b/tests/_data/schemaTestData/1.4/valid-empty-components-1.4.xml
new file mode 100644
index 000000000..5789e04cc
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-empty-components-1.4.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-evidence-1.4.json b/tests/_data/schemaTestData/1.4/valid-evidence-1.4.json
new file mode 100644
index 000000000..a588fdd29
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-evidence-1.4.json
@@ -0,0 +1,53 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "application",
+      "group": "com.google.code.findbugs",
+      "name": "findbugs-project",
+      "version": "3.0.0",
+      "licenses": [
+        {
+          "license": {
+            "id": "LGPL-3.0-or-later",
+            "url": "https://www.gnu.org/licenses/lgpl-3.0-standalone.html"
+          }
+        }
+      ],
+      "purl": "pkg:maven/com.google.code.findbugs/findbugs-project@3.0.0",
+      "evidence": {
+        "licenses": [
+          {
+            "license": {
+              "id": "Apache-2.0",
+              "url": "http://www.apache.org/licenses/LICENSE-2.0"
+            }
+          },
+          {
+            "license": {
+              "id": "LGPL-2.1-only",
+              "url": "https://opensource.org/licenses/LGPL-2.1"
+            }
+          }
+        ],
+        "copyright": [
+          {
+            "text": "Copyright 2012 Google Inc. All Rights Reserved."
+          },
+          {
+            "text": "Copyright (C) 2004,2005 Dave Brosius <dbrosius@users.sourceforge.net>"
+          },
+          {
+            "text": "Copyright (C) 2005 William Pugh"
+          },
+          {
+            "text": "Copyright (C) 2004,2005 University of Maryland"
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-evidence-1.4.xml b/tests/_data/schemaTestData/1.4/valid-evidence-1.4.xml
new file mode 100644
index 000000000..3e03c8c30
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-evidence-1.4.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <group>com.google.code.findbugs</group>
+            <name>findbugs-project</name>
+            <version>3.0.0</version>
+            <licenses>
+                <license>
+                    <id>LGPL-3.0-or-later</id>
+                    <url>https://www.gnu.org/licenses/lgpl-3.0-standalone.html</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.google.code.findbugs/findbugs-project@3.0.0</purl>
+            <evidence>
+                <licenses>
+                    <license>
+                        <id>Apache-2.0</id>
+                        <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+                    </license>
+                    <license>
+                        <id>LGPL-2.1-only</id>
+                        <url>https://opensource.org/licenses/LGPL-2.1</url>
+                    </license>
+                </licenses>
+                <copyright>
+                    <text><![CDATA[Copyright 2012 Google Inc. All Rights Reserved.]]></text>
+                    <text><![CDATA[Copyright (C) 2004,2005 Dave Brosius <dbrosius@users.sourceforge.net>]]></text>
+                    <text><![CDATA[Copyright (C) 2005 William Pugh]]></text>
+                    <text><![CDATA[Copyright (C) 2004,2005 University of Maryland]]></text>
+                </copyright>
+            </evidence>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-external-elements-1.4.xml b/tests/_data/schemaTestData/1.4/valid-external-elements-1.4.xml
new file mode 100644
index 000000000..25c7e5b75
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-external-elements-1.4.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                                <foo:fruit xmlns:foo="foo">
+                                    <foo:name>Banana</foo:name>
+                                </foo:fruit>
+                                <foo:fruit xmlns:foo="foo">
+                                    <foo:name>Banana</foo:name>
+                                </foo:fruit>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </ancestors>
+                <descendants>
+                    <component type="library">
+                        <name>foo</name>
+                        <version>1.0</version>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </descendants>
+                <variants>
+                    <component type="library">
+                        <name>bar</name>
+                        <version>1.0</version>
+                    </component>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </variants>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                            <foo:fruit xmlns:foo="foo">
+                                <foo:name>Banana</foo:name>
+                            </foo:fruit>
+                        </committer>
+                        <message>Initial commit</message>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                        <foo:fruit xmlns:foo="foo">
+                            <foo:name>Banana</foo:name>
+                        </foo:fruit>
+                    </commit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                    <foo:fruit xmlns:foo="foo">
+                        <foo:name>Banana</foo:name>
+                    </foo:fruit>
+                </commits>
+                <notes>Commentary here</notes>
+                <foo:fruit xmlns:foo="foo">
+                    <foo:name>Banana</foo:name>
+                </foo:fruit>
+                <foo:fruit xmlns:foo="foo">
+                    <foo:name>Banana</foo:name>
+                </foo:fruit>
+            </pedigree>
+            <foo:fruit xmlns:foo="foo">
+                <foo:name>Banana</foo:name>
+            </foo:fruit>
+            <foo:fruit xmlns:foo="foo">
+                <foo:name>Banana</foo:name>
+            </foo:fruit>
+        </component>
+        <foo:fruit xmlns:foo="foo">
+            <foo:name>Banana</foo:name>
+        </foo:fruit>
+        <foo:fruit xmlns:foo="foo">
+            <foo:name>Banana</foo:name>
+        </foo:fruit>
+    </components>
+    <foo:fruit xmlns:foo="foo">
+        <foo:name>Banana</foo:name>
+    </foo:fruit>
+    <foo:fruit xmlns:foo="foo">
+        <foo:name>Banana</foo:name>
+    </foo:fruit>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-external-reference-1.4.json b/tests/_data/schemaTestData/1.4/valid-external-reference-1.4.json
new file mode 100644
index 000000000..088172ea1
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-external-reference-1.4.json
@@ -0,0 +1,38 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "org.example",
+      "name": "mylibrary",
+      "version": "1.0.0",
+      "externalReferences": [
+        {
+          "type": "advisories",
+          "url": "https://example.org/security/feed/csaf",
+          "comment": "Security advisories from the vendor"
+        },
+        {
+          "type": "bom",
+          "url": "https://example.org/support/sbom/portal-server/1.0.0",
+          "comment": "An external SBOM that describes what this component includes",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313"
+            }
+          ]
+        },
+        {
+          "type": "documentation",
+          "url": "https://example.org/support/documentation/portal-server/1.0.0",
+          "comment": "Vendor provided documentation for the product"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-external-reference-1.4.xml b/tests/_data/schemaTestData/1.4/valid-external-reference-1.4.xml
new file mode 100644
index 000000000..7e9ec93e9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-external-reference-1.4.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <externalReferences>
+                <reference type="advisories">
+                    <url>https://example.org/security/feed/csaf</url>
+                    <comment>Security advisories from the vendor</comment>
+                </reference>
+                <reference type="bom">
+                    <url>https://example.org/support/sbom/portal-server/1.0.0</url>
+                    <comment>An external SBOM that describes what this component includes</comment>
+                    <hashes>
+                        <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                    </hashes>
+                </reference>
+                <reference type="documentation">
+                    <url>https://example.org/support/documentation/portal-server/1.0.0</url>
+                    <comment>Vendor provided documentation for the product</comment>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-license-expression-1.4.json b/tests/_data/schemaTestData/1.4/valid-license-expression-1.4.json
new file mode 100644
index 000000000..c101ebe99
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-license-expression-1.4.json
@@ -0,0 +1,20 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "expression": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-license-expression-1.4.xml b/tests/_data/schemaTestData/1.4/valid-license-expression-1.4.xml
new file mode 100644
index 000000000..6e939d32d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-license-expression-1.4.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-license-id-1.4.json b/tests/_data/schemaTestData/1.4/valid-license-id-1.4.json
new file mode 100644
index 000000000..1d0974852
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-license-id-1.4.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-license-id-1.4.xml b/tests/_data/schemaTestData/1.4/valid-license-id-1.4.xml
new file mode 100644
index 000000000..e0b514f43
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-license-id-1.4.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-license-name-1.4.json b/tests/_data/schemaTestData/1.4/valid-license-name-1.4.json
new file mode 100644
index 000000000..03c884ca8
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-license-name-1.4.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "tomcat-catalina",
+      "version": "9.0.14",
+      "licenses": [
+        {
+          "license": {
+            "name": "Apache License 2.0"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-license-name-1.4.xml b/tests/_data/schemaTestData/1.4/valid-license-name-1.4.xml
new file mode 100644
index 000000000..7feade6b9
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-license-name-1.4.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Apache License 2.0</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-author-1.4.json b/tests/_data/schemaTestData/1.4/valid-metadata-author-1.4.json
new file mode 100644
index 000000000..febeed4fc
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-author-1.4.json
@@ -0,0 +1,16 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "authors": [
+      {
+        "name": "Samantha Wright",
+        "email": "samantha.wright@example.com",
+        "phone": "800-555-1212"
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-author-1.4.xml b/tests/_data/schemaTestData/1.4/valid-metadata-author-1.4.xml
new file mode 100644
index 000000000..807fc5c64
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-author-1.4.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <authors>
+            <author>
+                <name>Samantha Wright</name>
+                <email>samantha.wright@example.com</email>
+                <phone>800-555-1212</phone>
+            </author>
+        </authors>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-license-1.4.json b/tests/_data/schemaTestData/1.4/valid-metadata-license-1.4.json
new file mode 100644
index 000000000..10e75af0a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-license-1.4.json
@@ -0,0 +1,16 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "licenses": [
+      {
+        "license": {
+          "id": "Apache-2.0"
+        }
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-license-1.4.xml b/tests/_data/schemaTestData/1.4/valid-metadata-license-1.4.xml
new file mode 100644
index 000000000..295389f8d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-license-1.4.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <licenses>
+            <license>
+                <id>Apache-2.0</id>
+            </license>
+        </licenses>
+    </metadata>
+    <components />
+</bom>
\ No newline at end of file
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-manufacture-1.4.json b/tests/_data/schemaTestData/1.4/valid-metadata-manufacture-1.4.json
new file mode 100644
index 000000000..68705c418
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-manufacture-1.4.json
@@ -0,0 +1,21 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "manufacture": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Professional Services",
+          "email": "professional.services@example.com"
+        }
+      ]
+    }
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-manufacture-1.4.xml b/tests/_data/schemaTestData/1.4/valid-metadata-manufacture-1.4.xml
new file mode 100644
index 000000000..36b70a5bb
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-manufacture-1.4.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <manufacture>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Professional Services</name>
+                <email>professional.services@example.com</email>
+            </contact>
+        </manufacture>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-supplier-1.4.json b/tests/_data/schemaTestData/1.4/valid-metadata-supplier-1.4.json
new file mode 100644
index 000000000..33b1af255
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-supplier-1.4.json
@@ -0,0 +1,21 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "supplier": {
+      "name": "Acme, Inc.",
+      "url": [
+        "https://example.com"
+      ],
+      "contact": [
+        {
+          "name": "Acme Distribution",
+          "email": "distribution@example.com"
+        }
+      ]
+    }
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-supplier-1.4.xml b/tests/_data/schemaTestData/1.4/valid-metadata-supplier-1.4.xml
new file mode 100644
index 000000000..37a222daf
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-supplier-1.4.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <supplier>
+            <name>Acme, Inc.</name>
+            <url>https://example.com</url>
+            <contact>
+                <name>Acme Distribution</name>
+                <email>distribution@example.com</email>
+            </contact>
+        </supplier>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-timestamp-1.4.json b/tests/_data/schemaTestData/1.4/valid-metadata-timestamp-1.4.json
new file mode 100644
index 000000000..26ab14ad6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-timestamp-1.4.json
@@ -0,0 +1,10 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "timestamp": "2020-04-13T20:20:39+00:00"
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-timestamp-1.4.xml b/tests/_data/schemaTestData/1.4/valid-metadata-timestamp-1.4.xml
new file mode 100644
index 000000000..06adc1b0b
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-timestamp-1.4.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <timestamp>2020-04-07T07:01:00Z</timestamp>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-tool-1.4.json b/tests/_data/schemaTestData/1.4/valid-metadata-tool-1.4.json
new file mode 100644
index 000000000..19175ee01
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-tool-1.4.json
@@ -0,0 +1,26 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "tools": [
+      {
+        "vendor": "Awesome Vendor",
+        "name": "Awesome Tool",
+        "version": "9.1.2",
+        "hashes": [
+          {
+            "alg": "SHA-1",
+            "content": "25ed8e31b995bb927966616df2a42b979a2717f0"
+          },
+          {
+            "alg": "SHA-256",
+            "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df"
+          }
+        ]
+      }
+    ]
+  },
+  "components": []
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-metadata-tool-1.4.xml b/tests/_data/schemaTestData/1.4/valid-metadata-tool-1.4.xml
new file mode 100644
index 000000000..ead4ea0dd
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-metadata-tool-1.4.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <tools>
+            <tool>
+                <vendor>Awesome Vendor</vendor>
+                <name>Awesome Tool</name>
+                <version>9.1.2</version>
+                <hashes>
+                    <hash alg="SHA-1">25ed8e31b995bb927966616df2a42b979a2717f0</hash>
+                    <hash alg="SHA-256">a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df</hash>
+                </hashes>
+            </tool>
+        </tools>
+    </metadata>
+    <components />
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-minimal-viable-1.4.json b/tests/_data/schemaTestData/1.4/valid-minimal-viable-1.4.json
new file mode 100644
index 000000000..c1029f0f6
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-minimal-viable-1.4.json
@@ -0,0 +1,12 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library"
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-minimal-viable-1.4.xml b/tests/_data/schemaTestData/1.4/valid-minimal-viable-1.4.xml
new file mode 100644
index 000000000..92ac5cc7d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-minimal-viable-1.4.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-patch-1.4.json b/tests/_data/schemaTestData/1.4/valid-patch-1.4.json
new file mode 100644
index 000000000..66db19aa5
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-patch-1.4.json
@@ -0,0 +1,88 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "group": "com.acme",
+      "name": "sample-library",
+      "version": "1.0.0",
+      "pedigree": {
+        "ancestors": [
+          {
+            "type": "library",
+            "group": "org.example",
+            "name": "sample-library",
+            "version": "1.0.0"
+          }
+        ],
+        "patches": [
+          {
+            "type": "unofficial",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "enhancement",
+                "id": "JIRA-17240",
+                "description": "Great new feature that does something",
+                "source": {
+                  "name": "Acme Org",
+                  "url": "https://issues.acme.org/17240"
+                }
+              }
+            ]
+          },
+          {
+            "type": "backport",
+            "diff": {
+              "text": {
+                "contentType": "text/plain",
+                "encoding": "base64",
+                "content": "blah"
+              },
+              "url": "uri/to/changes.diff"
+            },
+            "resolves": [
+              {
+                "type": "security",
+                "id": "CVE-2019-9997",
+                "name": "CVE-2019-9997",
+                "description": "blah blah",
+                "source": {
+                  "name": "NVD",
+                  "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9997"
+                },
+                "references": [
+                  "http://some/other/site-1",
+                  "http://some/other/site-2"
+                ]
+              },
+              {
+                "type": "defect",
+                "id": "JIRA-874319",
+                "description": "Enable to do something",
+                "source": {
+                  "name": "Example Org",
+                  "url": "https://issues.example.org/874319"
+                },
+                "references": [
+                  "http://some/other/site-1",
+                  "http://some/other/site-2"
+                ]
+              }
+            ]
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-patch-1.4.xml b/tests/_data/schemaTestData/1.4/valid-patch-1.4.xml
new file mode 100644
index 000000000..7c0a3d77d
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-patch-1.4.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <group>com.acme</group>
+            <name>sample-library</name>
+            <version>1.0.0</version>
+            <pedigree>
+                <ancestors>
+                    <component type="library">
+                        <group>org.example</group>
+                        <name>sample-library</name>
+                        <version>1.0.0</version>
+                    </component>
+                </ancestors>
+                <patches>
+                    <patch type="unofficial">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="enhancement">
+                                <id>JIRA-17240</id>
+                                <description>Great new feature that does something</description>
+                                <source>
+                                    <name>Acme Org</name>
+                                    <url>https://issues.acme.org/17240</url>
+                                </source>
+                            </issue>
+                        </resolves>
+                    </patch>
+                    <patch type="backport">
+                        <diff>
+                            <text content-type="text/plain" encoding="base64">blah</text>
+                            <url>uri/to/changes.diff</url>
+                        </diff>
+                        <resolves>
+                            <issue type="security">
+                                <id>CVE-2019-9997</id>
+                                <name>CVE-2019-9997</name>
+                                <description>blah blah</description>
+                                <source>
+                                    <name>NVD</name>
+                                    <url>https://nvd.nist.gov/vuln/detail/CVE-2019-9997</url>
+                                </source>
+                                <references>
+                                    <url>http://some/other/site-1</url>
+                                    <url>http://some/other/site-2</url>
+                                </references>
+                            </issue>
+                            <issue type="defect">
+                                <id>JIRA-874319</id>
+                                <description>Enable to do something</description>
+                                <source>
+                                    <name>Example Org</name>
+                                    <url>https://issues.example.org/874319</url>
+                                </source>
+                                <references>
+                                    <url>http://some/other/site-1</url>
+                                    <url>http://some/other/site-2</url>
+                                </references>
+                            </issue>
+                        </resolves>
+                    </patch>
+                </patches>
+            </pedigree>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-properties-1.4.json b/tests/_data/schemaTestData/1.4/valid-properties-1.4.json
new file mode 100644
index 000000000..bdf67f7ee
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-properties-1.4.json
@@ -0,0 +1,55 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "metadata": {
+    "properties": [
+      {
+        "name": "Foo",
+        "value": "Bar"
+      },
+      {
+        "name": "Foo",
+        "value": "You"
+      },
+      {
+        "name": "Foo",
+        "value": "Two"
+      },
+      {
+        "name": "Bar",
+        "value": "Foo"
+      }
+    ]
+  },
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-library",
+      "version": "1.0.0",
+      "properties": [
+        {
+          "name": "Foo",
+          "value": "Bar"
+        }
+      ]
+    }
+  ],
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "group": "org.partner",
+      "name": "Stock ticker service",
+      "endpoints": [
+        "https://partner.org/api/v1/stock"
+      ],
+      "properties": [
+        {
+          "name": "Foo",
+          "value": "Bar"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-properties-1.4.xml b/tests/_data/schemaTestData/1.4/valid-properties-1.4.xml
new file mode 100644
index 000000000..38d41faf2
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-properties-1.4.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <metadata>
+        <properties>
+            <property name="Foo">Bar</property>
+            <property name="Foo">You</property>
+            <property name="Foo">Two</property>
+            <property name="Bar">Foo</property>
+        </properties>
+    </metadata>
+    <components>
+        <component type="library">
+            <name>acme-library</name>
+            <version>1.0.0</version>
+            <properties>
+                <property name="Foo">Bar</property>
+                <property name="Bar">Foo</property>
+            </properties>
+        </component>
+    </components>
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <group>org.partner</group>
+            <name>Stock ticker service</name>
+            <endpoints>
+                <endpoint>https://partner.org/api/v1/stock</endpoint>
+            </endpoints>
+            <properties>
+                <property name="Foo">Bar</property>
+                <property name="Bar">Foo</property>
+            </properties>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-random-attributes-1.4.xml b/tests/_data/schemaTestData/1.4/valid-random-attributes-1.4.xml
new file mode 100644
index 000000000..428692adb
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-random-attributes-1.4.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<bom foo="bar" bar="foo" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components foo="bar" bar="foo" >
+        <component foo="bar" bar="foo"  type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <description>Modified version of Apache Catalina</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/plain" encoding="base64">CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAgICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAxLiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAgICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAgICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5zZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNvbmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAgYW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAgICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNoaXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQgYW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMgYW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVyZm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBvZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAgICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYgYW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBub3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAgIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4=</text>
+                    <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors foo="bar" bar="foo">
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <description>Apache Catalina</description>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>john.doe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>Jane Doe</name>
+                            <email>jane.doe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+                <notes>Commentary here</notes>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <expression>EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0</expression>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="documentation">
+                    <url>http://example.org/docs</url>
+                    <comment>All component versions are documented here</comment>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.org/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <name>Some random license</name>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-release-notes-1.4.json b/tests/_data/schemaTestData/1.4/valid-release-notes-1.4.json
new file mode 100644
index 000000000..bd45f9407
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-release-notes-1.4.json
@@ -0,0 +1,194 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "type": "library",
+      "name": "acme-example",
+      "version": "1.0.0",
+      "releaseNotes": {
+        "type": "major",
+        "title": "My new release",
+        "featuredImage": "https://example.com/featured_image.png",
+        "socialImage": "https://example.com/social_image.png",
+        "description": "The main description of your release",
+        "timestamp": "2021-09-17T00:51:18+00:00",
+        "aliases": [
+          "Project Orion"
+        ],
+        "tags": [
+          "CMS",
+          "SEO",
+          "wysiwyg"
+        ],
+        "resolves": [
+          {
+            "type": "enhancement",
+            "id": "JIRA-17240",
+            "description": "Great new feature that does something",
+            "source": {
+              "name": "Acme Org",
+              "url": "https://issues.example.com/17240"
+            }
+          },
+          {
+            "type": "security",
+            "id": "CVE-2019-9997",
+            "name": "CVE-2019-9997",
+            "description": "Great new feature that does something",
+            "source": {
+              "name": "NVD",
+              "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9997"
+            },
+            "references": [
+              "http://some/other/site-1",
+              "http://some/other/site-2"
+            ]
+          }
+        ],
+        "notes": [
+          {
+            "locale": "en-US",
+            "text":  {
+              "contentType": "text/html",
+              "encoding": "base64",
+              "content": "PGgxPk15IG5ldyByZWxlYXNlPGgxPgo8cD5SZWxlYXNlIG5vdGVzIGhlcmU8L3A+"
+            }
+          },
+          {
+            "locale": "es",
+            "text":  {
+              "contentType": "text/html",
+              "encoding": "base64",
+              "content": "PGgxPk15IG5ldyByZWxlYXNlPGgxPgo8cD5Ob3RhcyBkZSBsYSB2ZXJzacOzbiBhcXXDrTwvcD4="
+            }
+          }
+        ]
+      }
+    }
+  ],
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "provider": {
+        "name": "Partner Org",
+        "url": [
+          "https://partner.org"
+        ],
+        "contact": [
+          {
+            "name": "Support",
+            "email": "support@partner.org",
+            "phone": "800-555-1212"
+          }
+        ]
+      },
+      "group": "org.partner",
+      "name": "Stock ticker service",
+      "version": "2020-Q2",
+      "description": "Provides real-time stock information",
+      "endpoints": [
+        "https://partner.org/api/v1/lookup",
+        "https://partner.org/api/v1/stock"
+      ],
+      "authenticated": true,
+      "x-trust-boundary": true,
+      "data": [
+        {
+          "classification": "PII",
+          "flow": "inbound"
+        },
+        {
+          "classification": "PIFI",
+          "flow": "outbound"
+        },
+        {
+          "classification": "pubic",
+          "flow": "bi-directional"
+        },
+        {
+          "classification": "partner-data",
+          "flow": "unknown"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "name": "Partner license"
+          }
+        }
+      ],
+      "externalReferences": [
+        {
+          "type": "website",
+          "url": "http://partner.org"
+        },
+        {
+          "type": "documentation",
+          "url": "http://api.partner.org/swagger"
+        }
+      ],
+      "releaseNotes": {
+        "type": "major",
+        "title": "My new release",
+        "featuredImage": "https://example.com/featured_image.png",
+        "socialImage": "https://example.com/social_image.png",
+        "description": "The main description of your release",
+        "timestamp": "2021-09-17T00:51:18+00:00",
+        "aliases": [
+          "Project Orion"
+        ],
+        "tags": [
+          "CMS",
+          "SEO",
+          "wysiwyg"
+        ],
+        "resolves": [
+          {
+            "type": "enhancement",
+            "id": "JIRA-17240",
+            "description": "Great new feature that does something",
+            "source": {
+              "name": "Acme Org",
+              "url": "https://issues.example.com/17240"
+            }
+          },
+          {
+            "type": "security",
+            "id": "CVE-2019-9997",
+            "name": "CVE-2019-9997",
+            "description": "Great new feature that does something",
+            "source": {
+              "name": "NVD",
+              "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9997"
+            },
+            "references": [
+              "http://some/other/site-1",
+              "http://some/other/site-2"
+            ]
+          }
+        ],
+        "notes": [
+          {
+            "locale": "en-US",
+            "text":  {
+              "contentType": "text/html",
+              "encoding": "base64",
+              "content": "PGgxPk15IG5ldyByZWxlYXNlPGgxPgo8cD5SZWxlYXNlIG5vdGVzIGhlcmU8L3A+"
+            }
+          },
+          {
+            "locale": "es",
+            "text":  {
+              "contentType": "text/html",
+              "encoding": "base64",
+              "content": "PGgxPk15IG5ldyByZWxlYXNlPGgxPgo8cD5Ob3RhcyBkZSBsYSB2ZXJzacOzbiBhcXXDrTwvcD4="
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-release-notes-1.4.xml b/tests/_data/schemaTestData/1.4/valid-release-notes-1.4.xml
new file mode 100644
index 000000000..7102926fe
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-release-notes-1.4.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library">
+            <name>acme-example</name>
+            <version>1.0.0</version>
+            <releaseNotes>
+                <type>major</type>
+                <title>My new release</title>
+                <featuredImage>https://example.com/featured_image.png</featuredImage>
+                <socialImage>https://example.com/social_image.png</socialImage>
+                <description>The main description of your release</description>
+                <timestamp>2021-09-17T00:51:18+00:00</timestamp>
+                <aliases>
+                    <alias>Project Orion</alias>
+                </aliases>
+                <tags>
+                    <tag>CMS</tag>
+                    <tag>SEO</tag>
+                    <tag>wysiwyg</tag>
+                </tags>
+                <resolves>
+                    <issue type="enhancement">
+                        <id>JIRA-17240</id>
+                        <description>Great new feature that does something</description>
+                        <source>
+                            <name>Acme Org</name>
+                            <url>https://issues.example.com/17240</url>
+                        </source>
+                    </issue>
+                    <issue type="security">
+                        <id>CVE-2019-9997</id>
+                        <name>CVE-2019-9997</name>
+                        <description>A security issue was fixed that did something bad</description>
+                        <source>
+                            <name>NVD</name>
+                            <url>https://nvd.nist.gov/vuln/detail/CVE-2019-9997</url>
+                        </source>
+                        <references>
+                            <url>http://some/other/site-1</url>
+                            <url>http://some/other/site-2</url>
+                        </references>
+                    </issue>
+                </resolves>
+                <notes>
+                    <note>
+                        <locale>en-US</locale>
+                        <text content-type="text/html" encoding="base64">PGgxPk15IG5ldyByZWxlYXNlPGgxPgo8cD5SZWxlYXNlIG5vdGVzIGhlcmU8L3A+</text>
+                    </note>
+                    <note>
+                        <locale>es</locale>
+                        <text content-type="text/html" encoding="base64">PGgxPk15IG5ldyByZWxlYXNlPGgxPgo8cD5Ob3RhcyBkZSBsYSB2ZXJzacOzbiBhcXXDrTwvcD4=</text>
+                    </note>
+                </notes>
+            </releaseNotes>
+        </component>
+    </components>
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <provider>
+                <name>Partner Org</name>
+                <url>https://partner.org</url>
+                <contact>
+                    <name>Support</name>
+                    <email>support@partner</email>
+                    <phone>800-555-1212</phone>
+                </contact>
+            </provider>
+            <group>org.partner</group>
+            <name>Stock ticker service</name>
+            <version>2020-Q2</version>
+            <description>Provides real-time stock information</description>
+            <endpoints>
+                <endpoint>https://partner.org/api/v1/lookup</endpoint>
+                <endpoint>https://partner.org/api/v1/stock</endpoint>
+            </endpoints>
+            <authenticated>true</authenticated>
+            <x-trust-boundary>true</x-trust-boundary>
+            <data>
+                <classification flow="inbound">PII</classification>
+                <classification flow="outbound">PIFI</classification>
+                <classification flow="bi-directional">pubic</classification>
+                <classification flow="unknown">partner-data</classification>
+            </data>
+            <licenses>
+                <license>
+                    <name>Partner license</name>
+                </license>
+            </licenses>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://partner.org</url>
+                </reference>
+                <reference type="documentation">
+                    <url>http://api.partner.org/swagger</url>
+                </reference>
+            </externalReferences>
+            <releaseNotes>
+                <type>major</type>
+                <title>My new release</title>
+                <featuredImage>https://example.com/featured_image.png</featuredImage>
+                <socialImage>https://example.com/social_image.png</socialImage>
+                <description>The main description of your release</description>
+                <timestamp>2021-09-17T00:51:18+00:00</timestamp>
+                <aliases>
+                    <alias>Project Orion</alias>
+                </aliases>
+                <tags>
+                    <tag>CMS</tag>
+                    <tag>SEO</tag>
+                    <tag>wysiwyg</tag>
+                </tags>
+                <resolves>
+                    <issue type="enhancement">
+                        <id>JIRA-17240</id>
+                        <description>Great new feature that does something</description>
+                        <source>
+                            <name>Acme Org</name>
+                            <url>https://issues.example.com/17240</url>
+                        </source>
+                    </issue>
+                    <issue type="security">
+                        <id>CVE-2019-9997</id>
+                        <name>CVE-2019-9997</name>
+                        <description>A security issue was fixed that did something bad</description>
+                        <source>
+                            <name>NVD</name>
+                            <url>https://nvd.nist.gov/vuln/detail/CVE-2019-9997</url>
+                        </source>
+                        <references>
+                            <url>http://some/other/site-1</url>
+                            <url>http://some/other/site-2</url>
+                        </references>
+                    </issue>
+                </resolves>
+                <notes>
+                    <note>
+                        <locale>en-US</locale>
+                        <text content-type="text/html" encoding="base64">PGgxPk15IG5ldyByZWxlYXNlPGgxPgo8cD5SZWxlYXNlIG5vdGVzIGhlcmU8L3A+</text>
+                    </note>
+                    <note>
+                        <locale>es</locale>
+                        <text content-type="text/html" encoding="base64">PGgxPk15IG5ldyByZWxlYXNlPGgxPgo8cD5Ob3RhcyBkZSBsYSB2ZXJzacOzbiBhcXXDrTwvcD4=</text>
+                    </note>
+                </notes>
+            </releaseNotes>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-service-1.4.json b/tests/_data/schemaTestData/1.4/valid-service-1.4.json
new file mode 100644
index 000000000..2b23fce28
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-service-1.4.json
@@ -0,0 +1,101 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:maven/com.acme/stock-java-client@1.0.12",
+      "type": "library",
+      "publisher": "Acme Inc",
+      "group": "com.acme",
+      "name": "stock-java-client",
+      "version": "1.0.12",
+      "hashes": [
+        {
+          "alg": "SHA-1",
+          "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "purl": "pkg:maven/com.acme/stock-java-client@1.0.12"
+    }
+  ],
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "provider": {
+        "name": "Partner Org",
+        "url": [
+          "https://partner.org"
+        ],
+        "contact": [
+          {
+            "name": "Support",
+            "email": "support@partner.org",
+            "phone": "800-555-1212"
+          }
+        ]
+      },
+      "group": "org.partner",
+      "name": "Stock ticker service",
+      "version": "2020-Q2",
+      "description": "Provides real-time stock information",
+      "endpoints": [
+        "https://partner.org/api/v1/lookup",
+        "https://partner.org/api/v1/stock"
+      ],
+      "authenticated": true,
+      "x-trust-boundary": true,
+      "data": [
+        {
+          "classification": "PII",
+          "flow": "inbound"
+        },
+        {
+          "classification": "PIFI",
+          "flow": "outbound"
+        },
+        {
+          "classification": "pubic",
+          "flow": "bi-directional"
+        },
+        {
+          "classification": "partner-data",
+          "flow": "unknown"
+        }
+      ],
+      "licenses": [
+        {
+          "license": {
+            "name": "Partner license"
+          }
+        }
+      ],
+      "externalReferences": [
+        {
+          "type": "website",
+          "url": "http://partner.org"
+        },
+        {
+          "type": "documentation",
+          "url": "http://api.partner.org/swagger"
+        }
+      ]
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:maven/com.acme/stock-java-client@1.0.12",
+      "dependsOn": [
+        "b2a46a4b-8367-4bae-9820-95557cfe03a8"
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-service-1.4.xml b/tests/_data/schemaTestData/1.4/valid-service-1.4.xml
new file mode 100644
index 000000000..c315ec045
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-service-1.4.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library" bom-ref="pkg:maven/com.acme/stock-java-client@1.0.12">
+            <group>com.acme</group>
+            <name>stock-java-client</name>
+            <version>1.0.12</version>
+            <hashes>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/stock-java-client@1.0.12</purl>
+        </component>
+    </components>
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <provider>
+                <name>Partner Org</name>
+                <url>https://partner.org</url>
+                <contact>
+                    <name>Support</name>
+                    <email>support@partner</email>
+                    <phone>800-555-1212</phone>
+                </contact>
+            </provider>
+            <group>org.partner</group>
+            <name>Stock ticker service</name>
+            <version>2020-Q2</version>
+            <description>Provides real-time stock information</description>
+            <endpoints>
+                <endpoint>https://partner.org/api/v1/lookup</endpoint>
+                <endpoint>https://partner.org/api/v1/stock</endpoint>
+            </endpoints>
+            <authenticated>true</authenticated>
+            <x-trust-boundary>true</x-trust-boundary>
+            <data>
+                <classification flow="inbound">PII</classification>
+                <classification flow="outbound">PIFI</classification>
+                <classification flow="bi-directional">pubic</classification>
+                <classification flow="unknown">partner-data</classification>
+            </data>
+            <licenses>
+                <license>
+                    <name>Partner license</name>
+                </license>
+            </licenses>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://partner.org</url>
+                </reference>
+                <reference type="documentation">
+                    <url>http://api.partner.org/swagger</url>
+                </reference>
+            </externalReferences>
+        </service>
+    </services>
+    <dependencies>
+        <dependency ref="pkg:maven/com.acme/stock-java-client@1.0.12">
+            <dependency ref="b2a46a4b-8367-4bae-9820-95557cfe03a8"/>
+        </dependency>
+    </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-service-empty-objects-1.4.json b/tests/_data/schemaTestData/1.4/valid-service-empty-objects-1.4.json
new file mode 100644
index 000000000..c54c1efe8
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-service-empty-objects-1.4.json
@@ -0,0 +1,22 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "services": [
+    {
+      "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8",
+      "provider": {
+        "contact": [
+        ]
+      },
+      "name": "Stock ticker service",
+      "endpoints": [
+      ],
+      "data": [
+      ],
+      "externalReferences": [
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-service-empty-objects-1.4.xml b/tests/_data/schemaTestData/1.4/valid-service-empty-objects-1.4.xml
new file mode 100644
index 000000000..4c97cfa81
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-service-empty-objects-1.4.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <services>
+        <service bom-ref="b2a46a4b-8367-4bae-9820-95557cfe03a8">
+            <provider>
+            </provider>
+            <name>Stock ticker service</name>
+            <endpoints>
+            </endpoints>
+            <data>
+            </data>
+            <licenses>
+            </licenses>
+        </service>
+    </services>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-signatures-1.4.json b/tests/_data/schemaTestData/1.4/valid-signatures-1.4.json
new file mode 100644
index 000000000..48dec3efe
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-signatures-1.4.json
@@ -0,0 +1,78 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "5366293e-0740-4dcf-b1d0-0c1fc26e4981",
+      "type": "application",
+      "name": "amce app",
+      "version": "1.0",
+      "signature": {
+        "algorithm": "ES256",
+        "certificatePath": [
+          "MIIB-TCCAVigAwIBAgIGAWFcc4YkMAwGCCqGSM49BAMEBQAwLTELMAkGA1UEBhMCRVUxHjAcBgNVBAMTFVRydXN0IE5ldHdvcmsgU3ViIENBMzAeFw0xODAxMDEwMDAwMDBaFw0yMjEyMzEyMzU5NTlaMDIxCzAJBgNVBAYTAkZSMQ0wCwYDVQQFEwQ0NTAxMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHHp7A83DBJIInj8-g1we3A7sBXprIQBUfdFDVUBQoPExq8rze6ewG0-eVcSF72J77gKiD0IHnzpwHaU7t6nVeajXTBbMAkGA1UdEwQCMAAwDgYDVR0PAQH_BAQDAgP4MB0GA1UdDgQWBBQQyJ9rXSIskoUuA946von62LoxqzAfBgNVHSMEGDAWgBTUWrS54qC2NgG3UK6rVAr0gbQ0MTAMBggqhkjOPQQDBAUAA4GMADCBiAJCAaWoVQ0r6jFjhO5e0WJTgyMmA8BhpO1t7gXQ6xoKGso9jCOYf9OG9BFfZoVmdIyfYiwkhy1ld27tiOJ5X4m6WasRAkIBpEkUDf8irbSZ1V7zXALaR2mJTjKQV_5jRHsiBQWA-5DxEa-x_zJVRz8tpp-jjT2tSCU82bwUOBLu6te1YIDpWCA",
+          "MIIDsTCCAZmgAwIBAgIBAzANBgkqhkiG9w0BAQ0FADAuMQswCQYDVQQGEwJVUzEfMB0GA1UEAxMWVHJ1c3QgTmV0d29yayBSb290IENBMTAeFw0xNjA3MTAxMDAwMDBaFw0yNTA3MTAwOTU5NTlaMC0xCzAJBgNVBAYTAkVVMR4wHAYDVQQDExVUcnVzdCBOZXR3b3JrIFN1YiBDQTMwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAGJzPZsjniwyZeXrgrlQM3Y13r3znR8FSQpKbC2bplrOWySQJPGm-GFObe5Dk4t3Jrtk_Pbs8-3VW_4q5drL0YqYwBYNJPhqjbSM6SGHrc6wNdPZRw_WnJVa0ELXKICC73lkjskWPfE-cLpZ3sTq1ovEmoNjgaySVRUH1wFDdkqyReJaKNjMGEwDwYDVR0TAQH_BAUwAwEB_zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNRatLnioLY2AbdQrqtUCvSBtDQxMB8GA1UdIwQYMBaAFEkmC1HDAh0fXehpiUhUGE868Hk2MA0GCSqGSIb3DQEBDQUAA4ICAQAs2KADYyGQCVy8tJZWakNtGdww4OumZpBuR66p_2xK7veRubQEhG-nJn7oVkJ4w5pEec3sYQEqtPbHyZcEKEYbOJ2cVf1nMH-DvFZ6ypQocGRp3WSWsTzL3SgqiWrQdPX1Y5dO6Hvx7p9ST9H2WgkxB-Q75Jov1gVF3bScAbxb7Mw7tf5z3Cvqmfo0Gatkgzz6-jDPrtUK7AAAOw3C0kHMbE3EnNarsfhBkUerE8QVmHIvz373mWt0SnguaHq0A9ZuSia_pF7bgfVRZi2ZzIzpu2O276sB2Yji9tcSn5l21jq63rXtvY_DLAi4kaLyf9sHT_tkH-gkTdkdkfQq8sA5ysRW21wPQbmjTIVwsfY4JjajVIUitjPbkUJqURpf2VD0JXdYQHS6KVPWqHWTlKPlsKbhw4ghuLqCMYda88L9rxWnSC5L8s0DJSuBBm-nq23NtHl5FbCzeXWcKRayIgimT-An1WIOeJP4F7-BctYLIooKoQzJZR1tOWvprUs22_xAivVBz7J_LmJyVlKesB2ic8qYdt7YVoCsWrnEUgoNoJPwLHeva8KPvd0gLXrwaMyTCCjeoemXFj6nCbbMHJeVffh6jYBAzlbcAEvTiZcdzrVVr54kOtWskyaeDnAcMXW4Of1vWdUJ2as5nyfletfTp4E6A9P2dZ5g7nMoL90yIw"
+        ],
+        "value": "tqITqIm0gUMWXIjqDgwqzqPw1CwTUKRewZQ5YpX3VwFMWV68NJgX4npU91cSwSC-MRlx1QfOYwSQkeU26VpXSg"
+      }
+    }
+  ],
+  "services": [
+    {
+      "bom-ref": "ee10d0a2-baba-4656-a5ac-d49e172a0d3d",
+      "group": "org.partner",
+      "name": "Stock ticker service",
+      "version": "2020-Q2",
+      "endpoints": [
+        "https://partner.org/api/v1/lookup",
+        "https://partner.org/api/v1/stock"
+      ],
+      "authenticated": true,
+      "x-trust-boundary": true,
+      "data": [
+        {
+          "classification": "PII",
+          "flow": "inbound"
+        }
+      ],
+      "signature": {
+        "algorithm": "ES256",
+        "certificatePath": [
+          "MIIB-TCCAVigAwIBAgIGAWFcc4YkMAwGCCqGSM49BAMEBQAwLTELMAkGA1UEBhMCRVUxHjAcBgNVBAMTFVRydXN0IE5ldHdvcmsgU3ViIENBMzAeFw0xODAxMDEwMDAwMDBaFw0yMjEyMzEyMzU5NTlaMDIxCzAJBgNVBAYTAkZSMQ0wCwYDVQQFEwQ0NTAxMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHHp7A83DBJIInj8-g1we3A7sBXprIQBUfdFDVUBQoPExq8rze6ewG0-eVcSF72J77gKiD0IHnzpwHaU7t6nVeajXTBbMAkGA1UdEwQCMAAwDgYDVR0PAQH_BAQDAgP4MB0GA1UdDgQWBBQQyJ9rXSIskoUuA946von62LoxqzAfBgNVHSMEGDAWgBTUWrS54qC2NgG3UK6rVAr0gbQ0MTAMBggqhkjOPQQDBAUAA4GMADCBiAJCAaWoVQ0r6jFjhO5e0WJTgyMmA8BhpO1t7gXQ6xoKGso9jCOYf9OG9BFfZoVmdIyfYiwkhy1ld27tiOJ5X4m6WasRAkIBpEkUDf8irbSZ1V7zXALaR2mJTjKQV_5jRHsiBQWA-5DxEa-x_zJVRz8tpp-jjT2tSCU82bwUOBLu6te1YIDpWCA",
+          "MIIDsTCCAZmgAwIBAgIBAzANBgkqhkiG9w0BAQ0FADAuMQswCQYDVQQGEwJVUzEfMB0GA1UEAxMWVHJ1c3QgTmV0d29yayBSb290IENBMTAeFw0xNjA3MTAxMDAwMDBaFw0yNTA3MTAwOTU5NTlaMC0xCzAJBgNVBAYTAkVVMR4wHAYDVQQDExVUcnVzdCBOZXR3b3JrIFN1YiBDQTMwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAGJzPZsjniwyZeXrgrlQM3Y13r3znR8FSQpKbC2bplrOWySQJPGm-GFObe5Dk4t3Jrtk_Pbs8-3VW_4q5drL0YqYwBYNJPhqjbSM6SGHrc6wNdPZRw_WnJVa0ELXKICC73lkjskWPfE-cLpZ3sTq1ovEmoNjgaySVRUH1wFDdkqyReJaKNjMGEwDwYDVR0TAQH_BAUwAwEB_zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNRatLnioLY2AbdQrqtUCvSBtDQxMB8GA1UdIwQYMBaAFEkmC1HDAh0fXehpiUhUGE868Hk2MA0GCSqGSIb3DQEBDQUAA4ICAQAs2KADYyGQCVy8tJZWakNtGdww4OumZpBuR66p_2xK7veRubQEhG-nJn7oVkJ4w5pEec3sYQEqtPbHyZcEKEYbOJ2cVf1nMH-DvFZ6ypQocGRp3WSWsTzL3SgqiWrQdPX1Y5dO6Hvx7p9ST9H2WgkxB-Q75Jov1gVF3bScAbxb7Mw7tf5z3Cvqmfo0Gatkgzz6-jDPrtUK7AAAOw3C0kHMbE3EnNarsfhBkUerE8QVmHIvz373mWt0SnguaHq0A9ZuSia_pF7bgfVRZi2ZzIzpu2O276sB2Yji9tcSn5l21jq63rXtvY_DLAi4kaLyf9sHT_tkH-gkTdkdkfQq8sA5ysRW21wPQbmjTIVwsfY4JjajVIUitjPbkUJqURpf2VD0JXdYQHS6KVPWqHWTlKPlsKbhw4ghuLqCMYda88L9rxWnSC5L8s0DJSuBBm-nq23NtHl5FbCzeXWcKRayIgimT-An1WIOeJP4F7-BctYLIooKoQzJZR1tOWvprUs22_xAivVBz7J_LmJyVlKesB2ic8qYdt7YVoCsWrnEUgoNoJPwLHeva8KPvd0gLXrwaMyTCCjeoemXFj6nCbbMHJeVffh6jYBAzlbcAEvTiZcdzrVVr54kOtWskyaeDnAcMXW4Of1vWdUJ2as5nyfletfTp4E6A9P2dZ5g7nMoL90yIw"
+        ],
+        "value": "6A77T3RBTAuVpZOgFFFfOvGOQ1hqMbfSQ91VucRM1RIP6QqX9kEF1Pi1_vCl37qpVzK51kIyppgUF_i9s999XA"
+      }
+    }
+  ],
+  "compositions": [
+    {
+      "aggregate": "complete",
+      "assemblies": [
+        "5366293e-0740-4dcf-b1d0-0c1fc26e4981",
+        "ee10d0a2-baba-4656-a5ac-d49e172a0d3d"
+      ],
+      "dependencies": [
+        "5366293e-0740-4dcf-b1d0-0c1fc26e4981"
+      ],
+      "signature": {
+        "algorithm": "ES256",
+        "certificatePath": [
+          "MIIB-TCCAVigAwIBAgIGAWFcc4YkMAwGCCqGSM49BAMEBQAwLTELMAkGA1UEBhMCRVUxHjAcBgNVBAMTFVRydXN0IE5ldHdvcmsgU3ViIENBMzAeFw0xODAxMDEwMDAwMDBaFw0yMjEyMzEyMzU5NTlaMDIxCzAJBgNVBAYTAkZSMQ0wCwYDVQQFEwQ0NTAxMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHHp7A83DBJIInj8-g1we3A7sBXprIQBUfdFDVUBQoPExq8rze6ewG0-eVcSF72J77gKiD0IHnzpwHaU7t6nVeajXTBbMAkGA1UdEwQCMAAwDgYDVR0PAQH_BAQDAgP4MB0GA1UdDgQWBBQQyJ9rXSIskoUuA946von62LoxqzAfBgNVHSMEGDAWgBTUWrS54qC2NgG3UK6rVAr0gbQ0MTAMBggqhkjOPQQDBAUAA4GMADCBiAJCAaWoVQ0r6jFjhO5e0WJTgyMmA8BhpO1t7gXQ6xoKGso9jCOYf9OG9BFfZoVmdIyfYiwkhy1ld27tiOJ5X4m6WasRAkIBpEkUDf8irbSZ1V7zXALaR2mJTjKQV_5jRHsiBQWA-5DxEa-x_zJVRz8tpp-jjT2tSCU82bwUOBLu6te1YIDpWCA",
+          "MIIDsTCCAZmgAwIBAgIBAzANBgkqhkiG9w0BAQ0FADAuMQswCQYDVQQGEwJVUzEfMB0GA1UEAxMWVHJ1c3QgTmV0d29yayBSb290IENBMTAeFw0xNjA3MTAxMDAwMDBaFw0yNTA3MTAwOTU5NTlaMC0xCzAJBgNVBAYTAkVVMR4wHAYDVQQDExVUcnVzdCBOZXR3b3JrIFN1YiBDQTMwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAGJzPZsjniwyZeXrgrlQM3Y13r3znR8FSQpKbC2bplrOWySQJPGm-GFObe5Dk4t3Jrtk_Pbs8-3VW_4q5drL0YqYwBYNJPhqjbSM6SGHrc6wNdPZRw_WnJVa0ELXKICC73lkjskWPfE-cLpZ3sTq1ovEmoNjgaySVRUH1wFDdkqyReJaKNjMGEwDwYDVR0TAQH_BAUwAwEB_zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNRatLnioLY2AbdQrqtUCvSBtDQxMB8GA1UdIwQYMBaAFEkmC1HDAh0fXehpiUhUGE868Hk2MA0GCSqGSIb3DQEBDQUAA4ICAQAs2KADYyGQCVy8tJZWakNtGdww4OumZpBuR66p_2xK7veRubQEhG-nJn7oVkJ4w5pEec3sYQEqtPbHyZcEKEYbOJ2cVf1nMH-DvFZ6ypQocGRp3WSWsTzL3SgqiWrQdPX1Y5dO6Hvx7p9ST9H2WgkxB-Q75Jov1gVF3bScAbxb7Mw7tf5z3Cvqmfo0Gatkgzz6-jDPrtUK7AAAOw3C0kHMbE3EnNarsfhBkUerE8QVmHIvz373mWt0SnguaHq0A9ZuSia_pF7bgfVRZi2ZzIzpu2O276sB2Yji9tcSn5l21jq63rXtvY_DLAi4kaLyf9sHT_tkH-gkTdkdkfQq8sA5ysRW21wPQbmjTIVwsfY4JjajVIUitjPbkUJqURpf2VD0JXdYQHS6KVPWqHWTlKPlsKbhw4ghuLqCMYda88L9rxWnSC5L8s0DJSuBBm-nq23NtHl5FbCzeXWcKRayIgimT-An1WIOeJP4F7-BctYLIooKoQzJZR1tOWvprUs22_xAivVBz7J_LmJyVlKesB2ic8qYdt7YVoCsWrnEUgoNoJPwLHeva8KPvd0gLXrwaMyTCCjeoemXFj6nCbbMHJeVffh6jYBAzlbcAEvTiZcdzrVVr54kOtWskyaeDnAcMXW4Of1vWdUJ2as5nyfletfTp4E6A9P2dZ5g7nMoL90yIw"
+        ],
+        "value": "lm6wx-elyBTbNMKNF8riooZhvrm6f5j8JpvgP9JtVv50dd7sXQLH7PqJcn9fmKV8eoF8cszPllEsQQhEQOM4hA"
+      }
+    }
+  ],
+  "signature": {
+    "algorithm": "ES256",
+    "certificatePath": [
+      "MIIB-TCCAVigAwIBAgIGAWFcc4YkMAwGCCqGSM49BAMEBQAwLTELMAkGA1UEBhMCRVUxHjAcBgNVBAMTFVRydXN0IE5ldHdvcmsgU3ViIENBMzAeFw0xODAxMDEwMDAwMDBaFw0yMjEyMzEyMzU5NTlaMDIxCzAJBgNVBAYTAkZSMQ0wCwYDVQQFEwQ0NTAxMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHHp7A83DBJIInj8-g1we3A7sBXprIQBUfdFDVUBQoPExq8rze6ewG0-eVcSF72J77gKiD0IHnzpwHaU7t6nVeajXTBbMAkGA1UdEwQCMAAwDgYDVR0PAQH_BAQDAgP4MB0GA1UdDgQWBBQQyJ9rXSIskoUuA946von62LoxqzAfBgNVHSMEGDAWgBTUWrS54qC2NgG3UK6rVAr0gbQ0MTAMBggqhkjOPQQDBAUAA4GMADCBiAJCAaWoVQ0r6jFjhO5e0WJTgyMmA8BhpO1t7gXQ6xoKGso9jCOYf9OG9BFfZoVmdIyfYiwkhy1ld27tiOJ5X4m6WasRAkIBpEkUDf8irbSZ1V7zXALaR2mJTjKQV_5jRHsiBQWA-5DxEa-x_zJVRz8tpp-jjT2tSCU82bwUOBLu6te1YIDpWCA",
+      "MIIDsTCCAZmgAwIBAgIBAzANBgkqhkiG9w0BAQ0FADAuMQswCQYDVQQGEwJVUzEfMB0GA1UEAxMWVHJ1c3QgTmV0d29yayBSb290IENBMTAeFw0xNjA3MTAxMDAwMDBaFw0yNTA3MTAwOTU5NTlaMC0xCzAJBgNVBAYTAkVVMR4wHAYDVQQDExVUcnVzdCBOZXR3b3JrIFN1YiBDQTMwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAGJzPZsjniwyZeXrgrlQM3Y13r3znR8FSQpKbC2bplrOWySQJPGm-GFObe5Dk4t3Jrtk_Pbs8-3VW_4q5drL0YqYwBYNJPhqjbSM6SGHrc6wNdPZRw_WnJVa0ELXKICC73lkjskWPfE-cLpZ3sTq1ovEmoNjgaySVRUH1wFDdkqyReJaKNjMGEwDwYDVR0TAQH_BAUwAwEB_zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNRatLnioLY2AbdQrqtUCvSBtDQxMB8GA1UdIwQYMBaAFEkmC1HDAh0fXehpiUhUGE868Hk2MA0GCSqGSIb3DQEBDQUAA4ICAQAs2KADYyGQCVy8tJZWakNtGdww4OumZpBuR66p_2xK7veRubQEhG-nJn7oVkJ4w5pEec3sYQEqtPbHyZcEKEYbOJ2cVf1nMH-DvFZ6ypQocGRp3WSWsTzL3SgqiWrQdPX1Y5dO6Hvx7p9ST9H2WgkxB-Q75Jov1gVF3bScAbxb7Mw7tf5z3Cvqmfo0Gatkgzz6-jDPrtUK7AAAOw3C0kHMbE3EnNarsfhBkUerE8QVmHIvz373mWt0SnguaHq0A9ZuSia_pF7bgfVRZi2ZzIzpu2O276sB2Yji9tcSn5l21jq63rXtvY_DLAi4kaLyf9sHT_tkH-gkTdkdkfQq8sA5ysRW21wPQbmjTIVwsfY4JjajVIUitjPbkUJqURpf2VD0JXdYQHS6KVPWqHWTlKPlsKbhw4ghuLqCMYda88L9rxWnSC5L8s0DJSuBBm-nq23NtHl5FbCzeXWcKRayIgimT-An1WIOeJP4F7-BctYLIooKoQzJZR1tOWvprUs22_xAivVBz7J_LmJyVlKesB2ic8qYdt7YVoCsWrnEUgoNoJPwLHeva8KPvd0gLXrwaMyTCCjeoemXFj6nCbbMHJeVffh6jYBAzlbcAEvTiZcdzrVVr54kOtWskyaeDnAcMXW4Of1vWdUJ2as5nyfletfTp4E6A9P2dZ5g7nMoL90yIw"
+    ],
+    "value": "m4pMbQQVV61TlP4Og7a75SeY8lh00LkkUDXZ4PIhXsR512MPRgZmusFYorJlYq9wM3P9n9gM3T8BTg9XdFdQkQ"
+  }
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-vulnerability-1.4.json b/tests/_data/schemaTestData/1.4/valid-vulnerability-1.4.json
new file mode 100644
index 000000000..184a6641a
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-vulnerability-1.4.json
@@ -0,0 +1,140 @@
+{
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.4",
+      "type": "library",
+      "group": "com.fasterxml.jackson.core",
+      "name": "jackson-databind",
+      "version": "2.9.4",
+      "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.4"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "bom-ref": "6eee14da-8f42-4cc4-bb65-203235f02415",
+      "id": "SNYK-JAVA-COMFASTERXMLJACKSONCORE-32111",
+      "source": {
+        "name": "Snyk",
+        "url": "https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-32111"
+      },
+      "references": [
+        {
+          "id": "CVE-2018-7489",
+          "source": {
+            "name": "NVD",
+            "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9997"
+          }
+        }
+      ],
+      "ratings": [
+        {
+          "source": {
+            "name": "NVD",
+            "url": "https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H&version=3.0"
+          },
+          "score": 9.8,
+          "severity": "critical",
+          "method": "CVSSv3",
+          "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
+          "justification": "An optional reason for rating the vulnerability as it was"
+        }
+      ],
+      "cwes": [
+        184,
+        502
+      ],
+      "description": "FasterXML jackson-databind before 2.7.9.3, 2.8.x before 2.8.11.1 and 2.9.x before 2.9.5 allows unauthenticated remote code execution because of an incomplete fix for the CVE-2017-7525 deserialization flaw. This is exploitable by sending maliciously crafted JSON input to the readValue method of the ObjectMapper, bypassing a blacklist that is ineffective if the c3p0 libraries are available in the classpath.",
+      "detail": "",
+      "recommendation": "Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.6.7.5, 2.8.11.1, 2.9.5 or higher.",
+      "advisories": [
+        {
+          "title": "GitHub Commit",
+          "url": "https://github.com/FasterXML/jackson-databind/commit/6799f8f10cc78e9af6d443ed6982d00a13f2e7d2"
+        },
+        {
+          "title": "GitHub Issue",
+          "url": "https://github.com/FasterXML/jackson-databind/issues/1931"
+        }
+      ],
+      "created": "2021-01-01T00:00:00.000Z",
+      "published": "2021-01-01T00:00:00.000Z",
+      "updated": "2021-01-01T00:00:00.000Z",
+      "credits": {
+        "organizations": [
+          {
+            "name": "Acme, Inc.",
+            "url": [
+              "https://example.com"
+            ]
+          }
+        ],
+        "individuals": [
+          {
+            "name": "Jane Doe",
+            "email": "jane.doe@example.com"
+          }
+        ]
+      },
+      "tools": [
+        {
+          "vendor": "Snyk",
+          "name": "Snyk CLI (Linux)",
+          "version": "1.729.0",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "2eaf8c62831a1658c95d41fdc683cd177c147733c64a93e59cb2362829e45b7d"
+            }
+          ]
+        }
+      ],
+      "analysis": {
+        "state": "not_affected",
+        "justification": "code_not_reachable",
+        "response": ["will_not_fix", "update"],
+        "detail": "An optional explanation of why the application is not affected by the vulnerable component."
+      },
+      "affects": [
+        {
+          "ref": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.4",
+          "versions": [
+            {
+              "range": "vers:semver/<2.6.7.5",
+              "status": "affected"
+            },
+            {
+              "range": "vers:semver/2.7.0|<2.8.11.1",
+              "status": "affected"
+            },
+            {
+              "range": "vers:semver/2.9.0|<2.9.5",
+              "status": "affected"
+            }
+          ]
+        }
+      ],
+      "properties": [
+        {
+          "name": "Foo",
+          "value": "Bar"
+        },
+        {
+          "name": "Foo",
+          "value": "You"
+        },
+        {
+          "name": "Foo",
+          "value": "Two"
+        },
+        {
+          "name": "Bar",
+          "value": "Foo"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/_data/schemaTestData/1.4/valid-vulnerability-1.4.xml b/tests/_data/schemaTestData/1.4/valid-vulnerability-1.4.xml
new file mode 100644
index 000000000..8e21f5522
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-vulnerability-1.4.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="library" bom-ref="pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.4">
+            <group>com.fasterxml.jackson.core</group>
+            <name>jackson-databind</name>
+            <version>2.9.4</version>
+            <purl>pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.4</purl>
+        </component>
+    </components>
+    <vulnerabilities>
+        <vulnerability bom-ref="6eee14da-8f42-4cc4-bb65-203235f02415">
+            <id>SNYK-JAVA-COMFASTERXMLJACKSONCORE-32111</id>
+            <source>
+                <name>Snyk</name>
+                <url>https://snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-32111</url>
+            </source>
+            <references>
+                <reference>
+                    <id>CVE-2018-7489</id>
+                    <source>
+                        <name>NVD</name>
+                        <url>https://nvd.nist.gov/vuln/detail/CVE-2019-9997</url>
+                    </source>
+                </reference>
+                <reference>
+                    <id>CVE-2018-7489</id>
+                    <source>
+                        <name>NVD</name>
+                        <url>https://nvd.nist.gov/vuln/detail/CVE-2019-9997</url>
+                    </source>
+                </reference>
+            </references>
+            <ratings>
+                <rating>
+                    <source>
+                        <name>NVD</name>
+                        <url>https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H&amp;version=3.0</url>
+                    </source>
+                    <score>9.8</score>
+                    <severity>critical</severity>
+                    <method>CVSSv3</method>
+                    <vector>AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H</vector>
+                    <justification>An optional reason for rating the vulnerability as it was</justification>
+                </rating>
+            </ratings>
+            <cwes>
+                <cwe>184</cwe>
+                <cwe>502</cwe>
+            </cwes>
+            <description>FasterXML jackson-databind before 2.7.9.3, 2.8.x before 2.8.11.1 and 2.9.x before 2.9.5 allows unauthenticated remote code execution because of an incomplete fix for the CVE-2017-7525 deserialization flaw. This is exploitable by sending maliciously crafted JSON input to the readValue method of the ObjectMapper, bypassing a blacklist that is ineffective if the c3p0 libraries are available in the classpath.</description>
+            <detail></detail>
+            <recommendation>Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.6.7.5, 2.8.11.1, 2.9.5 or higher.</recommendation>
+            <advisories>
+                <advisory>
+                    <title>GitHub Commit</title>
+                    <url>https://github.com/FasterXML/jackson-databind/commit/6799f8f10cc78e9af6d443ed6982d00a13f2e7d2</url>
+                </advisory>
+                <advisory>
+                    <title>GitHub Issue</title>
+                    <url>https://github.com/FasterXML/jackson-databind/issues/1931</url>
+                </advisory>
+            </advisories>
+            <created>2021-01-01T00:00:00.000Z</created>
+            <published>2021-01-01T00:00:00.000Z</published>
+            <updated>2021-01-01T00:00:00.000Z</updated>
+            <credits>
+                <organizations>
+                    <organization>
+                        <name>Acme, Inc.</name>
+                        <url>https://example.com</url>
+                    </organization>
+                </organizations>
+                <individuals>
+                    <individual>
+                        <name>Jane Doe</name>
+                        <email>jane.doe@example.com</email>
+                    </individual>
+                </individuals>
+            </credits>
+            <tools>
+                <tool>
+                    <vendor>Snyk</vendor>
+                    <name>Snyk CLI (Linux)</name>
+                    <version>1.729.0</version>
+                    <hashes>
+                        <hash alg="SHA-256">2eaf8c62831a1658c95d41fdc683cd177c147733c64a93e59cb2362829e45b7d</hash>
+                    </hashes>
+                </tool>
+            </tools>
+            <analysis>
+                <state>not_affected</state>
+                <justification>code_not_reachable</justification>
+                <responses>
+                    <response>will_not_fix</response>
+                    <response>update</response>
+                </responses>
+                <detail>An optional explanation of why the application is not affected by the vulnerable component.</detail>
+            </analysis>
+            <affects>
+                <target>
+                    <ref>pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.4</ref>
+                    <versions>
+                        <version>
+                            <range>vers:semver/&lt;2.6.7.5</range>
+                            <status>affected</status>
+                        </version>
+                        <version>
+                            <range>vers:semver/2.7.0|&lt;2.8.11.1</range>
+                            <status>affected</status>
+                        </version>
+                        <version>
+                            <range>vers:semver/2.9.0|&lt;2.9.5</range>
+                            <status>affected</status>
+                        </version>
+                    </versions>
+                </target>
+            </affects>
+            <properties>
+                <property name="Foo">Bar</property>
+                <property name="Foo">You</property>
+                <property name="Foo">Two</property>
+                <property name="Bar">Foo</property>
+            </properties>
+        </vulnerability>
+    </vulnerabilities>
+</bom>
diff --git a/tests/_data/schemaTestData/1.4/valid-xml-signature-1.4.xml b/tests/_data/schemaTestData/1.4/valid-xml-signature-1.4.xml
new file mode 100644
index 000000000..b3ee4e616
--- /dev/null
+++ b/tests/_data/schemaTestData/1.4/valid-xml-signature-1.4.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0"?>
+<bom serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1" xmlns="http://cyclonedx.org/schema/bom/1.4">
+    <components>
+        <component type="application">
+            <publisher>Acme Inc</publisher>
+            <group>com.acme</group>
+            <name>tomcat-catalina</name>
+            <version>9.0.14</version>
+            <hashes>
+                <hash alg="MD5">3942447fac867ae5cdb3229b658f4d48</hash>
+                <hash alg="SHA-1">e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a</hash>
+                <hash alg="SHA-256">f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b</hash>
+                <hash alg="SHA-512">e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar</purl>
+            <pedigree>
+                <ancestors>
+                    <component type="application">
+                        <publisher>Apache</publisher>
+                        <group>org.apache.tomcat</group>
+                        <name>tomcat-catalina</name>
+                        <version>9.0.14</version>
+                        <licenses>
+                            <license>
+                                <id>Apache-2.0</id>
+                            </license>
+                        </licenses>
+                        <purl>pkg:maven/org.apache.tomcat/tomcat-catalina@9.0.14?packaging=jar</purl>
+
+                    </component>
+                </ancestors>
+                <commits>
+                    <commit>
+                        <uid>7638417db6d59f3c431d3e1f261cc637155684cd</uid>
+                        <url>https://location/to/7638417db6d59f3c431d3e1f261cc637155684cd</url>
+                        <author>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>jdoe@example.com</email>
+                        </author>
+                        <committer>
+                            <timestamp>2018-11-07T22:01:45Z</timestamp>
+                            <name>John Doe</name>
+                            <email>jdoe@example.com</email>
+                        </committer>
+                        <message>Initial commit</message>
+                    </commit>
+                </commits>
+            </pedigree>
+        </component>
+        <component type="library">
+            <group>org.example</group>
+            <name>mylibrary</name>
+            <version>1.0.0</version>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">2342c2eaf1feb9a80195dbaddf2ebaa3</hash>
+                <hash alg="SHA-1">68b78babe00a053f9e35ec6a2d9080f5b90122b0</hash>
+                <hash alg="SHA-256">708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313</hash>
+                <hash alg="SHA-512">387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                    <text content-type="text/xml" encoding="base64">blah</text>
+                    <url>fdaf</url>
+                </license>
+            </licenses>
+            <copyright>Copyright Example Inc. All rights reserved.</copyright>
+            <cpe>cpe:/a:example:myapplication:1.0.0</cpe>
+            <purl>pkg:maven/com.example/myapplication@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+        </component>
+        <component type="framework">
+            <group>com.example</group>
+            <name>myframework</name>
+            <version>1.0.0</version>
+            <description>Example Inc, enterprise framework</description>
+            <scope>required</scope>
+            <hashes>
+                <hash alg="MD5">cfcb0b64aacd2f81c1cd546543de965a</hash>
+                <hash alg="SHA-1">7fbeef2346c45d565c3341f037bce4e088af8a52</hash>
+                <hash alg="SHA-256">0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1</hash>
+                <hash alg="SHA-512">854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79</hash>
+            </hashes>
+            <licenses>
+                <license>
+                    <id>Apache-2.0</id>
+                </license>
+            </licenses>
+            <purl>pkg:maven/com.example/myframework@1.0.0?packaging=war</purl>
+            <modified>false</modified>
+            <externalReferences>
+                <reference type="website">
+                    <url>http://example.com/myframework</url>
+                </reference>
+                <reference type="advisories">
+                    <url>http://example.com/security</url>
+                </reference>
+            </externalReferences>
+        </component>
+    </components>
+    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+        <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+            <ds:Reference URI="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+                </ds:Transforms>
+                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
+                <ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">PrB8/rofGs34XwIX5OIdYSjV2aKSe5VaztJKBvsgjIk=</ds:DigestValue>
+            </ds:Reference>
+        </ds:SignedInfo>
+        <ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            ePGNg30Zl9CW7RZdcRn8gFCp1AlWncjudA9pQDXyqZOvyj9RC2YtkI688WdfDOdVRZs6mflJFXr7
+            IKA9wY6jVrEqZmlef55Qp/8iGwOjOjWbwYsm2AhrdkUi9gaFSWEd8uITYHOpWbiPFSsnimiK9+ft
+            56dkg/oJMLdXzlaukzq9iGkRcafRkW433OQcZIXwD2K8lg4cdD0pNNNqBa+PgIvzbxA5H84TyQDB
+            HBcQiw/j1edRBJgPOwlqzZDUawOJaFhAPUQ+GGKMetIJH2FqqrHXGuV1NIwnbWTCg40RdOcBdCrl
+            PDtDVjFh34uZ4dYBpJBIlM4daD2N4B6WPB5iHRyuZTczF2q03ObabuTgkpK6EeadFVqFNsEOOPPt
+            MDDyda+Lwff5KjvUHvRRtUDIOm2rNIQKzaseulwYcA9UWQHAFcupJmWcLLM4zzY7F/uOdZuSurzh
+            U6h5kdb76Juepof6ee4Q5YpwNOGNL5JfB4C3sc/Dbbv8dZ8OuXFYSZN7reUGZzCNksByqERPEbAe
+            n1ldJu1HnRXRQpwaon8Asy9CuNmPfFCfDwOs2B4p4tb+tLNIKFHdRlpd19Zr9vCMCbltXeqq0Cpq
+            OejSyLYGqSWzzzUh449dJrg6KTevrTNEln5GAlLBFSdjM5JA7KV2u/GyDVFwSEW7UKooGN4CtgU=
+        </ds:SignatureValue>
+        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            <ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:X509SubjectName xmlns:ds="http://www.w3.org/2000/09/xmldsig#">CN=bomsigner,OU=development,O=cyclonedx</ds:X509SubjectName>
+                <ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    MIIE+DCCAuCgAwIBAgIEXGzayTANBgkqhkiG9w0BAQsFADA+MRIwEAYDVQQKDAljeWNsb25lZHgx
+                    FDASBgNVBAsMC2RldmVsb3BtZW50MRIwEAYDVQQDDAlib21zaWduZXIwHhcNMTkwMjIwMDQ0MjQ5
+                    WhcNNDkwMjIwMDQ0MjQ5WjA+MRIwEAYDVQQKDAljeWNsb25lZHgxFDASBgNVBAsMC2RldmVsb3Bt
+                    ZW50MRIwEAYDVQQDDAlib21zaWduZXIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo
+                    5JZsM4ZLfWW/dpRlU6CpnItWspddF+bEVDETKVwVj9tGpqR5jURgKS/BOQP2TGUsR3/ZJJBhYRll
+                    ONhrUQrVKV/I6wp3Z40qPEa1RJLE+QlG9iL8qBV52CnXkLmnUSax3dspSzmSct5vDiTnvpHG9jr0
+                    AKFeTjy7U9rv8GJybz0ijwlpBoO9JRdYPX2PrrzoSeJLoxKq+GwuyCZ5LhXRN0p1a+NAirTAmY+c
+                    G1ZTLkMmfeCUy1t6H/bG4RnYOSSPOvk7Rb68lQpUqb+pbbNuB2o/b9cDwtLLCtGVlu+5Wj8mrytY
+                    3FGFQM20j3yVeRInmGqTTDBelQa/CO4JKqBlmaeYEIvNYbFs9+AlqadivwDO51RpdPo9fPSpsBpy
+                    ZMv6S2bXNuUML+Rk99WyKJTPM0PTZhRLZ64ZXEhlz3kQWVoSlrcwwim6sj6LRUb5IRqA3lxRFUI6
+                    NXKyiQLamQp+t3/9OGW9L1rLCcw7yFo0s8LhMTPMiv4ol9/hQViT+8ICzDsr0OM9ZiF4/UagFRlt
+                    IClV70cjh1DpsZjzQIRVGaj8uQ/JdtfRz4E43Ki7U0a2Vpho/t6poLVndv46tkX5nYGtMW4WfMoD
+                    ZflQ9pajvvKtr2jB1wob6nsU+VTmAcWZy4BCPH+XyfDw/0SFBdUceJJJtPWIeYFDUY7onptf+wID
+                    AQABMA0GCSqGSIb3DQEBCwUAA4ICAQCOVariNgK+9OF/5T9ZaSvZbkk45RTmzgQNXtFc5xfRvqwP
+                    s+pu/DFXm1R+ltjyS5j3w6NBZUFUI5MqLQr6JEEDrbu8BvfBO57wJNAEATj1JIHEfDfh7BxnBF8f
+                    oYFOwbrh4jOt0wz0FW2obsSVmF4GSvS7tTlWqTcsxjdZVmwP40RWu18B9jzv7M61adrWD3ksDA5O
+                    amSOsZi3Nt0aacDkyGRdCIEFi0fplxQInXMtD1z3RhXu2JSTAIr54Cei49Bh71kAXSWHMCog/f8a
+                    lSrZyqZBty/ACfU9DqlPIM+giHePKm4z2bcdpUdKZk6wcKDn4CvuBOqsMBMg7L05UEyyqTPD/4dk
+                    2GwJ8Nv0E5gsYHCIXF2cZ3OUVsw0mB/ozleEJVDE02uZZN/1wW1Xq028LsMdgN0Wk1WvWyF5MEdh
+                    nPWuhqp6tNaDI/kK6XQF+LjYJUzua3AQFOHfYNLKhO6d+bJ4rr0833v4v3cLW34kbXkKb6U3Yv8X
+                    SK3jBGCACiPgnc0N6awkh1kDlrZQ7GMsl14c+2+vpl9Lf0sL0mRUIyICfSC8MjlsP/BZH3emyfsk
+                    iWivPALomycKqP+PSkt1WaWApGENZWk1wNN99FYSYlt6LViW2p6T97fRx4jPRlHu+wecfD2k9RP4
+                    bt5W2HWfOP0zNAS7SnAVLEl2QZxXKw==
+                </ds:X509Certificate>
+            </ds:X509Data>
+            <ds:KeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:RSAKeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                    <ds:Modulus xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                        qOSWbDOGS31lv3aUZVOgqZyLVrKXXRfmxFQxEylcFY/bRqakeY1EYCkvwTkD9kxlLEd/2SSQYWEZ
+                        ZTjYa1EK1SlfyOsKd2eNKjxGtUSSxPkJRvYi/KgVedgp15C5p1Emsd3bKUs5knLebw4k576RxvY6
+                        9AChXk48u1Pa7/Bicm89Io8JaQaDvSUXWD19j6686EniS6MSqvhsLsgmeS4V0TdKdWvjQIq0wJmP
+                        nBtWUy5DJn3glMtbeh/2xuEZ2Dkkjzr5O0W+vJUKVKm/qW2zbgdqP2/XA8LSywrRlZbvuVo/Jq8r
+                        WNxRhUDNtI98lXkSJ5hqk0wwXpUGvwjuCSqgZZmnmBCLzWGxbPfgJamnYr8AzudUaXT6PXz0qbAa
+                        cmTL+ktm1zblDC/kZPfVsiiUzzND02YUS2euGVxIZc95EFlaEpa3MMIpurI+i0VG+SEagN5cURVC
+                        OjVysokC2pkKfrd//ThlvS9aywnMO8haNLPC4TEzzIr+KJff4UFYk/vCAsw7K9DjPWYheP1GoBUZ
+                        bSApVe9HI4dQ6bGY80CEVRmo/LkPyXbX0c+BONyou1NGtlaYaP7eqaC1Z3b+OrZF+Z2BrTFuFnzK
+                        A2X5UPaWo77yra9owdcKG+p7FPlU5gHFmcuAQjx/l8nw8P9EhQXVHHiSSbT1iHmBQ1GO6J6bX/s=
+                    </ds:Modulus>
+                    <ds:Exponent xmlns:ds="http://www.w3.org/2000/09/xmldsig#">AQAB</ds:Exponent>
+                </ds:RSAKeyValue>
+            </ds:KeyValue>
+        </ds:KeyInfo>
+    </ds:Signature></bom>
diff --git a/tests/_data/schemaTestData/README.md b/tests/_data/schemaTestData/README.md
new file mode 100644
index 000000000..4f45a14d6
--- /dev/null
+++ b/tests/_data/schemaTestData/README.md
@@ -0,0 +1,2 @@
+files in here are taken from https://github.com/CycloneDX/specification/tree/master/tools/src/test/resources
+they are fetched via [`fetch.sh`](fetch.sh)
diff --git a/tests/_data/schemaTestData/fetch.sh b/tests/_data/schemaTestData/fetch.sh
new file mode 100755
index 000000000..8a3f34a20
--- /dev/null
+++ b/tests/_data/schemaTestData/fetch.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -eux
+
+SOURCE_PACKAGE='https://github.com/CycloneDX/specification/archive/refs/heads/master.zip'
+SOURCE_DIR='specification-master/tools/src/test/resources'
+
+THIS_DIR="$(dirname "$0")"
+TEMP_DIR="$(mktemp -d)"
+LOCAL_PACKAGE="$TEMP_DIR/source_package.zip"
+
+wget -O "$LOCAL_PACKAGE" "$SOURCE_PACKAGE"
+for SCHEMA_VERSION in '1.4' '1.3' '1.2' '1.1' '1.0'
+do
+  unzip -d "$TEMP_DIR" "$LOCAL_PACKAGE" "$SOURCE_DIR/$SCHEMA_VERSION/*"
+  rm -rf "${THIS_DIR:?}/$SCHEMA_VERSION"
+  mkdir -p "$THIS_DIR/$SCHEMA_VERSION"
+  cp -rf "$TEMP_DIR/$SOURCE_DIR/$SCHEMA_VERSION/"*.xml "$THIS_DIR/$SCHEMA_VERSION/"
+  cp -rf "$TEMP_DIR/$SOURCE_DIR/$SCHEMA_VERSION/"*.json "$THIS_DIR/$SCHEMA_VERSION/" || true
+done
+
+rm -rf "${TEMP_DIR:?}"
diff --git a/tests/base.py b/tests/base.py
index 1727fa35e..fff18cdfc 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -17,10 +17,7 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
-import io
 import json
-import os
-import sys
 import xml.etree.ElementTree
 from datetime import datetime, timezone
 from typing import Any
@@ -28,16 +25,13 @@
 from uuid import uuid4
 
 from lxml import etree
-from lxml.etree import DocumentInvalid
 from xmldiff import main
 from xmldiff.actions import MoveNode
 
+from cyclonedx.exception import MissingOptionalDependencyException
 from cyclonedx.output import SchemaVersion
-
-if sys.version_info >= (3, 7):
-    from jsonschema import ValidationError, validate as json_validate
-
-from . import CDX_SCHEMA_DIRECTORY
+from cyclonedx.validation.json import JsonValidator
+from cyclonedx.validation.xml import XmlValidator
 
 single_uuid: str = 'urn:uuid:{}'.format(uuid4())
 
@@ -45,19 +39,12 @@
 class BaseJsonTestCase(TestCase):
 
     def assertValidAgainstSchema(self, bom_json: str, schema_version: SchemaVersion) -> None:
-        schema_fn = os.path.join(
-            CDX_SCHEMA_DIRECTORY,
-            f'bom-{schema_version.name.replace("_", ".").replace("V", "")}.schema.json'
-        )
-        with open(schema_fn) as schema_fd:
-            schema_doc = json.load(schema_fd)
-
         try:
-            json_validate(instance=json.loads(bom_json), schema=schema_doc)
-        except ValidationError as e:
-            self.assertTrue(False, f'Failed to validate SBOM against JSON schema: {str(e)}')
-
-        self.assertTrue(True)
+            validation_error = JsonValidator(schema_version).validate_str(bom_json)
+        except MissingOptionalDependencyException:
+            return  # some deps are missing - skip the validation
+        self.assertIsNone(validation_error,
+                          f'Failed to validate SBOM against JSON schema: {str(validation_error)}')
 
     @staticmethod
     def _sort_json_dict(item: object) -> Any:
@@ -98,21 +85,12 @@ def assertEqualJsonBom(self, a: str, b: str) -> None:
 class BaseXmlTestCase(TestCase):
 
     def assertValidAgainstSchema(self, bom_xml: str, schema_version: SchemaVersion) -> None:
-        xsd_fn = os.path.join(CDX_SCHEMA_DIRECTORY, f'bom-{schema_version.name.replace("_", ".").replace("V", "")}.xsd')
-        with open(xsd_fn) as xsd_fd:
-            xsd_doc = etree.parse(xsd_fd)
-
-        xml_schema = etree.XMLSchema(xsd_doc)
-        schema_validates = False
         try:
-            schema_validates = xml_schema.validate(etree.parse(io.BytesIO(bytes(bom_xml, 'ascii'))))
-        except DocumentInvalid as e:
-            print(f'Failed to validate SBOM against schema: {str(e)}')
-
-        if not schema_validates:
-            print(xml_schema.error_log.last_error)
-        self.assertTrue(schema_validates, f'Failed to validate Generated SBOM against XSD Schema:'
-                                          f'{bom_xml}')
+            validation_error = XmlValidator(schema_version).validate_str(bom_xml)
+        except MissingOptionalDependencyException:
+            return  # some deps are missing - skip the validation
+        self.assertIsNone(validation_error,
+                          f'Failed to validate Generated SBOM against XSD Schema: {str(validation_error)}')
 
     def assertEqualXml(self, a: str, b: str) -> None:
         diff_results = main.diff_texts(a, b, diff_options={'F': 0.5})
diff --git a/tests/test_component.py b/tests/test_component.py
index d1cf3dfc0..d2fe16fa4 100644
--- a/tests/test_component.py
+++ b/tests/test_component.py
@@ -17,7 +17,7 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
-from os.path import dirname, join
+from os.path import join
 from unittest import TestCase
 
 # See https://github.com/package-url/packageurl-python/issues/65
@@ -26,9 +26,10 @@
 from cyclonedx.model import sha1sum
 from cyclonedx.model.component import Component
 
+from . import TESTDATA_DIRECTORY
 from .data import get_component_setuptools_simple
 
-FIXTURES_DIRECTORY = join('fixtures', 'xml', '1.4')
+RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml', '1.4')
 
 
 class TestComponent(TestCase):
@@ -67,7 +68,7 @@ def test_purl_incorrect_name(self) -> None:
         self.assertEqual(purl.qualifiers, {'extension': 'tar.gz'})
 
     def test_from_file_with_path_for_bom(self) -> None:
-        test_file = join(dirname(__file__), FIXTURES_DIRECTORY, 'bom_setuptools.xml')
+        test_file = join(RELEVANT_TESTDATA_DIRECTORY, 'bom_setuptools.xml')
         c = Component.for_file(absolute_file_path=test_file, path_for_bom='fixtures/bom_setuptools.xml')
         sha1_hash: str = sha1sum(filename=test_file)
         expected_version = '0.0.0-{}'.format(sha1_hash[0:12])
diff --git a/tests/test_deserialize_json.py b/tests/test_deserialize_json.py
index 8962ee518..4535c8c05 100644
--- a/tests/test_deserialize_json.py
+++ b/tests/test_deserialize_json.py
@@ -19,7 +19,7 @@
 
 import json
 from datetime import datetime
-from os.path import dirname, join
+from os.path import join
 from typing import cast
 from unittest.mock import Mock, patch
 from uuid import UUID
@@ -54,6 +54,10 @@
     get_bom_with_services_simple,
 )
 
+from . import TESTDATA_DIRECTORY
+
+RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'json')
+
 
 def fixed_date_time() -> datetime:
     return datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
@@ -417,8 +421,7 @@ def _validate_json_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: s
             outputter = get_instance(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
             bom = cast(Bom, Bom.from_json(data=json.loads(outputter.output_as_string())))
 
-        with open(
-                join(dirname(__file__), f'fixtures/json/{schema_version.to_version()}/{fixture}')) as input_json:
+        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as input_json:
             deserialized_bom = cast(Bom, Bom.from_json(data=json.loads(input_json.read())))
 
             self.assertEqual(bom.metadata, deserialized_bom.metadata)
diff --git a/tests/test_deserialize_xml.py b/tests/test_deserialize_xml.py
index 81b174f53..b097ab87f 100644
--- a/tests/test_deserialize_xml.py
+++ b/tests/test_deserialize_xml.py
@@ -18,7 +18,7 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 from datetime import datetime
-from os.path import dirname, join
+from os.path import join
 from typing import cast
 from unittest.mock import Mock, patch
 from uuid import UUID
@@ -53,6 +53,10 @@
     get_bom_with_services_simple,
 )
 
+from . import TESTDATA_DIRECTORY
+
+RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
+
 
 def fixed_date_time() -> datetime:
     return datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
@@ -687,7 +691,7 @@ def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: st
             outputter = get_instance(bom=bom, output_format=OutputFormat.XML, schema_version=schema_version)
             bom = cast(Bom, Bom.from_xml(data=ElementTree.fromstring(outputter.output_as_string())))
 
-        with open(join(dirname(__file__), f'fixtures/xml/{schema_version.to_version()}/{fixture}')) as input_xml:
+        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as input_xml:
             xml = input_xml.read()
             deserialized_bom = cast(Bom, Bom.from_xml(data=ElementTree.fromstring(xml)))
 
diff --git a/tests/test_output_json.py b/tests/test_output_json.py
index f853da180..ab4303db0 100644
--- a/tests/test_output_json.py
+++ b/tests/test_output_json.py
@@ -16,7 +16,7 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
-from os.path import dirname, join
+from os.path import join
 from unittest.mock import Mock, patch
 from uuid import UUID
 
@@ -51,6 +51,10 @@
     get_bom_with_services_simple,
 )
 
+from . import TESTDATA_DIRECTORY
+
+RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'json')
+
 
 @patch('cyclonedx.model.ThisTool._version', 'TESTING')
 class TestOutputJson(BaseJsonTestCase):
@@ -399,8 +403,7 @@ def test_bom_v1_4_warn_dependencies(self) -> None:
     def _validate_json_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
         outputter = get_instance(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
         self.assertEqual(outputter.schema_version, schema_version)
-        with open(
-                join(dirname(__file__), f'fixtures/json/{schema_version.to_version()}/{fixture}')) as expected_json:
+        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as expected_json:
             output_as_string = outputter.output_as_string()
             self.assertValidAgainstSchema(bom_json=output_as_string, schema_version=schema_version)
             self.assertEqualJsonBom(expected_json.read(), output_as_string)
diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py
index 101ce9523..353cbf8d7 100644
--- a/tests/test_output_xml.py
+++ b/tests/test_output_xml.py
@@ -16,7 +16,7 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
-from os.path import dirname, join
+from os.path import join
 from unittest.mock import Mock, patch
 from uuid import UUID
 
@@ -50,6 +50,10 @@
     get_bom_with_services_simple,
 )
 
+from . import TESTDATA_DIRECTORY
+
+RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
+
 
 @patch('cyclonedx.model.ThisTool._version', 'TESTING')
 class TestOutputXml(BaseXmlTestCase):
@@ -529,8 +533,7 @@ def test_bom_v1_4_warn_dependencies(self) -> None:
     def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
         outputter = get_instance(bom=bom, schema_version=schema_version)
         self.assertEqual(outputter.schema_version, schema_version)
-        with open(
-                join(dirname(__file__), f'fixtures/xml/{schema_version.to_version()}/{fixture}')) as expected_xml:
+        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as expected_xml:
             output_as_string = outputter.output_as_string()
             self.assertValidAgainstSchema(bom_xml=output_as_string, schema_version=schema_version)
             self.assertEqualXmlBom(
diff --git a/tests/test_real_world_examples.py b/tests/test_real_world_examples.py
index 43aa11a91..185b51c8b 100644
--- a/tests/test_real_world_examples.py
+++ b/tests/test_real_world_examples.py
@@ -17,7 +17,7 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 import unittest
 from datetime import datetime
-from os.path import dirname, join
+from os.path import join
 from typing import cast
 from unittest.mock import patch
 from xml.etree import ElementTree
@@ -25,6 +25,10 @@
 from cyclonedx.model.bom import Bom
 from cyclonedx.schema import SchemaVersion
 
+from . import TESTDATA_DIRECTORY
+
+RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
+
 
 def fixed_date_time() -> datetime:
     return datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
@@ -40,6 +44,6 @@ def test_webgoat_6_1(self) -> None:
         )
 
     def _attempt_load_example(self, schema_version: SchemaVersion, fixture: str) -> None:
-        with open(join(dirname(__file__), f'fixtures/xml/{schema_version.to_version()}/{fixture}')) as input_xml:
+        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as input_xml:
             xml = input_xml.read()
             cast(Bom, Bom.from_xml(data=ElementTree.fromstring(xml)))
diff --git a/tests/test_schema__res.py b/tests/test_schema__res.py
new file mode 100644
index 000000000..0ac92db2a
--- /dev/null
+++ b/tests/test_schema__res.py
@@ -0,0 +1,44 @@
+# encoding: utf-8
+
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+from os.path import isfile
+from typing import Generator
+from unittest import TestCase
+
+from ddt import ddt, idata
+
+from cyclonedx.schema import _res
+
+
+def _dp_files() -> Generator:
+    for bom in (_res.BOM_XML, _res.BOM_JSON, _res.BOM_JSON):
+        for file in bom.values():
+            if file is not None:
+                yield file
+    yield _res.SPDX_JSON
+    yield _res.SPDX_XML
+    yield _res.JSF
+
+
+@ddt
+class SchemaRes(TestCase):
+
+    @idata(_dp_files())
+    def test_file_exists(self, file: str) -> None:
+        self.assertTrue(isfile(file), file)
diff --git a/tests/test_spdx.py b/tests/test_spdx.py
index d4399e31b..98c51dc69 100644
--- a/tests/test_spdx.py
+++ b/tests/test_spdx.py
@@ -19,16 +19,15 @@
 
 from itertools import chain
 from json import load as json_load
-from os.path import join as path_join
 from unittest import TestCase
 
 from ddt import data, ddt, idata, unpack
 
 from cyclonedx import spdx
+from cyclonedx.schema._res import SPDX_JSON
 
-from . import CDX_SCHEMA_DIRECTORY
-
-with open(path_join(CDX_SCHEMA_DIRECTORY, 'spdx.schema.json')) as spdx_schema:
+# rework access
+with open(SPDX_JSON) as spdx_schema:
     KNOWN_SPDX_IDS = json_load(spdx_schema)['enum']
 
 VALID_COMPOUND_EXPRESSIONS = {
diff --git a/tests/test_validation_json.py b/tests/test_validation_json.py
new file mode 100644
index 000000000..ab00304e5
--- /dev/null
+++ b/tests/test_validation_json.py
@@ -0,0 +1,110 @@
+# encoding: utf-8
+
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+from glob import iglob
+from os.path import join
+from typing import Generator
+from unittest import TestCase
+
+from ddt import data, ddt, idata, unpack
+
+from cyclonedx.exception import MissingOptionalDependencyException
+from cyclonedx.schema import SchemaVersion
+from cyclonedx.validation.json import JsonStrictValidator, JsonValidator
+
+from . import TESTDATA_DIRECTORY
+
+RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'schemaTestData')
+
+UNSUPPORTED_SCHEMA_VERSIONS = (SchemaVersion.V1_0, SchemaVersion.V1_1,)
+
+
+def _dp(prefix: str) -> Generator:
+    return (
+        (sv, tf) for sv in SchemaVersion if sv not in UNSUPPORTED_SCHEMA_VERSIONS
+        for tf in iglob(join(RELEVANT_TESTDATA_DIRECTORY, sv.to_version(), f'{prefix}-*.json'))
+    )
+
+
+@ddt
+class TestJsonValidator(TestCase):
+
+    @data(*UNSUPPORTED_SCHEMA_VERSIONS)
+    def test_throws_with_unsupported_schema_version(self, schema_version: SchemaVersion) -> None:
+        with self.assertRaisesRegex(ValueError, 'unsupported schema:'):
+            JsonValidator(schema_version)
+
+    @idata(_dp('valid'))
+    @unpack
+    def test_validate_no_none(self, schema_version: SchemaVersion, test_data_file: str) -> None:
+        validator = JsonValidator(schema_version)
+        with open(join(test_data_file), 'r') as tdfh:
+            test_data = tdfh.read()
+        try:
+            validation_error = validator.validate_str(test_data)
+        except MissingOptionalDependencyException:
+            self.skipTest('MissingOptionalDependencyException')
+        self.assertIsNone(validation_error)
+
+    @idata(_dp('invalid'))
+    @unpack
+    def test_validate_expected_error(self, schema_version: SchemaVersion, test_data_file: str) -> None:
+        validator = JsonValidator(schema_version)
+        with open(join(test_data_file), 'r') as tdfh:
+            test_data = tdfh.read()
+        try:
+            validation_error = validator.validate_str(test_data)
+        except MissingOptionalDependencyException:
+            self.skipTest('MissingOptionalDependencyException')
+        self.assertIsNotNone(validation_error)
+        self.assertIsNotNone(validation_error.data)
+
+
+@ddt
+class TestJsonStrictValidator(TestCase):
+
+    @data(*UNSUPPORTED_SCHEMA_VERSIONS)
+    def test_throws_with_unsupported_schema_version(self, schema_version: SchemaVersion) -> None:
+        with self.assertRaisesRegex(ValueError, 'unsupported schema:'):
+            JsonStrictValidator(schema_version)
+
+    @idata(_dp('valid'))
+    @unpack
+    def test_validate_no_none(self, schema_version: SchemaVersion, test_data_file: str) -> None:
+        validator = JsonStrictValidator(schema_version)
+        with open(join(test_data_file), 'r') as tdfh:
+            test_data = tdfh.read()
+        try:
+            validation_error = validator.validate_str(test_data)
+        except MissingOptionalDependencyException:
+            self.skipTest('MissingOptionalDependencyException')
+        self.assertIsNone(validation_error)
+
+    @idata(_dp('invalid'))
+    @unpack
+    def test_validate_expected_error(self, schema_version: SchemaVersion, test_data_file: str) -> None:
+        validator = JsonStrictValidator(schema_version)
+        with open(join(test_data_file), 'r') as tdfh:
+            test_data = tdfh.read()
+        try:
+            validation_error = validator.validate_str(test_data)
+        except MissingOptionalDependencyException:
+            self.skipTest('MissingOptionalDependencyException')
+        self.assertIsNotNone(validation_error)
+        self.assertIsNotNone(validation_error.data)
diff --git a/tests/test_validation_xml.py b/tests/test_validation_xml.py
new file mode 100644
index 000000000..8f6ef247c
--- /dev/null
+++ b/tests/test_validation_xml.py
@@ -0,0 +1,76 @@
+# encoding: utf-8
+
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+from glob import iglob
+from os.path import join
+from typing import Generator
+from unittest import TestCase
+
+from ddt import data, ddt, idata, unpack
+
+from cyclonedx.exception import MissingOptionalDependencyException
+from cyclonedx.schema import SchemaVersion
+from cyclonedx.validation.xml import XmlValidator
+
+from . import TESTDATA_DIRECTORY
+
+RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'schemaTestData')
+
+UNSUPPORTED_SCHEMA_VERSIONS = set()
+
+
+def _dp(prefix: str) -> Generator:
+    return (
+        (sv, tf) for sv in SchemaVersion if sv not in UNSUPPORTED_SCHEMA_VERSIONS
+        for tf in iglob(join(RELEVANT_TESTDATA_DIRECTORY, sv.to_version(), f'{prefix}-*.xml'))
+    )
+
+
+@ddt
+class TestXmlValidator(TestCase):
+
+    @data(*UNSUPPORTED_SCHEMA_VERSIONS)
+    def test_throws_with_unsupported_schema_version(self, schema_version: SchemaVersion) -> None:
+        with self.assertRaisesRegex(ValueError, 'unsupported schema'):
+            XmlValidator(schema_version)
+
+    @idata(_dp('valid'))
+    @unpack
+    def test_validate_no_none(self, schema_version: SchemaVersion, test_data_file: str) -> None:
+        validator = XmlValidator(schema_version)
+        with open(join(test_data_file), 'r') as tdfh:
+            test_data = tdfh.read()
+        try:
+            validation_error = validator.validate_str(test_data)
+        except MissingOptionalDependencyException:
+            self.skipTest('MissingOptionalDependencyException')
+        self.assertIsNone(validation_error)
+
+    @idata(_dp('invalid'))
+    @unpack
+    def test_validate_expected_error(self, schema_version: SchemaVersion, test_data_file: str) -> None:
+        validator = XmlValidator(schema_version)
+        with open(join(test_data_file), 'r') as tdfh:
+            test_data = tdfh.read()
+        try:
+            validation_error = validator.validate_str(test_data)
+        except MissingOptionalDependencyException:
+            self.skipTest('MissingOptionalDependencyException')
+        self.assertIsNotNone(validation_error)
+        self.assertIsNotNone(validation_error.data)
diff --git a/tools/schema-downloader.py b/tools/schema-downloader.py
new file mode 100644
index 000000000..b27982807
--- /dev/null
+++ b/tools/schema-downloader.py
@@ -0,0 +1,109 @@
+# encoding: utf-8
+import re
+from os.path import dirname, join
+from urllib.request import urlretrieve
+
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+
+SOURCE_ROOT = 'https://raw.githubusercontent.com/CycloneDX/specification/master/schema/'
+TARGET_ROOT = join(dirname(__file__), '..', 'cyclonedx', 'schema', '_res')
+
+bom_xsd = {
+    'versions': ['1.4', '1.3', '1.2', '1.1', '1.0'],
+    'sourcePattern': f'{SOURCE_ROOT}bom-%s.xsd',
+    'targetPattern': join(TARGET_ROOT, 'bom-%s.SNAPSHOT.xsd'),
+    'replace': [],
+    'replaceRE': [
+        (re.compile(r'schemaLocation="https?://cyclonedx.org/schema/spdx"'), 'schemaLocation="spdx.SNAPSHOT.xsd"')
+    ]
+}
+
+# "version" is not required but optional with a default value!
+#   this is wrong in schema<1.5
+_bomSchemaEnumMatch = re.compile(
+    r'("\$id": "(http://cyclonedx\.org/schema/bom.+?\.schema\.json)".*"enum": \[\s+")http://cyclonedx\.org/schema/bom.+?\.schema\.json"',
+    re.DOTALL)
+_bomSchemaEnumReplace = r'\1\2"'
+
+
+# "version" is not required but optional with a default value!
+# this is wrong in schema<1.5
+_bomRequired = """
+  "required": [
+    "bomFormat",
+    "specVersion",
+    "version"
+  ],"""
+_bomRequiredReplace = """
+  "required": [
+    "bomFormat",
+    "specVersion"
+  ],"""
+
+
+# there was a case where the default value did not match the own pattern ...
+# this is wrong in schema<1.5
+_defaultWithPatternMatch = re.compile(r'\s+"default": "",(?![^}]*?"pattern": "\^\(\.\*\)\$")', re.MULTILINE)
+_defaultWithPatternReplace = r''
+
+bom_json_lax = {
+    'versions': ['1.4', '1.3', '1.2'],
+    'sourcePattern': f'{SOURCE_ROOT}bom-%s.schema.json',
+    'targetPattern': join(TARGET_ROOT, 'bom-%s.SNAPSHOT.schema.json'),
+    'replace': [
+        ('spdx.schema.json', 'spdx.SNAPSHOT.schema.json'),
+        ('jsf-0.82.schema.json', 'jsf-0.82.SNAPSHOT.schema.json'),
+        (_bomRequired, _bomRequiredReplace),
+    ],
+    'replaceRE': [
+        (_bomSchemaEnumMatch, _bomSchemaEnumReplace),
+        # there was a case where the default value did not match the own pattern ...
+        # this is wrong in schema<1.5
+        # with current SchemaValidator this is no longer required, as defaults are not applied
+        # (re.compile(r'\s+"default": "",(?![^}]*?"pattern": "\^\(\.\*\)\$")', re.MULTILINE), '')
+    ]
+}
+
+bom_json_strict = {
+    'versions': ['1.3', '1.2'],
+    'sourcePattern': f'{SOURCE_ROOT}bom-%s-strict.schema.json',
+    'targetPattern': join(TARGET_ROOT, 'bom-%s-strict.SNAPSHOT.schema.json'),
+    'replace': bom_json_lax['replace'],
+    'replaceRE': bom_json_lax['replaceRE']
+}
+
+other_downloadables = [
+    (f'{SOURCE_ROOT}spdx.schema.json', join(TARGET_ROOT, 'spdx.SNAPSHOT.schema.json')),
+    (f'{SOURCE_ROOT}spdx.xsd', join(TARGET_ROOT, 'spdx.SNAPSHOT.xsd')),
+    (f'{SOURCE_ROOT}jsf-0.82.schema.json', join(TARGET_ROOT, 'jsf-0.82.SNAPSHOT.schema.json')),
+]
+
+for dspec in (bom_xsd, bom_json_lax, bom_json_strict):
+    for version in dspec['versions']:
+        source = dspec['sourcePattern'].replace('%s', version)
+        target = dspec['targetPattern'].replace('%s', version)
+        tempfile, _ = urlretrieve(source)
+        with open(tempfile, 'r') as tmpf:
+            with open(target, 'w') as tarf:
+                text = tmpf.read()
+                for search, replace in dspec['replace']:
+                    text = text.replace(search, replace)
+                for search, replace in dspec['replaceRE']:
+                    text = search.sub(replace, text)
+                tarf.write(text)
+
+for source, target in other_downloadables:
+    urlretrieve(source, target)
diff --git a/tox.ini b/tox.ini
index 5f6bc97eb..cc8a302dc 100644
--- a/tox.ini
+++ b/tox.ini
@@ -7,8 +7,8 @@
 minversion = 4.0
 envlist =
     flake8
-    mypy-{locked,lowest}
-    py{311,310,39,38}-{locked,lowest}
+    mypy-{current,lowest}
+    py{311,310,39,38}-{allExtras,noExtras}
 skip_missing_interpreters = True
 usedevelop = False
 download = False
@@ -19,8 +19,8 @@ skip_install = True
 allowlist_externals = poetry
 commands_pre =
     {envpython} --version
-    poetry install -v
-    lowest: poetry run pip install -U -r deps.lowest.r
+    !noExtras: poetry install -v --all-extras
+    noExtras: poetry install -v
     poetry run pip freeze
 commands =
     poetry run coverage run --source=cyclonedx -m unittest discover -t . -s tests -v
@@ -28,7 +28,7 @@ setenv =
     PYTHONHASHSEED=0
     CDX_TEST_RECREATE_SNAPSHOTS={env:CDX_TEST_RECREATE_SNAPSHOTS:}
 
-[testenv:mypy{,-locked,-lowest}]
+[testenv:mypy{,-current,-lowest}]
 commands =
     # mypy config is in own file: `.mypy.ini`
     !lowest: poetry run mypy
@@ -36,7 +36,7 @@ commands =
 
 [testenv:flake8]
 commands =
-    poetry run flake8 cyclonedx/ tests/ typings/
+    poetry run flake8 cyclonedx/ tests/ typings/ examples/
 
 [flake8]
 ## keep in sync with isort config - in `isort.cfg` file

From 3de24936533a51c0cbf61de4b19785ee7407526c Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Wed, 20 Sep 2023 09:20:15 +0200
Subject: [PATCH 05/42] typo

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 examples/complex.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/complex.py b/examples/complex.py
index f64b1652a..dede34f52 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -57,7 +57,7 @@
 try:
     validation_errors = JsonValidator(SchemaVersion.V1_4).validate_str(serialized_json)
     if validation_errors:
-        print('', 'JSON ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
+        print('JSON valid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
         sys.exit(2)
     print('JSON valid')
 except MissingOptionalDependencyException as error:
@@ -68,8 +68,8 @@
 try:
     validation_errors = XmlValidator(SchemaVersion.V1_4).validate_str(serialized_xml)
     if validation_errors:
-        print('', 'JSON ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
+        print('XML invalid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
         sys.exit(2)
-    print('JSON valid')
+    print('XML valid')
 except MissingOptionalDependencyException as error:
     print('XML-validation was skipped due to', error)

From 06b5eb03d479e9908b9b62bcee48d23a873dd4ba Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Thu, 21 Sep 2023 16:28:23 +0200
Subject: [PATCH 06/42] proper enums (#447)

fixes #442
part of #446

BREAKING CHANGE

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/output/__init__.py       | 38 ++++++++------
 cyclonedx/output/json.py           | 19 +++++--
 cyclonedx/output/xml.py            | 22 +++++++--
 cyclonedx/schema/__init__.py       | 79 ++++++++++++++++++++++++------
 cyclonedx/schema/schema.py         | 15 +++---
 tests/test_output.py               | 53 ++++++++++++++++++++
 tests/test_output_json.py          | 20 ++++++--
 tests/test_output_xml.py           | 22 +++++++--
 tests/test_schema_SchemaVersion.py | 78 +++++++++++++++++++++++++++++
 tests/test_schema__res.py          |  2 +-
 tools/schema-downloader.py         |  3 +-
 tox.ini                            |  2 +-
 12 files changed, 297 insertions(+), 56 deletions(-)
 create mode 100644 tests/test_output.py
 create mode 100644 tests/test_schema_SchemaVersion.py

diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index 2f8658faa..0a25d2b18 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -19,10 +19,10 @@
 and according to different versions of the CycloneDX schema standard.
 """
 
-import importlib
 import os
 from abc import ABC, abstractmethod
-from typing import Iterable, Union, cast
+from importlib import import_module
+from typing import Iterable, Optional, Type, Union
 
 from ..model.bom import Bom
 from ..model.component import Component
@@ -46,7 +46,12 @@ def _chained_components(self, container: Union[Bom, Component]) -> Iterable[Comp
     @property
     @abstractmethod
     def schema_version(self) -> SchemaVersion:
-        pass
+        ...
+
+    @property
+    @abstractmethod
+    def output_format(self) -> OutputFormat:
+        ...
 
     @property
     def generated(self) -> bool:
@@ -64,28 +69,23 @@ def set_bom(self, bom: Bom) -> None:
 
     @abstractmethod
     def generate(self, force_regeneration: bool = False) -> None:
-        pass
+        ...
 
     @abstractmethod
     def output_as_string(self) -> str:
-        pass
+        ...
 
     def output_to_file(self, filename: str, allow_overwrite: bool = False) -> None:
         # Check directory writable
         output_filename = os.path.realpath(filename)
         output_directory = os.path.dirname(output_filename)
-
         if not os.access(output_directory, os.W_OK):
             raise PermissionError(output_directory)
-
         if os.path.exists(output_filename) and not allow_overwrite:
             raise FileExistsError(output_filename)
-
         with open(output_filename, mode='wb') as f_out:
             f_out.write(self.output_as_string().encode('utf-8'))
 
-        f_out.close()
-
 
 def get_instance(bom: Bom, output_format: OutputFormat = OutputFormat.XML,
                  schema_version: SchemaVersion = LATEST_SUPPORTED_SCHEMA_VERSION) -> BaseOutput:
@@ -99,10 +99,16 @@ def get_instance(bom: Bom, output_format: OutputFormat = OutputFormat.XML,
     :param schema_version: SchemaVersion
     :return:
     """
+    # all exceptions are undocumented, as they are pure functional, and should be prevented by correct typing...
+    if not isinstance(output_format, OutputFormat):
+        raise TypeError(f"unexpected output_format: {output_format!r}")
+    if not isinstance(schema_version, SchemaVersion):
+        raise TypeError(f"unexpected schema_version: {schema_version!r}")
     try:
-        module = importlib.import_module(f"cyclonedx.output.{output_format.value.lower()}")
-        output_klass = getattr(module, f"{output_format.value}{schema_version.value}")
-    except (ImportError, AttributeError) as e:
-        raise ValueError(f"Unknown format {output_format.value.lower()!r}: {e}") from None
-
-    return cast(BaseOutput, output_klass(bom=bom))
+        module = import_module(f'.{output_format.name.lower()}', __package__)
+    except ImportError as error:  # pragma: no cover
+        raise ValueError(f'Unknown output_format: {output_format.name}') from error
+    output_klass: Optional[Type[BaseOutput]] = module.BY_SCHEMA_VERSION.get(schema_version, None)
+    if output_klass is None:  # pragma: no cover
+        raise ValueError(f'Unknown {output_format.name}/schema_version: {schema_version.name}')
+    return output_klass(bom=bom)
diff --git a/cyclonedx/output/json.py b/cyclonedx/output/json.py
index 75bc030bc..83f83b27c 100644
--- a/cyclonedx/output/json.py
+++ b/cyclonedx/output/json.py
@@ -19,11 +19,11 @@
 
 import json
 from abc import abstractmethod
-from typing import Optional
+from typing import Dict, Optional, Type
 
 from ..exception.output import FormatNotSupportedException
 from ..model.bom import Bom
-from ..schema import SchemaVersion
+from ..schema import OutputFormat, SchemaVersion
 from ..schema.schema import (
     SCHEMA_VERSIONS,
     BaseSchemaVersion,
@@ -46,6 +46,10 @@ def __init__(self, bom: Bom) -> None:
     def schema_version(self) -> SchemaVersion:
         return self.schema_version_enum
 
+    @property
+    def output_format(self) -> OutputFormat:
+        return OutputFormat.JSON
+
     def generate(self, force_regeneration: bool = False) -> None:
         # New Way
         schema_uri: Optional[str] = self._get_schema_uri()
@@ -58,7 +62,7 @@ def generate(self, force_regeneration: bool = False) -> None:
             'bomFormat': 'CycloneDX',
             'specVersion': self.schema_version.to_version()
         }
-        _view = SCHEMA_VERSIONS.get(self.get_schema_version())
+        _view = SCHEMA_VERSIONS.get(self.schema_version_enum)
         if self.generated and force_regeneration:
             self.get_bom().validate()
             bom_json = json.loads(self.get_bom().as_json(view_=_view))  # type: ignore
@@ -113,3 +117,12 @@ class JsonV1Dot4(Json, SchemaVersion1Dot4):
 
     def _get_schema_uri(self) -> Optional[str]:
         return 'http://cyclonedx.org/schema/bom-1.4.schema.json'
+
+
+BY_SCHEMA_VERSION: Dict[SchemaVersion, Type[Json]] = {
+    SchemaVersion.V1_4: JsonV1Dot4,  # type:ignore[type-abstract]
+    SchemaVersion.V1_3: JsonV1Dot3,  # type:ignore[type-abstract]
+    SchemaVersion.V1_2: JsonV1Dot2,  # type:ignore[type-abstract]
+    SchemaVersion.V1_1: JsonV1Dot1,  # type:ignore[type-abstract]
+    SchemaVersion.V1_0: JsonV1Dot0,  # type:ignore[type-abstract]
+}
diff --git a/cyclonedx/output/xml.py b/cyclonedx/output/xml.py
index e85219fa7..a72e5041e 100644
--- a/cyclonedx/output/xml.py
+++ b/cyclonedx/output/xml.py
@@ -17,12 +17,13 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
-from typing import Optional
+
+from typing import Dict, Optional, Type
 from xml.etree import ElementTree
 
 from ..exception.output import BomGenerationErrorException
 from ..model.bom import Bom
-from ..schema import SchemaVersion
+from ..schema import OutputFormat, SchemaVersion
 from ..schema.schema import (
     SCHEMA_VERSIONS,
     BaseSchemaVersion,
@@ -35,7 +36,7 @@
 from . import BaseOutput
 
 
-class Xml(BaseOutput, BaseSchemaVersion):
+class Xml(BaseSchemaVersion, BaseOutput):
     XML_VERSION_DECLARATION: str = '<?xml version="1.0" encoding="UTF-8"?>'
 
     def __init__(self, bom: Bom) -> None:
@@ -46,9 +47,13 @@ def __init__(self, bom: Bom) -> None:
     def schema_version(self) -> SchemaVersion:
         return self.schema_version_enum
 
+    @property
+    def output_format(self) -> OutputFormat:
+        return OutputFormat.XML
+
     def generate(self, force_regeneration: bool = False) -> None:
         # New way
-        _view = SCHEMA_VERSIONS.get(self.get_schema_version())
+        _view = SCHEMA_VERSIONS[self.schema_version_enum]
         if self.generated and force_regeneration:
             self.get_bom().validate()
             self._root_bom_element = self.get_bom().as_xml(  # type: ignore
@@ -97,3 +102,12 @@ class XmlV1Dot3(Xml, SchemaVersion1Dot3):
 
 class XmlV1Dot4(Xml, SchemaVersion1Dot4):
     pass
+
+
+BY_SCHEMA_VERSION: Dict[SchemaVersion, Type[Xml]] = {
+    SchemaVersion.V1_4: XmlV1Dot4,  # type:ignore[type-abstract]
+    SchemaVersion.V1_3: XmlV1Dot3,  # type:ignore[type-abstract]
+    SchemaVersion.V1_2: XmlV1Dot2,  # type:ignore[type-abstract]
+    SchemaVersion.V1_1: XmlV1Dot1,  # type:ignore[type-abstract]
+    SchemaVersion.V1_0: XmlV1Dot0,  # type:ignore[type-abstract]
+}
diff --git a/cyclonedx/schema/__init__.py b/cyclonedx/schema/__init__.py
index 9741a8e8f..361dcbca3 100644
--- a/cyclonedx/schema/__init__.py
+++ b/cyclonedx/schema/__init__.py
@@ -14,26 +14,73 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
-from enum import Enum
+from enum import Enum, auto, unique
 
 
-class OutputFormat(str, Enum):
-    JSON: str = 'Json'
-    XML: str = 'Xml'
+@unique
+class OutputFormat(Enum):
+    """Output formats.
 
+    Do not rely on the actual/literal values, just use enum cases.
+    """
+    JSON = auto()
+    XML = auto()
 
-class SchemaVersion(str, Enum):
-    V1_0: str = 'V1Dot0'
-    V1_1: str = 'V1Dot1'
-    V1_2: str = 'V1Dot2'
-    V1_3: str = 'V1Dot3'
-    V1_4: str = 'V1Dot4'
+
+@unique
+class SchemaVersion(Enum):
+    """
+    Schema version.
+
+    Cases are hashable.
+    Cases are comparable(!=,>=,>,==,<,<=)
+
+    Do not rely on the actual/literal values, just use enum cases.
+    """
+    V1_4 = (1, 4)
+    V1_3 = (1, 3)
+    V1_2 = (1, 2)
+    V1_1 = (1, 1)
+    V1_0 = (1, 0)
+
+    @classmethod
+    def from_version(cls, version: str) -> 'SchemaVersion':
+        """Return instance from  a version string - e.g. `1.4`"""
+        return cls(tuple(map(int, version.split('.')))[:2])
 
     def to_version(self) -> str:
-        """
-        Return as a version string - e.g. `1.4`
+        """Return as a version string - e.g. `1.4`"""
+        return '.'.join(map(str, self.value))
+
+    def __ne__(self, other: object) -> bool:
+        return self.value != other.value \
+            if isinstance(other, self.__class__) \
+            else NotImplemented  # type:ignore[return-value]
+
+    def __lt__(self, other: object) -> bool:
+        return self.value < other.value \
+            if isinstance(other, self.__class__) \
+            else NotImplemented  # type:ignore[return-value]
+
+    def __le__(self, other: object) -> bool:
+        return self.value <= other.value \
+            if isinstance(other, self.__class__) \
+            else NotImplemented  # type:ignore[return-value]
+
+    def __eq__(self, other: object) -> bool:
+        return self.value == other.value \
+            if isinstance(other, self.__class__) \
+            else NotImplemented  # type:ignore[return-value]
+
+    def __ge__(self, other: object) -> bool:
+        return self.value >= other.value \
+            if isinstance(other, self.__class__) \
+            else NotImplemented  # type:ignore[return-value]
+
+    def __gt__(self, other: object) -> bool:
+        return self.value > other.value \
+            if isinstance(other, self.__class__) \
+            else NotImplemented  # type:ignore[return-value]
 
-        Returns:
-            `str` version
-        """
-        return f'{self.value[1]}.{self.value[5]}'
+    def __hash__(self) -> int:
+        return hash(self.name)
diff --git a/cyclonedx/schema/schema.py b/cyclonedx/schema/schema.py
index 248376a51..5de943db9 100644
--- a/cyclonedx/schema/schema.py
+++ b/cyclonedx/schema/schema.py
@@ -18,6 +18,7 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 from abc import ABC, abstractmethod
+from typing import Dict, Type
 
 from serializable import ViewType
 
@@ -29,7 +30,7 @@ class BaseSchemaVersion(ABC, ViewType):
     @property
     @abstractmethod
     def schema_version_enum(self) -> SchemaVersion:
-        pass
+        ...
 
     def get_schema_version(self) -> str:
         return self.schema_version_enum.to_version()
@@ -70,10 +71,10 @@ def schema_version_enum(self) -> SchemaVersion:
         return SchemaVersion.V1_0
 
 
-SCHEMA_VERSIONS = {
-    '1.0': SchemaVersion1Dot0,
-    '1.1': SchemaVersion1Dot1,
-    '1.2': SchemaVersion1Dot2,
-    '1.3': SchemaVersion1Dot3,
-    '1.4': SchemaVersion1Dot4
+SCHEMA_VERSIONS: Dict[SchemaVersion, Type[BaseSchemaVersion]] = {
+    SchemaVersion.V1_4: SchemaVersion1Dot4,  # type:ignore[type-abstract]
+    SchemaVersion.V1_3: SchemaVersion1Dot3,  # type:ignore[type-abstract]
+    SchemaVersion.V1_2: SchemaVersion1Dot2,  # type:ignore[type-abstract]
+    SchemaVersion.V1_1: SchemaVersion1Dot1,  # type:ignore[type-abstract]
+    SchemaVersion.V1_0: SchemaVersion1Dot0,  # type:ignore[type-abstract]
 }
diff --git a/tests/test_output.py b/tests/test_output.py
new file mode 100644
index 000000000..afecbc20a
--- /dev/null
+++ b/tests/test_output.py
@@ -0,0 +1,53 @@
+# encoding: utf-8
+
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+
+from itertools import product
+from typing import Tuple
+from unittest import TestCase
+from unittest.mock import Mock
+
+from ddt import data, ddt, named_data, unpack
+
+from cyclonedx.model.bom import Bom
+from cyclonedx.output import get_instance as get_outputter
+from cyclonedx.schema import OutputFormat, SchemaVersion
+
+
+@ddt
+class Test(TestCase):
+
+    @named_data(*([f'{x[0].name} {x[1].name}', *x] for x in product(OutputFormat, SchemaVersion)))
+    @unpack
+    def test_get_instance_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
+        bom = Mock(spec=Bom)
+        outputter = get_outputter(bom, of, sv)
+        self.assertIs(outputter.get_bom(), bom)
+        self.assertIs(outputter.output_format, of)
+        self.assertIs(outputter.schema_version, sv)
+
+    @data(
+        *((of, 'foo', (TypeError, "unexpected schema_version: 'foo'")) for of in OutputFormat),
+        *(('foo', sv, (TypeError, "unexpected output_format: 'foo'")) for sv in SchemaVersion),
+    )
+    @unpack
+    def test_get_instance_fails(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
+        bom = Mock(spec=Bom)
+        with self.assertRaisesRegexp(*raisesRegex):
+            get_outputter(bom, of, sv)
diff --git a/tests/test_output_json.py b/tests/test_output_json.py
index ab4303db0..816dc66c3 100644
--- a/tests/test_output_json.py
+++ b/tests/test_output_json.py
@@ -17,13 +17,18 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 from os.path import join
+from unittest import TestCase
 from unittest.mock import Mock, patch
 from uuid import UUID
 
+from ddt import ddt, idata
+
 from cyclonedx.exception.output import FormatNotSupportedException
 from cyclonedx.model.bom import Bom
 from cyclonedx.output import get_instance
+from cyclonedx.output.json import BY_SCHEMA_VERSION, Json
 from cyclonedx.schema import OutputFormat, SchemaVersion
+from tests import TESTDATA_DIRECTORY
 from tests.base import BaseJsonTestCase
 from tests.data import (
     MOCK_UUID_1,
@@ -51,8 +56,6 @@
     get_bom_with_services_simple,
 )
 
-from . import TESTDATA_DIRECTORY
-
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'json')
 
 
@@ -402,7 +405,6 @@ def test_bom_v1_4_warn_dependencies(self) -> None:
 
     def _validate_json_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
         outputter = get_instance(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
-        self.assertEqual(outputter.schema_version, schema_version)
         with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as expected_json:
             output_as_string = outputter.output_as_string()
             self.assertValidAgainstSchema(bom_json=output_as_string, schema_version=schema_version)
@@ -414,3 +416,15 @@ def _validate_json_bom_not_supported(self, bom: Bom, schema_version: SchemaVersi
             outputter.output_as_string()
 
     # endregion Helper methods
+
+
+@ddt
+class TestFunctionalBySchemaVersion(TestCase):
+
+    @idata(SchemaVersion)
+    def test_get_instance_expected(self, sv: SchemaVersion) -> None:
+        outputterClass = BY_SCHEMA_VERSION[sv]
+        self.assertTrue(issubclass(outputterClass, Json))
+        outputter = outputterClass(Mock(spec=Bom))
+        self.assertIs(outputter.schema_version, sv)
+        self.assertIs(outputter.output_format, OutputFormat.JSON)
diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py
index 353cbf8d7..c5c94d0a1 100644
--- a/tests/test_output_xml.py
+++ b/tests/test_output_xml.py
@@ -17,12 +17,17 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 from os.path import join
+from unittest import TestCase
 from unittest.mock import Mock, patch
 from uuid import UUID
 
+from ddt import ddt, idata
+
 from cyclonedx.model.bom import Bom
 from cyclonedx.output import get_instance
-from cyclonedx.schema import SchemaVersion
+from cyclonedx.output.xml import BY_SCHEMA_VERSION, Xml
+from cyclonedx.schema import OutputFormat, SchemaVersion
+from tests import TESTDATA_DIRECTORY
 from tests.base import BaseXmlTestCase
 from tests.data import (
     MOCK_UUID_1,
@@ -50,8 +55,6 @@
     get_bom_with_services_simple,
 )
 
-from . import TESTDATA_DIRECTORY
-
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
 
 
@@ -532,7 +535,6 @@ def test_bom_v1_4_warn_dependencies(self) -> None:
 
     def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
         outputter = get_instance(bom=bom, schema_version=schema_version)
-        self.assertEqual(outputter.schema_version, schema_version)
         with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as expected_xml:
             output_as_string = outputter.output_as_string()
             self.assertValidAgainstSchema(bom_xml=output_as_string, schema_version=schema_version)
@@ -541,3 +543,15 @@ def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: st
             )
 
     # endregion Helper methods
+
+
+@ddt
+class TestFunctionalBySchemaVersion(TestCase):
+
+    @idata(SchemaVersion)
+    def test_get_instance_expected(self, sv: SchemaVersion) -> None:
+        outputterClass = BY_SCHEMA_VERSION[sv]
+        self.assertTrue(issubclass(outputterClass, Xml))
+        outputter = outputterClass(Mock(spec=Bom))
+        self.assertIs(outputter.schema_version, sv)
+        self.assertIs(outputter.output_format, OutputFormat.XML)
diff --git a/tests/test_schema_SchemaVersion.py b/tests/test_schema_SchemaVersion.py
new file mode 100644
index 000000000..988b5fe0d
--- /dev/null
+++ b/tests/test_schema_SchemaVersion.py
@@ -0,0 +1,78 @@
+# encoding: utf-8
+
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+from unittest import TestCase
+
+from ddt import ddt, idata, unpack
+
+from cyclonedx.schema import SchemaVersion
+
+SORTED_SV = (SchemaVersion.V1_4,
+             SchemaVersion.V1_3,
+             SchemaVersion.V1_2,
+             SchemaVersion.V1_1,
+             SchemaVersion.V1_0)
+
+# do not use any value-comparisons or implicit hash-functions here !
+# just work with the position in tuple SORTED_SCHEMA_VERSIONS
+td_gt = tuple((a, b) for i, a in enumerate(SORTED_SV) for b in SORTED_SV[i + 1:])
+td_ge = tuple((a, b) for i, a in enumerate(SORTED_SV) for b in SORTED_SV[i:])
+td_eq = tuple((v, v) for v in SORTED_SV)
+td_le = tuple((b, a) for a, b in td_ge)
+td_lt = tuple((b, a) for a, b in td_gt)
+td_ne = tuple((a, b) for i, a in enumerate(SORTED_SV) for j, b in enumerate(SORTED_SV) if i != j)
+
+
+@ddt
+class TestSchemaVersion(TestCase):
+
+    @idata(v for v in SchemaVersion)
+    def test_version_roundtrip(self, v: SchemaVersion) -> None:
+        v2 = SchemaVersion.from_version(v.to_version())
+        self.assertIs(v, v2)
+
+    @idata(td_ne)
+    @unpack
+    def test_ne(self, a: SchemaVersion, b: SchemaVersion) -> None:
+        self.assertNotEqual(a, b)
+
+    @idata(td_gt)
+    @unpack
+    def test_gt(self, a: SchemaVersion, b: SchemaVersion) -> None:
+        self.assertGreater(a, b)
+
+    @idata(td_ge)
+    @unpack
+    def test_ge(self, a: SchemaVersion, b: SchemaVersion) -> None:
+        self.assertGreaterEqual(a, b)
+
+    @idata(td_eq)
+    @unpack
+    def test_eq(self, a: SchemaVersion, b: SchemaVersion) -> None:
+        self.assertEqual(a, b)
+
+    @idata(td_lt)
+    @unpack
+    def test_lt(self, a: SchemaVersion, b: SchemaVersion) -> None:
+        self.assertLess(a, b)
+
+    @idata(td_le)
+    @unpack
+    def test_le(self, a: SchemaVersion, b: SchemaVersion) -> None:
+        self.assertLessEqual(a, b)
diff --git a/tests/test_schema__res.py b/tests/test_schema__res.py
index 0ac92db2a..93981bcc5 100644
--- a/tests/test_schema__res.py
+++ b/tests/test_schema__res.py
@@ -37,7 +37,7 @@ def _dp_files() -> Generator:
 
 
 @ddt
-class SchemaRes(TestCase):
+class SchemaResTest(TestCase):
 
     @idata(_dp_files())
     def test_file_exists(self, file: str) -> None:
diff --git a/tools/schema-downloader.py b/tools/schema-downloader.py
index b27982807..928b00106 100644
--- a/tools/schema-downloader.py
+++ b/tools/schema-downloader.py
@@ -34,7 +34,8 @@
 # "version" is not required but optional with a default value!
 #   this is wrong in schema<1.5
 _bomSchemaEnumMatch = re.compile(
-    r'("\$id": "(http://cyclonedx\.org/schema/bom.+?\.schema\.json)".*"enum": \[\s+")http://cyclonedx\.org/schema/bom.+?\.schema\.json"',
+    r'("\$id": "(http://cyclonedx\.org/schema/bom.+?\.schema\.json)".*"enum": \[\s+")'
+    r'http://cyclonedx\.org/schema/bom.+?\.schema\.json"',
     re.DOTALL)
 _bomSchemaEnumReplace = r'\1\2"'
 
diff --git a/tox.ini b/tox.ini
index cc8a302dc..334865927 100644
--- a/tox.ini
+++ b/tox.ini
@@ -36,7 +36,7 @@ commands =
 
 [testenv:flake8]
 commands =
-    poetry run flake8 cyclonedx/ tests/ typings/ examples/
+    poetry run flake8 cyclonedx/ tests/ typings/ examples/ tools/
 
 [flake8]
 ## keep in sync with isort config - in `isort.cfg` file

From 39e0eb9af29a13e1cad6a073e5eb20955e492484 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Thu, 21 Sep 2023 16:33:07 +0200
Subject: [PATCH 07/42] chore: absolute tet imports

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 tests/test_component.py           | 5 ++---
 tests/test_deserialize_json.py    | 3 +--
 tests/test_deserialize_xml.py     | 3 +--
 tests/test_model.py               | 3 +--
 tests/test_model_bom.py           | 3 +--
 tests/test_model_bom_ref.py       | 3 +--
 tests/test_model_issue.py         | 3 +--
 tests/test_real_world_examples.py | 3 +--
 tests/test_validation_json.py     | 3 +--
 tests/test_validation_xml.py      | 3 +--
 10 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/tests/test_component.py b/tests/test_component.py
index d2fe16fa4..baa578304 100644
--- a/tests/test_component.py
+++ b/tests/test_component.py
@@ -25,9 +25,8 @@
 
 from cyclonedx.model import sha1sum
 from cyclonedx.model.component import Component
-
-from . import TESTDATA_DIRECTORY
-from .data import get_component_setuptools_simple
+from tests import TESTDATA_DIRECTORY
+from tests.data import get_component_setuptools_simple
 
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml', '1.4')
 
diff --git a/tests/test_deserialize_json.py b/tests/test_deserialize_json.py
index 4535c8c05..bb9b626fc 100644
--- a/tests/test_deserialize_json.py
+++ b/tests/test_deserialize_json.py
@@ -26,6 +26,7 @@
 
 from cyclonedx.model.bom import Bom
 from cyclonedx.output import LATEST_SUPPORTED_SCHEMA_VERSION, OutputFormat, SchemaVersion, get_instance
+from tests import TESTDATA_DIRECTORY
 from tests.base import BaseJsonTestCase
 from tests.data import (
     MOCK_BOM_UUID_1,
@@ -54,8 +55,6 @@
     get_bom_with_services_simple,
 )
 
-from . import TESTDATA_DIRECTORY
-
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'json')
 
 
diff --git a/tests/test_deserialize_xml.py b/tests/test_deserialize_xml.py
index b097ab87f..f1a955779 100644
--- a/tests/test_deserialize_xml.py
+++ b/tests/test_deserialize_xml.py
@@ -27,6 +27,7 @@
 from cyclonedx.model.bom import Bom
 from cyclonedx.output import LATEST_SUPPORTED_SCHEMA_VERSION, SchemaVersion, get_instance
 from cyclonedx.schema import OutputFormat
+from tests import TESTDATA_DIRECTORY
 from tests.base import BaseXmlTestCase
 from tests.data import (
     MOCK_BOM_UUID_1,
@@ -53,8 +54,6 @@
     get_bom_with_services_simple,
 )
 
-from . import TESTDATA_DIRECTORY
-
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
 
 
diff --git a/tests/test_model.py b/tests/test_model.py
index 1b0558e5c..0ee5b3bd0 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -47,8 +47,7 @@
     XsUri,
 )
 from cyclonedx.model.issue import IssueClassification, IssueType, IssueTypeSource
-
-from .data import reorder
+from tests.data import reorder
 
 
 class DummyStringEnum(str, Enum):
diff --git a/tests/test_model_bom.py b/tests/test_model_bom.py
index 6e702dd83..f3db17731 100644
--- a/tests/test_model_bom.py
+++ b/tests/test_model_bom.py
@@ -32,8 +32,7 @@
 from cyclonedx.model.bom import Bom, BomMetaData
 from cyclonedx.model.bom_ref import BomRef
 from cyclonedx.model.component import Component, ComponentType
-
-from .data import (
+from tests.data import (
     get_bom_for_issue_275_components,
     get_bom_with_component_setuptools_with_vulnerability,
     get_component_setuptools_simple,
diff --git a/tests/test_model_bom_ref.py b/tests/test_model_bom_ref.py
index ced649be4..f7ae4a48d 100644
--- a/tests/test_model_bom_ref.py
+++ b/tests/test_model_bom_ref.py
@@ -20,8 +20,7 @@
 from unittest import TestCase
 
 from cyclonedx.model.bom_ref import BomRef
-
-from .data import reorder
+from tests.data import reorder
 
 
 class TestBomRef(TestCase):
diff --git a/tests/test_model_issue.py b/tests/test_model_issue.py
index 2d65d731d..383df5d4c 100644
--- a/tests/test_model_issue.py
+++ b/tests/test_model_issue.py
@@ -22,8 +22,7 @@
 from cyclonedx.exception.model import NoPropertiesProvidedException
 from cyclonedx.model import XsUri
 from cyclonedx.model.issue import IssueClassification, IssueType, IssueTypeSource
-
-from .data import get_issue_1, get_issue_2, reorder
+from tests.data import get_issue_1, get_issue_2, reorder
 
 
 class TestModelIssueType(TestCase):
diff --git a/tests/test_real_world_examples.py b/tests/test_real_world_examples.py
index 185b51c8b..6ce3cf90b 100644
--- a/tests/test_real_world_examples.py
+++ b/tests/test_real_world_examples.py
@@ -24,8 +24,7 @@
 
 from cyclonedx.model.bom import Bom
 from cyclonedx.schema import SchemaVersion
-
-from . import TESTDATA_DIRECTORY
+from tests import TESTDATA_DIRECTORY
 
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
 
diff --git a/tests/test_validation_json.py b/tests/test_validation_json.py
index ab00304e5..c5242b466 100644
--- a/tests/test_validation_json.py
+++ b/tests/test_validation_json.py
@@ -27,8 +27,7 @@
 from cyclonedx.exception import MissingOptionalDependencyException
 from cyclonedx.schema import SchemaVersion
 from cyclonedx.validation.json import JsonStrictValidator, JsonValidator
-
-from . import TESTDATA_DIRECTORY
+from tests import TESTDATA_DIRECTORY
 
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'schemaTestData')
 
diff --git a/tests/test_validation_xml.py b/tests/test_validation_xml.py
index 8f6ef247c..c74fef225 100644
--- a/tests/test_validation_xml.py
+++ b/tests/test_validation_xml.py
@@ -27,8 +27,7 @@
 from cyclonedx.exception import MissingOptionalDependencyException
 from cyclonedx.schema import SchemaVersion
 from cyclonedx.validation.xml import XmlValidator
-
-from . import TESTDATA_DIRECTORY
+from tests import TESTDATA_DIRECTORY
 
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'schemaTestData')
 

From 1c9ea9e22e53933347a8f366c5fc06febe811757 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Thu, 21 Sep 2023 18:31:02 +0200
Subject: [PATCH 08/42] feat: easy access validators (#448)

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/output/__init__.py     |  6 ++--
 cyclonedx/validation/__init__.py | 27 ++++++++++++++--
 cyclonedx/validation/json.py     |  5 +++
 cyclonedx/validation/xml.py      |  5 +++
 examples/complex.py              | 17 +++++-----
 tests/test_output.py             |  6 ++--
 tests/test_validation.py         | 53 ++++++++++++++++++++++++++++++++
 tests/test_validation_json.py    | 14 ++++++---
 tests/test_validation_xml.py     | 14 ++++++---
 9 files changed, 124 insertions(+), 23 deletions(-)
 create mode 100644 tests/test_validation.py

diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index 0a25d2b18..a9a09f1a5 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -108,7 +108,7 @@ def get_instance(bom: Bom, output_format: OutputFormat = OutputFormat.XML,
         module = import_module(f'.{output_format.name.lower()}', __package__)
     except ImportError as error:  # pragma: no cover
         raise ValueError(f'Unknown output_format: {output_format.name}') from error
-    output_klass: Optional[Type[BaseOutput]] = module.BY_SCHEMA_VERSION.get(schema_version, None)
-    if output_klass is None:  # pragma: no cover
+    klass: Optional[Type[BaseOutput]] = module.BY_SCHEMA_VERSION.get(schema_version, None)
+    if klass is None:  # pragma: no cover
         raise ValueError(f'Unknown {output_format.name}/schema_version: {schema_version.name}')
-    return output_klass(bom=bom)
+    return klass(bom=bom)
diff --git a/cyclonedx/validation/__init__.py b/cyclonedx/validation/__init__.py
index c6eada0ab..445613f34 100644
--- a/cyclonedx/validation/__init__.py
+++ b/cyclonedx/validation/__init__.py
@@ -15,7 +15,10 @@
 # SPDX-License-Identifier: Apache-2.0
 
 from abc import ABC, abstractmethod
-from typing import TYPE_CHECKING, Any, Optional, Protocol
+from importlib import import_module
+from typing import TYPE_CHECKING, Any, Optional, Protocol, Type
+
+from ..schema import OutputFormat
 
 if TYPE_CHECKING:
     from ..schema import SchemaVersion
@@ -59,15 +62,35 @@ class BaseValidator(ABC, Validator):
     def __init__(self, schema_version: 'SchemaVersion') -> None:
         self.__schema_version = schema_version
         if not self._schema_file:
-            raise ValueError(f'unsupported schema: {schema_version}')
+            raise ValueError(f'unsupported schema_version: {schema_version}')
 
     @property
     def schema_version(self) -> 'SchemaVersion':
         """get the schema version."""
         return self.__schema_version
 
+    @property
+    @abstractmethod
+    def output_format(self) -> OutputFormat:
+        """get the format."""
+        ...
+
     @property
     @abstractmethod
     def _schema_file(self) -> Optional[str]:
         """get the schema file according to schema version."""
         ...
+
+
+def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion') -> BaseValidator:
+    """get the default validator for a certain `OutputFormat`"""
+    if not isinstance(output_format, OutputFormat):
+        raise TypeError(f"unexpected output_format: {output_format!r}")
+    try:
+        module = import_module(f'.{output_format.name.lower()}', __package__)
+    except ImportError as error:  # pragma: no cover
+        raise ValueError(f'Unknown output_format: {output_format.name}') from error
+    klass: Optional[Type[BaseValidator]] = getattr(module, f'{output_format.name.capitalize()}Validator', None)
+    if klass is None:  # pragma: no cover
+        raise ValueError(f'Missing Validator for {output_format.name}')
+    return klass(schema_version)
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
index 34c1aca63..edf4616fc 100644
--- a/cyclonedx/validation/json.py
+++ b/cyclonedx/validation/json.py
@@ -20,6 +20,8 @@
 from json import loads as json_loads
 from typing import TYPE_CHECKING, Any, Optional, Tuple
 
+from ..schema import OutputFormat
+
 if TYPE_CHECKING:
     from ..schema import SchemaVersion
 
@@ -44,6 +46,9 @@
 
 
 class _BaseJsonValidator(BaseValidator, ABC):
+    @property
+    def output_format(self) -> OutputFormat:
+        return OutputFormat.JSON
 
     def __init__(self, schema_version: 'SchemaVersion') -> None:
         # this is the def that is used for generating the documentation
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index f49a75f46..18a55061f 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -20,6 +20,7 @@
 from typing import TYPE_CHECKING, Any, Optional, Tuple
 
 from ..exception import MissingOptionalDependencyException
+from ..schema import OutputFormat
 from ..schema._res import BOM_XML as _S_BOM
 from . import BaseValidator, ValidationError, Validator
 
@@ -38,6 +39,10 @@
 
 class _BaseXmlValidator(BaseValidator, ABC):
 
+    @property
+    def output_format(self) -> OutputFormat:
+        return OutputFormat.XML
+
     def __init__(self, schema_version: 'SchemaVersion') -> None:
         # this is the def that is used for generating the documentation
         super().__init__(schema_version)
diff --git a/examples/complex.py b/examples/complex.py
index dede34f52..5d75eb400 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -7,11 +7,11 @@
 from cyclonedx.model import OrganizationalEntity, XsUri
 from cyclonedx.model.bom import Bom
 from cyclonedx.model.component import Component, ComponentType
+from cyclonedx.output import get_instance as get_outputter
 from cyclonedx.output.json import JsonV1Dot4
-from cyclonedx.output.xml import XmlV1Dot4
-from cyclonedx.schema import SchemaVersion
-from cyclonedx.validation.json import JsonValidator
-from cyclonedx.validation.xml import XmlValidator
+from cyclonedx.schema import SchemaVersion, OutputFormat
+from cyclonedx.validation.json import JsonStrictValidator
+from cyclonedx.validation import get_instance as get_validator
 
 lc_factory = LicenseChoiceFactory(license_factory=LicenseFactory())
 
@@ -55,7 +55,7 @@
 serialized_json = JsonV1Dot4(bom).output_as_string()
 print(serialized_json)
 try:
-    validation_errors = JsonValidator(SchemaVersion.V1_4).validate_str(serialized_json)
+    validation_errors = JsonStrictValidator(SchemaVersion.V1_4).validate_str(serialized_json)
     if validation_errors:
         print('JSON valid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
         sys.exit(2)
@@ -63,10 +63,13 @@
 except MissingOptionalDependencyException as error:
     print('JSON-validation was skipped due to', error)
 
-serialized_xml = XmlV1Dot4(bom).output_as_string()
+my_outputter = get_outputter(bom, OutputFormat.XML, SchemaVersion.V1_4)
+serialized_xml = my_outputter.output_as_string()
 print(serialized_xml)
 try:
-    validation_errors = XmlValidator(SchemaVersion.V1_4).validate_str(serialized_xml)
+    validation_errors = get_validator(my_outputter.output_format,
+                                      my_outputter.schema_version
+                                      ).validate_str(serialized_xml)
     if validation_errors:
         print('XML invalid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
         sys.exit(2)
diff --git a/tests/test_output.py b/tests/test_output.py
index afecbc20a..e9737180f 100644
--- a/tests/test_output.py
+++ b/tests/test_output.py
@@ -31,11 +31,11 @@
 
 
 @ddt
-class Test(TestCase):
+class TestTestGetInstance(TestCase):
 
     @named_data(*([f'{x[0].name} {x[1].name}', *x] for x in product(OutputFormat, SchemaVersion)))
     @unpack
-    def test_get_instance_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
+    def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
         bom = Mock(spec=Bom)
         outputter = get_outputter(bom, of, sv)
         self.assertIs(outputter.get_bom(), bom)
@@ -47,7 +47,7 @@ def test_get_instance_expected(self, of: OutputFormat, sv: SchemaVersion) -> Non
         *(('foo', sv, (TypeError, "unexpected output_format: 'foo'")) for sv in SchemaVersion),
     )
     @unpack
-    def test_get_instance_fails(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
+    def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
         bom = Mock(spec=Bom)
         with self.assertRaisesRegexp(*raisesRegex):
             get_outputter(bom, of, sv)
diff --git a/tests/test_validation.py b/tests/test_validation.py
new file mode 100644
index 000000000..cc2217144
--- /dev/null
+++ b/tests/test_validation.py
@@ -0,0 +1,53 @@
+# encoding: utf-8
+
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+
+from itertools import product
+from typing import Tuple
+from unittest import TestCase
+
+from ddt import data, ddt, named_data, unpack
+
+from cyclonedx.schema import OutputFormat, SchemaVersion
+from cyclonedx.validation import get_instance as get_validator
+
+UndefinedFormatVersion = {(OutputFormat.JSON, SchemaVersion.V1_1), (OutputFormat.JSON, SchemaVersion.V1_0), }
+
+
+@ddt
+class TestGetInstance(TestCase):
+
+    @named_data(*([f'{f.name} {v.name}', f, v]
+                  for f, v
+                  in product(OutputFormat, SchemaVersion)
+                  if (f, v) not in UndefinedFormatVersion))
+    @unpack
+    def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
+        validator = get_validator(of, sv)
+        self.assertIs(validator.output_format, of)
+        self.assertIs(validator.schema_version, sv)
+
+    @data(
+        *(('foo', sv, (TypeError, "unexpected output_format: 'foo'")) for sv in SchemaVersion),
+        *((f, v, (ValueError, f'unsupported schema_version: {v}')) for f, v in UndefinedFormatVersion)
+    )
+    @unpack
+    def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
+        with self.assertRaisesRegexp(*raisesRegex):
+            get_validator(of, sv)
diff --git a/tests/test_validation_json.py b/tests/test_validation_json.py
index c5242b466..18edb10b1 100644
--- a/tests/test_validation_json.py
+++ b/tests/test_validation_json.py
@@ -25,7 +25,7 @@
 from ddt import data, ddt, idata, unpack
 
 from cyclonedx.exception import MissingOptionalDependencyException
-from cyclonedx.schema import SchemaVersion
+from cyclonedx.schema import OutputFormat, SchemaVersion
 from cyclonedx.validation.json import JsonStrictValidator, JsonValidator
 from tests import TESTDATA_DIRECTORY
 
@@ -44,9 +44,15 @@ def _dp(prefix: str) -> Generator:
 @ddt
 class TestJsonValidator(TestCase):
 
-    @data(*UNSUPPORTED_SCHEMA_VERSIONS)
+    @idata(sv for sv in SchemaVersion if sv not in UNSUPPORTED_SCHEMA_VERSIONS)
+    def test_validator_as_expected(self, schema_version: SchemaVersion) -> None:
+        validator = JsonValidator(schema_version)
+        self.assertIs(validator.schema_version, schema_version)
+        self.assertIs(validator.output_format, OutputFormat.JSON)
+
+    @idata(UNSUPPORTED_SCHEMA_VERSIONS)
     def test_throws_with_unsupported_schema_version(self, schema_version: SchemaVersion) -> None:
-        with self.assertRaisesRegex(ValueError, 'unsupported schema:'):
+        with self.assertRaisesRegex(ValueError, f'unsupported schema_version: {schema_version}'):
             JsonValidator(schema_version)
 
     @idata(_dp('valid'))
@@ -80,7 +86,7 @@ class TestJsonStrictValidator(TestCase):
 
     @data(*UNSUPPORTED_SCHEMA_VERSIONS)
     def test_throws_with_unsupported_schema_version(self, schema_version: SchemaVersion) -> None:
-        with self.assertRaisesRegex(ValueError, 'unsupported schema:'):
+        with self.assertRaisesRegex(ValueError, f'unsupported schema_version: {schema_version}'):
             JsonStrictValidator(schema_version)
 
     @idata(_dp('valid'))
diff --git a/tests/test_validation_xml.py b/tests/test_validation_xml.py
index c74fef225..60bc749cd 100644
--- a/tests/test_validation_xml.py
+++ b/tests/test_validation_xml.py
@@ -22,10 +22,10 @@
 from typing import Generator
 from unittest import TestCase
 
-from ddt import data, ddt, idata, unpack
+from ddt import ddt, idata, unpack
 
 from cyclonedx.exception import MissingOptionalDependencyException
-from cyclonedx.schema import SchemaVersion
+from cyclonedx.schema import OutputFormat, SchemaVersion
 from cyclonedx.validation.xml import XmlValidator
 from tests import TESTDATA_DIRECTORY
 
@@ -44,9 +44,15 @@ def _dp(prefix: str) -> Generator:
 @ddt
 class TestXmlValidator(TestCase):
 
-    @data(*UNSUPPORTED_SCHEMA_VERSIONS)
+    @idata(sv for sv in SchemaVersion if sv not in UNSUPPORTED_SCHEMA_VERSIONS)
+    def test_validator_as_expected(self, schema_version: SchemaVersion) -> None:
+        validator = XmlValidator(schema_version)
+        self.assertIs(validator.schema_version, schema_version)
+        self.assertIs(validator.output_format, OutputFormat.XML)
+
+    @idata(UNSUPPORTED_SCHEMA_VERSIONS)
     def test_throws_with_unsupported_schema_version(self, schema_version: SchemaVersion) -> None:
-        with self.assertRaisesRegex(ValueError, 'unsupported schema'):
+        with self.assertRaisesRegex(ValueError, f'unsupported schema_version: {schema_version}'):
             XmlValidator(schema_version)
 
     @idata(_dp('valid'))

From 18b4eca2c0fe2a2b4f1ca79976719c1afa0816bc Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Sat, 23 Sep 2023 06:53:21 +0200
Subject: [PATCH 09/42] chore: sem-release config

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 pyproject.toml | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/pyproject.toml b/pyproject.toml
index d0bc7f55b..3255d2fee 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -84,6 +84,8 @@ mypy = "1.5.1"
 tox = "4.11.3"
 xmldiff = "2.6.3"
 
+
+
 [tool.semantic_release]
 # see https://python-semantic-release.readthedocs.io/en/latest/configuration.html
 commit_message = "chore(release): {version}\n\nAutomatically generated by python-semantic-release"
@@ -94,19 +96,27 @@ version_variables = [
   "cyclonedx/__init__.py:__version__",
   "docs/conf.py:release",
 ]
+
+[tool.semantic_release.publish]
+dist_glob_patterns = ["dist/*"]
+upload_to_vcs_release = true
+
 [tool.semantic_release.changelog]
 changelog_file = "CHANGELOG.md"
 exclude_commit_patterns = [
   "chore\\(release\\):",
 ]
+
 [tool.semantic_release.branches.main]
 match = "(main|master)"
 prerelease = false
-[tool.semantic_release.branches."feat|fix|tests|style|docs|chore"]
-match = "(feat|fix|tests|style|docs|chore)"
+
+[tool.semantic_release.branches."step"]
+match = "(build|chore|ci|docs|feat|fix|perf|style|refactor|test)"
 prerelease = true
 prerelease_token = "alpha"
+
 [tool.semantic_release.branches."major-dev"]
-match = "\\d+\\.0\\.0-dev"
+match = "\\d+\\.0\\.0-(dev|rc)"
 prerelease = true
-prerelease_token = "alpha"
+prerelease_token = "rc"

From 839fe114bafac6117879175eb54a8759b7ef8963 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Sat, 23 Sep 2023 07:06:15 +0200
Subject: [PATCH 10/42] chore: config sem-release

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 pyproject.toml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/pyproject.toml b/pyproject.toml
index 3255d2fee..1b159d7ac 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -88,7 +88,8 @@ xmldiff = "2.6.3"
 
 [tool.semantic_release]
 # see https://python-semantic-release.readthedocs.io/en/latest/configuration.html
-commit_message = "chore(release): {version}\n\nAutomatically generated by python-semantic-release"
+commit_author = "semantic-release <semantic-release>"
+commit_message = "chore(release): {version}\n\nAutomatically generated by python-semantic-release\n\nSigned-off-by: semantic-release <semantic-release>"
 upload_to_vcs_release = true
 build_command = "pip install poetry && poetry build"
 version_toml = ["pyproject.toml:tool.poetry.version"]

From 7186b52a540e478196799ef7a3580f48f77544e9 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Sat, 23 Sep 2023 07:38:42 +0200
Subject: [PATCH 11/42] tests: use internal json strict validation

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 tests/base.py            | 4 ++--
 tests/test_output.py     | 2 +-
 tests/test_validation.py | 9 ++++++---
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/tests/base.py b/tests/base.py
index fff18cdfc..5d4fec7db 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -30,7 +30,7 @@
 
 from cyclonedx.exception import MissingOptionalDependencyException
 from cyclonedx.output import SchemaVersion
-from cyclonedx.validation.json import JsonValidator
+from cyclonedx.validation.json import JsonStrictValidator
 from cyclonedx.validation.xml import XmlValidator
 
 single_uuid: str = 'urn:uuid:{}'.format(uuid4())
@@ -40,7 +40,7 @@ class BaseJsonTestCase(TestCase):
 
     def assertValidAgainstSchema(self, bom_json: str, schema_version: SchemaVersion) -> None:
         try:
-            validation_error = JsonValidator(schema_version).validate_str(bom_json)
+            validation_error = JsonStrictValidator(schema_version).validate_str(bom_json)
         except MissingOptionalDependencyException:
             return  # some deps are missing - skip the validation
         self.assertIsNone(validation_error,
diff --git a/tests/test_output.py b/tests/test_output.py
index e9737180f..90e991a18 100644
--- a/tests/test_output.py
+++ b/tests/test_output.py
@@ -49,5 +49,5 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
     @unpack
     def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
         bom = Mock(spec=Bom)
-        with self.assertRaisesRegexp(*raisesRegex):
+        with self.assertRaisesRegex(*raisesRegex):
             get_outputter(bom, of, sv)
diff --git a/tests/test_validation.py b/tests/test_validation.py
index cc2217144..82fadd6e5 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -27,7 +27,10 @@
 from cyclonedx.schema import OutputFormat, SchemaVersion
 from cyclonedx.validation import get_instance as get_validator
 
-UndefinedFormatVersion = {(OutputFormat.JSON, SchemaVersion.V1_1), (OutputFormat.JSON, SchemaVersion.V1_0), }
+UNDEFINED_FORMAT_VERSION = {
+    (OutputFormat.JSON, SchemaVersion.V1_1),
+    (OutputFormat.JSON, SchemaVersion.V1_0),
+}
 
 
 @ddt
@@ -36,7 +39,7 @@ class TestGetInstance(TestCase):
     @named_data(*([f'{f.name} {v.name}', f, v]
                   for f, v
                   in product(OutputFormat, SchemaVersion)
-                  if (f, v) not in UndefinedFormatVersion))
+                  if (f, v) not in UNDEFINED_FORMAT_VERSION))
     @unpack
     def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
         validator = get_validator(of, sv)
@@ -45,7 +48,7 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
 
     @data(
         *(('foo', sv, (TypeError, "unexpected output_format: 'foo'")) for sv in SchemaVersion),
-        *((f, v, (ValueError, f'unsupported schema_version: {v}')) for f, v in UndefinedFormatVersion)
+        *((f, v, (ValueError, f'unsupported schema_version: {v}')) for f, v in UNDEFINED_FORMAT_VERSION)
     )
     @unpack
     def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:

From 6adc98f66da94b7bac987bc5b25da7099498fe3a Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Mon, 25 Sep 2023 07:48:15 +0200
Subject: [PATCH 12/42] docs: fix typo

Signed-off-by: Jan Kowalleck <jan.kowalleck@owasp.org>
---
 examples/complex.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/complex.py b/examples/complex.py
index 5d75eb400..0ba13287c 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -57,7 +57,7 @@
 try:
     validation_errors = JsonStrictValidator(SchemaVersion.V1_4).validate_str(serialized_json)
     if validation_errors:
-        print('JSON valid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
+        print('JSON invalid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
         sys.exit(2)
     print('JSON valid')
 except MissingOptionalDependencyException as error:

From 9d49280b680a4f8a7c4b8795f35928584e29baee Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Mon, 25 Sep 2023 14:37:54 +0200
Subject: [PATCH 13/42] docs: fix hilighter

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 docs/install.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/install.rst b/docs/install.rst
index 62bbb625b..6e8514f7c 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -17,7 +17,7 @@ Installation
 
 Install from `pypi.org`_ as you would any other Python module using your preferred package manager:
 
-.. code-block:: bash
+.. code-block:: sh
 
     pip install cyclonedx-python-lib
 
@@ -40,6 +40,6 @@ The following extras are available when installing this package:
 
 They can be used when installing in order to include additional dependencies, e.g.:
 
-.. code-block:: bash
+.. code-block:: sh
 
     pip install 'cyclonedx-python-lib[validation]'

From 16843b29086d8f871a7239c33beb930543cfde45 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Mon, 25 Sep 2023 18:49:22 +0200
Subject: [PATCH 14/42] fix: `bom.validate()` detects invalid license
 constellations (#452)

If a LicenseExpression is set, then there must be no other license.

fixes #453


Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/exception/model.py | 11 +++++++
 cyclonedx/model/bom.py       | 18 +++++++++--
 tests/data.py                | 53 ++++++++++++++++++++++++++++++++
 tests/test_model_bom.py      | 59 +++++++++++++++++++++++++-----------
 tests/test_validation.py     |  2 +-
 5 files changed, 122 insertions(+), 21 deletions(-)

diff --git a/cyclonedx/exception/model.py b/cyclonedx/exception/model.py
index 43b3045d0..f0c07383e 100644
--- a/cyclonedx/exception/model.py
+++ b/cyclonedx/exception/model.py
@@ -73,6 +73,7 @@ class UnknownComponentDependencyException(CycloneDxModelException):
     """
     Exception raised when a dependency has been noted for a Component that is NOT a Component BomRef in this Bom.
     """
+    pass
 
 
 class UnknownHashTypeException(CycloneDxModelException):
@@ -80,3 +81,13 @@ class UnknownHashTypeException(CycloneDxModelException):
     Exception raised when we are unable to determine the type of hash from a composite hash string.
     """
     pass
+
+
+class LicenseExpressionAlongWithOthersException(CycloneDxModelException):
+    """
+    Exception raised when a LicenseExpression was detected along with other licenses.
+    If a LicenseExpression exists, than it must stand alone.
+
+    See https://github.com/CycloneDX/specification/pull/205
+    """
+    pass
diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
index 5c559a089..a66ba0c64 100644
--- a/cyclonedx/model/bom.py
+++ b/cyclonedx/model/bom.py
@@ -18,7 +18,8 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 import warnings
 from datetime import datetime
-from typing import TYPE_CHECKING, Iterable, Optional, Set
+from itertools import chain
+from typing import TYPE_CHECKING, Iterable, Optional, Set, Union
 from uuid import UUID, uuid4
 
 import serializable
@@ -26,7 +27,7 @@
 
 from cyclonedx.serialization import UrnUuidHelper
 
-from ..exception.model import UnknownComponentDependencyException
+from ..exception.model import LicenseExpressionAlongWithOthersException, UnknownComponentDependencyException
 from ..parser import BaseParser
 from ..schema.schema import (
     SchemaVersion1Dot0,
@@ -573,6 +574,19 @@ def validate(self) -> bool:
                 UserWarning
             )
 
+        # 3. If a LicenseExpression is set, then there must be no other license.
+        # see https://github.com/CycloneDX/specification/pull/205
+        elem: Union[BomMetaData, Component, Service]
+        for elem in chain(  # type: ignore[assignment]
+            [self.metadata],
+            self.metadata.component.get_all_nested_components(include_self=True) if self.metadata.component else [],
+            chain.from_iterable(c.get_all_nested_components(include_self=True) for c in self.components),
+            self.services
+        ):
+            if len(elem.licenses) > 1 and any(li.expression for li in elem.licenses):
+                raise LicenseExpressionAlongWithOthersException(
+                    f'Found LicenseExpression along with others licenses in: {elem!r}')
+
         return True
 
     def __eq__(self, other: object) -> bool:
diff --git a/tests/data.py b/tests/data.py
index 51e7679bd..d0d3afb51 100644
--- a/tests/data.py
+++ b/tests/data.py
@@ -640,6 +640,59 @@ def get_vulnerability_source_owasp() -> VulnerabilitySource:
     return VulnerabilitySource(name='OWASP', url=XsUri('https://owasp.org'))
 
 
+def get_bom_metadata_licenses_invalid() -> Bom:
+    return Bom(metadata=BomMetaData(licenses=[
+        LicenseChoice(expression='Apache-2.0 OR MIT'),
+        LicenseChoice(license=License(id='MIT')),
+    ]))
+
+
+def get_invalid_license_repository() -> List[LicenseChoice]:
+    """
+    license expression and a license -- this is an invalid constellation according to schema
+    see https://github.com/CycloneDX/specification/pull/205
+    """
+    return [
+        LicenseChoice(expression='Apache-2.0 OR MIT'),
+        LicenseChoice(license=License(id='GPL-2.0-only')),
+    ]
+
+
+def get_component_licenses_invalid() -> Component:
+    return Component(name='foo', type=ComponentType.LIBRARY,
+                     licenses=get_invalid_license_repository())
+
+
+def get_bom_metadata_component_licenses_invalid() -> Bom:
+    comp = get_component_licenses_invalid()
+    return Bom(metadata=BomMetaData(component=comp),
+               dependencies=[Dependency(comp.bom_ref)])
+
+
+def get_bom_metadata_component_nested_licenses_invalid() -> Bom:
+    comp = Component(name='bar', type=ComponentType.LIBRARY,
+                     components=[get_component_licenses_invalid()])
+    return Bom(metadata=BomMetaData(component=comp),
+               dependencies=[Dependency(comp.bom_ref)])
+
+
+def get_bom_component_licenses_invalid() -> Bom:
+    return Bom(components=[get_component_licenses_invalid()])
+
+
+def get_bom_component_nested_licenses_invalid() -> Bom:
+    return Bom(components=[
+        Component(name='bar', type=ComponentType.LIBRARY,
+                  components=[get_component_licenses_invalid()])
+    ])
+
+
+def get_bom_service_licenses_invalid() -> Bom:
+    return Bom(services=[
+        Service(name='foo', licenses=get_invalid_license_repository())
+    ])
+
+
 T = TypeVar('T')
 
 
diff --git a/tests/test_model_bom.py b/tests/test_model_bom.py
index f3db17731..18567c72c 100644
--- a/tests/test_model_bom.py
+++ b/tests/test_model_bom.py
@@ -1,25 +1,11 @@
 # encoding: utf-8
-
-# This file is part of CycloneDX Python Lib
-#
-# 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-# Copyright (c) OWASP Foundation. All Rights Reserved.
-
+from typing import Callable
 from unittest import TestCase
 from uuid import uuid4
 
+from ddt import ddt, named_data
+
+from cyclonedx.exception.model import LicenseExpressionAlongWithOthersException
 from cyclonedx.model import (
     License,
     LicenseChoice,
@@ -33,12 +19,35 @@
 from cyclonedx.model.bom_ref import BomRef
 from cyclonedx.model.component import Component, ComponentType
 from tests.data import (
+    get_bom_component_licenses_invalid,
+    get_bom_component_nested_licenses_invalid,
     get_bom_for_issue_275_components,
+    get_bom_metadata_component_licenses_invalid,
+    get_bom_metadata_component_nested_licenses_invalid,
+    get_bom_metadata_licenses_invalid,
+    get_bom_service_licenses_invalid,
     get_bom_with_component_setuptools_with_vulnerability,
     get_component_setuptools_simple,
     get_component_setuptools_simple_no_version,
 )
 
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 class TestBomMetaData(TestCase):
 
@@ -96,6 +105,7 @@ def test_basic_bom_metadata(self) -> None:
         self.assertTrue(tools[1] in metadata.tools)
 
 
+@ddt
 class TestBom(TestCase):
 
     def test_bom_metadata_tool_this_tool(self) -> None:
@@ -168,6 +178,19 @@ def test_bom_nested_components_issue_275(self) -> None:
         self.assertEqual(2, len(bom.components))
         bom.validate()
 
+    @named_data(
+        ['metadata_licenses', get_bom_metadata_licenses_invalid],
+        ['metadata_component_licenses', get_bom_metadata_component_licenses_invalid],
+        ['metadata_component_nested_licenses', get_bom_metadata_component_nested_licenses_invalid],
+        ['component_licenses', get_bom_component_licenses_invalid],
+        ['component_nested_licenses', get_bom_component_nested_licenses_invalid],
+        ['service_licenses', get_bom_service_licenses_invalid],
+    )
+    def test_validate_with_invalid_license_constellation_throws(self, get_bom: Callable[[], Bom]) -> None:
+        bom = get_bom()
+        with self.assertRaises(LicenseExpressionAlongWithOthersException):
+            bom.validate()
+
     # def test_bom_nested_services_issue_275(self) -> None:
     #    """regression test for issue #275
     #    see https://github.com/CycloneDX/cyclonedx-python-lib/issues/275
diff --git a/tests/test_validation.py b/tests/test_validation.py
index 82fadd6e5..b7e3dfbd5 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -52,5 +52,5 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
     )
     @unpack
     def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
-        with self.assertRaisesRegexp(*raisesRegex):
+        with self.assertRaisesRegex(*raisesRegex):
             get_validator(of, sv)

From 3bcd9e99a58b74c9dc1fc474b468e67fc92fb7c4 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Wed, 4 Oct 2023 12:21:56 +0200
Subject: [PATCH 15/42] feat: options for beautiful output (#458)

add indention to outputters. this may come at a cost!


Breaking Changes
------------------
* abstract Method `output.BaseOutput.output_as_string()` got new optional kwarg `indent`
* abstract Method `output.BaseOutput.output_as_string()` accepts arbitrary kwargs

Changed
----------
* XML output uses a default namespace, which makes results smaller.


Added
------------------
* All outputters' method `output_as_string()` got new optional kwarg `indent`
* All outputters' method `output_as_string()` accepts arbitrary kwargs
* All outputters' method `output_to_file()` got new optional kwarg `indent`
* All outputters' method `output_to_file()` accepts arbitrary kwargs

-----

- [x] implementation
- [x] tests (snapshot binary compare; structural equal compare)

-----

enables https://github.com/CycloneDX/cyclonedx-python/issues/424
fixes #437
fixes #438
supersedes #449

---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/output/__init__.py                  | 12 ++--
 cyclonedx/output/json.py                      | 42 +++++------
 cyclonedx/output/xml.py                       | 66 +++++++++--------
 examples/complex.py                           |  6 +-
 pyproject.toml                                |  2 +-
 tests/_data/own/.gitattributes                |  5 +-
 .../_data/own/json/1.4/indented_4spaces.json  | 71 +++++++++++++++++++
 tests/_data/own/json/1.4/indented_None.json   |  1 +
 tests/_data/own/json/1.4/indented_tab.json    | 71 +++++++++++++++++++
 tests/_data/own/json/1.4/indented_two.json    | 71 +++++++++++++++++++
 tests/_data/own/xml/1.4/indented_4spaces.xml  | 53 ++++++++++++++
 tests/_data/own/xml/1.4/indented_None.xml     |  2 +
 tests/_data/own/xml/1.4/indented_tab.xml      | 53 ++++++++++++++
 tests/_data/own/xml/1.4/indented_two.xml      | 53 ++++++++++++++
 tests/_data/schemaTestData/.gitattributes     |  5 +-
 tests/test_output_json.py                     | 32 +++++++--
 tests/test_output_xml.py                      | 30 ++++++--
 17 files changed, 502 insertions(+), 73 deletions(-)
 create mode 100644 tests/_data/own/json/1.4/indented_4spaces.json
 create mode 100644 tests/_data/own/json/1.4/indented_None.json
 create mode 100644 tests/_data/own/json/1.4/indented_tab.json
 create mode 100644 tests/_data/own/json/1.4/indented_two.json
 create mode 100644 tests/_data/own/xml/1.4/indented_4spaces.xml
 create mode 100644 tests/_data/own/xml/1.4/indented_None.xml
 create mode 100644 tests/_data/own/xml/1.4/indented_tab.xml
 create mode 100644 tests/_data/own/xml/1.4/indented_two.xml

diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index a9a09f1a5..474a710d9 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -22,7 +22,7 @@
 import os
 from abc import ABC, abstractmethod
 from importlib import import_module
-from typing import Iterable, Optional, Type, Union
+from typing import Any, Dict, Iterable, Optional, Type, Union
 
 from ..model.bom import Bom
 from ..model.component import Component
@@ -72,10 +72,14 @@ def generate(self, force_regeneration: bool = False) -> None:
         ...
 
     @abstractmethod
-    def output_as_string(self) -> str:
+    def output_as_string(self, *,
+                         indent: Optional[Union[int, str]] = None,
+                         **kwargs: Dict[str, Any]) -> str:
         ...
 
-    def output_to_file(self, filename: str, allow_overwrite: bool = False) -> None:
+    def output_to_file(self, filename: str, allow_overwrite: bool = False, *,
+                       indent: Optional[Union[int, str]] = None,
+                       **kwargs: Dict[str, Any]) -> None:
         # Check directory writable
         output_filename = os.path.realpath(filename)
         output_directory = os.path.dirname(output_filename)
@@ -84,7 +88,7 @@ def output_to_file(self, filename: str, allow_overwrite: bool = False) -> None:
         if os.path.exists(output_filename) and not allow_overwrite:
             raise FileExistsError(output_filename)
         with open(output_filename, mode='wb') as f_out:
-            f_out.write(self.output_as_string().encode('utf-8'))
+            f_out.write(self.output_as_string(indent=indent).encode('utf-8'))
 
 
 def get_instance(bom: Bom, output_format: OutputFormat = OutputFormat.XML,
diff --git a/cyclonedx/output/json.py b/cyclonedx/output/json.py
index 83f83b27c..c4ba023d6 100644
--- a/cyclonedx/output/json.py
+++ b/cyclonedx/output/json.py
@@ -17,9 +17,9 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
-import json
 from abc import abstractmethod
-from typing import Dict, Optional, Type
+from json import dumps as json_dumps, loads as json_loads
+from typing import Any, Dict, Optional, Type, Union
 
 from ..exception.output import FormatNotSupportedException
 from ..model.bom import Bom
@@ -40,7 +40,7 @@ class Json(BaseOutput, BaseSchemaVersion):
 
     def __init__(self, bom: Bom) -> None:
         super().__init__(bom=bom)
-        self._json_output: str = ''
+        self._bom_json: Dict[str, Any] = dict()
 
     @property
     def schema_version(self) -> SchemaVersion:
@@ -51,7 +51,9 @@ def output_format(self) -> OutputFormat:
         return OutputFormat.JSON
 
     def generate(self, force_regeneration: bool = False) -> None:
-        # New Way
+        if self.generated and not force_regeneration:
+            return
+
         schema_uri: Optional[str] = self._get_schema_uri()
         if not schema_uri:
             raise FormatNotSupportedException(
@@ -63,26 +65,20 @@ def generate(self, force_regeneration: bool = False) -> None:
             'specVersion': self.schema_version.to_version()
         }
         _view = SCHEMA_VERSIONS.get(self.schema_version_enum)
-        if self.generated and force_regeneration:
-            self.get_bom().validate()
-            bom_json = json.loads(self.get_bom().as_json(view_=_view))  # type: ignore
-            bom_json.update(_json_core)
-            self._json_output = json.dumps(bom_json)
-            self.generated = True
-            return
-        elif self.generated:
-            return
-        else:
-            self.get_bom().validate()
-            bom_json = json.loads(self.get_bom().as_json(view_=_view))  # type: ignore
-            bom_json.update(_json_core)
-            self._json_output = json.dumps(bom_json)
-            self.generated = True
-            return
-
-    def output_as_string(self) -> str:
+        self.get_bom().validate()
+        bom_json: Dict[str, Any] = json_loads(
+            self.get_bom().as_json(  # type:ignore[attr-defined]
+                view_=_view))
+        bom_json.update(_json_core)
+        self._bom_json = bom_json
+        self.generated = True
+
+    def output_as_string(self, *,
+                         indent: Optional[Union[int, str]] = None,
+                         **kwargs: Dict[str, Any]) -> str:
         self.generate()
-        return self._json_output
+        return json_dumps(self._bom_json,
+                          indent=indent)
 
     @abstractmethod
     def _get_schema_uri(self) -> Optional[str]:
diff --git a/cyclonedx/output/xml.py b/cyclonedx/output/xml.py
index a72e5041e..8642ec509 100644
--- a/cyclonedx/output/xml.py
+++ b/cyclonedx/output/xml.py
@@ -18,10 +18,10 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 
-from typing import Dict, Optional, Type
-from xml.etree import ElementTree
+from typing import Any, Dict, Optional, Type, Union
+from xml.dom.minidom import parseString as dom_parseString
+from xml.etree.ElementTree import Element as XmlElement, tostring as xml_dumps
 
-from ..exception.output import BomGenerationErrorException
 from ..model.bom import Bom
 from ..schema import OutputFormat, SchemaVersion
 from ..schema.schema import (
@@ -37,11 +37,9 @@
 
 
 class Xml(BaseSchemaVersion, BaseOutput):
-    XML_VERSION_DECLARATION: str = '<?xml version="1.0" encoding="UTF-8"?>'
-
     def __init__(self, bom: Bom) -> None:
         super().__init__(bom=bom)
-        self._root_bom_element: Optional[ElementTree.Element] = None
+        self._bom_xml: str = ''
 
     @property
     def schema_version(self) -> SchemaVersion:
@@ -52,31 +50,39 @@ def output_format(self) -> OutputFormat:
         return OutputFormat.XML
 
     def generate(self, force_regeneration: bool = False) -> None:
-        # New way
-        _view = SCHEMA_VERSIONS[self.schema_version_enum]
-        if self.generated and force_regeneration:
-            self.get_bom().validate()
-            self._root_bom_element = self.get_bom().as_xml(  # type: ignore
-                view_=_view, as_string=False, xmlns=self.get_target_namespace()
-            )
-            self.generated = True
-            return
-        elif self.generated:
-            return
-        else:
-            self.get_bom().validate()
-            self._root_bom_element = self.get_bom().as_xml(  # type: ignore
-                view_=_view, as_string=False, xmlns=self.get_target_namespace()
-            )
-            self.generated = True
+        if self.generated and not force_regeneration:
             return
 
-    def output_as_string(self) -> str:
+        _view = SCHEMA_VERSIONS[self.schema_version_enum]
+        self.get_bom().validate()
+        xmlns = self.get_target_namespace()
+        self._bom_xml = '<?xml version="1.0" ?>\n' + xml_dumps(
+            self.get_bom().as_xml(  # type:ignore[attr-defined]
+                _view, as_string=False, xmlns=xmlns),
+            method='xml', default_namespace=xmlns, encoding='unicode',
+            # `xml-declaration` is inconsistent/bugged in py38, especially on Windows it will print a non-UTF8 codepage.
+            # Furthermore, it might add an encoding of "utf-8" which is redundant default value of XML.
+            # -> so we write the declaration manually, as long as py38 is supported.
+            xml_declaration=False)
+
+        self.generated = True
+
+    @staticmethod
+    def __make_indent(v: Optional[Union[int, str]]) -> str:
+        if isinstance(v, int):
+            return ' ' * v
+        if isinstance(v, str):
+            return v
+        return ''
+
+    def output_as_string(self, *,
+                         indent: Optional[Union[int, str]] = None,
+                         **kwargs: Dict[str, Any]) -> str:
         self.generate()
-        if self.generated and self._root_bom_element is not None:
-            return str(Xml.XML_VERSION_DECLARATION + ElementTree.tostring(self._root_bom_element, encoding='unicode'))
-
-        raise BomGenerationErrorException('There was no Root XML Element after BOM generation.')
+        return self._bom_xml if indent is None else dom_parseString(self._bom_xml).toprettyxml(
+            indent=self.__make_indent(indent)
+            # do not set `encoding` - this would convert result to binary, not string
+        )
 
     def get_target_namespace(self) -> str:
         return f'http://cyclonedx.org/schema/bom/{self.get_schema_version()}'
@@ -84,8 +90,8 @@ def get_target_namespace(self) -> str:
 
 class XmlV1Dot0(Xml, SchemaVersion1Dot0):
 
-    def _create_bom_element(self) -> ElementTree.Element:
-        return ElementTree.Element('bom', {'xmlns': self.get_target_namespace(), 'version': '1'})
+    def _create_bom_element(self) -> XmlElement:
+        return XmlElement('bom', {'xmlns': self.get_target_namespace(), 'version': '1'})
 
 
 class XmlV1Dot1(Xml, SchemaVersion1Dot1):
diff --git a/examples/complex.py b/examples/complex.py
index 0ba13287c..a2f5fb6f3 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -52,7 +52,7 @@
 # endregion build the BOM
 
 
-serialized_json = JsonV1Dot4(bom).output_as_string()
+serialized_json = JsonV1Dot4(bom).output_as_string(indent=2)
 print(serialized_json)
 try:
     validation_errors = JsonStrictValidator(SchemaVersion.V1_4).validate_str(serialized_json)
@@ -63,8 +63,10 @@
 except MissingOptionalDependencyException as error:
     print('JSON-validation was skipped due to', error)
 
+print('', '=' * 30, '', sep='\n')
+
 my_outputter = get_outputter(bom, OutputFormat.XML, SchemaVersion.V1_4)
-serialized_xml = my_outputter.output_as_string()
+serialized_xml = my_outputter.output_as_string(indent=2)
 print(serialized_xml)
 try:
     validation_errors = get_validator(my_outputter.output_format,
diff --git a/pyproject.toml b/pyproject.toml
index 1b159d7ac..0dcc1f0ae 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -60,7 +60,7 @@ keywords = [
 # ATTENTION: keep `deps.lowest.r` file in sync
 python = "^3.8"
 packageurl-python = ">= 0.11"
-py-serializable = "^0.11.1"
+py-serializable = "^0.13.0"
 sortedcontainers = "^2.4.0"
 license-expression = "^30"
 jsonschema = { version = "^4.18", extras=['format'], optional=true, python="^3.8" }
diff --git a/tests/_data/own/.gitattributes b/tests/_data/own/.gitattributes
index 6558d375e..759d4136b 100644
--- a/tests/_data/own/.gitattributes
+++ b/tests/_data/own/.gitattributes
@@ -1,2 +1,3 @@
-xml/*/*.xml     linguist-generated
-json/*/*.josn   linguist-generated
+*               binary
+xml/*/*.xml     linguist-generated diff=xml
+json/*/*.json   linguist-generated diff=json
diff --git a/tests/_data/own/json/1.4/indented_4spaces.json b/tests/_data/own/json/1.4/indented_4spaces.json
new file mode 100644
index 000000000..a37dc693d
--- /dev/null
+++ b/tests/_data/own/json/1.4/indented_4spaces.json
@@ -0,0 +1,71 @@
+{
+    "components": [
+        {
+            "author": "Test Author",
+            "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "licenses": [
+                {
+                    "expression": "MIT License"
+                }
+            ],
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
+        }
+    ],
+    "dependencies": [
+        {
+            "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+        }
+    ],
+    "metadata": {
+        "timestamp": "2021-12-31T10:00:00+00:00",
+        "tools": [
+            {
+                "externalReferences": [
+                    {
+                        "type": "build-system",
+                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+                    },
+                    {
+                        "type": "distribution",
+                        "url": "https://pypi.org/project/cyclonedx-python-lib/"
+                    },
+                    {
+                        "type": "documentation",
+                        "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+                    },
+                    {
+                        "type": "issue-tracker",
+                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+                    },
+                    {
+                        "type": "license",
+                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+                    },
+                    {
+                        "type": "release-notes",
+                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+                    },
+                    {
+                        "type": "vcs",
+                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+                    },
+                    {
+                        "type": "website",
+                        "url": "https://cyclonedx.org"
+                    }
+                ],
+                "name": "cyclonedx-python-lib",
+                "vendor": "CycloneDX",
+                "version": "TESTING"
+            }
+        ]
+    },
+    "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+    "version": 1,
+    "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+    "bomFormat": "CycloneDX",
+    "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/own/json/1.4/indented_None.json b/tests/_data/own/json/1.4/indented_None.json
new file mode 100644
index 000000000..5f0687d8c
--- /dev/null
+++ b/tests/_data/own/json/1.4/indented_None.json
@@ -0,0 +1 @@
+{"components": [{"author": "Test Author", "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", "licenses": [{"expression": "MIT License"}], "name": "setuptools", "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", "type": "library", "version": "50.3.2"}], "dependencies": [{"ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"}], "metadata": {"timestamp": "2021-12-31T10:00:00+00:00", "tools": [{"externalReferences": [{"type": "build-system", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"}, {"type": "distribution", "url": "https://pypi.org/project/cyclonedx-python-lib/"}, {"type": "documentation", "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"}, {"type": "issue-tracker", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"}, {"type": "license", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"}, {"type": "release-notes", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"}, {"type": "vcs", "url": "https://github.com/CycloneDX/cyclonedx-python-lib"}, {"type": "website", "url": "https://cyclonedx.org"}], "name": "cyclonedx-python-lib", "vendor": "CycloneDX", "version": "TESTING"}]}, "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", "version": 1, "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json", "bomFormat": "CycloneDX", "specVersion": "1.4"}
\ No newline at end of file
diff --git a/tests/_data/own/json/1.4/indented_tab.json b/tests/_data/own/json/1.4/indented_tab.json
new file mode 100644
index 000000000..5f4ddb09a
--- /dev/null
+++ b/tests/_data/own/json/1.4/indented_tab.json
@@ -0,0 +1,71 @@
+{
+	"components": [
+		{
+			"author": "Test Author",
+			"bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+			"licenses": [
+				{
+					"expression": "MIT License"
+				}
+			],
+			"name": "setuptools",
+			"purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+			"type": "library",
+			"version": "50.3.2"
+		}
+	],
+	"dependencies": [
+		{
+			"ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+		}
+	],
+	"metadata": {
+		"timestamp": "2021-12-31T10:00:00+00:00",
+		"tools": [
+			{
+				"externalReferences": [
+					{
+						"type": "build-system",
+						"url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+					},
+					{
+						"type": "distribution",
+						"url": "https://pypi.org/project/cyclonedx-python-lib/"
+					},
+					{
+						"type": "documentation",
+						"url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+					},
+					{
+						"type": "issue-tracker",
+						"url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+					},
+					{
+						"type": "license",
+						"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+					},
+					{
+						"type": "release-notes",
+						"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+					},
+					{
+						"type": "vcs",
+						"url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+					},
+					{
+						"type": "website",
+						"url": "https://cyclonedx.org"
+					}
+				],
+				"name": "cyclonedx-python-lib",
+				"vendor": "CycloneDX",
+				"version": "TESTING"
+			}
+		]
+	},
+	"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+	"version": 1,
+	"$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+	"bomFormat": "CycloneDX",
+	"specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/own/json/1.4/indented_two.json b/tests/_data/own/json/1.4/indented_two.json
new file mode 100644
index 000000000..8d60c03db
--- /dev/null
+++ b/tests/_data/own/json/1.4/indented_two.json
@@ -0,0 +1,71 @@
+{
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+    }
+  ],
+  "metadata": {
+    "timestamp": "2021-12-31T10:00:00+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/own/xml/1.4/indented_4spaces.xml b/tests/_data/own/xml/1.4/indented_4spaces.xml
new file mode 100644
index 000000000..d59c71266
--- /dev/null
+++ b/tests/_data/own/xml/1.4/indented_4spaces.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
+    <metadata>
+        <timestamp>2021-12-31T10:00:00+00:00</timestamp>
+        <tools>
+            <tool>
+                <vendor>CycloneDX</vendor>
+                <name>cyclonedx-python-lib</name>
+                <version>TESTING</version>
+                <externalReferences>
+                    <reference type="build-system">
+                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+                    </reference>
+                    <reference type="distribution">
+                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+                    </reference>
+                    <reference type="documentation">
+                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+                    </reference>
+                    <reference type="issue-tracker">
+                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+                    </reference>
+                    <reference type="license">
+                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+                    </reference>
+                    <reference type="release-notes">
+                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+                    </reference>
+                    <reference type="vcs">
+                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+                    </reference>
+                    <reference type="website">
+                        <url>https://cyclonedx.org</url>
+                    </reference>
+                </externalReferences>
+            </tool>
+        </tools>
+    </metadata>
+    <components>
+        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+                <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+        </component>
+    </components>
+    <dependencies>
+        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+    </dependencies>
+</bom>
diff --git a/tests/_data/own/xml/1.4/indented_None.xml b/tests/_data/own/xml/1.4/indented_None.xml
new file mode 100644
index 000000000..52d425fb9
--- /dev/null
+++ b/tests/_data/own/xml/1.4/indented_None.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1"><metadata><timestamp>2021-12-31T10:00:00+00:00</timestamp><tools><tool><vendor>CycloneDX</vendor><name>cyclonedx-python-lib</name><version>TESTING</version><externalReferences><reference type="build-system"><url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url></reference><reference type="distribution"><url>https://pypi.org/project/cyclonedx-python-lib/</url></reference><reference type="documentation"><url>https://cyclonedx.github.io/cyclonedx-python-lib/</url></reference><reference type="issue-tracker"><url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url></reference><reference type="license"><url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url></reference><reference type="release-notes"><url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url></reference><reference type="vcs"><url>https://github.com/CycloneDX/cyclonedx-python-lib</url></reference><reference type="website"><url>https://cyclonedx.org</url></reference></externalReferences></tool></tools></metadata><components><component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"><author>Test Author</author><name>setuptools</name><version>50.3.2</version><licenses><expression>MIT License</expression></licenses><purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl></component></components><dependencies><dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz" /></dependencies></bom>
\ No newline at end of file
diff --git a/tests/_data/own/xml/1.4/indented_tab.xml b/tests/_data/own/xml/1.4/indented_tab.xml
new file mode 100644
index 000000000..48d7c99f3
--- /dev/null
+++ b/tests/_data/own/xml/1.4/indented_tab.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
+	<metadata>
+		<timestamp>2021-12-31T10:00:00+00:00</timestamp>
+		<tools>
+			<tool>
+				<vendor>CycloneDX</vendor>
+				<name>cyclonedx-python-lib</name>
+				<version>TESTING</version>
+				<externalReferences>
+					<reference type="build-system">
+						<url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+					</reference>
+					<reference type="distribution">
+						<url>https://pypi.org/project/cyclonedx-python-lib/</url>
+					</reference>
+					<reference type="documentation">
+						<url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+					</reference>
+					<reference type="issue-tracker">
+						<url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+					</reference>
+					<reference type="license">
+						<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+					</reference>
+					<reference type="release-notes">
+						<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+					</reference>
+					<reference type="vcs">
+						<url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+					</reference>
+					<reference type="website">
+						<url>https://cyclonedx.org</url>
+					</reference>
+				</externalReferences>
+			</tool>
+		</tools>
+	</metadata>
+	<components>
+		<component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+			<author>Test Author</author>
+			<name>setuptools</name>
+			<version>50.3.2</version>
+			<licenses>
+				<expression>MIT License</expression>
+			</licenses>
+			<purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+		</component>
+	</components>
+	<dependencies>
+		<dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+	</dependencies>
+</bom>
diff --git a/tests/_data/own/xml/1.4/indented_two.xml b/tests/_data/own/xml/1.4/indented_two.xml
new file mode 100644
index 000000000..ce7e1a87c
--- /dev/null
+++ b/tests/_data/own/xml/1.4/indented_two.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
+  <metadata>
+    <timestamp>2021-12-31T10:00:00+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/schemaTestData/.gitattributes b/tests/_data/schemaTestData/.gitattributes
index bcf7bae75..60a50df0b 100644
--- a/tests/_data/schemaTestData/.gitattributes
+++ b/tests/_data/schemaTestData/.gitattributes
@@ -1,2 +1,3 @@
-*/*.json    linguist-vendored
-*/*.xml     linguist-vendored
+*           binary
+*/*.json    linguist-vendored diff=json
+*/*.xml     linguist-vendored diff=xml
diff --git a/tests/test_output_json.py b/tests/test_output_json.py
index 816dc66c3..be72360b3 100644
--- a/tests/test_output_json.py
+++ b/tests/test_output_json.py
@@ -17,20 +17,23 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 from os.path import join
+from typing import Optional, Union
 from unittest import TestCase
 from unittest.mock import Mock, patch
 from uuid import UUID
 
-from ddt import ddt, idata
+from ddt import ddt, idata, named_data
 
 from cyclonedx.exception.output import FormatNotSupportedException
 from cyclonedx.model.bom import Bom
-from cyclonedx.output import get_instance
+from cyclonedx.output import get_instance as get_outputter
 from cyclonedx.output.json import BY_SCHEMA_VERSION, Json
 from cyclonedx.schema import OutputFormat, SchemaVersion
 from tests import TESTDATA_DIRECTORY
 from tests.base import BaseJsonTestCase
 from tests.data import (
+    MOCK_BOM_UUID_1,
+    MOCK_TIMESTAMP,
     MOCK_UUID_1,
     MOCK_UUID_2,
     MOCK_UUID_3,
@@ -59,6 +62,7 @@
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'json')
 
 
+@ddt
 @patch('cyclonedx.model.ThisTool._version', 'TESTING')
 class TestOutputJson(BaseJsonTestCase):
 
@@ -401,10 +405,28 @@ def test_bom_v1_4_warn_dependencies(self) -> None:
                 fixture='bom_with_dependencies_hanging.json'
             )
 
+    @named_data(
+        ('None', 'None', None),
+        ('two', 'two', 2),
+        ('4spaces', '4spaces', '    '),
+        ('tab', 'tab', '\t')
+    )
+    def test_indent(self, name: str, indent: Optional[Union[str, int]]) -> None:
+        bom = get_bom_with_component_setuptools_basic()
+        bom.serial_number = MOCK_BOM_UUID_1
+        bom.metadata.timestamp = MOCK_TIMESTAMP
+        schema_version = SchemaVersion.V1_4
+        outputter = get_outputter(bom=bom, schema_version=schema_version, output_format=OutputFormat.JSON)
+        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), f'indented_{name}.json')
+                  ) as expected_xml:
+            bom_json = outputter.output_as_string(indent=indent)
+            self.assertEqual(expected_xml.read(), bom_json)
+            self.assertValidAgainstSchema(bom_json=bom_json, schema_version=schema_version)
+
     # region Helper methods
 
     def _validate_json_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
-        outputter = get_instance(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
+        outputter = get_outputter(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
         with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as expected_json:
             output_as_string = outputter.output_as_string()
             self.assertValidAgainstSchema(bom_json=output_as_string, schema_version=schema_version)
@@ -412,7 +434,7 @@ def _validate_json_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: s
 
     def _validate_json_bom_not_supported(self, bom: Bom, schema_version: SchemaVersion) -> None:
         with self.assertRaises(FormatNotSupportedException):
-            outputter = get_instance(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
+            outputter = get_outputter(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
             outputter.output_as_string()
 
     # endregion Helper methods
@@ -422,7 +444,7 @@ def _validate_json_bom_not_supported(self, bom: Bom, schema_version: SchemaVersi
 class TestFunctionalBySchemaVersion(TestCase):
 
     @idata(SchemaVersion)
-    def test_get_instance_expected(self, sv: SchemaVersion) -> None:
+    def test_get_outputter_expected(self, sv: SchemaVersion) -> None:
         outputterClass = BY_SCHEMA_VERSION[sv]
         self.assertTrue(issubclass(outputterClass, Json))
         outputter = outputterClass(Mock(spec=Bom))
diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py
index c5c94d0a1..dc6e19898 100644
--- a/tests/test_output_xml.py
+++ b/tests/test_output_xml.py
@@ -17,19 +17,22 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 from os.path import join
+from typing import Optional, Union
 from unittest import TestCase
 from unittest.mock import Mock, patch
 from uuid import UUID
 
-from ddt import ddt, idata
+from ddt import ddt, idata, named_data
 
 from cyclonedx.model.bom import Bom
-from cyclonedx.output import get_instance
+from cyclonedx.output import get_instance as get_outputter
 from cyclonedx.output.xml import BY_SCHEMA_VERSION, Xml
 from cyclonedx.schema import OutputFormat, SchemaVersion
 from tests import TESTDATA_DIRECTORY
 from tests.base import BaseXmlTestCase
 from tests.data import (
+    MOCK_BOM_UUID_1,
+    MOCK_TIMESTAMP,
     MOCK_UUID_1,
     MOCK_UUID_2,
     MOCK_UUID_3,
@@ -58,6 +61,7 @@
 RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
 
 
+@ddt
 @patch('cyclonedx.model.ThisTool._version', 'TESTING')
 class TestOutputXml(BaseXmlTestCase):
 
@@ -531,10 +535,28 @@ def test_bom_v1_4_warn_dependencies(self) -> None:
                 fixture='bom_with_dependencies_hanging.xml'
             )
 
+    @named_data(
+        ('None', 'None', None),
+        ('two', 'two', 2),
+        ('4spaces', '4spaces', '    '),
+        ('tab', 'tab', '\t')
+    )
+    def test_indent(self, name: str, indent: Optional[Union[str, int]]) -> None:
+        bom = get_bom_with_component_setuptools_basic()
+        bom.serial_number = MOCK_BOM_UUID_1
+        bom.metadata.timestamp = MOCK_TIMESTAMP
+        schema_version = SchemaVersion.V1_4
+        outputter = get_outputter(bom=bom, schema_version=schema_version, output_format=OutputFormat.XML)
+        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), f'indented_{name}.xml')
+                  ) as expected_xml:
+            bom_xml = outputter.output_as_string(indent=indent)
+            self.assertEqual(expected_xml.read(), bom_xml)
+            self.assertValidAgainstSchema(bom_xml=bom_xml, schema_version=schema_version)
+
     # region Helper methods
 
     def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
-        outputter = get_instance(bom=bom, schema_version=schema_version)
+        outputter = get_outputter(bom=bom, schema_version=schema_version)
         with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as expected_xml:
             output_as_string = outputter.output_as_string()
             self.assertValidAgainstSchema(bom_xml=output_as_string, schema_version=schema_version)
@@ -549,7 +571,7 @@ def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: st
 class TestFunctionalBySchemaVersion(TestCase):
 
     @idata(SchemaVersion)
-    def test_get_instance_expected(self, sv: SchemaVersion) -> None:
+    def test_get_outputter_expected(self, sv: SchemaVersion) -> None:
         outputterClass = BY_SCHEMA_VERSION[sv]
         self.assertTrue(issubclass(outputterClass, Xml))
         outputter = outputterClass(Mock(spec=Bom))

From 5d7b86c0ba84fe17becc53b2ccf4385113f90905 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Wed, 4 Oct 2023 12:52:55 +0200
Subject: [PATCH 16/42] perf: make validation more secure

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/validation/xml.py | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index 18a55061f..2fbb585e4 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -65,11 +65,16 @@ def _validata_data(self, data: Any) -> Optional[ValidationError]:
 
         __validator: Optional['XMLSchema'] = None
 
-        __xml_parser = XMLParser(
-            resolve_entities=False,
-            no_network=True,
-            huge_tree=True,
-            compact=True)
+        @property
+        def __xml_parser(self) -> XMLParser:
+            return XMLParser(
+                attribute_defaults=False, dtd_validation=False, load_dtd=False,
+                no_network=True,
+                resolve_entities=False,
+                huge_tree=True,
+                compact=True,
+                recover=False
+            )
 
         @property
         def _validator(self) -> 'XMLSchema':

From 37219c321ac7ce5b507a0c0a74776f8204b400bf Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Wed, 4 Oct 2023 22:54:46 +0200
Subject: [PATCH 17/42] chore: remove encoding hint (#459)

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .readthedocs.yaml                   |  4 +---
 cyclonedx/__init__.py               |  2 --
 cyclonedx/exception/__init__.py     |  2 --
 cyclonedx/exception/factory.py      |  2 --
 cyclonedx/exception/model.py        |  2 --
 cyclonedx/exception/output.py       |  2 --
 cyclonedx/factory/__init__.py       |  2 --
 cyclonedx/factory/license.py        |  2 --
 cyclonedx/model/__init__.py         |  2 --
 cyclonedx/model/bom.py              |  2 --
 cyclonedx/model/bom_ref.py          |  2 --
 cyclonedx/model/component.py        |  2 --
 cyclonedx/model/dependency.py       |  2 --
 cyclonedx/model/impact_analysis.py  |  2 --
 cyclonedx/model/issue.py            |  2 --
 cyclonedx/model/release_note.py     |  2 --
 cyclonedx/model/service.py          |  2 --
 cyclonedx/model/vulnerability.py    |  2 --
 cyclonedx/output/__init__.py        |  2 --
 cyclonedx/output/json.py            |  2 --
 cyclonedx/output/xml.py             |  2 --
 cyclonedx/parser/__init__.py        |  2 --
 cyclonedx/schema/__init__.py        |  2 --
 cyclonedx/schema/_res/__init__.py   |  2 --
 cyclonedx/schema/schema.py          |  2 --
 cyclonedx/serialization/__init__.py |  2 --
 cyclonedx/spdx.py                   |  2 --
 cyclonedx/validation/__init__.py    |  2 --
 cyclonedx/validation/json.py        |  2 --
 cyclonedx/validation/xml.py         |  2 --
 docs/conf.py                        |  2 --
 examples/complex.py                 | 17 ++++++++++++++
 tests/__init__.py                   |  2 --
 tests/base.py                       |  2 --
 tests/data.py                       |  2 --
 tests/test_component.py             |  2 --
 tests/test_deserialize_json.py      |  2 --
 tests/test_deserialize_xml.py       |  2 --
 tests/test_e2e_environment.py       |  2 --
 tests/test_factory_license.py       |  2 --
 tests/test_model.py                 |  2 --
 tests/test_model_bom.py             | 36 ++++++++++++++---------------
 tests/test_model_bom_ref.py         |  2 --
 tests/test_model_component.py       |  2 --
 tests/test_model_dependency.py      |  2 --
 tests/test_model_issue.py           |  2 --
 tests/test_model_release_note.py    |  2 --
 tests/test_model_service.py         |  2 --
 tests/test_model_vulnerability.py   |  2 --
 tests/test_output.py                |  2 --
 tests/test_output_generic.py        |  2 --
 tests/test_output_json.py           |  2 --
 tests/test_output_xml.py            |  2 --
 tests/test_real_world_examples.py   |  1 -
 tests/test_schema_SchemaVersion.py  |  2 --
 tests/test_schema__res.py           |  2 --
 tests/test_spdx.py                  |  2 --
 tests/test_validation.py            |  2 --
 tests/test_validation_json.py       |  2 --
 tests/test_validation_xml.py        |  2 --
 tools/schema-downloader.py          |  8 +++----
 61 files changed, 39 insertions(+), 139 deletions(-)

diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 2249d1491..18c0946dd 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
@@ -42,4 +40,4 @@ python:
    install:
      - method: pip
        path: .
-     - requirements: docs/requirements.txt
\ No newline at end of file
+     - requirements: docs/requirements.txt
diff --git a/cyclonedx/__init__.py b/cyclonedx/__init__.py
index 53b0998ac..449a92d85 100644
--- a/cyclonedx/__init__.py
+++ b/cyclonedx/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/exception/__init__.py b/cyclonedx/exception/__init__.py
index 1845b0063..72752a732 100644
--- a/cyclonedx/exception/__init__.py
+++ b/cyclonedx/exception/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/exception/factory.py b/cyclonedx/exception/factory.py
index 87540f859..5211f9e83 100644
--- a/cyclonedx/exception/factory.py
+++ b/cyclonedx/exception/factory.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/exception/model.py b/cyclonedx/exception/model.py
index f0c07383e..5481983c9 100644
--- a/cyclonedx/exception/model.py
+++ b/cyclonedx/exception/model.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/exception/output.py b/cyclonedx/exception/output.py
index 4dbb70780..7bdf45ce1 100644
--- a/cyclonedx/exception/output.py
+++ b/cyclonedx/exception/output.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/factory/__init__.py b/cyclonedx/factory/__init__.py
index 4cf62cdc3..50e0bf375 100644
--- a/cyclonedx/factory/__init__.py
+++ b/cyclonedx/factory/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/factory/license.py b/cyclonedx/factory/license.py
index 5d21c0124..9974c0462 100644
--- a/cyclonedx/factory/license.py
+++ b/cyclonedx/factory/license.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
index 47f709a10..53beba00d 100644
--- a/cyclonedx/model/__init__.py
+++ b/cyclonedx/model/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
index a66ba0c64..67f04ed64 100644
--- a/cyclonedx/model/bom.py
+++ b/cyclonedx/model/bom.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/model/bom_ref.py b/cyclonedx/model/bom_ref.py
index 79dad0a3b..bd35f1ff7 100644
--- a/cyclonedx/model/bom_ref.py
+++ b/cyclonedx/model/bom_ref.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py
index f3fd386d3..516e11b71 100644
--- a/cyclonedx/model/component.py
+++ b/cyclonedx/model/component.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/model/dependency.py b/cyclonedx/model/dependency.py
index d275b1600..34155874f 100644
--- a/cyclonedx/model/dependency.py
+++ b/cyclonedx/model/dependency.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/model/impact_analysis.py b/cyclonedx/model/impact_analysis.py
index 830912f6e..16d5914b4 100644
--- a/cyclonedx/model/impact_analysis.py
+++ b/cyclonedx/model/impact_analysis.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/model/issue.py b/cyclonedx/model/issue.py
index 8584fb0a5..722cb5b65 100644
--- a/cyclonedx/model/issue.py
+++ b/cyclonedx/model/issue.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/model/release_note.py b/cyclonedx/model/release_note.py
index c5164352f..4464f587f 100644
--- a/cyclonedx/model/release_note.py
+++ b/cyclonedx/model/release_note.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/model/service.py b/cyclonedx/model/service.py
index 7dbbccf75..16efea3a3 100644
--- a/cyclonedx/model/service.py
+++ b/cyclonedx/model/service.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py
index 07f284a34..4742db42b 100644
--- a/cyclonedx/model/vulnerability.py
+++ b/cyclonedx/model/vulnerability.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index 474a710d9..b126501d2 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/output/json.py b/cyclonedx/output/json.py
index c4ba023d6..2f6c4c778 100644
--- a/cyclonedx/output/json.py
+++ b/cyclonedx/output/json.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/output/xml.py b/cyclonedx/output/xml.py
index 8642ec509..9bbf945dd 100644
--- a/cyclonedx/output/xml.py
+++ b/cyclonedx/output/xml.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/parser/__init__.py b/cyclonedx/parser/__init__.py
index 1589f3cd1..c69cdf1c2 100644
--- a/cyclonedx/parser/__init__.py
+++ b/cyclonedx/parser/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/schema/__init__.py b/cyclonedx/schema/__init__.py
index 361dcbca3..fbbe92d7d 100644
--- a/cyclonedx/schema/__init__.py
+++ b/cyclonedx/schema/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/schema/_res/__init__.py b/cyclonedx/schema/_res/__init__.py
index 13b30823e..8089d9432 100644
--- a/cyclonedx/schema/_res/__init__.py
+++ b/cyclonedx/schema/_res/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/schema/schema.py b/cyclonedx/schema/schema.py
index 5de943db9..cb5d1e271 100644
--- a/cyclonedx/schema/schema.py
+++ b/cyclonedx/schema/schema.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/cyclonedx/serialization/__init__.py b/cyclonedx/serialization/__init__.py
index 7e84379e7..925dd4d45 100644
--- a/cyclonedx/serialization/__init__.py
+++ b/cyclonedx/serialization/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/spdx.py b/cyclonedx/spdx.py
index 6a684f978..3eae62217 100644
--- a/cyclonedx/spdx.py
+++ b/cyclonedx/spdx.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/validation/__init__.py b/cyclonedx/validation/__init__.py
index 445613f34..e8b207de8 100644
--- a/cyclonedx/validation/__init__.py
+++ b/cyclonedx/validation/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
index edf4616fc..d97d276c7 100644
--- a/cyclonedx/validation/json.py
+++ b/cyclonedx/validation/json.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index 2fbb585e4..668903165 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/docs/conf.py b/docs/conf.py
index 5abdefc51..f6672dbc5 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # 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
diff --git a/examples/complex.py b/examples/complex.py
index a2f5fb6f3..4c291b2dc 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -1,3 +1,20 @@
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 import sys
 
 from packageurl import PackageURL
diff --git a/tests/__init__.py b/tests/__init__.py
index 0b497f9e5..ff33a2b8e 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/base.py b/tests/base.py
index 5d4fec7db..371b53c63 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/data.py b/tests/data.py
index d0d3afb51..3d8829318 100644
--- a/tests/data.py
+++ b/tests/data.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_component.py b/tests/test_component.py
index baa578304..a344d880c 100644
--- a/tests/test_component.py
+++ b/tests/test_component.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_deserialize_json.py b/tests/test_deserialize_json.py
index bb9b626fc..1f07252fb 100644
--- a/tests/test_deserialize_json.py
+++ b/tests/test_deserialize_json.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_deserialize_xml.py b/tests/test_deserialize_xml.py
index f1a955779..f9502fb4d 100644
--- a/tests/test_deserialize_xml.py
+++ b/tests/test_deserialize_xml.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_e2e_environment.py b/tests/test_e2e_environment.py
index 165fc9d93..3a7460ea2 100644
--- a/tests/test_e2e_environment.py
+++ b/tests/test_e2e_environment.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_factory_license.py b/tests/test_factory_license.py
index 007989676..022f6ac25 100644
--- a/tests/test_factory_license.py
+++ b/tests/test_factory_license.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_model.py b/tests/test_model.py
index 0ee5b3bd0..edbe7a9cc 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_model_bom.py b/tests/test_model_bom.py
index 18567c72c..50897ef42 100644
--- a/tests/test_model_bom.py
+++ b/tests/test_model_bom.py
@@ -1,4 +1,21 @@
-# encoding: utf-8
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+
 from typing import Callable
 from unittest import TestCase
 from uuid import uuid4
@@ -31,23 +48,6 @@
     get_component_setuptools_simple_no_version,
 )
 
-# This file is part of CycloneDX Python Lib
-#
-# 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-# Copyright (c) OWASP Foundation. All Rights Reserved.
-
 
 class TestBomMetaData(TestCase):
 
diff --git a/tests/test_model_bom_ref.py b/tests/test_model_bom_ref.py
index f7ae4a48d..955469bc3 100644
--- a/tests/test_model_bom_ref.py
+++ b/tests/test_model_bom_ref.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_model_component.py b/tests/test_model_component.py
index eeb2fda62..bb58049bd 100644
--- a/tests/test_model_component.py
+++ b/tests/test_model_component.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_model_dependency.py b/tests/test_model_dependency.py
index 40186a706..165bcfca8 100644
--- a/tests/test_model_dependency.py
+++ b/tests/test_model_dependency.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_model_issue.py b/tests/test_model_issue.py
index 383df5d4c..bc156169d 100644
--- a/tests/test_model_issue.py
+++ b/tests/test_model_issue.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_model_release_note.py b/tests/test_model_release_note.py
index a06025afe..c65f1ad28 100644
--- a/tests/test_model_release_note.py
+++ b/tests/test_model_release_note.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_model_service.py b/tests/test_model_service.py
index 909aa2b1f..588cf2d53 100644
--- a/tests/test_model_service.py
+++ b/tests/test_model_service.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_model_vulnerability.py b/tests/test_model_vulnerability.py
index c3e331348..257b82a8b 100644
--- a/tests/test_model_vulnerability.py
+++ b/tests/test_model_vulnerability.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_output.py b/tests/test_output.py
index 90e991a18..71a1b995b 100644
--- a/tests/test_output.py
+++ b/tests/test_output.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_output_generic.py b/tests/test_output_generic.py
index 7325cbeef..c664e50f8 100644
--- a/tests/test_output_generic.py
+++ b/tests/test_output_generic.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_output_json.py b/tests/test_output_json.py
index be72360b3..f40802625 100644
--- a/tests/test_output_json.py
+++ b/tests/test_output_json.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py
index dc6e19898..5303cb9f0 100644
--- a/tests/test_output_xml.py
+++ b/tests/test_output_xml.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_real_world_examples.py b/tests/test_real_world_examples.py
index 6ce3cf90b..7be3b081e 100644
--- a/tests/test_real_world_examples.py
+++ b/tests/test_real_world_examples.py
@@ -1,4 +1,3 @@
-# encoding: utf-8
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_schema_SchemaVersion.py b/tests/test_schema_SchemaVersion.py
index 988b5fe0d..912c43b2e 100644
--- a/tests/test_schema_SchemaVersion.py
+++ b/tests/test_schema_SchemaVersion.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_schema__res.py b/tests/test_schema__res.py
index 93981bcc5..930d3709b 100644
--- a/tests/test_schema__res.py
+++ b/tests/test_schema__res.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_spdx.py b/tests/test_spdx.py
index 98c51dc69..b5ea6cde5 100644
--- a/tests/test_spdx.py
+++ b/tests/test_spdx.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_validation.py b/tests/test_validation.py
index b7e3dfbd5..eae92c930 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_validation_json.py b/tests/test_validation_json.py
index 18edb10b1..45f06179e 100644
--- a/tests/test_validation_json.py
+++ b/tests/test_validation_json.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tests/test_validation_xml.py b/tests/test_validation_xml.py
index 60bc749cd..a08c932d7 100644
--- a/tests/test_validation_xml.py
+++ b/tests/test_validation_xml.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 # This file is part of CycloneDX Python Lib
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/tools/schema-downloader.py b/tools/schema-downloader.py
index 928b00106..6027117ff 100644
--- a/tools/schema-downloader.py
+++ b/tools/schema-downloader.py
@@ -1,8 +1,3 @@
-# encoding: utf-8
-import re
-from os.path import dirname, join
-from urllib.request import urlretrieve
-
 # 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
@@ -17,6 +12,9 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
+import re
+from os.path import dirname, join
+from urllib.request import urlretrieve
 
 SOURCE_ROOT = 'https://raw.githubusercontent.com/CycloneDX/specification/master/schema/'
 TARGET_ROOT = join(dirname(__file__), '..', 'cyclonedx', 'schema', '_res')

From eaba7a048de190bce0797fb9ce40c4e2de49c5d9 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Wed, 4 Oct 2023 22:55:09 +0200
Subject: [PATCH 18/42] feat: support python 3.12 (#460)

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .github/workflows/python.yml | 7 ++++---
 pyproject.toml               | 1 +
 tox.ini                      | 2 +-
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 6d6f69d2c..dd4799f98 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -58,7 +58,7 @@ jobs:
         include:
           - # test with the latest dependencies
             os: ubuntu-latest
-            python-version: '3.11'
+            python-version: '3.12'
             toxenv-factors: '-current'
           - # test with the lowest dependencies
             os: ubuntu-latest
@@ -93,7 +93,8 @@ jobs:
       matrix:
         os: ['ubuntu-latest', 'windows-latest', 'macos-latest']
         python-version:
-          - "3.11" # highest supported
+          - "3.12" # highest supported
+          - "3.11"
           - "3.10"
           - "3.9"
           - "3.8"  # lowest supported
@@ -189,7 +190,7 @@ jobs:
         # see https://github.com/actions/setup-python
         uses: actions/setup-python@v4
         with:
-          python-version: '>=3.8 <=3.11'  # supported version range
+          python-version: '>=3.8 <=3.12'  # supported version range
       - name: Validate Python Environment
         shell: python
         run: |
diff --git a/pyproject.toml b/pyproject.toml
index 0dcc1f0ae..9010a7779 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -47,6 +47,7 @@ classifiers = [
   'Programming Language :: Python :: 3.9',
   'Programming Language :: Python :: 3.10',
   'Programming Language :: Python :: 3.11',
+  'Programming Language :: Python :: 3.12',
   'Typing :: Typed',
 ]
 keywords = [
diff --git a/tox.ini b/tox.ini
index 334865927..6b16c1c89 100644
--- a/tox.ini
+++ b/tox.ini
@@ -8,7 +8,7 @@ minversion = 4.0
 envlist =
     flake8
     mypy-{current,lowest}
-    py{311,310,39,38}-{allExtras,noExtras}
+    py{312,311,310,39,38}-{allExtras,noExtras}
 skip_missing_interpreters = True
 usedevelop = False
 download = False

From ac6ad0ed5b5933f03d1132c3bbce0ada1915fc40 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Thu, 5 Oct 2023 10:29:10 +0200
Subject: [PATCH 19/42] chore: clean deps

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 pyproject.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyproject.toml b/pyproject.toml
index 9010a7779..805eb347e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -64,7 +64,7 @@ packageurl-python = ">= 0.11"
 py-serializable = "^0.13.0"
 sortedcontainers = "^2.4.0"
 license-expression = "^30"
-jsonschema = { version = "^4.18", extras=['format'], optional=true, python="^3.8" }
+jsonschema = { version = "^4.18", extras=['format'], optional=true }
 lxml = { version="^4", optional=true }
 
 [tool.poetry.extras]

From 84c6504fc92d1207135f7719b6b6477fae7950cb Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Thu, 5 Oct 2023 10:29:30 +0200
Subject: [PATCH 20/42] fix: tuple stuff (#461)

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/model/__init__.py      | 17 +++++++----------
 cyclonedx/model/vulnerability.py |  2 +-
 tests/test_model.py              |  8 ++++++++
 tests/test_model_component.py    |  2 +-
 4 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
index 53beba00d..68ce6dc84 100644
--- a/cyclonedx/model/__init__.py
+++ b/cyclonedx/model/__init__.py
@@ -18,6 +18,7 @@
 import warnings
 from datetime import datetime, timezone
 from enum import Enum
+from itertools import zip_longest
 from typing import Any, Iterable, Optional, Tuple, TypeVar
 
 import serializable
@@ -72,31 +73,27 @@ class ComparableTuple(Tuple[Optional[_T], ...]):
     """
 
     def __lt__(self, other: Any) -> bool:
-        for s, o in zip(self, other):
+        for s, o in zip_longest(self, other):
             if s == o:
                 continue
+            # the idea is to have any consistent order, not necessarily "natural" order.
             if s is None:
                 return False
             if o is None:
                 return True
-            if s < o:
-                return True
-            if s > o:
-                return False
+            return True if s < o else False
         return False
 
     def __gt__(self, other: Any) -> bool:
-        for s, o in zip(self, other):
+        for s, o in zip_longest(self, other):
             if s == o:
                 continue
+            # the idea is to have any consistent order, not necessarily "natural" order.
             if s is None:
                 return True
             if o is None:
                 return False
-            if s < o:
-                return False
-            if s > o:
-                return True
+            return True if s > o else False
         return False
 
 
diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py
index 4742db42b..004a28e18 100644
--- a/cyclonedx/model/vulnerability.py
+++ b/cyclonedx/model/vulnerability.py
@@ -561,7 +561,7 @@ class VulnerabilitySeverity(str, Enum):
     UNKNOWN = 'unknown'
 
     @staticmethod
-    def get_from_cvss_scores(scores: Union[Tuple[float], float, None]) -> 'VulnerabilitySeverity':
+    def get_from_cvss_scores(scores: Union[Tuple[float, ...], float, None]) -> 'VulnerabilitySeverity':
         """
         Derives the Severity of a Vulnerability from it's declared CVSS scores.
 
diff --git a/tests/test_model.py b/tests/test_model.py
index edbe7a9cc..8459af3bd 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -132,6 +132,14 @@ def test_compare_last_item_none(self) -> None:
         self.assertNotEqual(tuple1, tuple2)
         self.assertNotEqual(tuple2, tuple1)
 
+    def test_compare_last_item_missing(self) -> None:
+        tuple1 = ComparableTuple((1, 2, 3, 4, 5))
+        tuple2 = ComparableTuple((1, 2, 3, 4))
+        self.assertLess(tuple1, tuple2)
+        self.assertGreater(tuple2, tuple1)
+        self.assertNotEqual(tuple1, tuple2)
+        self.assertNotEqual(tuple2, tuple1)
+
     def test_compare_enum(self) -> None:
         tuple1 = ComparableTuple((DummyStringEnum.FIRST, ))
         tuple2 = ComparableTuple((DummyStringEnum.SECOND, ))
diff --git a/tests/test_model_component.py b/tests/test_model_component.py
index bb58049bd..c48bb630c 100644
--- a/tests/test_model_component.py
+++ b/tests/test_model_component.py
@@ -427,7 +427,7 @@ def test_sort(self) -> None:
         ]
 
         # expected sort order: (type, [diff], sorted(resolves))
-        expected_order = [5, 4, 2, 3, 1, 0]
+        expected_order = [5, 4, 3, 2, 1, 0]
         patches = [
             Patch(type=PatchClassification.MONKEY),
             Patch(type=PatchClassification.MONKEY, diff=diff_b),

From 2240b4dda824c13bc563bce1574dffe563016ac2 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Thu, 5 Oct 2023 13:23:18 +0200
Subject: [PATCH 21/42] fix: typing for `kwargs` (#462)

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/output/__init__.py | 6 +++---
 cyclonedx/output/json.py     | 2 +-
 cyclonedx/output/xml.py      | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index b126501d2..e151c1bf0 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -20,7 +20,7 @@
 import os
 from abc import ABC, abstractmethod
 from importlib import import_module
-from typing import Any, Dict, Iterable, Optional, Type, Union
+from typing import Any, Iterable, Optional, Type, Union
 
 from ..model.bom import Bom
 from ..model.component import Component
@@ -72,12 +72,12 @@ def generate(self, force_regeneration: bool = False) -> None:
     @abstractmethod
     def output_as_string(self, *,
                          indent: Optional[Union[int, str]] = None,
-                         **kwargs: Dict[str, Any]) -> str:
+                         **kwargs: Any) -> str:
         ...
 
     def output_to_file(self, filename: str, allow_overwrite: bool = False, *,
                        indent: Optional[Union[int, str]] = None,
-                       **kwargs: Dict[str, Any]) -> None:
+                       **kwargs: Any) -> None:
         # Check directory writable
         output_filename = os.path.realpath(filename)
         output_directory = os.path.dirname(output_filename)
diff --git a/cyclonedx/output/json.py b/cyclonedx/output/json.py
index 2f6c4c778..4f9f6fce8 100644
--- a/cyclonedx/output/json.py
+++ b/cyclonedx/output/json.py
@@ -73,7 +73,7 @@ def generate(self, force_regeneration: bool = False) -> None:
 
     def output_as_string(self, *,
                          indent: Optional[Union[int, str]] = None,
-                         **kwargs: Dict[str, Any]) -> str:
+                         **kwargs: Any) -> str:
         self.generate()
         return json_dumps(self._bom_json,
                           indent=indent)
diff --git a/cyclonedx/output/xml.py b/cyclonedx/output/xml.py
index 9bbf945dd..d1fd7fcd7 100644
--- a/cyclonedx/output/xml.py
+++ b/cyclonedx/output/xml.py
@@ -75,7 +75,7 @@ def __make_indent(v: Optional[Union[int, str]]) -> str:
 
     def output_as_string(self, *,
                          indent: Optional[Union[int, str]] = None,
-                         **kwargs: Dict[str, Any]) -> str:
+                         **kwargs: Any) -> str:
         self.generate()
         return self._bom_xml if indent is None else dom_parseString(self._bom_xml).toprettyxml(
             indent=self.__make_indent(indent)

From a68ae2464539d07ed0fc037aa1e315e5ccda054a Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Fri, 6 Oct 2023 13:15:16 +0200
Subject: [PATCH 22/42] Feat: typing, typehints, & overload (#463)

also: bump `py-serializable@^0.14.0`

---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .mypy.ini                         |  2 +-
 cyclonedx/model/bom.py            |  2 +-
 cyclonedx/output/__init__.py      | 48 ++++++++++++++-----
 cyclonedx/output/json.py          | 35 +++++++-------
 cyclonedx/output/xml.py           | 25 +++++-----
 cyclonedx/schema/__init__.py      | 79 ++++++++++++++++++-------------
 cyclonedx/schema/schema.py        | 22 ++++-----
 cyclonedx/spdx.py                 |  2 +-
 cyclonedx/validation/__init__.py  | 34 +++++++++++--
 cyclonedx/validation/json.py      |  8 ++--
 cyclonedx/validation/xml.py       |  6 +--
 examples/complex.py               | 32 ++++++++++---
 pyproject.toml                    |  2 +-
 tests/test_deserialize_xml.py     |  7 ++-
 tests/test_real_world_examples.py |  5 +-
 15 files changed, 197 insertions(+), 112 deletions(-)

diff --git a/.mypy.ini b/.mypy.ini
index c15c04ab1..f86c19531 100644
--- a/.mypy.ini
+++ b/.mypy.ini
@@ -1,6 +1,6 @@
 [mypy]
 
-files = cyclonedx/
+files = cyclonedx/, examples/
 mypy_path = $MYPY_CONFIG_FILE_DIR/typings
 
 show_error_codes = True
diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
index 67f04ed64..776fa8344 100644
--- a/cyclonedx/model/bom.py
+++ b/cyclonedx/model/bom.py
@@ -50,7 +50,7 @@
 from .service import Service
 from .vulnerability import Vulnerability
 
-if TYPE_CHECKING:
+if TYPE_CHECKING:  # pragma: no cover
     from packageurl import PackageURL
 
 
diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index e151c1bf0..fde15bc1d 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -20,23 +20,27 @@
 import os
 from abc import ABC, abstractmethod
 from importlib import import_module
-from typing import Any, Iterable, Optional, Type, Union
+from typing import TYPE_CHECKING, Any, Iterable, Literal, Optional, Type, Union, overload
 
-from ..model.bom import Bom
-from ..model.component import Component
 from ..schema import OutputFormat, SchemaVersion
 
+if TYPE_CHECKING:  # pragma: no cover
+    from ..model.bom import Bom
+    from ..model.component import Component
+    from .json import Json as JsonOutputter
+    from .xml import Xml as XmlOutputter
+
 LATEST_SUPPORTED_SCHEMA_VERSION = SchemaVersion.V1_4
 
 
 class BaseOutput(ABC):
 
-    def __init__(self, bom: Bom, **kwargs: int) -> None:
+    def __init__(self, bom: 'Bom', **kwargs: int) -> None:
         super().__init__(**kwargs)
         self._bom = bom
         self._generated: bool = False
 
-    def _chained_components(self, container: Union[Bom, Component]) -> Iterable[Component]:
+    def _chained_components(self, container: Union['Bom', 'Component']) -> Iterable['Component']:
         for component in container.components:
             yield component
             yield from self._chained_components(component)
@@ -59,10 +63,10 @@ def generated(self) -> bool:
     def generated(self, generated: bool) -> None:
         self._generated = generated
 
-    def get_bom(self) -> Bom:
+    def get_bom(self) -> 'Bom':
         return self._bom
 
-    def set_bom(self, bom: Bom) -> None:
+    def set_bom(self, bom: 'Bom') -> None:
         self._bom = bom
 
     @abstractmethod
@@ -89,17 +93,39 @@ def output_to_file(self, filename: str, allow_overwrite: bool = False, *,
             f_out.write(self.output_as_string(indent=indent).encode('utf-8'))
 
 
-def get_instance(bom: Bom, output_format: OutputFormat = OutputFormat.XML,
+@overload
+def get_instance(bom: 'Bom', output_format: Literal[OutputFormat.JSON],
+                 schema_version: SchemaVersion = ...) -> 'JsonOutputter':
+    ...
+
+
+@overload
+def get_instance(bom: 'Bom', output_format: Literal[OutputFormat.XML] = ...,
+                 schema_version: SchemaVersion = ...) -> 'XmlOutputter':
+    ...
+
+
+@overload
+def get_instance(bom: 'Bom', output_format: OutputFormat = ...,
+                 schema_version: SchemaVersion = ...
+                 ) -> Union['XmlOutputter', 'JsonOutputter']:
+    ...
+
+
+def get_instance(bom: 'Bom', output_format: OutputFormat = OutputFormat.XML,
                  schema_version: SchemaVersion = LATEST_SUPPORTED_SCHEMA_VERSION) -> BaseOutput:
     """
     Helper method to quickly get the correct output class/formatter.
 
     Pass in your BOM and optionally an output format and schema version (defaults to XML and latest schema version).
 
+
+    Raises error when no instance could be built.
+
     :param bom: Bom
     :param output_format: OutputFormat
     :param schema_version: SchemaVersion
-    :return:
+    :return: BaseOutput
     """
     # all exceptions are undocumented, as they are pure functional, and should be prevented by correct typing...
     if not isinstance(output_format, OutputFormat):
@@ -108,9 +134,9 @@ def get_instance(bom: Bom, output_format: OutputFormat = OutputFormat.XML,
         raise TypeError(f"unexpected schema_version: {schema_version!r}")
     try:
         module = import_module(f'.{output_format.name.lower()}', __package__)
-    except ImportError as error:  # pragma: no cover
+    except ImportError as error:
         raise ValueError(f'Unknown output_format: {output_format.name}') from error
     klass: Optional[Type[BaseOutput]] = module.BY_SCHEMA_VERSION.get(schema_version, None)
-    if klass is None:  # pragma: no cover
+    if klass is None:
         raise ValueError(f'Unknown {output_format.name}/schema_version: {schema_version.name}')
     return klass(bom=bom)
diff --git a/cyclonedx/output/json.py b/cyclonedx/output/json.py
index 4f9f6fce8..2fadb30ed 100644
--- a/cyclonedx/output/json.py
+++ b/cyclonedx/output/json.py
@@ -17,10 +17,9 @@
 
 from abc import abstractmethod
 from json import dumps as json_dumps, loads as json_loads
-from typing import Any, Dict, Optional, Type, Union
+from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Type, Union
 
 from ..exception.output import FormatNotSupportedException
-from ..model.bom import Bom
 from ..schema import OutputFormat, SchemaVersion
 from ..schema.schema import (
     SCHEMA_VERSIONS,
@@ -33,10 +32,13 @@
 )
 from . import BaseOutput
 
+if TYPE_CHECKING:  # pragma: no cover
+    from ..model.bom import Bom
+
 
 class Json(BaseOutput, BaseSchemaVersion):
 
-    def __init__(self, bom: Bom) -> None:
+    def __init__(self, bom: 'Bom') -> None:
         super().__init__(bom=bom)
         self._bom_json: Dict[str, Any] = dict()
 
@@ -45,7 +47,7 @@ def schema_version(self) -> SchemaVersion:
         return self.schema_version_enum
 
     @property
-    def output_format(self) -> OutputFormat:
+    def output_format(self) -> Literal[OutputFormat.JSON]:
         return OutputFormat.JSON
 
     def generate(self, force_regeneration: bool = False) -> None:
@@ -63,9 +65,10 @@ def generate(self, force_regeneration: bool = False) -> None:
             'specVersion': self.schema_version.to_version()
         }
         _view = SCHEMA_VERSIONS.get(self.schema_version_enum)
-        self.get_bom().validate()
+        bom = self.get_bom()
+        bom.validate()
         bom_json: Dict[str, Any] = json_loads(
-            self.get_bom().as_json(  # type:ignore[attr-defined]
+            bom.as_json(  # type:ignore[attr-defined]
                 view_=_view))
         bom_json.update(_json_core)
         self._bom_json = bom_json
@@ -85,38 +88,38 @@ def _get_schema_uri(self) -> Optional[str]:
 
 class JsonV1Dot0(Json, SchemaVersion1Dot0):
 
-    def _get_schema_uri(self) -> Optional[str]:
+    def _get_schema_uri(self) -> None:
         return None
 
 
 class JsonV1Dot1(Json, SchemaVersion1Dot1):
 
-    def _get_schema_uri(self) -> Optional[str]:
+    def _get_schema_uri(self) -> None:
         return None
 
 
 class JsonV1Dot2(Json, SchemaVersion1Dot2):
 
-    def _get_schema_uri(self) -> Optional[str]:
+    def _get_schema_uri(self) -> str:
         return 'http://cyclonedx.org/schema/bom-1.2b.schema.json'
 
 
 class JsonV1Dot3(Json, SchemaVersion1Dot3):
 
-    def _get_schema_uri(self) -> Optional[str]:
+    def _get_schema_uri(self) -> str:
         return 'http://cyclonedx.org/schema/bom-1.3a.schema.json'
 
 
 class JsonV1Dot4(Json, SchemaVersion1Dot4):
 
-    def _get_schema_uri(self) -> Optional[str]:
+    def _get_schema_uri(self) -> str:
         return 'http://cyclonedx.org/schema/bom-1.4.schema.json'
 
 
 BY_SCHEMA_VERSION: Dict[SchemaVersion, Type[Json]] = {
-    SchemaVersion.V1_4: JsonV1Dot4,  # type:ignore[type-abstract]
-    SchemaVersion.V1_3: JsonV1Dot3,  # type:ignore[type-abstract]
-    SchemaVersion.V1_2: JsonV1Dot2,  # type:ignore[type-abstract]
-    SchemaVersion.V1_1: JsonV1Dot1,  # type:ignore[type-abstract]
-    SchemaVersion.V1_0: JsonV1Dot0,  # type:ignore[type-abstract]
+    SchemaVersion.V1_4: JsonV1Dot4,
+    SchemaVersion.V1_3: JsonV1Dot3,
+    SchemaVersion.V1_2: JsonV1Dot2,
+    SchemaVersion.V1_1: JsonV1Dot1,
+    SchemaVersion.V1_0: JsonV1Dot0,
 }
diff --git a/cyclonedx/output/xml.py b/cyclonedx/output/xml.py
index d1fd7fcd7..b57e2db89 100644
--- a/cyclonedx/output/xml.py
+++ b/cyclonedx/output/xml.py
@@ -16,11 +16,10 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 
-from typing import Any, Dict, Optional, Type, Union
+from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Type, Union
 from xml.dom.minidom import parseString as dom_parseString
 from xml.etree.ElementTree import Element as XmlElement, tostring as xml_dumps
 
-from ..model.bom import Bom
 from ..schema import OutputFormat, SchemaVersion
 from ..schema.schema import (
     SCHEMA_VERSIONS,
@@ -33,9 +32,12 @@
 )
 from . import BaseOutput
 
+if TYPE_CHECKING:  # pragma: no cover
+    from ..model.bom import Bom
+
 
 class Xml(BaseSchemaVersion, BaseOutput):
-    def __init__(self, bom: Bom) -> None:
+    def __init__(self, bom: 'Bom') -> None:
         super().__init__(bom=bom)
         self._bom_xml: str = ''
 
@@ -44,7 +46,7 @@ def schema_version(self) -> SchemaVersion:
         return self.schema_version_enum
 
     @property
-    def output_format(self) -> OutputFormat:
+    def output_format(self) -> Literal[OutputFormat.XML]:
         return OutputFormat.XML
 
     def generate(self, force_regeneration: bool = False) -> None:
@@ -52,10 +54,11 @@ def generate(self, force_regeneration: bool = False) -> None:
             return
 
         _view = SCHEMA_VERSIONS[self.schema_version_enum]
-        self.get_bom().validate()
+        bom = self.get_bom()
+        bom.validate()
         xmlns = self.get_target_namespace()
         self._bom_xml = '<?xml version="1.0" ?>\n' + xml_dumps(
-            self.get_bom().as_xml(  # type:ignore[attr-defined]
+            bom.as_xml(  # type:ignore[attr-defined]
                 _view, as_string=False, xmlns=xmlns),
             method='xml', default_namespace=xmlns, encoding='unicode',
             # `xml-declaration` is inconsistent/bugged in py38, especially on Windows it will print a non-UTF8 codepage.
@@ -109,9 +112,9 @@ class XmlV1Dot4(Xml, SchemaVersion1Dot4):
 
 
 BY_SCHEMA_VERSION: Dict[SchemaVersion, Type[Xml]] = {
-    SchemaVersion.V1_4: XmlV1Dot4,  # type:ignore[type-abstract]
-    SchemaVersion.V1_3: XmlV1Dot3,  # type:ignore[type-abstract]
-    SchemaVersion.V1_2: XmlV1Dot2,  # type:ignore[type-abstract]
-    SchemaVersion.V1_1: XmlV1Dot1,  # type:ignore[type-abstract]
-    SchemaVersion.V1_0: XmlV1Dot0,  # type:ignore[type-abstract]
+    SchemaVersion.V1_4: XmlV1Dot4,
+    SchemaVersion.V1_3: XmlV1Dot3,
+    SchemaVersion.V1_2: XmlV1Dot2,
+    SchemaVersion.V1_1: XmlV1Dot1,
+    SchemaVersion.V1_0: XmlV1Dot0,
 }
diff --git a/cyclonedx/schema/__init__.py b/cyclonedx/schema/__init__.py
index fbbe92d7d..9c592c252 100644
--- a/cyclonedx/schema/__init__.py
+++ b/cyclonedx/schema/__init__.py
@@ -13,17 +13,28 @@
 # SPDX-License-Identifier: Apache-2.0
 
 from enum import Enum, auto, unique
+from typing import Any, Type, TypeVar
 
 
 @unique
 class OutputFormat(Enum):
     """Output formats.
 
-    Do not rely on the actual/literal values, just use enum cases.
+    Cases are hashable.
+
+    Do not rely on the actual/literal values, just use enum cases, like so:
+        my_of = OutputFormat.XML
     """
+
     JSON = auto()
     XML = auto()
 
+    def __hash__(self) -> int:
+        return hash(self.name)
+
+
+_SV = TypeVar('_SV', bound='SchemaVersion')
+
 
 @unique
 class SchemaVersion(Enum):
@@ -33,8 +44,10 @@ class SchemaVersion(Enum):
     Cases are hashable.
     Cases are comparable(!=,>=,>,==,<,<=)
 
-    Do not rely on the actual/literal values, just use enum cases.
+    Do not rely on the actual/literal values, just use enum cases, like so:
+        my_sv = SchemaVersion.V1_3
     """
+
     V1_4 = (1, 4)
     V1_3 = (1, 3)
     V1_2 = (1, 2)
@@ -42,43 +55,43 @@ class SchemaVersion(Enum):
     V1_0 = (1, 0)
 
     @classmethod
-    def from_version(cls, version: str) -> 'SchemaVersion':
-        """Return instance from  a version string - e.g. `1.4`"""
+    def from_version(cls: Type[_SV], version: str) -> _SV:
+        """Return instance based of a version string - e.g. `1.4`"""
         return cls(tuple(map(int, version.split('.')))[:2])
 
     def to_version(self) -> str:
         """Return as a version string - e.g. `1.4`"""
         return '.'.join(map(str, self.value))
 
-    def __ne__(self, other: object) -> bool:
-        return self.value != other.value \
-            if isinstance(other, self.__class__) \
-            else NotImplemented  # type:ignore[return-value]
-
-    def __lt__(self, other: object) -> bool:
-        return self.value < other.value \
-            if isinstance(other, self.__class__) \
-            else NotImplemented  # type:ignore[return-value]
-
-    def __le__(self, other: object) -> bool:
-        return self.value <= other.value \
-            if isinstance(other, self.__class__) \
-            else NotImplemented  # type:ignore[return-value]
-
-    def __eq__(self, other: object) -> bool:
-        return self.value == other.value \
-            if isinstance(other, self.__class__) \
-            else NotImplemented  # type:ignore[return-value]
-
-    def __ge__(self, other: object) -> bool:
-        return self.value >= other.value \
-            if isinstance(other, self.__class__) \
-            else NotImplemented  # type:ignore[return-value]
-
-    def __gt__(self, other: object) -> bool:
-        return self.value > other.value \
-            if isinstance(other, self.__class__) \
-            else NotImplemented  # type:ignore[return-value]
+    def __ne__(self, other: Any) -> bool:
+        if isinstance(other, self.__class__):
+            return self.value != other.value
+        return NotImplemented  # pragma: no cover
+
+    def __lt__(self, other: Any) -> bool:
+        if isinstance(other, self.__class__):
+            return self.value < other.value
+        return NotImplemented  # pragma: no cover
+
+    def __le__(self, other: Any) -> bool:
+        if isinstance(other, self.__class__):
+            return self.value <= other.value
+        return NotImplemented  # pragma: no cover
+
+    def __eq__(self, other: Any) -> bool:
+        if isinstance(other, self.__class__):
+            return self.value == other.value
+        return NotImplemented  # pragma: no cover
+
+    def __ge__(self, other: Any) -> bool:
+        if isinstance(other, self.__class__):
+            return self.value >= other.value
+        return NotImplemented  # pragma: no cover
+
+    def __gt__(self, other: Any) -> bool:
+        if isinstance(other, self.__class__):
+            return self.value > other.value
+        return NotImplemented  # pragma: no cover
 
     def __hash__(self) -> int:
         return hash(self.name)
diff --git a/cyclonedx/schema/schema.py b/cyclonedx/schema/schema.py
index cb5d1e271..84434212c 100644
--- a/cyclonedx/schema/schema.py
+++ b/cyclonedx/schema/schema.py
@@ -16,7 +16,7 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 from abc import ABC, abstractmethod
-from typing import Dict, Type
+from typing import Dict, Literal, Type
 
 from serializable import ViewType
 
@@ -37,42 +37,42 @@ def get_schema_version(self) -> str:
 class SchemaVersion1Dot4(BaseSchemaVersion):
 
     @property
-    def schema_version_enum(self) -> SchemaVersion:
+    def schema_version_enum(self) -> Literal[SchemaVersion.V1_4]:
         return SchemaVersion.V1_4
 
 
 class SchemaVersion1Dot3(BaseSchemaVersion):
 
     @property
-    def schema_version_enum(self) -> SchemaVersion:
+    def schema_version_enum(self) -> Literal[SchemaVersion.V1_3]:
         return SchemaVersion.V1_3
 
 
 class SchemaVersion1Dot2(BaseSchemaVersion):
 
     @property
-    def schema_version_enum(self) -> SchemaVersion:
+    def schema_version_enum(self) -> Literal[SchemaVersion.V1_2]:
         return SchemaVersion.V1_2
 
 
 class SchemaVersion1Dot1(BaseSchemaVersion):
 
     @property
-    def schema_version_enum(self) -> SchemaVersion:
+    def schema_version_enum(self) -> Literal[SchemaVersion.V1_1]:
         return SchemaVersion.V1_1
 
 
 class SchemaVersion1Dot0(BaseSchemaVersion):
 
     @property
-    def schema_version_enum(self) -> SchemaVersion:
+    def schema_version_enum(self) -> Literal[SchemaVersion.V1_0]:
         return SchemaVersion.V1_0
 
 
 SCHEMA_VERSIONS: Dict[SchemaVersion, Type[BaseSchemaVersion]] = {
-    SchemaVersion.V1_4: SchemaVersion1Dot4,  # type:ignore[type-abstract]
-    SchemaVersion.V1_3: SchemaVersion1Dot3,  # type:ignore[type-abstract]
-    SchemaVersion.V1_2: SchemaVersion1Dot2,  # type:ignore[type-abstract]
-    SchemaVersion.V1_1: SchemaVersion1Dot1,  # type:ignore[type-abstract]
-    SchemaVersion.V1_0: SchemaVersion1Dot0,  # type:ignore[type-abstract]
+    SchemaVersion.V1_4: SchemaVersion1Dot4,
+    SchemaVersion.V1_3: SchemaVersion1Dot3,
+    SchemaVersion.V1_2: SchemaVersion1Dot2,
+    SchemaVersion.V1_1: SchemaVersion1Dot1,
+    SchemaVersion.V1_0: SchemaVersion1Dot0,
 }
diff --git a/cyclonedx/spdx.py b/cyclonedx/spdx.py
index 3eae62217..b7dfe0522 100644
--- a/cyclonedx/spdx.py
+++ b/cyclonedx/spdx.py
@@ -24,7 +24,7 @@
 
 from .schema._res import SPDX_JSON as __SPDX_JSON_SCHEMA
 
-if TYPE_CHECKING:
+if TYPE_CHECKING:  # pragma: no cover
     from license_expression import Licensing
 
 # region init
diff --git a/cyclonedx/validation/__init__.py b/cyclonedx/validation/__init__.py
index e8b207de8..87f183354 100644
--- a/cyclonedx/validation/__init__.py
+++ b/cyclonedx/validation/__init__.py
@@ -14,12 +14,14 @@
 
 from abc import ABC, abstractmethod
 from importlib import import_module
-from typing import TYPE_CHECKING, Any, Optional, Protocol, Type
+from typing import TYPE_CHECKING, Any, Literal, Optional, Protocol, Type, Union, overload
 
 from ..schema import OutputFormat
 
-if TYPE_CHECKING:
+if TYPE_CHECKING:  # pragma: no cover
     from ..schema import SchemaVersion
+    from .json import JsonValidator
+    from .xml import XmlValidator
 
 
 class ValidationError:
@@ -80,15 +82,37 @@ def _schema_file(self) -> Optional[str]:
         ...
 
 
+@overload
+def get_instance(output_format: Literal[OutputFormat.JSON], schema_version: 'SchemaVersion'
+                 ) -> 'JsonValidator':
+    ...
+
+
+@overload
+def get_instance(output_format: Literal[OutputFormat.XML], schema_version: 'SchemaVersion'
+                 ) -> 'XmlValidator':
+    ...
+
+
+@overload
+def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion'
+                 ) -> Union['JsonValidator', 'XmlValidator']:
+    ...
+
+
 def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion') -> BaseValidator:
-    """get the default validator for a certain `OutputFormat`"""
+    """get the default validator for a certain `OutputFormat`
+
+    Raises error when no instance could be built.
+    """
+    # all exceptions are undocumented, as they are pure functional, and should be prevented by correct typing...
     if not isinstance(output_format, OutputFormat):
         raise TypeError(f"unexpected output_format: {output_format!r}")
     try:
         module = import_module(f'.{output_format.name.lower()}', __package__)
-    except ImportError as error:  # pragma: no cover
+    except ImportError as error:
         raise ValueError(f'Unknown output_format: {output_format.name}') from error
     klass: Optional[Type[BaseValidator]] = getattr(module, f'{output_format.name.capitalize()}Validator', None)
-    if klass is None:  # pragma: no cover
+    if klass is None:
         raise ValueError(f'Missing Validator for {output_format.name}')
     return klass(schema_version)
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
index d97d276c7..721dd5d7d 100644
--- a/cyclonedx/validation/json.py
+++ b/cyclonedx/validation/json.py
@@ -16,11 +16,11 @@
 
 from abc import ABC
 from json import loads as json_loads
-from typing import TYPE_CHECKING, Any, Optional, Tuple
+from typing import TYPE_CHECKING, Any, Literal, Optional, Tuple
 
 from ..schema import OutputFormat
 
-if TYPE_CHECKING:
+if TYPE_CHECKING:  # pragma: no cover
     from ..schema import SchemaVersion
 
 from ..exception import MissingOptionalDependencyException
@@ -34,7 +34,7 @@
     from referencing import Registry
     from referencing.jsonschema import DRAFT7
 
-    if TYPE_CHECKING:
+    if TYPE_CHECKING:  # pragma: no cover
         from jsonschema.protocols import Validator as JsonSchemaValidator  # type: ignore[import]
 except ImportError as err:
     _missing_deps_error = MissingOptionalDependencyException(
@@ -45,7 +45,7 @@
 
 class _BaseJsonValidator(BaseValidator, ABC):
     @property
-    def output_format(self) -> OutputFormat:
+    def output_format(self) -> Literal[OutputFormat.JSON]:
         return OutputFormat.JSON
 
     def __init__(self, schema_version: 'SchemaVersion') -> None:
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index 668903165..6da23b2a7 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -15,14 +15,14 @@
 __all__ = ['XmlValidator']
 
 from abc import ABC
-from typing import TYPE_CHECKING, Any, Optional, Tuple
+from typing import TYPE_CHECKING, Any, Literal, Optional, Tuple
 
 from ..exception import MissingOptionalDependencyException
 from ..schema import OutputFormat
 from ..schema._res import BOM_XML as _S_BOM
 from . import BaseValidator, ValidationError, Validator
 
-if TYPE_CHECKING:
+if TYPE_CHECKING:  # pragma: no cover
     from ..schema import SchemaVersion
 
 _missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
@@ -38,7 +38,7 @@
 class _BaseXmlValidator(BaseValidator, ABC):
 
     @property
-    def output_format(self) -> OutputFormat:
+    def output_format(self) -> Literal[OutputFormat.XML]:
         return OutputFormat.XML
 
     def __init__(self, schema_version: 'SchemaVersion') -> None:
diff --git a/examples/complex.py b/examples/complex.py
index 4c291b2dc..641c2ed2c 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -30,6 +30,14 @@
 from cyclonedx.validation.json import JsonStrictValidator
 from cyclonedx.validation import get_instance as get_validator
 
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from cyclonedx.output.json import Json as JsonOutputter
+    from cyclonedx.output.xml import Xml as XmlOutputter
+    from cyclonedx.validation.xml import XmlValidator
+
+
 lc_factory = LicenseChoiceFactory(license_factory=LicenseFactory())
 
 # region build the BOM
@@ -68,11 +76,15 @@
 
 # endregion build the BOM
 
+# region JSON
+"""demo with explicit instructions for SchemaVersion, outputter and validator"""
 
-serialized_json = JsonV1Dot4(bom).output_as_string(indent=2)
+my_json_outputter: 'JsonOutputter' = JsonV1Dot4(bom)
+serialized_json = my_json_outputter.output_as_string(indent=2)
 print(serialized_json)
+my_json_validator = JsonStrictValidator(SchemaVersion.V1_4)
 try:
-    validation_errors = JsonStrictValidator(SchemaVersion.V1_4).validate_str(serialized_json)
+    validation_errors = my_json_validator.validate_str(serialized_json)
     if validation_errors:
         print('JSON invalid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
         sys.exit(2)
@@ -82,16 +94,22 @@
 
 print('', '=' * 30, '', sep='\n')
 
-my_outputter = get_outputter(bom, OutputFormat.XML, SchemaVersion.V1_4)
-serialized_xml = my_outputter.output_as_string(indent=2)
+# endregion JSON
+
+# region XML
+"""demo with implicit instructions for SchemaVersion, outputter and validator. TypeCheckers will catch errors."""
+
+my_xml_outputter: 'XmlOutputter' = get_outputter(bom, OutputFormat.XML)
+serialized_xml = my_xml_outputter.output_as_string(indent=2)
 print(serialized_xml)
+my_xml_validator: 'XmlValidator' = get_validator(my_xml_outputter.output_format, my_xml_outputter.schema_version)
 try:
-    validation_errors = get_validator(my_outputter.output_format,
-                                      my_outputter.schema_version
-                                      ).validate_str(serialized_xml)
+    validation_errors = my_xml_validator.validate_str(serialized_xml)
     if validation_errors:
         print('XML invalid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
         sys.exit(2)
     print('XML valid')
 except MissingOptionalDependencyException as error:
     print('XML-validation was skipped due to', error)
+
+# endregion XML
diff --git a/pyproject.toml b/pyproject.toml
index 805eb347e..feeaf0133 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -61,7 +61,7 @@ keywords = [
 # ATTENTION: keep `deps.lowest.r` file in sync
 python = "^3.8"
 packageurl-python = ">= 0.11"
-py-serializable = "^0.13.0"
+py-serializable =  "^0.14.0"
 sortedcontainers = "^2.4.0"
 license-expression = "^30"
 jsonschema = { version = "^4.18", extras=['format'], optional=true }
diff --git a/tests/test_deserialize_xml.py b/tests/test_deserialize_xml.py
index f9502fb4d..2b32ed95b 100644
--- a/tests/test_deserialize_xml.py
+++ b/tests/test_deserialize_xml.py
@@ -16,11 +16,11 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 from datetime import datetime
+from io import StringIO
 from os.path import join
 from typing import cast
 from unittest.mock import Mock, patch
 from uuid import UUID
-from xml.etree import ElementTree
 
 from cyclonedx.model.bom import Bom
 from cyclonedx.output import LATEST_SUPPORTED_SCHEMA_VERSION, SchemaVersion, get_instance
@@ -686,11 +686,10 @@ def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: st
         if schema_version != LATEST_SUPPORTED_SCHEMA_VERSION:
             # Rewind the BOM to only have data supported by the SchemaVersion in question
             outputter = get_instance(bom=bom, output_format=OutputFormat.XML, schema_version=schema_version)
-            bom = cast(Bom, Bom.from_xml(data=ElementTree.fromstring(outputter.output_as_string())))
+            bom = cast(Bom, Bom.from_xml(StringIO(outputter.output_as_string())))
 
         with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as input_xml:
-            xml = input_xml.read()
-            deserialized_bom = cast(Bom, Bom.from_xml(data=ElementTree.fromstring(xml)))
+            deserialized_bom = cast(Bom, Bom.from_xml(input_xml))
 
             self.assertEqual(bom.metadata, deserialized_bom.metadata)
 
diff --git a/tests/test_real_world_examples.py b/tests/test_real_world_examples.py
index 7be3b081e..795e38f4c 100644
--- a/tests/test_real_world_examples.py
+++ b/tests/test_real_world_examples.py
@@ -14,12 +14,12 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
+
 import unittest
 from datetime import datetime
 from os.path import join
 from typing import cast
 from unittest.mock import patch
-from xml.etree import ElementTree
 
 from cyclonedx.model.bom import Bom
 from cyclonedx.schema import SchemaVersion
@@ -43,5 +43,4 @@ def test_webgoat_6_1(self) -> None:
 
     def _attempt_load_example(self, schema_version: SchemaVersion, fixture: str) -> None:
         with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as input_xml:
-            xml = input_xml.read()
-            cast(Bom, Bom.from_xml(data=ElementTree.fromstring(xml)))
+            cast(Bom, Bom.from_xml(input_xml))

From 75437896c04e352b51d83e6e52cf94874347f4a6 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Sun, 8 Oct 2023 23:47:24 +0200
Subject: [PATCH 23/42] tests: snapshots and complete deep comparison, instead
 of pseudo-compare (#464)

part of https://github.com/CycloneDX/cyclonedx-python-lib/issues/437
also fixed a bug: unused first level dependencies were not detected. now they are.

---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/model/bom.py                        |   4 +-
 cyclonedx/model/component.py                  |   5 +-
 cyclonedx/model/dependency.py                 |   2 +-
 cyclonedx/model/service.py                    |   3 +-
 cyclonedx/model/vulnerability.py              |   3 +-
 cyclonedx/schema/__init__.py                  |   3 +
 pyproject.toml                                |   2 +-
 tests/__init__.py                             | 132 +++-
 tests/_data/__init__.py                       |  18 +
 tests/{data.py => _data/models.py}            | 196 +++--
 tests/_data/own/.gitattributes                |   5 +-
 tests/_data/own/README.md                     |  12 -
 tests/_data/own/json/1.4/bom_setuptools.json  |  71 --
 .../_data/own/json/1.4/indented_4spaces.json  |  71 --
 tests/_data/own/json/1.4/indented_None.json   |   1 -
 tests/_data/own/json/1.4/indented_tab.json    |  71 --
 .../own/xml/1.0/bom_issue_275_components.xml  |  22 -
 .../own/xml/1.0/bom_issue_328_components.xml  |  24 -
 tests/_data/own/xml/1.0/bom_setuptools.xml    |  11 -
 .../own/xml/1.0/bom_setuptools_complete.xml   |  33 -
 .../own/xml/1.0/bom_setuptools_no_version.xml |  11 -
 .../own/xml/1.0/bom_setuptools_with_cpe.xml   |  12 -
 .../1.0/bom_toml_hashes_and_references.xml    |  14 -
 tests/_data/own/xml/1.1/bom_dependencies.xml  |  28 -
 tests/_data/own/xml/1.1/bom_empty.xml         |   5 -
 .../own/xml/1.1/bom_external_references.xml   |  14 -
 .../own/xml/1.1/bom_issue_275_components.xml  |  20 -
 .../own/xml/1.1/bom_issue_328_components.xml  |  22 -
 tests/_data/own/xml/1.1/bom_setuptools.xml    |  14 -
 .../own/xml/1.1/bom_setuptools_complete.xml   | 124 ---
 .../own/xml/1.1/bom_setuptools_no_version.xml |  14 -
 .../own/xml/1.1/bom_setuptools_with_cpe.xml   |  15 -
 .../bom_setuptools_with_vulnerabilities.xml   |  53 --
 .../1.1/bom_toml_hashes_and_references.xml    |  20 -
 tests/_data/own/xml/1.2/bom_dependencies.xml  |  45 --
 .../xml/1.2/bom_dependencies_component.xml    |  45 --
 .../own/xml/1.2/bom_external_references.xml   |  23 -
 .../own/xml/1.2/bom_issue_275_components.xml  |  45 --
 .../own/xml/1.2/bom_issue_328_components.xml  |  48 --
 .../own/xml/1.2/bom_services_complex.xml      |  65 --
 .../_data/own/xml/1.2/bom_services_nested.xml | 113 ---
 .../_data/own/xml/1.2/bom_services_simple.xml |  31 -
 tests/_data/own/xml/1.2/bom_setuptools.xml    |  28 -
 .../own/xml/1.2/bom_setuptools_complete.xml   | 162 ----
 .../own/xml/1.2/bom_setuptools_no_version.xml |  28 -
 .../own/xml/1.2/bom_setuptools_with_cpe.xml   |  29 -
 .../bom_setuptools_with_vulnerabilities.xml   |  67 --
 .../1.2/bom_toml_hashes_and_references.xml    |  33 -
 .../own/xml/1.2/bom_with_full_metadata.xml    | 193 -----
 tests/_data/own/xml/1.3/bom_dependencies.xml  |  48 --
 .../xml/1.3/bom_dependencies_component.xml    |  48 --
 .../own/xml/1.3/bom_external_references.xml   |  26 -
 .../own/xml/1.3/bom_issue_275_components.xml  |  45 --
 .../own/xml/1.3/bom_issue_328_components.xml  |  48 --
 .../own/xml/1.3/bom_services_complex.xml      |  72 --
 .../_data/own/xml/1.3/bom_services_nested.xml | 120 ---
 .../_data/own/xml/1.3/bom_services_simple.xml |  31 -
 tests/_data/own/xml/1.3/bom_setuptools.xml    |  28 -
 .../own/xml/1.3/bom_setuptools_complete.xml   | 184 -----
 .../own/xml/1.3/bom_setuptools_no_version.xml |  28 -
 .../own/xml/1.3/bom_setuptools_with_cpe.xml   |  29 -
 .../bom_setuptools_with_vulnerabilities.xml   |  67 --
 .../1.3/bom_toml_hashes_and_references.xml    |  36 -
 .../own/xml/1.3/bom_with_full_metadata.xml    | 226 ------
 tests/_data/own/xml/1.4/bom_dependencies.xml  |  74 --
 .../xml/1.4/bom_dependencies_component.xml    |  74 --
 .../own/xml/1.4/bom_external_references.xml   |  51 --
 .../own/xml/1.4/bom_issue_275_components.xml  |  71 --
 .../own/xml/1.4/bom_issue_328_components.xml  |  73 --
 .../own/xml/1.4/bom_services_complex.xml      | 142 ----
 .../_data/own/xml/1.4/bom_services_nested.xml | 190 -----
 .../_data/own/xml/1.4/bom_services_simple.xml |  57 --
 .../own/xml/1.4/bom_setuptools_complete.xml   | 252 -------
 .../own/xml/1.4/bom_setuptools_no_version.xml |  53 --
 .../own/xml/1.4/bom_setuptools_with_cpe.xml   |  55 --
 .../1.4/bom_setuptools_with_release_notes.xml |  98 ---
 .../bom_setuptools_with_vulnerabilities.xml   | 166 ----
 .../1.4/bom_toml_hashes_and_references.xml    |  62 --
 .../xml/1.4/bom_with_dependencies_hanging.xml |  47 --
 .../own/xml/1.4/bom_with_full_metadata.xml    | 294 --------
 tests/_data/own/xml/1.4/indented_4spaces.xml  |  53 --
 tests/_data/own/xml/1.4/indented_None.xml     |   2 -
 tests/_data/own/xml/1.4/indented_tab.xml      |  53 --
 tests/_data/snapshots/.gitattributes          |   3 +
 tests/_data/snapshots/README.md               |  13 +
 ...t_bom_for_issue_275_components-1.0.xml.bin |  22 +
 ...t_bom_for_issue_275_components-1.1.xml.bin |  19 +
 ...bom_for_issue_275_components-1.2.json.bin} |  72 +-
 ...t_bom_for_issue_275_components-1.2.xml.bin |  44 ++
 ...bom_for_issue_275_components-1.3.json.bin} |  72 +-
 ...t_bom_for_issue_275_components-1.3.xml.bin |  44 ++
 ...bom_for_issue_275_components-1.4.json.bin} | 140 ++--
 ...t_bom_for_issue_275_components-1.4.xml.bin |  70 ++
 ...t_bom_for_issue_328_components-1.0.xml.bin |  24 +
 ...t_bom_for_issue_328_components-1.1.xml.bin |  21 +
 ...bom_for_issue_328_components-1.2.json.bin} |  87 ++-
 ...t_bom_for_issue_328_components-1.2.xml.bin |  47 ++
 ...bom_for_issue_328_components-1.3.json.bin} |  87 ++-
 ...t_bom_for_issue_328_components-1.3.xml.bin |  47 ++
 ...bom_for_issue_328_components-1.4.json.bin} | 155 ++--
 ...t_bom_for_issue_328_components-1.4.xml.bin |  73 ++
 ...et_bom_just_complete_metadata-1.0.xml.bin} |   4 +-
 ...get_bom_just_complete_metadata-1.1.xml.bin |   4 +
 ...t_bom_just_complete_metadata-1.2.json.bin} | 322 ++++----
 ...get_bom_just_complete_metadata-1.2.xml.bin | 192 +++++
 ...t_bom_just_complete_metadata-1.3.json.bin} | 410 +++++-----
 ...get_bom_just_complete_metadata-1.3.xml.bin | 225 ++++++
 ...t_bom_just_complete_metadata-1.4.json.bin} | 546 +++++++-------
 ...get_bom_just_complete_metadata-1.4.xml.bin | 293 ++++++++
 ...ith_component_setuptools_basic-1.0.xml.bin |  11 +
 ...ith_component_setuptools_basic-1.1.xml.bin |  13 +
 ...h_component_setuptools_basic-1.2.json.bin} |  44 +-
 ...ith_component_setuptools_basic-1.2.xml.bin |  27 +
 ...h_component_setuptools_basic-1.3.json.bin} |  44 +-
 ...ith_component_setuptools_basic-1.3.xml.bin |  27 +
 ...h_component_setuptools_basic-1.4.json.bin} |   4 +-
 ...th_component_setuptools_basic-1.4.xml.bin} |   4 +-
 ..._component_setuptools_complete-1.0.xml.bin |  33 +
 ..._component_setuptools_complete-1.1.xml.bin | 123 +++
 ...omponent_setuptools_complete-1.2.json.bin} | 302 ++++----
 ..._component_setuptools_complete-1.2.xml.bin | 161 ++++
 ...omponent_setuptools_complete-1.3.json.bin} | 352 ++++-----
 ..._component_setuptools_complete-1.3.xml.bin | 183 +++++
 ...omponent_setuptools_complete-1.4.json.bin} | 488 ++++++------
 ..._component_setuptools_complete-1.4.xml.bin | 251 +++++++
 ...etuptools_no_component_version-1.0.xml.bin |  11 +
 ...etuptools_no_component_version-1.1.xml.bin |  13 +
 ...uptools_no_component_version-1.2.json.bin} |  44 +-
 ...etuptools_no_component_version-1.2.xml.bin |  27 +
 ...uptools_no_component_version-1.3.json.bin} |  44 +-
 ...etuptools_no_component_version-1.3.xml.bin |  27 +
 ...uptools_no_component_version-1.4.json.bin} |  90 +--
 ...etuptools_no_component_version-1.4.xml.bin |  52 ++
 ..._component_setuptools_with_cpe-1.0.xml.bin |  12 +
 ..._component_setuptools_with_cpe-1.1.xml.bin |  14 +
 ...omponent_setuptools_with_cpe-1.2.json.bin} |  46 +-
 ..._component_setuptools_with_cpe-1.2.xml.bin |  28 +
 ...omponent_setuptools_with_cpe-1.3.json.bin} |  46 +-
 ..._component_setuptools_with_cpe-1.3.xml.bin |  28 +
 ...omponent_setuptools_with_cpe-1.4.json.bin} |  94 +--
 ..._component_setuptools_with_cpe-1.4.xml.bin |  54 ++
 ..._setuptools_with_release_notes-1.0.xml.bin |  11 +
 ..._setuptools_with_release_notes-1.1.xml.bin |  13 +
 ...setuptools_with_release_notes-1.2.json.bin |  37 +
 ..._setuptools_with_release_notes-1.2.xml.bin |  27 +
 ...setuptools_with_release_notes-1.3.json.bin |  37 +
 ..._setuptools_with_release_notes-1.3.xml.bin |  27 +
 ...etuptools_with_release_notes-1.4.json.bin} | 174 ++---
 ..._setuptools_with_release_notes-1.4.xml.bin |  97 +++
 ..._setuptools_with_vulnerability-1.0.xml.bin |  11 +
 ..._setuptools_with_vulnerability-1.1.xml.bin |  13 +
 ...setuptools_with_vulnerability-1.2.json.bin |  37 +
 ..._setuptools_with_vulnerability-1.2.xml.bin |  27 +
 ...setuptools_with_vulnerability-1.3.json.bin |  37 +
 ..._setuptools_with_vulnerability-1.3.xml.bin |  27 +
 ...etuptools_with_vulnerability-1.4.json.bin} | 268 +++----
 ..._setuptools_with_vulnerability-1.4.xml.bin | 166 ++++
 .../get_bom_with_component_toml_1-1.0.xml.bin |  14 +
 .../get_bom_with_component_toml_1-1.1.xml.bin |  19 +
 ...et_bom_with_component_toml_1-1.2.json.bin} |  54 +-
 .../get_bom_with_component_toml_1-1.2.xml.bin |  32 +
 ...et_bom_with_component_toml_1-1.3.json.bin} |  62 +-
 .../get_bom_with_component_toml_1-1.3.xml.bin |  35 +
 ...et_bom_with_component_toml_1-1.4.json.bin} | 118 +--
 .../get_bom_with_component_toml_1-1.4.xml.bin |  61 ++
 ..._bom_with_dependencies_hanging-1.0.xml.bin |  20 +
 ..._bom_with_dependencies_hanging-1.1.xml.bin |  27 +
 ...bom_with_dependencies_hanging-1.2.json.bin |  72 ++
 ..._bom_with_dependencies_hanging-1.2.xml.bin |  49 ++
 ...om_with_dependencies_hanging-1.3.json.bin} |  42 +-
 ..._bom_with_dependencies_hanging-1.3.xml.bin |  52 ++
 ...bom_with_dependencies_hanging-1.4.json.bin | 111 +++
 ..._bom_with_dependencies_hanging-1.4.xml.bin |  77 ++
 ...et_bom_with_dependencies_valid-1.0.xml.bin |  20 +
 ...et_bom_with_dependencies_valid-1.1.xml.bin |  27 +
 ..._bom_with_dependencies_valid-1.2.json.bin} |  68 +-
 ...et_bom_with_dependencies_valid-1.2.xml.bin |  44 ++
 ..._bom_with_dependencies_valid-1.3.json.bin} |  76 +-
 ...et_bom_with_dependencies_valid-1.3.xml.bin |  47 ++
 ..._bom_with_dependencies_valid-1.4.json.bin} | 144 ++--
 ...et_bom_with_dependencies_valid-1.4.xml.bin |  73 ++
 ...t_bom_with_external_references-1.0.xml.bin |   4 +
 ...t_bom_with_external_references-1.1.xml.bin |  13 +
 ...bom_with_external_references-1.2.json.bin} |  36 +-
 ...t_bom_with_external_references-1.2.xml.bin |  22 +
 ...bom_with_external_references-1.3.json.bin} |  44 +-
 ...t_bom_with_external_references-1.3.xml.bin |  25 +
 ...bom_with_external_references-1.4.json.bin} |  86 +--
 ...t_bom_with_external_references-1.4.xml.bin |  51 ++
 ...ata_component_and_dependencies-1.0.xml.bin |  14 +
 ...ata_component_and_dependencies-1.1.xml.bin |  19 +
 ...a_component_and_dependencies-1.2.json.bin} |  84 +--
 ...ata_component_and_dependencies-1.2.xml.bin |  44 ++
 ...a_component_and_dependencies-1.3.json.bin} |  92 +--
 ...ata_component_and_dependencies-1.3.xml.bin |  47 ++
 ...a_component_and_dependencies-1.4.json.bin} | 160 ++--
 ...ata_component_and_dependencies-1.4.xml.bin |  73 ++
 .../get_bom_with_nested_services-1.0.xml.bin  |   4 +
 .../get_bom_with_nested_services-1.1.xml.bin  |   4 +
 ...get_bom_with_nested_services-1.2.json.bin} |  70 +-
 .../get_bom_with_nested_services-1.2.xml.bin  | 112 +++
 ...get_bom_with_nested_services-1.3.json.bin} | 184 ++---
 .../get_bom_with_nested_services-1.3.xml.bin  | 119 +++
 ...get_bom_with_nested_services-1.4.json.bin} | 308 ++++----
 .../get_bom_with_nested_services-1.4.xml.bin  | 189 +++++
 .../get_bom_with_services_complex-1.0.xml.bin |   4 +
 .../get_bom_with_services_complex-1.1.xml.bin |   4 +
 ...et_bom_with_services_complex-1.2.json.bin} | 114 +--
 .../get_bom_with_services_complex-1.2.xml.bin |  64 ++
 ...et_bom_with_services_complex-1.3.json.bin} | 126 ++--
 .../get_bom_with_services_complex-1.3.xml.bin |  71 ++
 ...et_bom_with_services_complex-1.4.json.bin} | 242 +++---
 .../get_bom_with_services_complex-1.4.xml.bin | 141 ++++
 .../get_bom_with_services_simple-1.0.xml.bin  |   4 +
 .../get_bom_with_services_simple-1.1.xml.bin  |   4 +
 ...get_bom_with_services_simple-1.2.json.bin} |  54 +-
 .../get_bom_with_services_simple-1.2.xml.bin  |  30 +
 ...get_bom_with_services_simple-1.3.json.bin} |  54 +-
 .../get_bom_with_services_simple-1.3.xml.bin  |  30 +
 ...get_bom_with_services_simple-1.4.json.bin} |  92 +--
 .../get_bom_with_services_simple-1.4.xml.bin  |  56 ++
 tests/base.py                                 | 121 ---
 tests/test_component.py                       |  10 +-
 tests/test_deserialize_json.py                | 437 +----------
 tests/test_deserialize_xml.py                 | 706 +-----------------
 tests/test_e2e_environment.py                 |   3 +-
 tests/test_model.py                           |   2 +-
 tests/test_model_bom.py                       |   2 +-
 tests/test_model_bom_ref.py                   |   2 +-
 tests/test_model_component.py                 |  21 +-
 tests/test_model_dependency.py                |   2 +-
 tests/test_model_issue.py                     |   3 +-
 tests/test_model_service.py                   |  17 +-
 tests/test_model_vulnerability.py             |  12 +-
 tests/test_output_json.py                     | 455 ++---------
 tests/test_output_xml.py                      | 582 ++-------------
 tests/test_real_world_examples.py             |  24 +-
 tests/test_validation_json.py                 |   8 +-
 tests/test_validation_xml.py                  |   6 +-
 239 files changed, 8322 insertions(+), 9984 deletions(-)
 create mode 100644 tests/_data/__init__.py
 rename tests/{data.py => _data/models.py} (82%)
 delete mode 100644 tests/_data/own/json/1.4/bom_setuptools.json
 delete mode 100644 tests/_data/own/json/1.4/indented_4spaces.json
 delete mode 100644 tests/_data/own/json/1.4/indented_None.json
 delete mode 100644 tests/_data/own/json/1.4/indented_tab.json
 delete mode 100644 tests/_data/own/xml/1.0/bom_issue_275_components.xml
 delete mode 100644 tests/_data/own/xml/1.0/bom_issue_328_components.xml
 delete mode 100644 tests/_data/own/xml/1.0/bom_setuptools.xml
 delete mode 100644 tests/_data/own/xml/1.0/bom_setuptools_complete.xml
 delete mode 100644 tests/_data/own/xml/1.0/bom_setuptools_no_version.xml
 delete mode 100644 tests/_data/own/xml/1.0/bom_setuptools_with_cpe.xml
 delete mode 100644 tests/_data/own/xml/1.0/bom_toml_hashes_and_references.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_dependencies.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_empty.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_external_references.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_issue_275_components.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_issue_328_components.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_setuptools.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_setuptools_complete.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_setuptools_no_version.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_setuptools_with_cpe.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_setuptools_with_vulnerabilities.xml
 delete mode 100644 tests/_data/own/xml/1.1/bom_toml_hashes_and_references.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_dependencies.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_dependencies_component.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_external_references.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_issue_275_components.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_issue_328_components.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_services_complex.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_services_nested.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_services_simple.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_setuptools.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_setuptools_complete.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_setuptools_no_version.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_setuptools_with_cpe.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_setuptools_with_vulnerabilities.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_toml_hashes_and_references.xml
 delete mode 100644 tests/_data/own/xml/1.2/bom_with_full_metadata.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_dependencies.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_dependencies_component.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_external_references.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_issue_275_components.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_issue_328_components.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_services_complex.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_services_nested.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_services_simple.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_setuptools.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_setuptools_complete.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_setuptools_no_version.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_setuptools_with_cpe.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_setuptools_with_vulnerabilities.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_toml_hashes_and_references.xml
 delete mode 100644 tests/_data/own/xml/1.3/bom_with_full_metadata.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_dependencies.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_dependencies_component.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_external_references.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_issue_275_components.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_issue_328_components.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_services_complex.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_services_nested.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_services_simple.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_setuptools_complete.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_setuptools_no_version.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_setuptools_with_cpe.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_setuptools_with_release_notes.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_setuptools_with_vulnerabilities.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_toml_hashes_and_references.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_with_dependencies_hanging.xml
 delete mode 100644 tests/_data/own/xml/1.4/bom_with_full_metadata.xml
 delete mode 100644 tests/_data/own/xml/1.4/indented_4spaces.xml
 delete mode 100644 tests/_data/own/xml/1.4/indented_None.xml
 delete mode 100644 tests/_data/own/xml/1.4/indented_tab.xml
 create mode 100644 tests/_data/snapshots/.gitattributes
 create mode 100644 tests/_data/snapshots/README.md
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_275_components-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_275_components-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_issue_275_components.json => snapshots/get_bom_for_issue_275_components-1.2.json.bin} (79%)
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_275_components-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_issue_275_components.json => snapshots/get_bom_for_issue_275_components-1.3.json.bin} (79%)
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_275_components-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_issue_275_components.json => snapshots/get_bom_for_issue_275_components-1.4.json.bin} (71%)
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_275_components-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_328_components-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_328_components-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_issue_328_components.json => snapshots/get_bom_for_issue_328_components-1.2.json.bin} (72%)
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_328_components-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_issue_328_components.json => snapshots/get_bom_for_issue_328_components-1.3.json.bin} (72%)
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_328_components-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_issue_328_components.json => snapshots/get_bom_for_issue_328_components-1.4.json.bin} (66%)
 create mode 100644 tests/_data/snapshots/get_bom_for_issue_328_components-1.4.xml.bin
 rename tests/_data/{own/xml/1.0/bom_empty.xml => snapshots/get_bom_just_complete_metadata-1.0.xml.bin} (54%)
 create mode 100644 tests/_data/snapshots/get_bom_just_complete_metadata-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_with_full_metadata.json => snapshots/get_bom_just_complete_metadata-1.2.json.bin} (80%)
 create mode 100644 tests/_data/snapshots/get_bom_just_complete_metadata-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_with_full_metadata.json => snapshots/get_bom_just_complete_metadata-1.3.json.bin} (84%)
 create mode 100644 tests/_data/snapshots/get_bom_just_complete_metadata-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_with_full_metadata.json => snapshots/get_bom_just_complete_metadata-1.4.json.bin} (82%)
 create mode 100644 tests/_data/snapshots/get_bom_just_complete_metadata-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_setuptools.json => snapshots/get_bom_with_component_setuptools_basic-1.2.json.bin} (79%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_setuptools.json => snapshots/get_bom_with_component_setuptools_basic-1.3.json.bin} (79%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.xml.bin
 rename tests/_data/{own/json/1.4/indented_two.json => snapshots/get_bom_with_component_setuptools_basic-1.4.json.bin} (94%)
 rename tests/_data/{own/xml/1.4/indented_two.xml => snapshots/get_bom_with_component_setuptools_basic-1.4.xml.bin} (94%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_setuptools_complete.json => snapshots/get_bom_with_component_setuptools_complete-1.2.json.bin} (80%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_setuptools_complete.json => snapshots/get_bom_with_component_setuptools_complete-1.3.json.bin} (84%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_setuptools_complete.json => snapshots/get_bom_with_component_setuptools_complete-1.4.json.bin} (84%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_setuptools_no_version.json => snapshots/get_bom_with_component_setuptools_no_component_version-1.2.json.bin} (80%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_setuptools_no_version.json => snapshots/get_bom_with_component_setuptools_no_component_version-1.3.json.bin} (80%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_setuptools_no_version.json => snapshots/get_bom_with_component_setuptools_no_component_version-1.4.json.bin} (67%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_setuptools_with_cpe.json => snapshots/get_bom_with_component_setuptools_with_cpe-1.2.json.bin} (80%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_setuptools_with_cpe.json => snapshots/get_bom_with_component_setuptools_with_cpe-1.3.json.bin} (80%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_setuptools_with_cpe.json => snapshots/get_bom_with_component_setuptools_with_cpe-1.4.json.bin} (68%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.1.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_setuptools_with_release_notes.json => snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.json.bin} (78%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.1.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_setuptools_with_vulnerabilities.json => snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.json.bin} (77%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_toml_1-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_component_toml_1-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_toml_1.json => snapshots/get_bom_with_component_toml_1-1.2.json.bin} (80%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_toml_1-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_toml_1.json => snapshots/get_bom_with_component_toml_1-1.3.json.bin} (85%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_toml_1-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_toml_1.json => snapshots/get_bom_with_component_toml_1-1.4.json.bin} (72%)
 create mode 100644 tests/_data/snapshots/get_bom_with_component_toml_1-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_hanging-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_hanging-1.1.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.xml.bin
 rename tests/_data/{own/json/1.4/bom_with_dependencies_hanging.json => snapshots/get_bom_with_dependencies_hanging-1.3.json.bin} (75%)
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_valid-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_valid-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_dependencies.json => snapshots/get_bom_with_dependencies_valid-1.2.json.bin} (73%)
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_dependencies.json => snapshots/get_bom_with_dependencies_valid-1.3.json.bin} (77%)
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_dependencies.json => snapshots/get_bom_with_dependencies_valid-1.4.json.bin} (71%)
 create mode 100644 tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_external_references-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_external_references-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_external_references.json => snapshots/get_bom_with_external_references-1.2.json.bin} (64%)
 create mode 100644 tests/_data/snapshots/get_bom_with_external_references-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_external_references.json => snapshots/get_bom_with_external_references-1.3.json.bin} (74%)
 create mode 100644 tests/_data/snapshots/get_bom_with_external_references-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_external_references.json => snapshots/get_bom_with_external_references-1.4.json.bin} (65%)
 create mode 100644 tests/_data/snapshots/get_bom_with_external_references-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_dependencies_component.json => snapshots/get_bom_with_metadata_component_and_dependencies-1.2.json.bin} (72%)
 create mode 100644 tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_dependencies_component.json => snapshots/get_bom_with_metadata_component_and_dependencies-1.3.json.bin} (76%)
 create mode 100644 tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_dependencies_component.json => snapshots/get_bom_with_metadata_component_and_dependencies-1.4.json.bin} (69%)
 create mode 100644 tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_nested_services-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_nested_services-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_services_nested.json => snapshots/get_bom_with_nested_services-1.2.json.bin} (88%)
 create mode 100644 tests/_data/snapshots/get_bom_with_nested_services-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_services_nested.json => snapshots/get_bom_with_nested_services-1.3.json.bin} (79%)
 create mode 100644 tests/_data/snapshots/get_bom_with_nested_services-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_services_nested.json => snapshots/get_bom_with_nested_services-1.4.json.bin} (78%)
 create mode 100644 tests/_data/snapshots/get_bom_with_nested_services-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_services_complex-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_services_complex-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_services_complex.json => snapshots/get_bom_with_services_complex-1.2.json.bin} (82%)
 create mode 100644 tests/_data/snapshots/get_bom_with_services_complex-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_services_complex.json => snapshots/get_bom_with_services_complex-1.3.json.bin} (76%)
 create mode 100644 tests/_data/snapshots/get_bom_with_services_complex-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_services_complex.json => snapshots/get_bom_with_services_complex-1.4.json.bin} (76%)
 create mode 100644 tests/_data/snapshots/get_bom_with_services_complex-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_services_simple-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_services_simple-1.1.xml.bin
 rename tests/_data/{own/json/1.2/bom_services_simple.json => snapshots/get_bom_with_services_simple-1.2.json.bin} (57%)
 create mode 100644 tests/_data/snapshots/get_bom_with_services_simple-1.2.xml.bin
 rename tests/_data/{own/json/1.3/bom_services_simple.json => snapshots/get_bom_with_services_simple-1.3.json.bin} (57%)
 create mode 100644 tests/_data/snapshots/get_bom_with_services_simple-1.3.xml.bin
 rename tests/_data/{own/json/1.4/bom_services_simple.json => snapshots/get_bom_with_services_simple-1.4.json.bin} (58%)
 create mode 100644 tests/_data/snapshots/get_bom_with_services_simple-1.4.xml.bin
 delete mode 100644 tests/base.py

diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
index 776fa8344..a46708572 100644
--- a/cyclonedx/model/bom.py
+++ b/cyclonedx/model/bom.py
@@ -552,7 +552,9 @@ def validate(self) -> bool:
         # 1. Make sure dependencies are all in this Bom.
         all_bom_refs = set(map(lambda c: c.bom_ref, self._get_all_components())) | set(
             map(lambda s: s.bom_ref, self.services))
-        all_dependency_bom_refs = set().union(*(d.dependencies_as_bom_refs() for d in self.dependencies))
+        all_dependency_bom_refs = set(chain((d.ref for d in self.dependencies),
+                                            chain.from_iterable(
+                                                d.dependencies_as_bom_refs() for d in self.dependencies)))
 
         dependency_diff = all_dependency_bom_refs - all_bom_refs
         if len(dependency_diff) > 0:
diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py
index 516e11b71..29e51eed5 100644
--- a/cyclonedx/model/component.py
+++ b/cyclonedx/model/component.py
@@ -19,7 +19,6 @@
 from enum import Enum
 from os.path import exists
 from typing import Any, Iterable, Optional, Set, Union
-from uuid import uuid4
 
 # See https://github.com/package-url/packageurl-python/issues/65
 import serializable
@@ -769,7 +768,7 @@ def __init__(self, *, name: str, type: ComponentType = ComponentType.LIBRARY,
         if isinstance(bom_ref, BomRef):
             self._bom_ref = bom_ref
         else:
-            self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else str(uuid4()))
+            self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else None)
         self.supplier = supplier
         self.author = author
         self.publisher = publisher
@@ -809,8 +808,6 @@ def __init__(self, *, name: str, type: ComponentType = ComponentType.LIBRARY,
             if not licenses:
                 self.licenses = [LicenseChoice(expression=license_str)]  # type: ignore
 
-        self.__dependencies: "SortedSet[BomRef]" = SortedSet()
-
     @property
     @serializable.xml_attribute()
     def type(self) -> ComponentType:
diff --git a/cyclonedx/model/dependency.py b/cyclonedx/model/dependency.py
index 34155874f..317de1613 100644
--- a/cyclonedx/model/dependency.py
+++ b/cyclonedx/model/dependency.py
@@ -108,4 +108,4 @@ class Dependable(ABC):
     @property
     @abstractmethod
     def bom_ref(self) -> BomRef:
-        pass
+        ...
diff --git a/cyclonedx/model/service.py b/cyclonedx/model/service.py
index 16efea3a3..f681659a1 100644
--- a/cyclonedx/model/service.py
+++ b/cyclonedx/model/service.py
@@ -14,7 +14,6 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 from typing import Any, Iterable, Optional, Union
-from uuid import uuid4
 
 import serializable
 from sortedcontainers import SortedSet
@@ -66,7 +65,7 @@ def __init__(self, *, name: str, bom_ref: Optional[Union[str, BomRef]] = None,
         if isinstance(bom_ref, BomRef):
             self._bom_ref = bom_ref
         else:
-            self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else str(uuid4()))
+            self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else None)
         self.provider = provider
         self.group = group
         self.name = name
diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py
index 004a28e18..53bcf453a 100644
--- a/cyclonedx/model/vulnerability.py
+++ b/cyclonedx/model/vulnerability.py
@@ -21,7 +21,6 @@
 from decimal import Decimal
 from enum import Enum
 from typing import Any, Iterable, Optional, Tuple, Union
-from uuid import uuid4
 
 import serializable
 from sortedcontainers import SortedSet
@@ -837,7 +836,7 @@ def __init__(self, *, bom_ref: Optional[Union[str, BomRef]] = None, id: Optional
         if isinstance(bom_ref, BomRef):
             self._bom_ref = bom_ref
         else:
-            self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else str(uuid4()))
+            self._bom_ref = BomRef(value=str(bom_ref) if bom_ref else None)
         self.id = id
         self.source = source
         self.references = references or []  # type: ignore
diff --git a/cyclonedx/schema/__init__.py b/cyclonedx/schema/__init__.py
index 9c592c252..ef2a696fe 100644
--- a/cyclonedx/schema/__init__.py
+++ b/cyclonedx/schema/__init__.py
@@ -32,6 +32,9 @@ class OutputFormat(Enum):
     def __hash__(self) -> int:
         return hash(self.name)
 
+    def __eq__(self, other: Any) -> bool:
+        return self is other
+
 
 _SV = TypeVar('_SV', bound='SchemaVersion')
 
diff --git a/pyproject.toml b/pyproject.toml
index feeaf0133..dbe4a8743 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -61,7 +61,7 @@ keywords = [
 # ATTENTION: keep `deps.lowest.r` file in sync
 python = "^3.8"
 packageurl-python = ">= 0.11"
-py-serializable =  "^0.14.0"
+py-serializable =  "^0.14.1"
 sortedcontainers = "^2.4.0"
 license-expression = "^30"
 jsonschema = { version = "^4.18", extras=['format'], optional=true }
diff --git a/tests/__init__.py b/tests/__init__.py
index ff33a2b8e..f70814842 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -16,9 +16,137 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 from os import getenv, path
+from os.path import join
+from typing import TYPE_CHECKING, Any, Generator, Iterable, List, Optional, TypeVar, Union
+from unittest import TestCase
+from uuid import UUID
 
-TESTDATA_DIRECTORY = path.join(path.dirname(__file__), '_data')
+from sortedcontainers import SortedSet
 
-RECREATE_SNAPSHOTS = bool(getenv('CDX_TEST_RECREATE_SNAPSHOTS'))
+from cyclonedx.schema import OutputFormat, SchemaVersion
+
+if TYPE_CHECKING:
+    from cyclonedx.model.bom import Bom
+    from cyclonedx.model.dependency import Dependency
+
+_T = TypeVar('_T')
+
+_TESTDATA_DIRECTORY = path.join(path.dirname(__file__), '_data')
+
+SCHEMA_TESTDATA_DIRECTORY = path.join(_TESTDATA_DIRECTORY, 'schemaTestData')
+OWN_DATA_DIRECTORY = path.join(_TESTDATA_DIRECTORY, 'own')
+SNAPSHOTS_DIRECTORY = path.join(_TESTDATA_DIRECTORY, 'snapshots')
+
+RECREATE_SNAPSHOTS = '1' == getenv('CDX_TEST_RECREATE_SNAPSHOTS')
 if RECREATE_SNAPSHOTS:
     print('!!! WILL RECREATE ALL SNAPSHOTS !!!')
+
+
+class SnapshotMixin:
+
+    @staticmethod
+    def getSnapshotFile(snapshot_name: str) -> str:
+        return join(SNAPSHOTS_DIRECTORY, f'{snapshot_name}.bin')
+
+    @classmethod
+    def writeSnapshot(cls, snapshot_name: str, data: str) -> None:
+        with open(cls.getSnapshotFile(snapshot_name), 'w') as s:
+            s.write(data)
+
+    @classmethod
+    def readSnapshot(cls, snapshot_name: str) -> str:
+        with open(cls.getSnapshotFile(snapshot_name), 'r') as s:
+            return s.read()
+
+    def assertEqualSnapshot(self: Union[TestCase, 'SnapshotMixin'], actual: str, snapshot_name: str) -> None:
+        if RECREATE_SNAPSHOTS:
+            self.writeSnapshot(snapshot_name, actual)
+        _omd = self.maxDiff
+        _omd = self.maxDiff
+        self.maxDiff = None
+        try:
+            self.assertEqual(actual, self.readSnapshot(snapshot_name))
+        finally:
+            self.maxDiff = _omd
+
+
+class DeepCompareMixin:
+    def assertDeepEqual(self: Union[TestCase, 'DeepCompareMixin'], first: Any, second: Any,
+                        msg: Optional[str] = None) -> None:
+        """costly compare, but very verbose"""
+        _omd = self.maxDiff
+        self.maxDiff = None
+        try:
+            self.maxDiff = None
+            dd1 = self.__deepDict(first)
+            dd2 = self.__deepDict(second)
+            self.assertDictEqual(dd1, dd2, msg)
+        finally:
+            self.maxDiff = _omd
+
+    def __deepDict(self, o: Any) -> Any:
+        if isinstance(o, tuple):
+            return tuple(self.__deepDict(i) for i in o)
+        if isinstance(o, list):
+            return list(self.__deepDict(i) for i in o)
+        if isinstance(o, dict):
+            return {k: self.__deepDict(v) for k, v in o.items()}
+        if isinstance(o, (set, SortedSet)):
+            # this method returns dict. `dict` is not hashable, so use `tuple` instead.
+            return tuple(self.__deepDict(i) for i in sorted(o, key=hash)) + ('%conv:%set',)
+        if hasattr(o, '__dict__'):
+            d = {a: self.__deepDict(v) for a, v in o.__dict__.items() if '__' not in a}
+            d['%conv'] = str(type(o))
+            return d
+        return o
+
+    def assertBomDeepEqual(self: Union[TestCase, 'DeepCompareMixin'], expected: 'Bom', actual: 'Bom',
+                           msg: Optional[str] = None, *,
+                           fuzzy_deps: bool = True) -> None:
+        # deps might have been upgraded on serialization, so they might differ
+        edeps = expected.dependencies
+        adeps = actual.dependencies
+        if fuzzy_deps:
+            expected.dependencies = []
+            actual.dependencies = []
+        try:
+            self.assertDeepEqual(expected, actual, msg)
+            if fuzzy_deps:
+                self._assertDependenciesFuzzyEqual(edeps, adeps)
+        finally:
+            expected.dependencies = edeps
+            actual.dependencies = adeps
+
+    def _assertDependenciesFuzzyEqual(self: TestCase, a: Iterable['Dependency'], b: Iterable['Dependency']) -> None:
+        delta = set(a) ^ set(b)
+        for d in delta:
+            # only actual relevant dependencies shall be taken into account.
+            self.assertEqual(0, len(d.dependencies), f'unexpected dependencies for {d.ref}')
+
+
+def reorder(items: List[_T], indexes: List[int]) -> List[_T]:
+    """
+    Return list of items in the order indicated by indexes.
+    """
+    reordered_items = []
+    for i in range(len(items)):
+        reordered_items.append(items[indexes[i]])
+    return reordered_items
+
+
+def uuid_generator(offset: int = 0, version: int = 4) -> Generator[UUID, None, None]:
+    v = offset
+    while True:
+        v += 1
+        yield UUID(int=v, version=version)
+
+
+_SNAME_EXT = {
+    OutputFormat.JSON: 'json',
+    OutputFormat.XML: 'xml',
+}
+
+
+def mksname(purpose: Union[Any], sv: SchemaVersion, f: OutputFormat) -> str:
+    purpose = purpose if isinstance(purpose, str) else purpose.__name__
+    return f'{purpose}-{sv.to_version()}.{_SNAME_EXT[f]}'
diff --git a/tests/_data/__init__.py b/tests/_data/__init__.py
new file mode 100644
index 000000000..308d97e7c
--- /dev/null
+++ b/tests/_data/__init__.py
@@ -0,0 +1,18 @@
+# encoding: utf-8
+
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
diff --git a/tests/data.py b/tests/_data/models.py
similarity index 82%
rename from tests/data.py
rename to tests/_data/models.py
index 3d8829318..d1e6e2ba7 100644
--- a/tests/data.py
+++ b/tests/_data/models.py
@@ -16,9 +16,11 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 import base64
+import sys
 from datetime import datetime, timezone
 from decimal import Decimal
-from typing import List, Optional, TypeVar
+from inspect import getmembers, isfunction
+from typing import Any, List, Optional
 from uuid import UUID
 
 # See https://github.com/package-url/packageurl-python/issues/65
@@ -26,6 +28,7 @@
 
 from cyclonedx.model import (
     AttachedText,
+    Copyright,
     DataClassification,
     DataFlow,
     Encoding,
@@ -43,29 +46,31 @@
     XsUri,
 )
 from cyclonedx.model.bom import Bom, BomMetaData
+from cyclonedx.model.bom_ref import BomRef
 from cyclonedx.model.component import (
     Commit,
     Component,
     ComponentEvidence,
     ComponentScope,
     ComponentType,
-    Copyright,
     Patch,
     PatchClassification,
     Pedigree,
     Swid,
 )
 from cyclonedx.model.dependency import Dependency
+from cyclonedx.model.impact_analysis import (
+    ImpactAnalysisAffectedStatus,
+    ImpactAnalysisJustification,
+    ImpactAnalysisResponse,
+    ImpactAnalysisState,
+)
 from cyclonedx.model.issue import IssueClassification, IssueType, IssueTypeSource
 from cyclonedx.model.release_note import ReleaseNotes
 from cyclonedx.model.service import Service
 from cyclonedx.model.vulnerability import (
     BomTarget,
     BomTargetVersionRange,
-    ImpactAnalysisAffectedStatus,
-    ImpactAnalysisJustification,
-    ImpactAnalysisResponse,
-    ImpactAnalysisState,
     Vulnerability,
     VulnerabilityAdvisory,
     VulnerabilityAnalysis,
@@ -77,49 +82,64 @@
     VulnerabilitySource,
 )
 
-MOCK_TIMESTAMP: datetime = datetime(2021, 12, 31, 10, 0, 0, 0).replace(tzinfo=timezone.utc)
-MOCK_UUID_1 = 'be2c6502-7e9a-47db-9a66-e34f729810a3'
-MOCK_UUID_2 = '17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda'
-MOCK_UUID_3 = '0b049d09-64c0-4490-a0f5-c84d9aacf857'
-MOCK_UUID_4 = 'cd3e9c95-9d41-49e7-9924-8cf0465ae789'
-MOCK_UUID_5 = 'bb5911d6-1a1d-41c9-b6e0-46e848d16655'
-MOCK_UUID_6 = 'df70b5f1-8f53-47a4-be48-669ae78795e6'
-MOCK_UUID_7 = UUID('6f266d1c-760f-4552-ae3b-41a9b74232fa')
-MOCK_UUID_8 = UUID('77d15ab9-5602-4cca-8ed2-59ae579aafd3')
-MOCK_UUID_9 = UUID('859ff614-35a7-4d37-803b-d89130cb2577')
-MOCK_UUID_10 = UUID('0afa65bc-4acd-428b-9e17-8e97b1969745')
-MOCK_BOM_UUID_1 = UUID('3e671687-395b-41f5-a30f-a58921a69b79')
-MOCK_BOM_UUID_2 = UUID('d0b24ba4-102b-497e-b31f-4fdc3f0a3005')
-
-TEST_UUIDS = [
-    UUID(MOCK_UUID_1), UUID(MOCK_UUID_2), UUID(MOCK_UUID_3), UUID(MOCK_UUID_4), UUID(MOCK_UUID_5), UUID(MOCK_UUID_6)
-]
+MOCK_TIMESTAMP = datetime.fromisoformat('2023-08-15 01:23:45.678900+00:00')
+
+MOCK_UUID = (
+    'be2c6502-7e9a-47db-9a66-e34f729810a3',
+    '17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda',
+    '0b049d09-64c0-4490-a0f5-c84d9aacf857',
+    'cd3e9c95-9d41-49e7-9924-8cf0465ae789',
+    'bb5911d6-1a1d-41c9-b6e0-46e848d16655',
+    'df70b5f1-8f53-47a4-be48-669ae78795e6',
+    '6f266d1c-760f-4552-ae3b-41a9b74232fa',
+    '77d15ab9-5602-4cca-8ed2-59ae579aafd3',
+    '859ff614-35a7-4d37-803b-d89130cb2577',
+    '0afa65bc-4acd-428b-9e17-8e97b1969745',
+    '3e671687-395b-41f5-a30f-a58921a69b79',
+    'd0b24ba4-102b-497e-b31f-4fdc3f0a3005',
+    'd0e0a795-6177-478b-b293-b0d19e4469f4',
+    '7b2a7a2c-66d5-4b30-8ee2-df966a41024e',
+    '68f7b744-84c2-4f0d-ac8b-c14bd48c37ff',
+    '1a2f9dfc-3c86-48c7-8ca7-1db488d5c2a0',
+    'a3f4096d-4211-4d68-9d2b-13973c86aca9',
+)
+
+
+BOM_SERIAL_NUMBER = UUID('1441d33a-e0fc-45b5-af3b-61ee52a88bac')
+BOM_TIMESTAMP = datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
+
+
+def _makeBom(**kwargs: Any) -> Bom:
+    bom = Bom(**kwargs)
+    bom.serial_number = BOM_SERIAL_NUMBER
+    bom.metadata.timestamp = BOM_TIMESTAMP
+    return bom
 
 
 def get_bom_with_component_setuptools_basic() -> Bom:
-    return Bom(components=[get_component_setuptools_simple()])
+    return _makeBom(components=[get_component_setuptools_simple()])
 
 
 def get_bom_with_component_setuptools_with_cpe() -> Bom:
     component = get_component_setuptools_simple()
     component.cpe = 'cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*'
-    return Bom(components=[component])
+    return _makeBom(components=[component])
 
 
 def get_bom_with_component_setuptools_no_component_version() -> Bom:
-    return Bom(components=[get_component_setuptools_simple_no_version()])
+    return _makeBom(components=[get_component_setuptools_simple_no_version()])
 
 
 def get_bom_with_component_setuptools_with_release_notes() -> Bom:
     component = get_component_setuptools_simple()
     component.release_notes = get_release_notes()
-    return Bom(components=[component])
+    return _makeBom(components=[component])
 
 
 def get_bom_with_dependencies_valid() -> Bom:
     c1 = get_component_setuptools_simple()
     c2 = get_component_toml_with_hashes_with_references()
-    return Bom(
+    return _makeBom(
         components=[c1, c2], dependencies=[
             Dependency(ref=c1.bom_ref, dependencies=[
                 Dependency(ref=c2.bom_ref)
@@ -136,8 +156,7 @@ def get_bom_with_dependencies_hanging() -> Bom:
     """
     c1 = get_component_setuptools_simple('setuptools')
     c2 = get_component_toml_with_hashes_with_references('toml')
-    bom = Bom(
-        serial_number=UUID(hex='12345678395b41f5a30f1234567890ab'),
+    bom = _makeBom(
         version=23,
         metadata=BomMetaData(
             component=Component(name='rootComponent', type=ComponentType.APPLICATION, bom_ref='root-component'),
@@ -150,37 +169,38 @@ def get_bom_with_dependencies_hanging() -> Bom:
             Dependency(c2.bom_ref)
         ]
     )
-    bom.metadata.tools.clear()
-    bom.metadata.timestamp = datetime(
-        year=2023, month=6, day=1,
-        hour=3, minute=3, second=7, microsecond=0,
-        tzinfo=timezone.utc)
     return bom
 
 
-def get_bom_with_dependencies_invalid() -> Bom:
+def get_bom_with_dependencies_unlinked_invalid() -> Bom:
+    """generate a bom with an unlinked dependency.
+    it is expected to throw on output.
+    """
     c1 = get_component_setuptools_simple()
-    return Bom(components=[c1], dependencies=[Dependency(ref=c1.bom_ref)])
+    return _makeBom(components=[c1], dependencies=[Dependency(ref=BomRef('link-to-ref-not-in-document'))])
 
 
 def get_bom_with_metadata_component_and_dependencies() -> Bom:
-    bom = Bom(components=[get_component_toml_with_hashes_with_references()])
+    cs = get_component_toml_with_hashes_with_references()
+    bom = _makeBom(components=[cs])
     bom.metadata.component = get_component_setuptools_simple()
     bom.dependencies.add(
         Dependency(ref=bom.metadata.component.bom_ref, dependencies=[
-            Dependency(ref=get_component_toml_with_hashes_with_references().bom_ref)
+            Dependency(ref=cs.bom_ref)
         ])
     )
     return bom
 
 
 def get_bom_with_component_setuptools_complete() -> Bom:
-    return Bom(components=[get_component_setuptools_complete()])
+    return _makeBom(components=[get_component_setuptools_complete()])
 
 
 def get_bom_with_component_setuptools_with_vulnerability() -> Bom:
-    bom = Bom()
+    bom = _makeBom()
     component = get_component_setuptools_simple()
+    if not component.purl:
+        raise ValueError('purl is required here')
     bom.components.add(component)
     bom.vulnerabilities.add(Vulnerability(
         bom_ref='my-vuln-ref-1', id='CVE-2018-7489', source=get_vulnerability_source_nvd(),
@@ -191,12 +211,12 @@ def get_bom_with_component_setuptools_with_vulnerability() -> Bom:
         ],
         ratings=[
             VulnerabilityRating(
-                source=get_vulnerability_source_nvd(), score=Decimal(9.8), severity=VulnerabilitySeverity.CRITICAL,
+                source=get_vulnerability_source_nvd(), score=Decimal('9.8'), severity=VulnerabilitySeverity.CRITICAL,
                 method=VulnerabilityScoreSource.CVSS_V3,
                 vector='AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H', justification='Some justification'
             ),
             VulnerabilityRating(
-                source=get_vulnerability_source_owasp(), score=Decimal(2.7), severity=VulnerabilitySeverity.LOW,
+                source=get_vulnerability_source_owasp(), score=Decimal('2.7'), severity=VulnerabilitySeverity.LOW,
                 method=VulnerabilityScoreSource.CVSS_V3,
                 vector='AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N', justification='Some other justification'
             )
@@ -228,7 +248,7 @@ def get_bom_with_component_setuptools_with_vulnerability() -> Bom:
         ),
         affects=[
             BomTarget(
-                ref=component.purl.to_string() if component.purl else None,
+                ref=component.purl.to_string(),
                 versions=[BomTargetVersionRange(
                     range='49.0.0 - 54.0.0', status=ImpactAnalysisAffectedStatus.AFFECTED
                 )]
@@ -240,11 +260,11 @@ def get_bom_with_component_setuptools_with_vulnerability() -> Bom:
 
 
 def get_bom_with_component_toml_1() -> Bom:
-    return Bom(components=[get_component_toml_with_hashes_with_references()])
+    return _makeBom(components=[get_component_toml_with_hashes_with_references()])
 
 
 def get_bom_just_complete_metadata() -> Bom:
-    bom = Bom()
+    bom = _makeBom()
     bom.metadata.authors = [get_org_contact_1(), get_org_contact_2()]
     bom.metadata.component = get_component_setuptools_complete()
     bom.metadata.manufacture = get_org_entity_1()
@@ -259,25 +279,26 @@ def get_bom_just_complete_metadata() -> Bom:
 
 
 def get_bom_with_external_references() -> Bom:
-    bom = Bom(external_references=[
+    bom = _makeBom(external_references=[
         get_external_reference_1(), get_external_reference_2()
     ])
     return bom
 
 
 def get_bom_with_services_simple() -> Bom:
-    bom = Bom(services=[
-        Service(name='my-first-service'),
-        Service(name='my-second-service')
+    bom = _makeBom(services=[
+        Service(name='my-first-service', bom_ref='my-specific-bom-ref-for-my-first-service'),
+        Service(name='my-second-service', bom_ref='my-specific-bom-ref-for-my-second-service')
     ])
     bom.metadata.component = Component(
-        name='cyclonedx-python-lib', version='1.0.0', type=ComponentType.LIBRARY
+        name='cyclonedx-python-lib', version='1.0.0', type=ComponentType.LIBRARY,
+        bom_ref='my-specific-bom-ref-for-cpl'
     )
     return bom
 
 
 def get_bom_with_services_complex() -> Bom:
-    bom = Bom(services=[
+    bom = _makeBom(services=[
         Service(
             name='my-first-service', bom_ref='my-specific-bom-ref-for-my-first-service',
             provider=get_org_entity_1(), group='a-group', version='1.2.3',
@@ -297,16 +318,17 @@ def get_bom_with_services_complex() -> Bom:
             properties=get_properties_1(),
             release_notes=get_release_notes()
         ),
-        Service(name='my-second-service')
+        Service(name='my-second-service', bom_ref='my-specific-bom-ref-for-my-second-service')
     ])
     bom.metadata.component = Component(
-        name='cyclonedx-python-lib', version='1.0.0', type=ComponentType.LIBRARY
+        name='cyclonedx-python-lib', version='1.0.0', type=ComponentType.LIBRARY,
+        bom_ref='my-specific-bom-ref-for-cpl'
     )
     return bom
 
 
 def get_bom_with_nested_services() -> Bom:
-    bom = Bom(services=[
+    bom = _makeBom(services=[
         Service(
             name='my-first-service', bom_ref='my-specific-bom-ref-for-my-first-service',
             provider=get_org_entity_1(), group='a-group', version='1.2.3',
@@ -326,7 +348,7 @@ def get_bom_with_nested_services() -> Bom:
             properties=get_properties_1(),
             services=[
                 Service(
-                    name='first-nested-service'
+                    name='first-nested-service', bom_ref='my-specific-bom-ref-for-first-nested-service',
                 ),
                 Service(
                     name='second-nested-service', bom_ref='my-specific-bom-ref-for-second-nested-service',
@@ -338,6 +360,7 @@ def get_bom_with_nested_services() -> Bom:
         ),
         Service(
             name='my-second-service',
+            bom_ref='my-specific-bom-ref-for-my-second-service',
             services=[
                 Service(
                     name='yet-another-nested-service', provider=get_org_entity_1(), group='what-group', version='6.5.4'
@@ -350,7 +373,8 @@ def get_bom_with_nested_services() -> Bom:
         )
     ])
     bom.metadata.component = Component(
-        name='cyclonedx-python-lib', version='1.0.0', type=ComponentType.LIBRARY
+        name='cyclonedx-python-lib', version='1.0.0', type=ComponentType.LIBRARY,
+        bom_ref='my-specific-bom-ref-for-cpl'
     )
     return bom
 
@@ -360,10 +384,10 @@ def get_bom_for_issue_275_components() -> Bom:
     see https://github.com/CycloneDX/cyclonedx-python-lib/issues/275
     """
 
-    app = Component(bom_ref=MOCK_UUID_1, name="app", version="1.0.0")
-    comp_a = Component(bom_ref=MOCK_UUID_2, name="comp_a", version="1.0.0")
-    comp_b = Component(bom_ref=MOCK_UUID_3, name="comp_b", version="1.0.0")
-    comp_c = Component(bom_ref=MOCK_UUID_4, name="comp_c", version="1.0.0")
+    app = Component(bom_ref=MOCK_UUID[0], name="app", version="1.0.0")
+    comp_a = Component(bom_ref=MOCK_UUID[1], name="comp_a", version="1.0.0")
+    comp_b = Component(bom_ref=MOCK_UUID[2], name="comp_b", version="1.0.0")
+    comp_c = Component(bom_ref=MOCK_UUID[3], name="comp_c", version="1.0.0")
 
     comp_b.components.add(comp_c)
     # comp_b.dependencies.add(comp_c.bom_ref)
@@ -372,7 +396,7 @@ def get_bom_for_issue_275_components() -> Bom:
     # app.dependencies.add(comp_a.bom_ref)
     # app.dependencies.add(comp_b.bom_ref)
 
-    bom = Bom(components=libs)
+    bom = _makeBom(components=libs)
     bom.metadata.component = app
     bom.register_dependency(target=app, depends_on=[comp_a, comp_b])
     bom.register_dependency(target=comp_b, depends_on=[comp_c])
@@ -391,7 +415,7 @@ def get_bom_for_issue_275_components() -> Bom:
 #    serv_b.services.add(serv_c)
 #    serv_b.dependencies.add(serv_c.bom_ref)
 #
-#    bom = Bom(services=[serv_a, serv_b])
+#    bom = _makeBom(services=[serv_a, serv_b])
 #    bom.metadata.component = app
 #    return bom
 
@@ -400,6 +424,7 @@ def get_bom_for_issue_328_components() -> Bom:
     """regression test for issue #328
     see https://github.com/CycloneDX/cyclonedx-python-lib/issues/328
     """
+    bom = _makeBom()
 
     comp_root = Component(type=ComponentType.APPLICATION,
                           name='my-project', version='1', bom_ref='my-project')
@@ -410,19 +435,20 @@ def get_bom_for_issue_328_components() -> Bom:
     # Make a tree of components A -> B -> C
     comp_a.components = [comp_b]
     comp_b.components = [comp_c]
-    # Declare dependencies the same way: A -> B -> C
-    comp_a.dependencies = [comp_b.bom_ref]
-    comp_b.dependencies = [comp_c.bom_ref]
 
-    bom = Bom()
     bom.metadata.component = comp_root
-    comp_root.dependencies = [comp_a.bom_ref]
+    bom.register_dependency(comp_root, [comp_a])
     bom.components = [comp_a]
+
+    # Declare dependencies the same way: A -> B -> C
+    bom.register_dependency(comp_a, [comp_b])
+    bom.register_dependency(comp_b, [comp_c])
+
     return bom
 
 
 def get_component_setuptools_complete(include_pedigree: bool = True) -> Component:
-    component = get_component_setuptools_simple(bom_ref=None)
+    component = get_component_setuptools_simple(bom_ref='my-specific-bom-ref-for-dings')
     component.supplier = get_org_entity_1()
     component.publisher = 'CycloneDX'
     component.description = 'This component is awesome'
@@ -691,14 +717,28 @@ def get_bom_service_licenses_invalid() -> Bom:
     ])
 
 
-T = TypeVar('T')
+all_get_bom_funct_valid = tuple(
+    (n, f) for n, f in getmembers(sys.modules[__name__], isfunction)
+    if n.startswith('get_bom_') and not n.endswith('_invalid')
+)
 
+all_get_bom_funct_invalid = tuple(
+    (n, f) for n, f in getmembers(sys.modules[__name__], isfunction)
+    if n.startswith('get_bom_') and n.endswith('_invalid')
+)
 
-def reorder(items: List[T], indexes: List[int]) -> List[T]:
-    """
-    Return list of items in the order indicated by indexes.
-    """
-    reordered_items = []
-    for i in range(len(items)):
-        reordered_items.append(items[indexes[i]])
-    return reordered_items
+all_get_bom_funct_with_incomplete_deps = {
+    get_bom_just_complete_metadata,
+    get_bom_with_component_setuptools_basic,
+    get_bom_with_component_setuptools_complete,
+    get_bom_with_component_setuptools_no_component_version,
+    get_bom_with_component_setuptools_with_cpe,
+    get_bom_with_component_setuptools_with_release_notes,
+    get_bom_with_component_setuptools_with_vulnerability,
+    get_bom_with_component_toml_1,
+    get_bom_with_dependencies_hanging,
+    get_bom_with_metadata_component_and_dependencies,
+    get_bom_with_nested_services,
+    get_bom_with_services_complex,
+    get_bom_with_services_simple,
+}
diff --git a/tests/_data/own/.gitattributes b/tests/_data/own/.gitattributes
index 759d4136b..2b6ec797a 100644
--- a/tests/_data/own/.gitattributes
+++ b/tests/_data/own/.gitattributes
@@ -1,3 +1,2 @@
-*               binary
-xml/*/*.xml     linguist-generated diff=xml
-json/*/*.json   linguist-generated diff=json
+xml/*/*.xml     linguist-generated
+json/*/*.json   linguist-generated
diff --git a/tests/_data/own/README.md b/tests/_data/own/README.md
index f97432444..ad527e194 100644
--- a/tests/_data/own/README.md
+++ b/tests/_data/own/README.md
@@ -1,13 +1 @@
 # TEST FIXTURES
-
-## RE-CREATION
-
-Some assets here can be (re-)created automatically, by setting the env var `CDX_TEST_RECREATE_SNAPSHOTS=1`.  
-It might also help to set `PYTHONHASHSEED=0`!  
-As a shortcut just run:
-
-```shell
-CDX_TEST_RECREATE_SNAPSHOTS=1 poetry run tox -e py
-```
-
-The files will be written as is, which might not be human-readable. feel free to reformat the files manually.
diff --git a/tests/_data/own/json/1.4/bom_setuptools.json b/tests/_data/own/json/1.4/bom_setuptools.json
deleted file mode 100644
index 4fd30cacd..000000000
--- a/tests/_data/own/json/1.4/bom_setuptools.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
-        "externalReferences": [
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
-          },
-          {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
-          },
-          {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
-          },
-          {
-            "url": "https://cyclonedx.org",
-            "type": "website"
-          }
-        ]
-      }
-    ]
-  },
-  "components": [
-    {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "licenses": [
-        {
-          "expression": "MIT License"
-        }
-      ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  ],
-  "dependencies": [
-    {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  ]
-}
diff --git a/tests/_data/own/json/1.4/indented_4spaces.json b/tests/_data/own/json/1.4/indented_4spaces.json
deleted file mode 100644
index a37dc693d..000000000
--- a/tests/_data/own/json/1.4/indented_4spaces.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
-    "components": [
-        {
-            "author": "Test Author",
-            "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-            "licenses": [
-                {
-                    "expression": "MIT License"
-                }
-            ],
-            "name": "setuptools",
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-            "type": "library",
-            "version": "50.3.2"
-        }
-    ],
-    "dependencies": [
-        {
-            "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-        }
-    ],
-    "metadata": {
-        "timestamp": "2021-12-31T10:00:00+00:00",
-        "tools": [
-            {
-                "externalReferences": [
-                    {
-                        "type": "build-system",
-                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
-                    },
-                    {
-                        "type": "distribution",
-                        "url": "https://pypi.org/project/cyclonedx-python-lib/"
-                    },
-                    {
-                        "type": "documentation",
-                        "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
-                    },
-                    {
-                        "type": "issue-tracker",
-                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
-                    },
-                    {
-                        "type": "license",
-                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
-                    },
-                    {
-                        "type": "release-notes",
-                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
-                    },
-                    {
-                        "type": "vcs",
-                        "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
-                    },
-                    {
-                        "type": "website",
-                        "url": "https://cyclonedx.org"
-                    }
-                ],
-                "name": "cyclonedx-python-lib",
-                "vendor": "CycloneDX",
-                "version": "TESTING"
-            }
-        ]
-    },
-    "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-    "version": 1,
-    "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-    "bomFormat": "CycloneDX",
-    "specVersion": "1.4"
-}
\ No newline at end of file
diff --git a/tests/_data/own/json/1.4/indented_None.json b/tests/_data/own/json/1.4/indented_None.json
deleted file mode 100644
index 5f0687d8c..000000000
--- a/tests/_data/own/json/1.4/indented_None.json
+++ /dev/null
@@ -1 +0,0 @@
-{"components": [{"author": "Test Author", "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", "licenses": [{"expression": "MIT License"}], "name": "setuptools", "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", "type": "library", "version": "50.3.2"}], "dependencies": [{"ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"}], "metadata": {"timestamp": "2021-12-31T10:00:00+00:00", "tools": [{"externalReferences": [{"type": "build-system", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"}, {"type": "distribution", "url": "https://pypi.org/project/cyclonedx-python-lib/"}, {"type": "documentation", "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"}, {"type": "issue-tracker", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"}, {"type": "license", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"}, {"type": "release-notes", "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"}, {"type": "vcs", "url": "https://github.com/CycloneDX/cyclonedx-python-lib"}, {"type": "website", "url": "https://cyclonedx.org"}], "name": "cyclonedx-python-lib", "vendor": "CycloneDX", "version": "TESTING"}]}, "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", "version": 1, "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json", "bomFormat": "CycloneDX", "specVersion": "1.4"}
\ No newline at end of file
diff --git a/tests/_data/own/json/1.4/indented_tab.json b/tests/_data/own/json/1.4/indented_tab.json
deleted file mode 100644
index 5f4ddb09a..000000000
--- a/tests/_data/own/json/1.4/indented_tab.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
-	"components": [
-		{
-			"author": "Test Author",
-			"bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-			"licenses": [
-				{
-					"expression": "MIT License"
-				}
-			],
-			"name": "setuptools",
-			"purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-			"type": "library",
-			"version": "50.3.2"
-		}
-	],
-	"dependencies": [
-		{
-			"ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-		}
-	],
-	"metadata": {
-		"timestamp": "2021-12-31T10:00:00+00:00",
-		"tools": [
-			{
-				"externalReferences": [
-					{
-						"type": "build-system",
-						"url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
-					},
-					{
-						"type": "distribution",
-						"url": "https://pypi.org/project/cyclonedx-python-lib/"
-					},
-					{
-						"type": "documentation",
-						"url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
-					},
-					{
-						"type": "issue-tracker",
-						"url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
-					},
-					{
-						"type": "license",
-						"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
-					},
-					{
-						"type": "release-notes",
-						"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
-					},
-					{
-						"type": "vcs",
-						"url": "https://github.com/CycloneDX/cyclonedx-python-lib"
-					},
-					{
-						"type": "website",
-						"url": "https://cyclonedx.org"
-					}
-				],
-				"name": "cyclonedx-python-lib",
-				"vendor": "CycloneDX",
-				"version": "TESTING"
-			}
-		]
-	},
-	"serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-	"version": 1,
-	"$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-	"bomFormat": "CycloneDX",
-	"specVersion": "1.4"
-}
\ No newline at end of file
diff --git a/tests/_data/own/xml/1.0/bom_issue_275_components.xml b/tests/_data/own/xml/1.0/bom_issue_275_components.xml
deleted file mode 100644
index c7c26afb1..000000000
--- a/tests/_data/own/xml/1.0/bom_issue_275_components.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
-    <components>
-        <component type="library">
-            <name>comp_a</name>
-            <version>1.0.0</version>
-            <modified>false</modified>
-        </component>
-        <component type="library">
-            <name>comp_b</name>
-            <version>1.0.0</version>
-            <modified>false</modified>
-            <components>
-                <component type="library">
-                    <name>comp_c</name>
-                    <version>1.0.0</version>
-                    <modified>false</modified>
-                </component>
-            </components>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.0/bom_issue_328_components.xml b/tests/_data/own/xml/1.0/bom_issue_328_components.xml
deleted file mode 100644
index 3d2dc7ab9..000000000
--- a/tests/_data/own/xml/1.0/bom_issue_328_components.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
-    <components>
-        <component type="library">
-            <name>A</name>
-            <version>0.1</version>
-            <modified>false</modified>
-            <components>
-                <component type="library">
-                    <name>B</name>
-                    <version>1.0</version>
-                    <modified>false</modified>
-                    <components>
-                        <component type="library">
-                            <name>C</name>
-                            <version>1.0</version>
-                            <modified>false</modified>
-                        </component>
-                    </components>
-                </component>
-            </components>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.0/bom_setuptools.xml b/tests/_data/own/xml/1.0/bom_setuptools.xml
deleted file mode 100644
index a88232144..000000000
--- a/tests/_data/own/xml/1.0/bom_setuptools.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
-    <components>
-        <component type="library">
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <modified>false</modified>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.0/bom_setuptools_complete.xml b/tests/_data/own/xml/1.0/bom_setuptools_complete.xml
deleted file mode 100644
index 796fce001..000000000
--- a/tests/_data/own/xml/1.0/bom_setuptools_complete.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
-    <components>
-        <component type="library">
-            <publisher>CycloneDX</publisher>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <description>This component is awesome</description>
-            <scope>required</scope>
-            <copyright>Apache 2.0 baby!</copyright>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <modified>false</modified>
-            <components>
-                <component type="library">
-                    <name>setuptools</name>
-                    <version>50.3.2</version>
-                    <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    <modified>false</modified>
-                </component>
-                <component type="library">
-                    <name>toml</name>
-                    <version>0.10.2</version>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                    <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                    <modified>false</modified>
-                </component>
-            </components>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.0/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.0/bom_setuptools_no_version.xml
deleted file mode 100644
index 2871e097f..000000000
--- a/tests/_data/own/xml/1.0/bom_setuptools_no_version.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
-    <components>
-        <component type="library">
-            <name>setuptools</name>
-            <version/>
-            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-            <modified>false</modified>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.0/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.0/bom_setuptools_with_cpe.xml
deleted file mode 100644
index 0b7982aec..000000000
--- a/tests/_data/own/xml/1.0/bom_setuptools_with_cpe.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
-    <components>
-        <component type="library">
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <modified>false</modified>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.0/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.0/bom_toml_hashes_and_references.xml
deleted file mode 100644
index 04b1faa65..000000000
--- a/tests/_data/own/xml/1.0/bom_toml_hashes_and_references.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
-    <components>
-        <component type="library">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <modified>false</modified>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_dependencies.xml b/tests/_data/own/xml/1.1/bom_dependencies.xml
deleted file mode 100644
index 44cb1a8d7..000000000
--- a/tests/_data/own/xml/1.1/bom_dependencies.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_empty.xml b/tests/_data/own/xml/1.1/bom_empty.xml
deleted file mode 100644
index 07db9157f..000000000
--- a/tests/_data/own/xml/1.1/bom_empty.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components/>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_external_references.xml b/tests/_data/own/xml/1.1/bom_external_references.xml
deleted file mode 100644
index 1100a3e88..000000000
--- a/tests/_data/own/xml/1.1/bom_external_references.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components/>
-    <externalReferences>
-        <reference type="distribution">
-            <url>https://cyclonedx.org</url>
-            <comment>No comment</comment>
-        </reference>
-        <reference type="website">
-            <url>https://cyclonedx.org</url>
-        </reference>
-    </externalReferences>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_issue_275_components.xml b/tests/_data/own/xml/1.1/bom_issue_275_components.xml
deleted file mode 100644
index 19b2b3573..000000000
--- a/tests/_data/own/xml/1.1/bom_issue_275_components.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components>
-        <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-            <name>comp_a</name>
-            <version>1.0.0</version>
-        </component>
-        <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>comp_b</name>
-            <version>1.0.0</version>
-            <components>
-                <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-                    <name>comp_c</name>
-                    <version>1.0.0</version>
-                </component>
-            </components>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_issue_328_components.xml b/tests/_data/own/xml/1.1/bom_issue_328_components.xml
deleted file mode 100644
index b72c3bcc6..000000000
--- a/tests/_data/own/xml/1.1/bom_issue_328_components.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:fa443043-7dca-4c17-b9bc-e8b63faa9711">
-    <components>
-        <component type="library" bom-ref="component-A">
-            <name>A</name>
-            <version>0.1</version>
-            <components>
-                <component type="library" bom-ref="component-B">
-                    <name>B</name>
-                    <version>1.0</version>
-                    <components>
-                        <component type="library" bom-ref="component-C">
-                            <name>C</name>
-                            <version>1.0</version>
-                        </component>
-                    </components>
-                </component>
-            </components>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_setuptools.xml b/tests/_data/own/xml/1.1/bom_setuptools.xml
deleted file mode 100644
index 74c050f1a..000000000
--- a/tests/_data/own/xml/1.1/bom_setuptools.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_setuptools_complete.xml b/tests/_data/own/xml/1.1/bom_setuptools_complete.xml
deleted file mode 100644
index b18d1d36f..000000000
--- a/tests/_data/own/xml/1.1/bom_setuptools_complete.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components>
-        <component type="library" bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <publisher>CycloneDX</publisher>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <description>This component is awesome</description>
-            <scope>required</scope>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <copyright>Apache 2.0 baby!</copyright>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <pedigree>
-                <ancestors>
-                    <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                </ancestors>
-                <descendants>
-                    <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </descendants>
-                <variants>
-                    <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </variants>
-                <commits>
-                    <commit>
-                        <uid>a-random-uid</uid>
-                        <message>A commit message</message>
-                    </commit>
-                </commits>
-                <notes>Some notes here please</notes>
-            </pedigree>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-            <components>
-                <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <name>setuptools</name>
-                    <version>50.3.2</version>
-                    <licenses>
-                        <expression>MIT License</expression>
-                    </licenses>
-                    <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                </component>
-                <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-                    <name>toml</name>
-                    <version>0.10.2</version>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                    <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                    <externalReferences>
-                        <reference type="distribution">
-                            <url>https://cyclonedx.org</url>
-                            <comment>No comment</comment>
-                        </reference>
-                    </externalReferences>
-                </component>
-            </components>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.1/bom_setuptools_no_version.xml
deleted file mode 100644
index 2a24f4bc1..000000000
--- a/tests/_data/own/xml/1.1/bom_setuptools_no_version.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools?extension=tar.gz">
-            <name>setuptools</name>
-            <version/>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.1/bom_setuptools_with_cpe.xml
deleted file mode 100644
index b8e9cf150..000000000
--- a/tests/_data/own/xml/1.1/bom_setuptools_with_cpe.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_setuptools_with_vulnerabilities.xml b/tests/_data/own/xml/1.1/bom_setuptools_with_vulnerabilities.xml
deleted file mode 100644
index 555d41868..000000000
--- a/tests/_data/own/xml/1.1/bom_setuptools_with_vulnerabilities.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:98149a18-a918-4083-837f-e006d26ab3b4"
-     xmlns:v="http://cyclonedx.org/schema/ext/vulnerability/1.0">
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <v:vulnerabilities>
-                <v:vulnerability ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <v:id>CVE-2018-7489</v:id>
-                    <v:source name="NVD">
-                        <v:url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</v:url>
-                    </v:source>
-                    <v:ratings>
-                        <v:rating>
-                            <v:score>
-                                <v:base>9.8</v:base>
-                            </v:score>
-                            <v:severity>Critical</v:severity>
-                            <v:method>CVSSv3</v:method>
-                            <v:vector>AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H</v:vector>
-                        </v:rating>
-                        <v:rating>
-                            <v:score>
-                                <v:base>2.7</v:base>
-                            </v:score>
-                            <v:severity>Low</v:severity>
-                            <v:method>CVSSv3</v:method>
-                            <v:vector>AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N</v:vector>
-                        </v:rating>
-                    </v:ratings>
-                    <v:cwes>
-                        <v:cwe>22</v:cwe>
-                        <v:cwe>33</v:cwe>
-                    </v:cwes>
-                    <v:description>A description here</v:description>
-                    <v:recommendations>
-                        <v:recommendation>Upgrade</v:recommendation>
-                    </v:recommendations>
-                    <v:advisories>
-                        <v:advisory>http://www.securitytracker.com/id/1040693</v:advisory>
-                        <v:advisory>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</v:advisory>
-                    </v:advisories>
-                </v:vulnerability>
-            </v:vulnerabilities>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.1/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.1/bom_toml_hashes_and_references.xml
deleted file mode 100644
index 4020f6fef..000000000
--- a/tests/_data/own/xml/1.1/bom_toml_hashes_and_references.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.1" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <components>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_dependencies.xml b/tests/_data/own/xml/1.2/bom_dependencies.xml
deleted file mode 100644
index a3a52dc7d..000000000
--- a/tests/_data/own/xml/1.2/bom_dependencies.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-        </dependency>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_dependencies_component.xml b/tests/_data/own/xml/1.2/bom_dependencies_component.xml
deleted file mode 100644
index b301d92c0..000000000
--- a/tests/_data/own/xml/1.2/bom_dependencies_component.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-        </dependency>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_external_references.xml b/tests/_data/own/xml/1.2/bom_external_references.xml
deleted file mode 100644
index 3187c7a97..000000000
--- a/tests/_data/own/xml/1.2/bom_external_references.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <externalReferences>
-        <reference type="distribution">
-            <url>https://cyclonedx.org</url>
-            <comment>No comment</comment>
-        </reference>
-        <reference type="website">
-            <url>https://cyclonedx.org</url>
-        </reference>
-    </externalReferences>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_issue_275_components.xml b/tests/_data/own/xml/1.2/bom_issue_275_components.xml
deleted file mode 100644
index 2c0584bc8..000000000
--- a/tests/_data/own/xml/1.2/bom_issue_275_components.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>app</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-            <name>comp_a</name>
-            <version>1.0.0</version>
-        </component>
-        <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>comp_b</name>
-            <version>1.0.0</version>
-            <components>
-                <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-                    <name>comp_c</name>
-                    <version>1.0.0</version>
-                </component>
-            </components>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
-            <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-        </dependency>
-        <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-        </dependency>
-        <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_issue_328_components.xml b/tests/_data/own/xml/1.2/bom_issue_328_components.xml
deleted file mode 100644
index b5093aaea..000000000
--- a/tests/_data/own/xml/1.2/bom_issue_328_components.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:b348cb37-e5e3-4b10-81ac-fc4e2f72dbd6">
-    <metadata>
-        <timestamp>2023-01-07T13:52:31.865875+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="application" bom-ref="my-project">
-            <name>my-project</name>
-            <version>1</version>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="component-A">
-            <name>A</name>
-            <version>0.1</version>
-            <components>
-                <component type="library" bom-ref="component-B">
-                    <name>B</name>
-                    <version>1.0</version>
-                    <components>
-                        <component type="library" bom-ref="component-C">
-                            <name>C</name>
-                            <version>1.0</version>
-                        </component>
-                    </components>
-                </component>
-            </components>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="my-project">
-            <dependency ref="component-A"/>
-        </dependency>
-        <dependency ref="component-A">
-            <dependency ref="component-B"/>
-        </dependency>
-        <dependency ref="component-B">
-            <dependency ref="component-C"/>
-        </dependency>
-        <dependency ref="component-C"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_services_complex.xml b/tests/_data/own/xml/1.2/bom_services_complex.xml
deleted file mode 100644
index fb379dd24..000000000
--- a/tests/_data/own/xml/1.2/bom_services_complex.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="my-specific-bom-ref-for-my-first-service">
-            <provider>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </provider>
-            <group>a-group</group>
-            <name>my-first-service</name>
-            <version>1.2.3</version>
-            <description>Description goes here</description>
-            <endpoints>
-                <endpoint>/api/thing/1</endpoint>
-                <endpoint>/api/thing/2</endpoint>
-            </endpoints>
-            <authenticated>false</authenticated>
-            <x-trust-boundary>true</x-trust-boundary>
-            <data>
-                <classification flow="outbound">public</classification>
-            </data>
-            <licenses>
-                <expression>Commercial</expression>
-            </licenses>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-        </service>
-        <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>my-second-service</name>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3"/>
-        <dependency ref="my-specific-bom-ref-for-my-first-service"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_services_nested.xml b/tests/_data/own/xml/1.2/bom_services_nested.xml
deleted file mode 100644
index b3fce9899..000000000
--- a/tests/_data/own/xml/1.2/bom_services_nested.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="df70b5f1-8f53-47a4-be48-669ae78795e6">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="my-specific-bom-ref-for-my-first-service">
-            <provider>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </provider>
-            <group>a-group</group>
-            <name>my-first-service</name>
-            <version>1.2.3</version>
-            <description>Description goes here</description>
-            <endpoints>
-                <endpoint>/api/thing/1</endpoint>
-                <endpoint>/api/thing/2</endpoint>
-            </endpoints>
-            <authenticated>false</authenticated>
-            <x-trust-boundary>true</x-trust-boundary>
-            <data>
-                <classification flow="outbound">public</classification>
-            </data>
-            <licenses>
-                <expression>Commercial</expression>
-            </licenses>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-            <services>
-                <service bom-ref="my-specific-bom-ref-for-second-nested-service">
-                    <provider>
-                        <name>CycloneDX</name>
-                        <url>https://cyclonedx.org</url>
-                        <contact>
-                            <name>A N Other</name>
-                            <email>someone@somewhere.tld</email>
-                            <phone>+44 (0)1234 567890</phone>
-                        </contact>
-                        <contact>
-                            <name>Paul Horton</name>
-                            <email>paul.horton@owasp.org</email>
-                        </contact>
-                    </provider>
-                    <group>no-group</group>
-                    <name>second-nested-service</name>
-                    <version>3.2.1</version>
-                    <authenticated>true</authenticated>
-                    <x-trust-boundary>false</x-trust-boundary>
-                </service>
-                <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-                    <name>first-nested-service</name>
-                </service>
-            </services>
-        </service>
-        <service bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>my-second-service</name>
-            <services>
-                <service bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-                    <provider>
-                        <name>CycloneDX</name>
-                        <url>https://cyclonedx.org</url>
-                        <contact>
-                            <name>A N Other</name>
-                            <email>someone@somewhere.tld</email>
-                            <phone>+44 (0)1234 567890</phone>
-                        </contact>
-                        <contact>
-                            <name>Paul Horton</name>
-                            <email>paul.horton@owasp.org</email>
-                        </contact>
-                    </provider>
-                    <group>what-group</group>
-                    <name>yet-another-nested-service</name>
-                    <version>6.5.4</version>
-                </service>
-                <service bom-ref="my-specific-bom-ref-for-another-nested-service">
-                    <name>another-nested-service</name>
-                </service>
-            </services>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="df70b5f1-8f53-47a4-be48-669ae78795e6"/>
-        <dependency ref="my-specific-bom-ref-for-my-first-service"/>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_services_simple.xml b/tests/_data/own/xml/1.2/bom_services_simple.xml
deleted file mode 100644
index 7595971a2..000000000
--- a/tests/_data/own/xml/1.2/bom_services_simple.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>my-first-service</name>
-        </service>
-        <service bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-            <name>my-second-service</name>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3"/>
-        <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_setuptools.xml b/tests/_data/own/xml/1.2/bom_setuptools.xml
deleted file mode 100644
index ffdfcc422..000000000
--- a/tests/_data/own/xml/1.2/bom_setuptools.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_setuptools_complete.xml b/tests/_data/own/xml/1.2/bom_setuptools_complete.xml
deleted file mode 100644
index 4a16c92c7..000000000
--- a/tests/_data/own/xml/1.2/bom_setuptools_complete.xml
+++ /dev/null
@@ -1,162 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-            <supplier>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </supplier>
-            <author>Test Author</author>
-            <publisher>CycloneDX</publisher>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <description>This component is awesome</description>
-            <scope>required</scope>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <copyright>Apache 2.0 baby!</copyright>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
-                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
-            </swid>
-            <pedigree>
-                <ancestors>
-                    <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                </ancestors>
-                <descendants>
-                    <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </descendants>
-                <variants>
-                    <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </variants>
-                <commits>
-                    <commit>
-                        <uid>a-random-uid</uid>
-                        <message>A commit message</message>
-                    </commit>
-                </commits>
-                <patches>
-                    <patch type="backport"/>
-                </patches>
-                <notes>Some notes here please</notes>
-            </pedigree>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-            <components>
-                <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <author>Test Author</author>
-                    <name>setuptools</name>
-                    <version>50.3.2</version>
-                    <licenses>
-                        <expression>MIT License</expression>
-                    </licenses>
-                    <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                </component>
-                <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-                    <name>toml</name>
-                    <version>0.10.2</version>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                    <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                    <externalReferences>
-                        <reference type="distribution">
-                            <url>https://cyclonedx.org</url>
-                            <comment>No comment</comment>
-                        </reference>
-                    </externalReferences>
-                </component>
-            </components>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.2/bom_setuptools_no_version.xml
deleted file mode 100644
index c80352ac6..000000000
--- a/tests/_data/own/xml/1.2/bom_setuptools_no_version.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version/>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.2/bom_setuptools_with_cpe.xml
deleted file mode 100644
index f143d86ea..000000000
--- a/tests/_data/own/xml/1.2/bom_setuptools_with_cpe.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_setuptools_with_vulnerabilities.xml b/tests/_data/own/xml/1.2/bom_setuptools_with_vulnerabilities.xml
deleted file mode 100644
index 39e4c53c3..000000000
--- a/tests/_data/own/xml/1.2/bom_setuptools_with_vulnerabilities.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:985deff3-4e92-4284-a6da-eab046d13ecf"
-     xmlns:v="http://cyclonedx.org/schema/ext/vulnerability/1.0">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.626402+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <v:vulnerabilities>
-                <v:vulnerability ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <v:id>CVE-2018-7489</v:id>
-                    <v:source name="NVD">
-                        <v:url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</v:url>
-                    </v:source>
-                    <v:ratings>
-                        <v:rating>
-                            <v:score>
-                                <v:base>9.8</v:base>
-                            </v:score>
-                            <v:severity>Critical</v:severity>
-                            <v:method>CVSSv3</v:method>
-                            <v:vector>AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H</v:vector>
-                        </v:rating>
-                        <v:rating>
-                            <v:score>
-                                <v:base>2.7</v:base>
-                            </v:score>
-                            <v:severity>Low</v:severity>
-                            <v:method>CVSSv3</v:method>
-                            <v:vector>AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N</v:vector>
-                        </v:rating>
-                    </v:ratings>
-                    <v:cwes>
-                        <v:cwe>22</v:cwe>
-                        <v:cwe>33</v:cwe>
-                    </v:cwes>
-                    <v:description>A description here</v:description>
-                    <v:recommendations>
-                        <v:recommendation>Upgrade</v:recommendation>
-                    </v:recommendations>
-                    <v:advisories>
-                        <v:advisory>http://www.securitytracker.com/id/1040693</v:advisory>
-                        <v:advisory>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</v:advisory>
-                    </v:advisories>
-                </v:vulnerability>
-            </v:vulnerabilities>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.2/bom_toml_hashes_and_references.xml
deleted file mode 100644
index 30cf691b6..000000000
--- a/tests/_data/own/xml/1.2/bom_toml_hashes_and_references.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.2/bom_with_full_metadata.xml b/tests/_data/own/xml/1.2/bom_with_full_metadata.xml
deleted file mode 100644
index 056af1731..000000000
--- a/tests/_data/own/xml/1.2/bom_with_full_metadata.xml
+++ /dev/null
@@ -1,193 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <authors>
-            <author>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </author>
-            <author>
-                <name>Paul Horton</name>
-                <email>paul.horton@owasp.org</email>
-            </author>
-        </authors>
-        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-            <supplier>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </supplier>
-            <author>Test Author</author>
-            <publisher>CycloneDX</publisher>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <description>This component is awesome</description>
-            <scope>required</scope>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <copyright>Apache 2.0 baby!</copyright>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
-                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
-            </swid>
-            <pedigree>
-                <ancestors>
-                    <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                </ancestors>
-                <descendants>
-                    <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </descendants>
-                <variants>
-                    <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </variants>
-                <commits>
-                    <commit>
-                        <uid>a-random-uid</uid>
-                        <message>A commit message</message>
-                    </commit>
-                </commits>
-                <patches>
-                    <patch type="backport"/>
-                </patches>
-                <notes>Some notes here please</notes>
-            </pedigree>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                </reference>
-            </externalReferences>
-            <components>
-                <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <author>Test Author</author>
-                    <name>setuptools</name>
-                    <version>50.3.2</version>
-                    <licenses>
-                        <expression>MIT License</expression>
-                    </licenses>
-                    <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                </component>
-                <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-                    <name>toml</name>
-                    <version>0.10.2</version>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                    <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                    <externalReferences>
-                        <reference type="distribution">
-                            <url>https://cyclonedx.org</url>
-                            <comment>No comment</comment>
-                        </reference>
-                    </externalReferences>
-                </component>
-            </components>
-        </component>
-        <manufacture>
-            <name>CycloneDX</name>
-            <url>https://cyclonedx.org</url>
-            <contact>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </contact>
-            <contact>
-                <name>Paul Horton</name>
-                <email>paul.horton@owasp.org</email>
-            </contact>
-        </manufacture>
-        <supplier>
-            <name>Cyclone DX</name>
-            <url>https://cyclonedx.org/</url>
-            <contact>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </contact>
-        </supplier>
-    </metadata>
-    <dependencies>
-        <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_dependencies.xml b/tests/_data/own/xml/1.3/bom_dependencies.xml
deleted file mode 100644
index 3685ff849..000000000
--- a/tests/_data/own/xml/1.3/bom_dependencies.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-        </dependency>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_dependencies_component.xml b/tests/_data/own/xml/1.3/bom_dependencies_component.xml
deleted file mode 100644
index bbe61960d..000000000
--- a/tests/_data/own/xml/1.3/bom_dependencies_component.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-        </dependency>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_external_references.xml b/tests/_data/own/xml/1.3/bom_external_references.xml
deleted file mode 100644
index 443d36cc8..000000000
--- a/tests/_data/own/xml/1.3/bom_external_references.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <externalReferences>
-        <reference type="distribution">
-            <url>https://cyclonedx.org</url>
-            <comment>No comment</comment>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-        </reference>
-        <reference type="website">
-            <url>https://cyclonedx.org</url>
-        </reference>
-    </externalReferences>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_issue_275_components.xml b/tests/_data/own/xml/1.3/bom_issue_275_components.xml
deleted file mode 100644
index d41ae90b5..000000000
--- a/tests/_data/own/xml/1.3/bom_issue_275_components.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>app</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-            <name>comp_a</name>
-            <version>1.0.0</version>
-        </component>
-        <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>comp_b</name>
-            <version>1.0.0</version>
-            <components>
-                <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-                    <name>comp_c</name>
-                    <version>1.0.0</version>
-                </component>
-            </components>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
-            <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-        </dependency>
-        <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-        </dependency>
-        <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_issue_328_components.xml b/tests/_data/own/xml/1.3/bom_issue_328_components.xml
deleted file mode 100644
index ad5e62583..000000000
--- a/tests/_data/own/xml/1.3/bom_issue_328_components.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:2c421d7e-7a78-46db-a60c-6648b2b76eea">
-    <metadata>
-        <timestamp>2023-01-07T13:52:32.198166+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="application" bom-ref="my-project">
-            <name>my-project</name>
-            <version>1</version>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="component-A">
-            <name>A</name>
-            <version>0.1</version>
-            <components>
-                <component type="library" bom-ref="component-B">
-                    <name>B</name>
-                    <version>1.0</version>
-                    <components>
-                        <component type="library" bom-ref="component-C">
-                            <name>C</name>
-                            <version>1.0</version>
-                        </component>
-                    </components>
-                </component>
-            </components>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="my-project">
-            <dependency ref="component-A"/>
-        </dependency>
-        <dependency ref="component-A">
-            <dependency ref="component-B"/>
-        </dependency>
-        <dependency ref="component-B">
-            <dependency ref="component-C"/>
-        </dependency>
-        <dependency ref="component-C"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_services_complex.xml b/tests/_data/own/xml/1.3/bom_services_complex.xml
deleted file mode 100644
index f62058f0b..000000000
--- a/tests/_data/own/xml/1.3/bom_services_complex.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="my-specific-bom-ref-for-my-first-service">
-            <provider>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </provider>
-            <group>a-group</group>
-            <name>my-first-service</name>
-            <version>1.2.3</version>
-            <description>Description goes here</description>
-            <endpoints>
-                <endpoint>/api/thing/1</endpoint>
-                <endpoint>/api/thing/2</endpoint>
-            </endpoints>
-            <authenticated>false</authenticated>
-            <x-trust-boundary>true</x-trust-boundary>
-            <data>
-                <classification flow="outbound">public</classification>
-            </data>
-            <licenses>
-                <expression>Commercial</expression>
-            </licenses>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-        </service>
-        <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>my-second-service</name>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789" />
-        <dependency ref="my-specific-bom-ref-for-my-first-service"/>
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_services_nested.xml b/tests/_data/own/xml/1.3/bom_services_nested.xml
deleted file mode 100644
index ccb0684d6..000000000
--- a/tests/_data/own/xml/1.3/bom_services_nested.xml
+++ /dev/null
@@ -1,120 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="df70b5f1-8f53-47a4-be48-669ae78795e6">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="my-specific-bom-ref-for-my-first-service">
-            <provider>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </provider>
-            <group>a-group</group>
-            <name>my-first-service</name>
-            <version>1.2.3</version>
-            <description>Description goes here</description>
-            <endpoints>
-                <endpoint>/api/thing/1</endpoint>
-                <endpoint>/api/thing/2</endpoint>
-            </endpoints>
-            <authenticated>false</authenticated>
-            <x-trust-boundary>true</x-trust-boundary>
-            <data>
-                <classification flow="outbound">public</classification>
-            </data>
-            <licenses>
-                <expression>Commercial</expression>
-            </licenses>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-            <services>
-                <service bom-ref="my-specific-bom-ref-for-second-nested-service">
-                    <provider>
-                        <name>CycloneDX</name>
-                        <url>https://cyclonedx.org</url>
-                        <contact>
-                            <name>A N Other</name>
-                            <email>someone@somewhere.tld</email>
-                            <phone>+44 (0)1234 567890</phone>
-                        </contact>
-                        <contact>
-                            <name>Paul Horton</name>
-                            <email>paul.horton@owasp.org</email>
-                        </contact>
-                    </provider>
-                    <group>no-group</group>
-                    <name>second-nested-service</name>
-                    <version>3.2.1</version>
-                    <authenticated>true</authenticated>
-                    <x-trust-boundary>false</x-trust-boundary>
-                </service>
-                <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-                    <name>first-nested-service</name>
-                </service>
-            </services>
-        </service>
-        <service bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>my-second-service</name>
-            <services>
-                <service bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-                    <provider>
-                        <name>CycloneDX</name>
-                        <url>https://cyclonedx.org</url>
-                        <contact>
-                            <name>A N Other</name>
-                            <email>someone@somewhere.tld</email>
-                            <phone>+44 (0)1234 567890</phone>
-                        </contact>
-                        <contact>
-                            <name>Paul Horton</name>
-                            <email>paul.horton@owasp.org</email>
-                        </contact>
-                    </provider>
-                    <group>what-group</group>
-                    <name>yet-another-nested-service</name>
-                    <version>6.5.4</version>
-                </service>
-                <service bom-ref="my-specific-bom-ref-for-another-nested-service">
-                    <name>another-nested-service</name>
-                </service>
-            </services>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="df70b5f1-8f53-47a4-be48-669ae78795e6"/>
-        <dependency ref="my-specific-bom-ref-for-my-first-service"/>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_services_simple.xml b/tests/_data/own/xml/1.3/bom_services_simple.xml
deleted file mode 100644
index 7eaaaa6a5..000000000
--- a/tests/_data/own/xml/1.3/bom_services_simple.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>my-first-service</name>
-        </service>
-        <service bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-            <name>my-second-service</name>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3"/>
-        <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_setuptools.xml b/tests/_data/own/xml/1.3/bom_setuptools.xml
deleted file mode 100644
index dbe2a1578..000000000
--- a/tests/_data/own/xml/1.3/bom_setuptools.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_setuptools_complete.xml b/tests/_data/own/xml/1.3/bom_setuptools_complete.xml
deleted file mode 100644
index f9ac65f03..000000000
--- a/tests/_data/own/xml/1.3/bom_setuptools_complete.xml
+++ /dev/null
@@ -1,184 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <supplier>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </supplier>
-            <author>Test Author</author>
-            <publisher>CycloneDX</publisher>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <description>This component is awesome</description>
-            <scope>required</scope>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <copyright>Apache 2.0 baby!</copyright>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
-                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
-            </swid>
-            <pedigree>
-                <ancestors>
-                    <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                </ancestors>
-                <descendants>
-                    <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                                <hashes>
-                                    <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                                </hashes>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </descendants>
-                <variants>
-                    <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                                <hashes>
-                                    <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                                </hashes>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </variants>
-                <commits>
-                    <commit>
-                        <uid>a-random-uid</uid>
-                        <message>A commit message</message>
-                    </commit>
-                </commits>
-                <patches>
-                    <patch type="backport"/>
-                </patches>
-                <notes>Some notes here please</notes>
-            </pedigree>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-            <components>
-                <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <author>Test Author</author>
-                    <name>setuptools</name>
-                    <version>50.3.2</version>
-                    <licenses>
-                        <expression>MIT License</expression>
-                    </licenses>
-                    <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                </component>
-                <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-                    <name>toml</name>
-                    <version>0.10.2</version>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                    <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                    <externalReferences>
-                        <reference type="distribution">
-                            <url>https://cyclonedx.org</url>
-                            <comment>No comment</comment>
-                            <hashes>
-                                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                            </hashes>
-                        </reference>
-                    </externalReferences>
-                </component>
-            </components>
-            <evidence>
-                <copyright>
-                    <text>Commercial</text>
-                    <text>Commercial 2</text>
-                </copyright>
-            </evidence>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.3/bom_setuptools_no_version.xml
deleted file mode 100644
index 9fe150363..000000000
--- a/tests/_data/own/xml/1.3/bom_setuptools_no_version.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version/>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.3/bom_setuptools_with_cpe.xml
deleted file mode 100644
index 27abd9b21..000000000
--- a/tests/_data/own/xml/1.3/bom_setuptools_with_cpe.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_setuptools_with_vulnerabilities.xml b/tests/_data/own/xml/1.3/bom_setuptools_with_vulnerabilities.xml
deleted file mode 100644
index 6cce456e5..000000000
--- a/tests/_data/own/xml/1.3/bom_setuptools_with_vulnerabilities.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:962e7fd7-d097-4cbe-b2b7-19bf54f71075"
-     xmlns:v="http://cyclonedx.org/schema/ext/vulnerability/1.0">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.964601+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <v:vulnerabilities>
-                <v:vulnerability ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <v:id>CVE-2018-7489</v:id>
-                    <v:source name="NVD">
-                        <v:url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</v:url>
-                    </v:source>
-                    <v:ratings>
-                        <v:rating>
-                            <v:score>
-                                <v:base>9.8</v:base>
-                            </v:score>
-                            <v:severity>Critical</v:severity>
-                            <v:method>CVSSv3</v:method>
-                            <v:vector>AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H</v:vector>
-                        </v:rating>
-                        <v:rating>
-                            <v:score>
-                                <v:base>2.7</v:base>
-                            </v:score>
-                            <v:severity>Low</v:severity>
-                            <v:method>CVSSv3</v:method>
-                            <v:vector>AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N</v:vector>
-                        </v:rating>
-                    </v:ratings>
-                    <v:cwes>
-                        <v:cwe>22</v:cwe>
-                        <v:cwe>33</v:cwe>
-                    </v:cwes>
-                    <v:description>A description here</v:description>
-                    <v:recommendations>
-                        <v:recommendation>Upgrade</v:recommendation>
-                    </v:recommendations>
-                    <v:advisories>
-                        <v:advisory>http://www.securitytracker.com/id/1040693</v:advisory>
-                        <v:advisory>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</v:advisory>
-                    </v:advisories>
-                </v:vulnerability>
-            </v:vulnerabilities>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.3/bom_toml_hashes_and_references.xml
deleted file mode 100644
index 3e3c02bc1..000000000
--- a/tests/_data/own/xml/1.3/bom_toml_hashes_and_references.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.3/bom_with_full_metadata.xml b/tests/_data/own/xml/1.3/bom_with_full_metadata.xml
deleted file mode 100644
index 434dd66cf..000000000
--- a/tests/_data/own/xml/1.3/bom_with_full_metadata.xml
+++ /dev/null
@@ -1,226 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.3" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-            </tool>
-        </tools>
-        <authors>
-            <author>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </author>
-            <author>
-                <name>Paul Horton</name>
-                <email>paul.horton@owasp.org</email>
-            </author>
-        </authors>
-        <component type="library" bom-ref="bb5911d6-1a1d-41c9-b6e0-46e848d16655">
-            <supplier>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </supplier>
-            <author>Test Author</author>
-            <publisher>CycloneDX</publisher>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <description>This component is awesome</description>
-            <scope>required</scope>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <copyright>Apache 2.0 baby!</copyright>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
-                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
-            </swid>
-            <pedigree>
-                <ancestors>
-                    <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                </ancestors>
-                <descendants>
-                    <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version/>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                                <hashes>
-                                    <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                                </hashes>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </descendants>
-                <variants>
-                    <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                                <hashes>
-                                    <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                                </hashes>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </variants>
-                <commits>
-                    <commit>
-                        <uid>a-random-uid</uid>
-                        <message>A commit message</message>
-                    </commit>
-                </commits>
-                <patches>
-                    <patch type="backport"/>
-                </patches>
-                <notes>Some notes here please</notes>
-            </pedigree>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-            <components>
-                <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <author>Test Author</author>
-                    <name>setuptools</name>
-                    <version>50.3.2</version>
-                    <licenses>
-                        <expression>MIT License</expression>
-                    </licenses>
-                    <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                </component>
-                <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-                    <name>toml</name>
-                    <version>0.10.2</version>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                    <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                    <externalReferences>
-                        <reference type="distribution">
-                            <url>https://cyclonedx.org</url>
-                            <comment>No comment</comment>
-                            <hashes>
-                                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                            </hashes>
-                        </reference>
-                    </externalReferences>
-                </component>
-            </components>
-            <evidence>
-                <copyright>
-                    <text>Commercial</text>
-                    <text>Commercial 2</text>
-                </copyright>
-            </evidence>
-        </component>
-        <manufacture>
-            <name>CycloneDX</name>
-            <url>https://cyclonedx.org</url>
-            <contact>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </contact>
-            <contact>
-                <name>Paul Horton</name>
-                <email>paul.horton@owasp.org</email>
-            </contact>
-        </manufacture>
-        <supplier>
-            <name>Cyclone DX</name>
-            <url>https://cyclonedx.org/</url>
-            <contact>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </contact>
-        </supplier>
-        <licenses>
-            <license>
-                <id>Apache-2.0</id>
-                <text content-type="text/plain" encoding="base64">VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE=</text>
-                <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
-            </license>
-        </licenses>
-        <properties>
-            <property name="key1">val1</property>
-            <property name="key2">val2</property>
-        </properties>
-    </metadata>
-    <dependencies>
-        <dependency ref="bb5911d6-1a1d-41c9-b6e0-46e848d16655"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_dependencies.xml b/tests/_data/own/xml/1.4/bom_dependencies.xml
deleted file mode 100644
index ecdb150c4..000000000
--- a/tests/_data/own/xml/1.4/bom_dependencies.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-        </dependency>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_dependencies_component.xml b/tests/_data/own/xml/1.4/bom_dependencies_component.xml
deleted file mode 100644
index 0aadc91a1..000000000
--- a/tests/_data/own/xml/1.4/bom_dependencies_component.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-        </dependency>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_external_references.xml b/tests/_data/own/xml/1.4/bom_external_references.xml
deleted file mode 100644
index 146497d34..000000000
--- a/tests/_data/own/xml/1.4/bom_external_references.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <externalReferences>
-        <reference type="distribution">
-            <url>https://cyclonedx.org</url>
-            <comment>No comment</comment>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-        </reference>
-        <reference type="website">
-            <url>https://cyclonedx.org</url>
-        </reference>
-    </externalReferences>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_issue_275_components.xml b/tests/_data/own/xml/1.4/bom_issue_275_components.xml
deleted file mode 100644
index 7d6924a8b..000000000
--- a/tests/_data/own/xml/1.4/bom_issue_275_components.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>app</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-            <name>comp_a</name>
-            <version>1.0.0</version>
-        </component>
-        <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>comp_b</name>
-            <version>1.0.0</version>
-            <components>
-                <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-                    <name>comp_c</name>
-                    <version>1.0.0</version>
-                </component>
-            </components>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
-            <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-        </dependency>
-        <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-        </dependency>
-        <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_issue_328_components.xml b/tests/_data/own/xml/1.4/bom_issue_328_components.xml
deleted file mode 100644
index 004ce30d6..000000000
--- a/tests/_data/own/xml/1.4/bom_issue_328_components.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-        <component type="application" bom-ref="my-project">
-            <name>my-project</name>
-            <version>1</version>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="component-A">
-            <name>A</name>
-            <version>0.1</version>
-            <components>
-                <component type="library" bom-ref="component-B">
-                    <name>B</name>
-                    <version>1.0</version>
-                    <components>
-                        <component type="library" bom-ref="component-C">
-                            <name>C</name>
-                            <version>1.0</version>
-                        </component>
-                    </components>
-                </component>
-            </components>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="my-project">
-            <dependency ref="component-A"/>
-        </dependency>
-        <dependency ref="component-A">
-            <dependency ref="component-B"/>
-        </dependency>
-        <dependency ref="component-B">
-            <dependency ref="component-C"/>
-        </dependency>
-        <dependency ref="component-C"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_services_complex.xml b/tests/_data/own/xml/1.4/bom_services_complex.xml
deleted file mode 100644
index 03d2c4600..000000000
--- a/tests/_data/own/xml/1.4/bom_services_complex.xml
+++ /dev/null
@@ -1,142 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="my-specific-bom-ref-for-my-first-service">
-            <provider>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </provider>
-            <group>a-group</group>
-            <name>my-first-service</name>
-            <version>1.2.3</version>
-            <description>Description goes here</description>
-            <endpoints>
-                <endpoint>/api/thing/1</endpoint>
-                <endpoint>/api/thing/2</endpoint>
-            </endpoints>
-            <authenticated>false</authenticated>
-            <x-trust-boundary>true</x-trust-boundary>
-            <data>
-                <classification flow="outbound">public</classification>
-            </data>
-            <licenses>
-                <expression>Commercial</expression>
-            </licenses>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-            <releaseNotes>
-                <type>major</type>
-                <title>Release Notes Title</title>
-                <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
-                <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
-                <description>This release is a test release</description>
-                <timestamp>2021-12-31T10:00:00+00:00</timestamp>
-                <aliases>
-                    <alias>First Test Release</alias>
-                </aliases>
-                <tags>
-                    <tag>alpha</tag>
-                    <tag>test</tag>
-                </tags>
-                <resolves>
-                    <issue type="security">
-                        <id>CVE-2021-44228</id>
-                        <name>Apache Log3Shell</name>
-                        <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
-                        <source>
-                            <name>NVD</name>
-                            <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
-                        </source>
-                        <references>
-                            <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
-                            <url>https://logging.apache.org/log4j/2.x/security.html</url>
-                        </references>
-                    </issue>
-                </resolves>
-                <notes>
-                    <note>
-                        <locale>en-GB</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                    <note>
-                        <locale>en-US</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                </notes>
-                <properties>
-                    <property name="key1">val1</property>
-                    <property name="key2">val2</property>
-                </properties>
-            </releaseNotes>
-        </service>
-        <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>my-second-service</name>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-        <dependency ref="my-specific-bom-ref-for-my-first-service"/>
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_services_nested.xml b/tests/_data/own/xml/1.4/bom_services_nested.xml
deleted file mode 100644
index a0cc89ec4..000000000
--- a/tests/_data/own/xml/1.4/bom_services_nested.xml
+++ /dev/null
@@ -1,190 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="df70b5f1-8f53-47a4-be48-669ae78795e6">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="my-specific-bom-ref-for-my-first-service">
-            <provider>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </provider>
-            <group>a-group</group>
-            <name>my-first-service</name>
-            <version>1.2.3</version>
-            <description>Description goes here</description>
-            <endpoints>
-                <endpoint>/api/thing/1</endpoint>
-                <endpoint>/api/thing/2</endpoint>
-            </endpoints>
-            <authenticated>false</authenticated>
-            <x-trust-boundary>true</x-trust-boundary>
-            <data>
-                <classification flow="outbound">public</classification>
-            </data>
-            <licenses>
-                <expression>Commercial</expression>
-            </licenses>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-            <services>
-                <service bom-ref="my-specific-bom-ref-for-second-nested-service">
-                    <provider>
-                        <name>CycloneDX</name>
-                        <url>https://cyclonedx.org</url>
-                        <contact>
-                            <name>A N Other</name>
-                            <email>someone@somewhere.tld</email>
-                            <phone>+44 (0)1234 567890</phone>
-                        </contact>
-                        <contact>
-                            <name>Paul Horton</name>
-                            <email>paul.horton@owasp.org</email>
-                        </contact>
-                    </provider>
-                    <group>no-group</group>
-                    <name>second-nested-service</name>
-                    <version>3.2.1</version>
-                    <authenticated>true</authenticated>
-                    <x-trust-boundary>false</x-trust-boundary>
-                </service>
-                <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-                    <name>first-nested-service</name>
-                </service>
-            </services>
-            <releaseNotes>
-                <type>major</type>
-                <title>Release Notes Title</title>
-                <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
-                <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
-                <description>This release is a test release</description>
-                <timestamp>2021-12-31T10:00:00+00:00</timestamp>
-                <aliases>
-                    <alias>First Test Release</alias>
-                </aliases>
-                <tags>
-                    <tag>alpha</tag>
-                    <tag>test</tag>
-                </tags>
-                <resolves>
-                    <issue type="security">
-                        <id>CVE-2021-44228</id>
-                        <name>Apache Log3Shell</name>
-                        <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
-                        <source>
-                            <name>NVD</name>
-                            <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
-                        </source>
-                        <references>
-                            <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
-                            <url>https://logging.apache.org/log4j/2.x/security.html</url>
-                        </references>
-                    </issue>
-                </resolves>
-                <notes>
-                    <note>
-                        <locale>en-GB</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                    <note>
-                        <locale>en-US</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                </notes>
-                <properties>
-                    <property name="key1">val1</property>
-                    <property name="key2">val2</property>
-                </properties>
-            </releaseNotes>
-        </service>
-        <service bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>my-second-service</name>
-            <services>
-                <service bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-                    <provider>
-                        <name>CycloneDX</name>
-                        <url>https://cyclonedx.org</url>
-                        <contact>
-                            <name>A N Other</name>
-                            <email>someone@somewhere.tld</email>
-                            <phone>+44 (0)1234 567890</phone>
-                        </contact>
-                        <contact>
-                            <name>Paul Horton</name>
-                            <email>paul.horton@owasp.org</email>
-                        </contact>
-                    </provider>
-                    <group>what-group</group>
-                    <name>yet-another-nested-service</name>
-                    <version>6.5.4</version>
-                </service>
-                <service bom-ref="my-specific-bom-ref-for-another-nested-service">
-                    <name>another-nested-service</name>
-                </service>
-            </services>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="df70b5f1-8f53-47a4-be48-669ae78795e6"/>
-        <dependency ref="my-specific-bom-ref-for-my-first-service"/>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857" />
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_services_simple.xml b/tests/_data/own/xml/1.4/bom_services_simple.xml
deleted file mode 100644
index a8c80c9e6..000000000
--- a/tests/_data/own/xml/1.4/bom_services_simple.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-        <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
-            <name>cyclonedx-python-lib</name>
-            <version>1.0.0</version>
-        </component>
-    </metadata>
-    <services>
-        <service bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
-            <name>my-first-service</name>
-        </service>
-        <service bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
-            <name>my-second-service</name>
-        </service>
-    </services>
-    <dependencies>
-        <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857" />
-        <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3" />
-        <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda" />
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_setuptools_complete.xml b/tests/_data/own/xml/1.4/bom_setuptools_complete.xml
deleted file mode 100644
index 61ba86898..000000000
--- a/tests/_data/own/xml/1.4/bom_setuptools_complete.xml
+++ /dev/null
@@ -1,252 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
-            <supplier>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </supplier>
-            <author>Test Author</author>
-            <publisher>CycloneDX</publisher>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <description>This component is awesome</description>
-            <scope>required</scope>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <copyright>Apache 2.0 baby!</copyright>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
-                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
-            </swid>
-            <pedigree>
-                <ancestors>
-                    <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                </ancestors>
-                <descendants>
-                    <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                                <hashes>
-                                    <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                                </hashes>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </descendants>
-                <variants>
-                    <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                                <hashes>
-                                    <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                                </hashes>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </variants>
-                <commits>
-                    <commit>
-                        <uid>a-random-uid</uid>
-                        <message>A commit message</message>
-                    </commit>
-                </commits>
-                <patches>
-                    <patch type="backport"/>
-                </patches>
-                <notes>Some notes here please</notes>
-            </pedigree>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-            <components>
-                <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <author>Test Author</author>
-                    <name>setuptools</name>
-                    <version>50.3.2</version>
-                    <licenses>
-                        <expression>MIT License</expression>
-                    </licenses>
-                    <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                </component>
-                <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-                    <name>toml</name>
-                    <version>0.10.2</version>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                    <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                    <externalReferences>
-                        <reference type="distribution">
-                            <url>https://cyclonedx.org</url>
-                            <comment>No comment</comment>
-                            <hashes>
-                                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                            </hashes>
-                        </reference>
-                    </externalReferences>
-                </component>
-            </components>
-            <evidence>
-                <copyright>
-                    <text>Commercial</text>
-                    <text>Commercial 2</text>
-                </copyright>
-            </evidence>
-            <releaseNotes>
-                <type>major</type>
-                <title>Release Notes Title</title>
-                <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
-                <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
-                <description>This release is a test release</description>
-                <timestamp>2021-12-31T10:00:00+00:00</timestamp>
-                <aliases>
-                    <alias>First Test Release</alias>
-                </aliases>
-                <tags>
-                    <tag>alpha</tag>
-                    <tag>test</tag>
-                </tags>
-                <resolves>
-                    <issue type="security">
-                        <id>CVE-2021-44228</id>
-                        <name>Apache Log3Shell</name>
-                        <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
-                        <source>
-                            <name>NVD</name>
-                            <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
-                        </source>
-                        <references>
-                            <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
-                            <url>https://logging.apache.org/log4j/2.x/security.html</url>
-                        </references>
-                    </issue>
-                </resolves>
-                <notes>
-                    <note>
-                        <locale>en-GB</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                    <note>
-                        <locale>en-US</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                </notes>
-                <properties>
-                    <property name="key1">val1</property>
-                    <property name="key2">val2</property>
-                </properties>
-            </releaseNotes>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_setuptools_no_version.xml b/tests/_data/own/xml/1.4/bom_setuptools_no_version.xml
deleted file mode 100644
index 73becdb0e..000000000
--- a/tests/_data/own/xml/1.4/bom_setuptools_no_version.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_setuptools_with_cpe.xml b/tests/_data/own/xml/1.4/bom_setuptools_with_cpe.xml
deleted file mode 100644
index db9869876..000000000
--- a/tests/_data/own/xml/1.4/bom_setuptools_with_cpe.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_setuptools_with_release_notes.xml b/tests/_data/own/xml/1.4/bom_setuptools_with_release_notes.xml
deleted file mode 100644
index 5467da423..000000000
--- a/tests/_data/own/xml/1.4/bom_setuptools_with_release_notes.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <releaseNotes>
-                <type>major</type>
-                <title>Release Notes Title</title>
-                <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
-                <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
-                <description>This release is a test release</description>
-                <timestamp>2021-12-31T10:00:00+00:00</timestamp>
-                <aliases>
-                    <alias>First Test Release</alias>
-                </aliases>
-                <tags>
-                    <tag>alpha</tag>
-                    <tag>test</tag>
-                </tags>
-                <resolves>
-                    <issue type="security">
-                        <id>CVE-2021-44228</id>
-                        <name>Apache Log3Shell</name>
-                        <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
-                        <source>
-                            <name>NVD</name>
-                            <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
-                        </source>
-                        <references>
-                            <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
-                            <url>https://logging.apache.org/log4j/2.x/security.html</url>
-                        </references>
-                    </issue>
-                </resolves>
-                <notes>
-                    <note>
-                        <locale>en-GB</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                    <note>
-                        <locale>en-US</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                </notes>
-                <properties>
-                    <property name="key1">val1</property>
-                    <property name="key2">val2</property>
-                </properties>
-            </releaseNotes>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_setuptools_with_vulnerabilities.xml b/tests/_data/own/xml/1.4/bom_setuptools_with_vulnerabilities.xml
deleted file mode 100644
index 1936e2863..000000000
--- a/tests/_data/own/xml/1.4/bom_setuptools_with_vulnerabilities.xml
+++ /dev/null
@@ -1,166 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-    <vulnerabilities>
-        <vulnerability bom-ref="my-vuln-ref-1">
-            <id>CVE-2018-7489</id>
-            <source>
-                <name>NVD</name>
-                <url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</url>
-            </source>
-            <references>
-                <reference>
-                    <id>SOME-OTHER-ID</id>
-                    <source>
-                        <name>OSS Index</name>
-                        <url>https://ossindex.sonatype.org/component/pkg:pypi/setuptools</url>
-                    </source>
-                </reference>
-            </references>
-            <ratings>
-                <rating>
-                    <source>
-                        <name>NVD</name>
-                        <url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</url>
-                    </source>
-                    <score>9.8</score>
-                    <severity>critical</severity>
-                    <method>CVSSv3</method>
-                    <vector>AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H</vector>
-                    <justification>Some justification</justification>
-                </rating>
-                <rating>
-                    <source>
-                        <name>OWASP</name>
-                        <url>https://owasp.org</url>
-                    </source>
-                    <score>2.7</score>
-                    <severity>low</severity>
-                    <method>CVSSv3</method>
-                    <vector>AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N</vector>
-                    <justification>Some other justification</justification>
-                </rating>
-            </ratings>
-            <cwes>
-                <cwe>22</cwe>
-                <cwe>33</cwe>
-            </cwes>
-            <description>A description here</description>
-            <detail>Some detail here</detail>
-            <recommendation>Upgrade</recommendation>
-            <advisories>
-                <advisory>
-                    <url>http://www.securitytracker.com/id/1040693</url>
-                </advisory>
-                <advisory>
-                    <url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</url>
-                </advisory>
-            </advisories>
-            <created>2021-09-01T10:50:42.051979+00:00</created>
-            <published>2021-09-02T10:50:42.051979+00:00</published>
-            <updated>2021-09-03T10:50:42.051979+00:00</updated>
-            <credits>
-                <organizations>
-                    <organization>
-                        <name>CycloneDX</name>
-                        <url>https://cyclonedx.org</url>
-                        <contact>
-                            <name>A N Other</name>
-                            <email>someone@somewhere.tld</email>
-                            <phone>+44 (0)1234 567890</phone>
-                        </contact>
-                        <contact>
-                            <name>Paul Horton</name>
-                            <email>paul.horton@owasp.org</email>
-                        </contact>
-                    </organization>
-                </organizations>
-                <individuals>
-                    <individual>
-                        <name>A N Other</name>
-                        <email>someone@somewhere.tld</email>
-                        <phone>+44 (0)1234 567890</phone>
-                    </individual>
-                </individuals>
-            </credits>
-            <tools>
-                <tool>
-                    <vendor>CycloneDX</vendor>
-                    <name>cyclonedx-python-lib</name>
-                </tool>
-            </tools>
-            <analysis>
-                <state>exploitable</state>
-                <justification>requires_environment</justification>
-                <responses>
-                    <response>can_not_fix</response>
-                </responses>
-                <detail>Some extra detail</detail>
-            </analysis>
-            <affects>
-                <target>
-                    <ref>pkg:pypi/setuptools@50.3.2?extension=tar.gz</ref>
-                    <versions>
-                        <version>
-                            <range>49.0.0 - 54.0.0</range>
-                            <status>affected</status>
-                        </version>
-                    </versions>
-                </target>
-            </affects>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-        </vulnerability>
-    </vulnerabilities>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_toml_hashes_and_references.xml b/tests/_data/own/xml/1.4/bom_toml_hashes_and_references.xml
deleted file mode 100644
index 3ead1df94..000000000
--- a/tests/_data/own/xml/1.4/bom_toml_hashes_and_references.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/bom_with_dependencies_hanging.xml b/tests/_data/own/xml/1.4/bom_with_dependencies_hanging.xml
deleted file mode 100644
index 29395f604..000000000
--- a/tests/_data/own/xml/1.4/bom_with_dependencies_hanging.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4"
-     serialNumber="urn:uuid:12345678-395b-41f5-a30f-1234567890ab"
-     version="23">
-    <metadata>
-        <timestamp>2023-06-01T03:03:07+00:00</timestamp>
-        <component type="application" bom-ref="root-component">
-            <name>rootComponent</name>
-        </component>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="setuptools">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-        <component type="library" bom-ref="toml">
-            <name>toml</name>
-            <version>0.10.2</version>
-            <hashes>
-                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-            </hashes>
-            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="root-component"/>
-        <dependency ref="setuptools">
-            <dependency ref="toml"/>
-        </dependency>
-        <dependency ref="toml"/>
-    </dependencies>
-</bom>
-
diff --git a/tests/_data/own/xml/1.4/bom_with_full_metadata.xml b/tests/_data/own/xml/1.4/bom_with_full_metadata.xml
deleted file mode 100644
index 24ee7aa01..000000000
--- a/tests/_data/own/xml/1.4/bom_with_full_metadata.xml
+++ /dev/null
@@ -1,294 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"
-     serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79">
-    <metadata>
-        <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-        <authors>
-            <author>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </author>
-            <author>
-                <name>Paul Horton</name>
-                <email>paul.horton@owasp.org</email>
-            </author>
-        </authors>
-        <component type="library" bom-ref="df70b5f1-8f53-47a4-be48-669ae78795e6">
-            <supplier>
-                <name>CycloneDX</name>
-                <url>https://cyclonedx.org</url>
-                <contact>
-                    <name>A N Other</name>
-                    <email>someone@somewhere.tld</email>
-                    <phone>+44 (0)1234 567890</phone>
-                </contact>
-                <contact>
-                    <name>Paul Horton</name>
-                    <email>paul.horton@owasp.org</email>
-                </contact>
-            </supplier>
-            <author>Test Author</author>
-            <publisher>CycloneDX</publisher>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <description>This component is awesome</description>
-            <scope>required</scope>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <copyright>Apache 2.0 baby!</copyright>
-            <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-            <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
-                <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
-            </swid>
-            <pedigree>
-                <ancestors>
-                    <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                </ancestors>
-                <descendants>
-                    <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                                <hashes>
-                                    <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                                </hashes>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </descendants>
-                <variants>
-                    <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
-                        <author>Test Author</author>
-                        <name>setuptools</name>
-                        <version>50.3.2</version>
-                        <licenses>
-                            <expression>MIT License</expression>
-                        </licenses>
-                        <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                    </component>
-                    <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
-                        <name>toml</name>
-                        <version>0.10.2</version>
-                        <hashes>
-                            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                        </hashes>
-                        <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                        <externalReferences>
-                            <reference type="distribution">
-                                <url>https://cyclonedx.org</url>
-                                <comment>No comment</comment>
-                                <hashes>
-                                    <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                                </hashes>
-                            </reference>
-                        </externalReferences>
-                    </component>
-                </variants>
-                <commits>
-                    <commit>
-                        <uid>a-random-uid</uid>
-                        <message>A commit message</message>
-                    </commit>
-                </commits>
-                <patches>
-                    <patch type="backport"/>
-                </patches>
-                <notes>Some notes here please</notes>
-            </pedigree>
-            <externalReferences>
-                <reference type="distribution">
-                    <url>https://cyclonedx.org</url>
-                    <comment>No comment</comment>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                </reference>
-            </externalReferences>
-            <properties>
-                <property name="key1">val1</property>
-                <property name="key2">val2</property>
-            </properties>
-            <components>
-                <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-                    <author>Test Author</author>
-                    <name>setuptools</name>
-                    <version>50.3.2</version>
-                    <licenses>
-                        <expression>MIT License</expression>
-                    </licenses>
-                    <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-                </component>
-                <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
-                    <name>toml</name>
-                    <version>0.10.2</version>
-                    <hashes>
-                        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                    </hashes>
-                    <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
-                    <externalReferences>
-                        <reference type="distribution">
-                            <url>https://cyclonedx.org</url>
-                            <comment>No comment</comment>
-                            <hashes>
-                                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
-                            </hashes>
-                        </reference>
-                    </externalReferences>
-                </component>
-            </components>
-            <evidence>
-                <copyright>
-                    <text>Commercial</text>
-                    <text>Commercial 2</text>
-                </copyright>
-            </evidence>
-            <releaseNotes>
-                <type>major</type>
-                <title>Release Notes Title</title>
-                <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
-                <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
-                <description>This release is a test release</description>
-                <timestamp>2021-12-31T10:00:00+00:00</timestamp>
-                <aliases>
-                    <alias>First Test Release</alias>
-                </aliases>
-                <tags>
-                    <tag>alpha</tag>
-                    <tag>test</tag>
-                </tags>
-                <resolves>
-                    <issue type="security">
-                        <id>CVE-2021-44228</id>
-                        <name>Apache Log3Shell</name>
-                        <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
-                        <source>
-                            <name>NVD</name>
-                            <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
-                        </source>
-                        <references>
-                            <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
-                            <url>https://logging.apache.org/log4j/2.x/security.html</url>
-                        </references>
-                    </issue>
-                </resolves>
-                <notes>
-                    <note>
-                        <locale>en-GB</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                    <note>
-                        <locale>en-US</locale>
-                        <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
-                    </note>
-                </notes>
-                <properties>
-                    <property name="key1">val1</property>
-                    <property name="key2">val2</property>
-                </properties>
-            </releaseNotes>
-        </component>
-        <manufacture>
-            <name>CycloneDX</name>
-            <url>https://cyclonedx.org</url>
-            <contact>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </contact>
-            <contact>
-                <name>Paul Horton</name>
-                <email>paul.horton@owasp.org</email>
-            </contact>
-        </manufacture>
-        <supplier>
-            <name>Cyclone DX</name>
-            <url>https://cyclonedx.org/</url>
-            <contact>
-                <name>A N Other</name>
-                <email>someone@somewhere.tld</email>
-                <phone>+44 (0)1234 567890</phone>
-            </contact>
-        </supplier>
-        <licenses>
-            <license>
-                <id>Apache-2.0</id>
-                <text content-type="text/plain" encoding="base64">VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE=</text>
-                <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
-            </license>
-        </licenses>
-        <properties>
-            <property name="key1">val1</property>
-            <property name="key2">val2</property>
-        </properties>
-    </metadata>
-    <dependencies>
-        <dependency ref="df70b5f1-8f53-47a4-be48-669ae78795e6"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/indented_4spaces.xml b/tests/_data/own/xml/1.4/indented_4spaces.xml
deleted file mode 100644
index d59c71266..000000000
--- a/tests/_data/own/xml/1.4/indented_4spaces.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" ?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
-    <metadata>
-        <timestamp>2021-12-31T10:00:00+00:00</timestamp>
-        <tools>
-            <tool>
-                <vendor>CycloneDX</vendor>
-                <name>cyclonedx-python-lib</name>
-                <version>TESTING</version>
-                <externalReferences>
-                    <reference type="build-system">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-                    </reference>
-                    <reference type="distribution">
-                        <url>https://pypi.org/project/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="documentation">
-                        <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-                    </reference>
-                    <reference type="issue-tracker">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-                    </reference>
-                    <reference type="license">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-                    </reference>
-                    <reference type="release-notes">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-                    </reference>
-                    <reference type="vcs">
-                        <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-                    </reference>
-                    <reference type="website">
-                        <url>https://cyclonedx.org</url>
-                    </reference>
-                </externalReferences>
-            </tool>
-        </tools>
-    </metadata>
-    <components>
-        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-            <author>Test Author</author>
-            <name>setuptools</name>
-            <version>50.3.2</version>
-            <licenses>
-                <expression>MIT License</expression>
-            </licenses>
-            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-        </component>
-    </components>
-    <dependencies>
-        <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-    </dependencies>
-</bom>
diff --git a/tests/_data/own/xml/1.4/indented_None.xml b/tests/_data/own/xml/1.4/indented_None.xml
deleted file mode 100644
index 52d425fb9..000000000
--- a/tests/_data/own/xml/1.4/indented_None.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" ?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1"><metadata><timestamp>2021-12-31T10:00:00+00:00</timestamp><tools><tool><vendor>CycloneDX</vendor><name>cyclonedx-python-lib</name><version>TESTING</version><externalReferences><reference type="build-system"><url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url></reference><reference type="distribution"><url>https://pypi.org/project/cyclonedx-python-lib/</url></reference><reference type="documentation"><url>https://cyclonedx.github.io/cyclonedx-python-lib/</url></reference><reference type="issue-tracker"><url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url></reference><reference type="license"><url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url></reference><reference type="release-notes"><url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url></reference><reference type="vcs"><url>https://github.com/CycloneDX/cyclonedx-python-lib</url></reference><reference type="website"><url>https://cyclonedx.org</url></reference></externalReferences></tool></tools></metadata><components><component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"><author>Test Author</author><name>setuptools</name><version>50.3.2</version><licenses><expression>MIT License</expression></licenses><purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl></component></components><dependencies><dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz" /></dependencies></bom>
\ No newline at end of file
diff --git a/tests/_data/own/xml/1.4/indented_tab.xml b/tests/_data/own/xml/1.4/indented_tab.xml
deleted file mode 100644
index 48d7c99f3..000000000
--- a/tests/_data/own/xml/1.4/indented_tab.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" ?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
-	<metadata>
-		<timestamp>2021-12-31T10:00:00+00:00</timestamp>
-		<tools>
-			<tool>
-				<vendor>CycloneDX</vendor>
-				<name>cyclonedx-python-lib</name>
-				<version>TESTING</version>
-				<externalReferences>
-					<reference type="build-system">
-						<url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
-					</reference>
-					<reference type="distribution">
-						<url>https://pypi.org/project/cyclonedx-python-lib/</url>
-					</reference>
-					<reference type="documentation">
-						<url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
-					</reference>
-					<reference type="issue-tracker">
-						<url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
-					</reference>
-					<reference type="license">
-						<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
-					</reference>
-					<reference type="release-notes">
-						<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
-					</reference>
-					<reference type="vcs">
-						<url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
-					</reference>
-					<reference type="website">
-						<url>https://cyclonedx.org</url>
-					</reference>
-				</externalReferences>
-			</tool>
-		</tools>
-	</metadata>
-	<components>
-		<component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
-			<author>Test Author</author>
-			<name>setuptools</name>
-			<version>50.3.2</version>
-			<licenses>
-				<expression>MIT License</expression>
-			</licenses>
-			<purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
-		</component>
-	</components>
-	<dependencies>
-		<dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
-	</dependencies>
-</bom>
diff --git a/tests/_data/snapshots/.gitattributes b/tests/_data/snapshots/.gitattributes
new file mode 100644
index 000000000..cb164e3db
--- /dev/null
+++ b/tests/_data/snapshots/.gitattributes
@@ -0,0 +1,3 @@
+# files are compared bype-wise, so they need to be treated as binary
+xml/**      linguist-generated binary diff=xml
+json/**     linguist-generated binary diff=json
diff --git a/tests/_data/snapshots/README.md b/tests/_data/snapshots/README.md
new file mode 100644
index 000000000..f97432444
--- /dev/null
+++ b/tests/_data/snapshots/README.md
@@ -0,0 +1,13 @@
+# TEST FIXTURES
+
+## RE-CREATION
+
+Some assets here can be (re-)created automatically, by setting the env var `CDX_TEST_RECREATE_SNAPSHOTS=1`.  
+It might also help to set `PYTHONHASHSEED=0`!  
+As a shortcut just run:
+
+```shell
+CDX_TEST_RECREATE_SNAPSHOTS=1 poetry run tox -e py
+```
+
+The files will be written as is, which might not be human-readable. feel free to reformat the files manually.
diff --git a/tests/_data/snapshots/get_bom_for_issue_275_components-1.0.xml.bin b/tests/_data/snapshots/get_bom_for_issue_275_components-1.0.xml.bin
new file mode 100644
index 000000000..9c17482c6
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_275_components-1.0.xml.bin
@@ -0,0 +1,22 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>comp_a</name>
+      <version>1.0.0</version>
+      <modified>false</modified>
+    </component>
+    <component type="library">
+      <name>comp_b</name>
+      <version>1.0.0</version>
+      <modified>false</modified>
+      <components>
+        <component type="library">
+          <name>comp_c</name>
+          <version>1.0.0</version>
+          <modified>false</modified>
+        </component>
+      </components>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_for_issue_275_components-1.1.xml.bin b/tests/_data/snapshots/get_bom_for_issue_275_components-1.1.xml.bin
new file mode 100644
index 000000000..85289a746
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_275_components-1.1.xml.bin
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
+      <name>comp_a</name>
+      <version>1.0.0</version>
+    </component>
+    <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
+      <name>comp_b</name>
+      <version>1.0.0</version>
+      <components>
+        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
+          <name>comp_c</name>
+          <version>1.0.0</version>
+        </component>
+      </components>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_issue_275_components.json b/tests/_data/snapshots/get_bom_for_issue_275_components-1.2.json.bin
similarity index 79%
rename from tests/_data/own/json/1.2/bom_issue_275_components.json
rename to tests/_data/snapshots/get_bom_for_issue_275_components-1.2.json.bin
index 8fc7cf7e2..b4eef0f9f 100644
--- a/tests/_data/own/json/1.2/bom_issue_275_components.json
+++ b/tests/_data/snapshots/get_bom_for_issue_275_components-1.2.json.bin
@@ -1,66 +1,66 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:e8a76c00-84d4-447e-8bc5-d8a3cefd01f0",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:45:57.651650+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
-      "name": "app",
-      "version": "1.0.0"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
       "name": "comp_a",
+      "type": "library",
       "version": "1.0.0"
     },
     {
-      "type": "library",
       "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
-      "name": "comp_b",
-      "version": "1.0.0",
       "components": [
         {
-          "type": "library",
           "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789",
           "name": "comp_c",
+          "type": "library",
           "version": "1.0.0"
         }
-      ]
+      ],
+      "name": "comp_b",
+      "type": "library",
+      "version": "1.0.0"
     }
   ],
   "dependencies": [
     {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
       "dependsOn": [
-        "0b049d09-64c0-4490-a0f5-c84d9aacf857",
-        "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
-      ]
+        "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
+      ],
+      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857"
     },
     {
       "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
     },
     {
-      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
       "dependsOn": [
-        "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
-      ]
+        "0b049d09-64c0-4490-a0f5-c84d9aacf857",
+        "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
+      ],
+      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
     },
     {
       "ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "name": "app",
+      "type": "library",
+      "version": "1.0.0"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_for_issue_275_components-1.2.xml.bin b/tests/_data/snapshots/get_bom_for_issue_275_components-1.2.xml.bin
new file mode 100644
index 000000000..e9568f560
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_275_components-1.2.xml.bin
@@ -0,0 +1,44 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
+      <name>app</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
+      <name>comp_a</name>
+      <version>1.0.0</version>
+    </component>
+    <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
+      <name>comp_b</name>
+      <version>1.0.0</version>
+      <components>
+        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
+          <name>comp_c</name>
+          <version>1.0.0</version>
+        </component>
+      </components>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
+      <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
+    </dependency>
+    <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
+    <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
+      <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
+      <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
+    </dependency>
+    <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_issue_275_components.json b/tests/_data/snapshots/get_bom_for_issue_275_components-1.3.json.bin
similarity index 79%
rename from tests/_data/own/json/1.3/bom_issue_275_components.json
rename to tests/_data/snapshots/get_bom_for_issue_275_components-1.3.json.bin
index f1f7596de..b57b1676b 100644
--- a/tests/_data/own/json/1.3/bom_issue_275_components.json
+++ b/tests/_data/snapshots/get_bom_for_issue_275_components-1.3.json.bin
@@ -1,66 +1,66 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:4d8c5007-3d0b-4556-bbda-e9902c183b82",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:45:57.962469+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
-      "name": "app",
-      "version": "1.0.0"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
       "name": "comp_a",
+      "type": "library",
       "version": "1.0.0"
     },
     {
-      "type": "library",
       "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
-      "name": "comp_b",
-      "version": "1.0.0",
       "components": [
         {
-          "type": "library",
           "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789",
           "name": "comp_c",
+          "type": "library",
           "version": "1.0.0"
         }
-      ]
+      ],
+      "name": "comp_b",
+      "type": "library",
+      "version": "1.0.0"
     }
   ],
   "dependencies": [
     {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
       "dependsOn": [
-        "0b049d09-64c0-4490-a0f5-c84d9aacf857",
-        "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
-      ]
+        "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
+      ],
+      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857"
     },
     {
       "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
     },
     {
-      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
       "dependsOn": [
-        "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
-      ]
+        "0b049d09-64c0-4490-a0f5-c84d9aacf857",
+        "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
+      ],
+      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
     },
     {
       "ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "name": "app",
+      "type": "library",
+      "version": "1.0.0"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_for_issue_275_components-1.3.xml.bin b/tests/_data/snapshots/get_bom_for_issue_275_components-1.3.xml.bin
new file mode 100644
index 000000000..c77704fc5
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_275_components-1.3.xml.bin
@@ -0,0 +1,44 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
+      <name>app</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
+      <name>comp_a</name>
+      <version>1.0.0</version>
+    </component>
+    <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
+      <name>comp_b</name>
+      <version>1.0.0</version>
+      <components>
+        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
+          <name>comp_c</name>
+          <version>1.0.0</version>
+        </component>
+      </components>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
+      <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
+    </dependency>
+    <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
+    <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
+      <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
+      <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
+    </dependency>
+    <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_issue_275_components.json b/tests/_data/snapshots/get_bom_for_issue_275_components-1.4.json.bin
similarity index 71%
rename from tests/_data/own/json/1.4/bom_issue_275_components.json
rename to tests/_data/snapshots/get_bom_for_issue_275_components-1.4.json.bin
index 6826b7a16..32f27cdd8 100644
--- a/tests/_data/own/json/1.4/bom_issue_275_components.json
+++ b/tests/_data/snapshots/get_bom_for_issue_275_components-1.4.json.bin
@@ -1,100 +1,100 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:75d08821-33b4-4f66-8577-6caa2fc718ac",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:45:58.871481+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
-        "externalReferences": [
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
-          },
-          {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
-          },
-          {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
-          },
-          {
-            "url": "https://cyclonedx.org",
-            "type": "website"
-          }
-        ]
-      }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
-      "name": "app",
-      "version": "1.0.0"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
       "name": "comp_a",
+      "type": "library",
       "version": "1.0.0"
     },
     {
-      "type": "library",
       "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
-      "name": "comp_b",
-      "version": "1.0.0",
       "components": [
         {
-          "type": "library",
           "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789",
           "name": "comp_c",
+          "type": "library",
           "version": "1.0.0"
         }
-      ]
+      ],
+      "name": "comp_b",
+      "type": "library",
+      "version": "1.0.0"
     }
   ],
   "dependencies": [
     {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
       "dependsOn": [
-        "0b049d09-64c0-4490-a0f5-c84d9aacf857",
-        "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
-      ]
+        "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
+      ],
+      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857"
     },
     {
       "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
     },
     {
-      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
       "dependsOn": [
-        "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
-      ]
+        "0b049d09-64c0-4490-a0f5-c84d9aacf857",
+        "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
+      ],
+      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
     },
     {
       "ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "name": "app",
+      "type": "library",
+      "version": "1.0.0"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_for_issue_275_components-1.4.xml.bin b/tests/_data/snapshots/get_bom_for_issue_275_components-1.4.xml.bin
new file mode 100644
index 000000000..dcd23b6a7
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_275_components-1.4.xml.bin
@@ -0,0 +1,70 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
+      <name>app</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda">
+      <name>comp_a</name>
+      <version>1.0.0</version>
+    </component>
+    <component type="library" bom-ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
+      <name>comp_b</name>
+      <version>1.0.0</version>
+      <components>
+        <component type="library" bom-ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789">
+          <name>comp_c</name>
+          <version>1.0.0</version>
+        </component>
+      </components>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857">
+      <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
+    </dependency>
+    <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
+    <dependency ref="be2c6502-7e9a-47db-9a66-e34f729810a3">
+      <dependency ref="0b049d09-64c0-4490-a0f5-c84d9aacf857"/>
+      <dependency ref="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"/>
+    </dependency>
+    <dependency ref="cd3e9c95-9d41-49e7-9924-8cf0465ae789"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_for_issue_328_components-1.0.xml.bin b/tests/_data/snapshots/get_bom_for_issue_328_components-1.0.xml.bin
new file mode 100644
index 000000000..8f2aeebc8
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_328_components-1.0.xml.bin
@@ -0,0 +1,24 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>A</name>
+      <version>0.1</version>
+      <modified>false</modified>
+      <components>
+        <component type="library">
+          <name>B</name>
+          <version>1.0</version>
+          <modified>false</modified>
+          <components>
+            <component type="library">
+              <name>C</name>
+              <version>1.0</version>
+              <modified>false</modified>
+            </component>
+          </components>
+        </component>
+      </components>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_for_issue_328_components-1.1.xml.bin b/tests/_data/snapshots/get_bom_for_issue_328_components-1.1.xml.bin
new file mode 100644
index 000000000..210e36e9f
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_328_components-1.1.xml.bin
@@ -0,0 +1,21 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="component-A">
+      <name>A</name>
+      <version>0.1</version>
+      <components>
+        <component type="library" bom-ref="component-B">
+          <name>B</name>
+          <version>1.0</version>
+          <components>
+            <component type="library" bom-ref="component-C">
+              <name>C</name>
+              <version>1.0</version>
+            </component>
+          </components>
+        </component>
+      </components>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_issue_328_components.json b/tests/_data/snapshots/get_bom_for_issue_328_components-1.2.json.bin
similarity index 72%
rename from tests/_data/own/json/1.2/bom_issue_328_components.json
rename to tests/_data/snapshots/get_bom_for_issue_328_components-1.2.json.bin
index 1ad1cce25..80f814faa 100644
--- a/tests/_data/own/json/1.2/bom_issue_328_components.json
+++ b/tests/_data/snapshots/get_bom_for_issue_328_components-1.2.json.bin
@@ -1,71 +1,70 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:0e7ce694-c130-4965-8716-85015b42c729",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:52:27.732107+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ],
-    "component": {
-      "type": "application",
-      "bom-ref": "my-project",
-      "name": "my-project",
-      "version": "1"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "component-A",
-      "name": "A",
-      "version": "0.1",
       "components": [
         {
-          "type": "library",
           "bom-ref": "component-B",
-          "name": "B",
-          "version": "1.0",
           "components": [
             {
-              "type": "library",
               "bom-ref": "component-C",
               "name": "C",
+              "type": "library",
               "version": "1.0"
             }
-          ]
+          ],
+          "name": "B",
+          "type": "library",
+          "version": "1.0"
         }
-      ]
+      ],
+      "name": "A",
+      "type": "library",
+      "version": "0.1"
     }
   ],
   "dependencies": [
     {
-      "ref": "my-project",
-      "dependsOn": [
-        "component-A"
-      ]
-    },
-    {
-      "ref": "component-A",
       "dependsOn": [
         "component-B"
-      ]
+      ],
+      "ref": "component-A"
     },
     {
-      "ref": "component-B",
       "dependsOn": [
         "component-C"
-      ]
+      ],
+      "ref": "component-B"
     },
     {
-      "ref": "component-C",
-      "dependsOn": []
+      "ref": "component-C"
+    },
+    {
+      "dependsOn": [
+        "component-A"
+      ],
+      "ref": "my-project"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-project",
+      "name": "my-project",
+      "type": "application",
+      "version": "1"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_for_issue_328_components-1.2.xml.bin b/tests/_data/snapshots/get_bom_for_issue_328_components-1.2.xml.bin
new file mode 100644
index 000000000..4e712c8c5
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_328_components-1.2.xml.bin
@@ -0,0 +1,47 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-project">
+      <name>my-project</name>
+      <version>1</version>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="component-A">
+      <name>A</name>
+      <version>0.1</version>
+      <components>
+        <component type="library" bom-ref="component-B">
+          <name>B</name>
+          <version>1.0</version>
+          <components>
+            <component type="library" bom-ref="component-C">
+              <name>C</name>
+              <version>1.0</version>
+            </component>
+          </components>
+        </component>
+      </components>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="component-A">
+      <dependency ref="component-B"/>
+    </dependency>
+    <dependency ref="component-B">
+      <dependency ref="component-C"/>
+    </dependency>
+    <dependency ref="component-C"/>
+    <dependency ref="my-project">
+      <dependency ref="component-A"/>
+    </dependency>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_issue_328_components.json b/tests/_data/snapshots/get_bom_for_issue_328_components-1.3.json.bin
similarity index 72%
rename from tests/_data/own/json/1.3/bom_issue_328_components.json
rename to tests/_data/snapshots/get_bom_for_issue_328_components-1.3.json.bin
index 7d515941c..a4dce742d 100644
--- a/tests/_data/own/json/1.3/bom_issue_328_components.json
+++ b/tests/_data/snapshots/get_bom_for_issue_328_components-1.3.json.bin
@@ -1,71 +1,70 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:d59b94a8-25bc-4876-a1ae-c21a73fecd2c",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:52:28.562184+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ],
-    "component": {
-      "type": "application",
-      "bom-ref": "my-project",
-      "name": "my-project",
-      "version": "1"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "component-A",
-      "name": "A",
-      "version": "0.1",
       "components": [
         {
-          "type": "library",
           "bom-ref": "component-B",
-          "name": "B",
-          "version": "1.0",
           "components": [
             {
-              "type": "library",
               "bom-ref": "component-C",
               "name": "C",
+              "type": "library",
               "version": "1.0"
             }
-          ]
+          ],
+          "name": "B",
+          "type": "library",
+          "version": "1.0"
         }
-      ]
+      ],
+      "name": "A",
+      "type": "library",
+      "version": "0.1"
     }
   ],
   "dependencies": [
     {
-      "ref": "my-project",
-      "dependsOn": [
-        "component-A"
-      ]
-    },
-    {
-      "ref": "component-A",
       "dependsOn": [
         "component-B"
-      ]
+      ],
+      "ref": "component-A"
     },
     {
-      "ref": "component-B",
       "dependsOn": [
         "component-C"
-      ]
+      ],
+      "ref": "component-B"
     },
     {
-      "ref": "component-C",
-      "dependsOn": []
+      "ref": "component-C"
+    },
+    {
+      "dependsOn": [
+        "component-A"
+      ],
+      "ref": "my-project"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-project",
+      "name": "my-project",
+      "type": "application",
+      "version": "1"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_for_issue_328_components-1.3.xml.bin b/tests/_data/snapshots/get_bom_for_issue_328_components-1.3.xml.bin
new file mode 100644
index 000000000..022354c04
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_328_components-1.3.xml.bin
@@ -0,0 +1,47 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-project">
+      <name>my-project</name>
+      <version>1</version>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="component-A">
+      <name>A</name>
+      <version>0.1</version>
+      <components>
+        <component type="library" bom-ref="component-B">
+          <name>B</name>
+          <version>1.0</version>
+          <components>
+            <component type="library" bom-ref="component-C">
+              <name>C</name>
+              <version>1.0</version>
+            </component>
+          </components>
+        </component>
+      </components>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="component-A">
+      <dependency ref="component-B"/>
+    </dependency>
+    <dependency ref="component-B">
+      <dependency ref="component-C"/>
+    </dependency>
+    <dependency ref="component-C"/>
+    <dependency ref="my-project">
+      <dependency ref="component-A"/>
+    </dependency>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_issue_328_components.json b/tests/_data/snapshots/get_bom_for_issue_328_components-1.4.json.bin
similarity index 66%
rename from tests/_data/own/json/1.4/bom_issue_328_components.json
rename to tests/_data/snapshots/get_bom_for_issue_328_components-1.4.json.bin
index 278722235..a1ee1181a 100644
--- a/tests/_data/own/json/1.4/bom_issue_328_components.json
+++ b/tests/_data/snapshots/get_bom_for_issue_328_components-1.4.json.bin
@@ -1,105 +1,104 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:282ec6f4-455e-4b07-b4b8-561bad2010c5",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:52:30.247202+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
-        "externalReferences": [
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
-          },
-          {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
-          },
-          {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
-          },
-          {
-            "url": "https://cyclonedx.org",
-            "type": "website"
-          }
-        ]
-      }
-    ],
-    "component": {
-      "type": "application",
-      "bom-ref": "my-project",
-      "name": "my-project",
-      "version": "1"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "component-A",
-      "name": "A",
-      "version": "0.1",
       "components": [
         {
-          "type": "library",
           "bom-ref": "component-B",
-          "name": "B",
-          "version": "1.0",
           "components": [
             {
-              "type": "library",
               "bom-ref": "component-C",
               "name": "C",
+              "type": "library",
               "version": "1.0"
             }
-          ]
+          ],
+          "name": "B",
+          "type": "library",
+          "version": "1.0"
         }
-      ]
+      ],
+      "name": "A",
+      "type": "library",
+      "version": "0.1"
     }
   ],
   "dependencies": [
     {
-      "ref": "my-project",
-      "dependsOn": [
-        "component-A"
-      ]
-    },
-    {
-      "ref": "component-A",
       "dependsOn": [
         "component-B"
-      ]
+      ],
+      "ref": "component-A"
     },
     {
-      "ref": "component-B",
       "dependsOn": [
         "component-C"
-      ]
+      ],
+      "ref": "component-B"
+    },
+    {
+      "ref": "component-C"
     },
     {
-      "ref": "component-C",
-      "dependsOn": []
+      "dependsOn": [
+        "component-A"
+      ],
+      "ref": "my-project"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-project",
+      "name": "my-project",
+      "type": "application",
+      "version": "1"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_for_issue_328_components-1.4.xml.bin b/tests/_data/snapshots/get_bom_for_issue_328_components-1.4.xml.bin
new file mode 100644
index 000000000..d646d17d1
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_for_issue_328_components-1.4.xml.bin
@@ -0,0 +1,73 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-project">
+      <name>my-project</name>
+      <version>1</version>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="component-A">
+      <name>A</name>
+      <version>0.1</version>
+      <components>
+        <component type="library" bom-ref="component-B">
+          <name>B</name>
+          <version>1.0</version>
+          <components>
+            <component type="library" bom-ref="component-C">
+              <name>C</name>
+              <version>1.0</version>
+            </component>
+          </components>
+        </component>
+      </components>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="component-A">
+      <dependency ref="component-B"/>
+    </dependency>
+    <dependency ref="component-B">
+      <dependency ref="component-C"/>
+    </dependency>
+    <dependency ref="component-C"/>
+    <dependency ref="my-project">
+      <dependency ref="component-A"/>
+    </dependency>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/xml/1.0/bom_empty.xml b/tests/_data/snapshots/get_bom_just_complete_metadata-1.0.xml.bin
similarity index 54%
rename from tests/_data/own/xml/1.0/bom_empty.xml
rename to tests/_data/snapshots/get_bom_just_complete_metadata-1.0.xml.bin
index a803aa60f..acb066124 100644
--- a/tests/_data/own/xml/1.0/bom_empty.xml
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.0.xml.bin
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" ?>
 <bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
-    <components/>
+  <components/>
 </bom>
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.1.xml.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.1.xml.bin
new file mode 100644
index 000000000..55ef5cda2
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.1.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_with_full_metadata.json b/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.json.bin
similarity index 80%
rename from tests/_data/own/json/1.2/bom_with_full_metadata.json
rename to tests/_data/snapshots/get_bom_just_complete_metadata-1.2.json.bin
index d24684c69..7233c3c12 100644
--- a/tests/_data/own/json/1.2/bom_with_full_metadata.json
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.json.bin
@@ -1,262 +1,262 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-dings"
+    }
+  ],
   "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ],
     "authors": [
       {
-        "name": "A N Other",
         "email": "someone@somewhere.tld",
+        "name": "A N Other",
         "phone": "+44 (0)1234 567890"
       },
       {
-        "name": "Paul Horton",
-        "email": "paul.horton@owasp.org"
+        "email": "paul.horton@owasp.org",
+        "name": "Paul Horton"
       }
     ],
     "component": {
-      "type": "library",
-      "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
-      "supplier": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
-          {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
-          },
-          {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
-          }
-        ]
-      },
       "author": "Test Author",
-      "publisher": "CycloneDX",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "description": "This component is awesome",
-      "scope": "required",
-      "licenses": [
+      "bom-ref": "my-specific-bom-ref-for-dings",
+      "components": [
         {
-          "expression": "MIT License"
+          "author": "Test Author",
+          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "licenses": [
+            {
+              "expression": "MIT License"
+            }
+          ],
+          "name": "setuptools",
+          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "type": "library",
+          "version": "50.3.2"
+        },
+        {
+          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "externalReferences": [
+            {
+              "comment": "No comment",
+              "type": "distribution",
+              "url": "https://cyclonedx.org"
+            }
+          ],
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "name": "toml",
+          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "type": "library",
+          "version": "0.10.2"
         }
       ],
       "copyright": "Apache 2.0 baby!",
       "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "swid": {
-        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
-        "name": "Test Application",
-        "version": "3.4.5",
-        "text": {
-          "contentType": "text/xml",
-          "encoding": "base64",
-          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
+      "description": "This component is awesome",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
-      },
+      ],
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
       "pedigree": {
         "ancestors": [
           {
-            "type": "library",
-            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
-            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "",
+            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library",
+            "version": ""
+          }
+        ],
+        "commits": [
+          {
+            "message": "A commit message",
+            "uid": "a-random-uid"
           }
         ],
         "descendants": [
           {
-            "type": "library",
-            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "",
+            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library",
+            "version": ""
           },
           {
-            "type": "library",
             "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa",
-            "name": "toml",
-            "version": "0.10.2",
+            "externalReferences": [
+              {
+                "comment": "No comment",
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
+              }
+            ],
             "hashes": [
               {
                 "alg": "SHA-256",
                 "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
               }
             ],
+            "name": "toml",
             "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-            "externalReferences": [
-              {
-                "url": "https://cyclonedx.org",
-                "comment": "No comment",
-                "type": "distribution"
-              }
-            ]
+            "type": "library",
+            "version": "0.10.2"
+          }
+        ],
+        "notes": "Some notes here please",
+        "patches": [
+          {
+            "type": "backport"
           }
         ],
         "variants": [
           {
-            "type": "library",
-            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
             "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
-            "name": "toml",
-            "version": "0.10.2",
+            "externalReferences": [
+              {
+                "comment": "No comment",
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
+              }
+            ],
             "hashes": [
               {
                 "alg": "SHA-256",
                 "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
               }
             ],
+            "name": "toml",
             "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-            "externalReferences": [
-              {
-                "url": "https://cyclonedx.org",
-                "comment": "No comment",
-                "type": "distribution"
-              }
-            ]
+            "type": "library",
+            "version": "0.10.2"
           }
-        ],
-        "commits": [
+        ]
+      },
+      "publisher": "CycloneDX",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "scope": "required",
+      "supplier": {
+        "contact": [
           {
-            "uid": "a-random-uid",
-            "message": "A commit message"
-          }
-        ],
-        "patches": [
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          },
           {
-            "type": "backport"
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
           }
         ],
-        "notes": "Some notes here please"
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
+        ]
       },
-      "externalReferences": [
-        {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution"
-        }
-      ],
-      "components": [
-        {
-          "type": "library",
-          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-          "author": "Test Author",
-          "name": "setuptools",
-          "version": "50.3.2",
-          "licenses": [
-            {
-              "expression": "MIT License"
-            }
-          ],
-          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "swid": {
+        "name": "Test Application",
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "text": {
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==",
+          "contentType": "text/xml",
+          "encoding": "base64"
         },
-        {
-          "type": "library",
-          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "name": "toml",
-          "version": "0.10.2",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ],
-          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "externalReferences": [
-            {
-              "url": "https://cyclonedx.org",
-              "comment": "No comment",
-              "type": "distribution"
-            }
-          ]
-        }
-      ]
+        "version": "3.4.5"
+      },
+      "type": "library",
+      "version": "50.3.2"
     },
     "manufacture": {
-      "name": "CycloneDX",
-      "url": [
-        "https://cyclonedx.org"
-      ],
       "contact": [
         {
-          "name": "A N Other",
           "email": "someone@somewhere.tld",
+          "name": "A N Other",
           "phone": "+44 (0)1234 567890"
         },
         {
-          "name": "Paul Horton",
-          "email": "paul.horton@owasp.org"
+          "email": "paul.horton@owasp.org",
+          "name": "Paul Horton"
         }
+      ],
+      "name": "CycloneDX",
+      "url": [
+        "https://cyclonedx.org"
       ]
     },
     "supplier": {
-      "name": "Cyclone DX",
-      "url": [
-        "https://cyclonedx.org/"
-      ],
       "contact": [
         {
-          "name": "A N Other",
           "email": "someone@somewhere.tld",
+          "name": "A N Other",
           "phone": "+44 (0)1234 567890"
         }
+      ],
+      "name": "Cyclone DX",
+      "url": [
+        "https://cyclonedx.org/"
       ]
-    }
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
   },
-  "dependencies": [
-    {
-      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857"
-    }
-  ]
-}
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.xml.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.xml.bin
new file mode 100644
index 000000000..75b6733e3
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.xml.bin
@@ -0,0 +1,192 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <authors>
+      <author>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </author>
+      <author>
+        <name>Paul Horton</name>
+        <email>paul.horton@owasp.org</email>
+      </author>
+    </authors>
+    <component type="library" bom-ref="my-specific-bom-ref-for-dings">
+      <supplier>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </supplier>
+      <author>Test Author</author>
+      <publisher>CycloneDX</publisher>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <description>This component is awesome</description>
+      <scope>required</scope>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <copyright>Apache 2.0 baby!</copyright>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
+        <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+      </swid>
+      <pedigree>
+        <ancestors>
+          <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+        </ancestors>
+        <descendants>
+          <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+              </reference>
+            </externalReferences>
+          </component>
+        </descendants>
+        <variants>
+          <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+              </reference>
+            </externalReferences>
+          </component>
+        </variants>
+        <commits>
+          <commit>
+            <uid>a-random-uid</uid>
+            <message>A commit message</message>
+          </commit>
+        </commits>
+        <patches>
+          <patch type="backport"/>
+        </patches>
+        <notes>Some notes here please</notes>
+      </pedigree>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+      <components>
+        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+          <author>Test Author</author>
+          <name>setuptools</name>
+          <version>50.3.2</version>
+          <licenses>
+            <expression>MIT License</expression>
+          </licenses>
+          <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+        </component>
+        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+          <name>toml</name>
+          <version>0.10.2</version>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+          <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+          <externalReferences>
+            <reference type="distribution">
+              <url>https://cyclonedx.org</url>
+              <comment>No comment</comment>
+            </reference>
+          </externalReferences>
+        </component>
+      </components>
+    </component>
+    <manufacture>
+      <name>CycloneDX</name>
+      <url>https://cyclonedx.org</url>
+      <contact>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </contact>
+      <contact>
+        <name>Paul Horton</name>
+        <email>paul.horton@owasp.org</email>
+      </contact>
+    </manufacture>
+    <supplier>
+      <name>Cyclone DX</name>
+      <url>https://cyclonedx.org/</url>
+      <contact>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </contact>
+    </supplier>
+  </metadata>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-dings"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_with_full_metadata.json b/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.json.bin
similarity index 84%
rename from tests/_data/own/json/1.3/bom_with_full_metadata.json
rename to tests/_data/snapshots/get_bom_just_complete_metadata-1.3.json.bin
index 9cd5271c2..1a720cf21 100644
--- a/tests/_data/own/json/1.3/bom_with_full_metadata.json
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.json.bin
@@ -1,210 +1,221 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-dings"
+    }
+  ],
   "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ],
     "authors": [
       {
-        "name": "A N Other",
         "email": "someone@somewhere.tld",
+        "name": "A N Other",
         "phone": "+44 (0)1234 567890"
       },
       {
-        "name": "Paul Horton",
-        "email": "paul.horton@owasp.org"
+        "email": "paul.horton@owasp.org",
+        "name": "Paul Horton"
       }
     ],
     "component": {
-      "type": "library",
-      "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
-      "supplier": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
+      "author": "Test Author",
+      "bom-ref": "my-specific-bom-ref-for-dings",
+      "components": [
+        {
+          "author": "Test Author",
+          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "licenses": [
+            {
+              "expression": "MIT License"
+            }
+          ],
+          "name": "setuptools",
+          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "type": "library",
+          "version": "50.3.2"
+        },
+        {
+          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "externalReferences": [
+            {
+              "comment": "No comment",
+              "hashes": [
+                {
+                  "alg": "SHA-256",
+                  "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+                }
+              ],
+              "type": "distribution",
+              "url": "https://cyclonedx.org"
+            }
+          ],
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "name": "toml",
+          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "type": "library",
+          "version": "0.10.2"
+        }
+      ],
+      "copyright": "Apache 2.0 baby!",
+      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
+      "description": "This component is awesome",
+      "evidence": {
+        "copyright": [
           {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
+            "text": "Commercial"
           },
           {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
+            "text": "Commercial 2"
           }
         ]
       },
-      "author": "Test Author",
-      "publisher": "CycloneDX",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "description": "This component is awesome",
-      "scope": "required",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "copyright": "Apache 2.0 baby!",
-      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "swid": {
-        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
-        "name": "Test Application",
-        "version": "3.4.5",
-        "text": {
-          "contentType": "text/xml",
-          "encoding": "base64",
-          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
-        }
-      },
+      "name": "setuptools",
       "pedigree": {
         "ancestors": [
           {
-            "type": "library",
-            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
-            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "",
+            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library",
+            "version": ""
+          }
+        ],
+        "commits": [
+          {
+            "message": "A commit message",
+            "uid": "a-random-uid"
           }
         ],
         "descendants": [
           {
-            "type": "library",
-            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "",
+            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library",
+            "version": ""
           },
           {
-            "type": "library",
             "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa",
-            "name": "toml",
-            "version": "0.10.2",
-            "hashes": [
-              {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-              }
-            ],
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
             "externalReferences": [
               {
-                "url": "https://cyclonedx.org",
                 "comment": "No comment",
-                "type": "distribution",
                 "hashes": [
                   {
                     "alg": "SHA-256",
                     "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
                   }
-                ]
+                ],
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
+              }
+            ],
+            "hashes": [
+              {
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
               }
-            ]
+            ],
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
+          }
+        ],
+        "notes": "Some notes here please",
+        "patches": [
+          {
+            "type": "backport"
           }
         ],
         "variants": [
           {
-            "type": "library",
-            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
             "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
-            "name": "toml",
-            "version": "0.10.2",
-            "hashes": [
-              {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-              }
-            ],
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
             "externalReferences": [
               {
-                "url": "https://cyclonedx.org",
                 "comment": "No comment",
-                "type": "distribution",
                 "hashes": [
                   {
                     "alg": "SHA-256",
                     "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
                   }
-                ]
+                ],
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
               }
-            ]
-          }
-        ],
-        "commits": [
-          {
-            "uid": "a-random-uid",
-            "message": "A commit message"
-          }
-        ],
-        "patches": [
-          {
-            "type": "backport"
+            ],
+            "hashes": [
+              {
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+              }
+            ],
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
           }
-        ],
-        "notes": "Some notes here please"
+        ]
       },
-      "externalReferences": [
-        {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ]
-        }
-      ],
       "properties": [
         {
           "name": "key1",
@@ -215,101 +226,69 @@
           "value": "val2"
         }
       ],
-      "components": [
-        {
-          "type": "library",
-          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-          "author": "Test Author",
-          "name": "setuptools",
-          "version": "50.3.2",
-          "licenses": [
-            {
-              "expression": "MIT License"
-            }
-          ],
-          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-        },
-        {
-          "type": "library",
-          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "name": "toml",
-          "version": "0.10.2",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ],
-          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "externalReferences": [
-            {
-              "url": "https://cyclonedx.org",
-              "comment": "No comment",
-              "type": "distribution",
-              "hashes": [
-                {
-                  "alg": "SHA-256",
-                  "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-                }
-              ]
-            }
-          ]
-        }
-      ],
-      "evidence": {
-        "copyright": [
+      "publisher": "CycloneDX",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "scope": "required",
+      "supplier": {
+        "contact": [
           {
-            "text": "Commercial"
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
           },
           {
-            "text": "Commercial 2"
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
           }
+        ],
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
         ]
-      }
-    },
-    "manufacture": {
-      "name": "CycloneDX",
-      "url": [
-        "https://cyclonedx.org"
-      ],
-      "contact": [
-        {
-          "name": "A N Other",
-          "email": "someone@somewhere.tld",
-          "phone": "+44 (0)1234 567890"
+      },
+      "swid": {
+        "name": "Test Application",
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "text": {
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==",
+          "contentType": "text/xml",
+          "encoding": "base64"
         },
-        {
-          "name": "Paul Horton",
-          "email": "paul.horton@owasp.org"
-        }
-      ]
-    },
-    "supplier": {
-      "name": "Cyclone DX",
-      "url": [
-        "https://cyclonedx.org/"
-      ],
-      "contact": [
-        {
-          "name": "A N Other",
-          "email": "someone@somewhere.tld",
-          "phone": "+44 (0)1234 567890"
-        }
-      ]
+        "version": "3.4.5"
+      },
+      "type": "library",
+      "version": "50.3.2"
     },
     "licenses": [
       {
         "license": {
           "id": "Apache-2.0",
           "text": {
+            "content": "VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE=",
             "contentType": "text/plain",
-            "encoding": "base64",
-            "content": "VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE="
+            "encoding": "base64"
           },
           "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
         }
       }
     ],
+    "manufacture": {
+      "contact": [
+        {
+          "email": "someone@somewhere.tld",
+          "name": "A N Other",
+          "phone": "+44 (0)1234 567890"
+        },
+        {
+          "email": "paul.horton@owasp.org",
+          "name": "Paul Horton"
+        }
+      ],
+      "name": "CycloneDX",
+      "url": [
+        "https://cyclonedx.org"
+      ]
+    },
     "properties": [
       {
         "name": "key1",
@@ -319,11 +298,32 @@
         "name": "key2",
         "value": "val2"
       }
+    ],
+    "supplier": {
+      "contact": [
+        {
+          "email": "someone@somewhere.tld",
+          "name": "A N Other",
+          "phone": "+44 (0)1234 567890"
+        }
+      ],
+      "name": "Cyclone DX",
+      "url": [
+        "https://cyclonedx.org/"
+      ]
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
     ]
   },
-  "dependencies": [
-    {
-      "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
-    }
-  ]
-}
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.xml.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.xml.bin
new file mode 100644
index 000000000..4b03243b0
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.xml.bin
@@ -0,0 +1,225 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <authors>
+      <author>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </author>
+      <author>
+        <name>Paul Horton</name>
+        <email>paul.horton@owasp.org</email>
+      </author>
+    </authors>
+    <component type="library" bom-ref="my-specific-bom-ref-for-dings">
+      <supplier>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </supplier>
+      <author>Test Author</author>
+      <publisher>CycloneDX</publisher>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <description>This component is awesome</description>
+      <scope>required</scope>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <copyright>Apache 2.0 baby!</copyright>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
+        <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+      </swid>
+      <pedigree>
+        <ancestors>
+          <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+        </ancestors>
+        <descendants>
+          <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+                <hashes>
+                  <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+                </hashes>
+              </reference>
+            </externalReferences>
+          </component>
+        </descendants>
+        <variants>
+          <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+                <hashes>
+                  <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+                </hashes>
+              </reference>
+            </externalReferences>
+          </component>
+        </variants>
+        <commits>
+          <commit>
+            <uid>a-random-uid</uid>
+            <message>A commit message</message>
+          </commit>
+        </commits>
+        <patches>
+          <patch type="backport"/>
+        </patches>
+        <notes>Some notes here please</notes>
+      </pedigree>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+      <components>
+        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+          <author>Test Author</author>
+          <name>setuptools</name>
+          <version>50.3.2</version>
+          <licenses>
+            <expression>MIT License</expression>
+          </licenses>
+          <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+        </component>
+        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+          <name>toml</name>
+          <version>0.10.2</version>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+          <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+          <externalReferences>
+            <reference type="distribution">
+              <url>https://cyclonedx.org</url>
+              <comment>No comment</comment>
+              <hashes>
+                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+              </hashes>
+            </reference>
+          </externalReferences>
+        </component>
+      </components>
+      <evidence>
+        <copyright>
+          <text>Commercial</text>
+          <text>Commercial 2</text>
+        </copyright>
+      </evidence>
+    </component>
+    <manufacture>
+      <name>CycloneDX</name>
+      <url>https://cyclonedx.org</url>
+      <contact>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </contact>
+      <contact>
+        <name>Paul Horton</name>
+        <email>paul.horton@owasp.org</email>
+      </contact>
+    </manufacture>
+    <supplier>
+      <name>Cyclone DX</name>
+      <url>https://cyclonedx.org/</url>
+      <contact>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </contact>
+    </supplier>
+    <licenses>
+      <license>
+        <id>Apache-2.0</id>
+        <text content-type="text/plain" encoding="base64">VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE=</text>
+        <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      </license>
+    </licenses>
+    <properties>
+      <property name="key1">val1</property>
+      <property name="key2">val2</property>
+    </properties>
+  </metadata>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-dings"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_with_full_metadata.json b/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.json.bin
similarity index 82%
rename from tests/_data/own/json/1.4/bom_with_full_metadata.json
rename to tests/_data/snapshots/get_bom_just_complete_metadata-1.4.json.bin
index 0fab3971e..60b9249af 100644
--- a/tests/_data/own/json/1.4/bom_with_full_metadata.json
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.json.bin
@@ -1,242 +1,219 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-dings"
+    }
+  ],
   "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
-        "externalReferences": [
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
-          },
-          {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
-          },
-          {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
-          },
-          {
-            "url": "https://cyclonedx.org",
-            "type": "website"
-          }
-        ]
-      }
-    ],
     "authors": [
       {
-        "name": "A N Other",
         "email": "someone@somewhere.tld",
+        "name": "A N Other",
         "phone": "+44 (0)1234 567890"
       },
       {
-        "name": "Paul Horton",
-        "email": "paul.horton@owasp.org"
+        "email": "paul.horton@owasp.org",
+        "name": "Paul Horton"
       }
     ],
     "component": {
-      "type": "library",
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
-      "supplier": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
+      "author": "Test Author",
+      "bom-ref": "my-specific-bom-ref-for-dings",
+      "components": [
+        {
+          "author": "Test Author",
+          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "licenses": [
+            {
+              "expression": "MIT License"
+            }
+          ],
+          "name": "setuptools",
+          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "type": "library",
+          "version": "50.3.2"
+        },
+        {
+          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "externalReferences": [
+            {
+              "comment": "No comment",
+              "hashes": [
+                {
+                  "alg": "SHA-256",
+                  "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+                }
+              ],
+              "type": "distribution",
+              "url": "https://cyclonedx.org"
+            }
+          ],
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "name": "toml",
+          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "type": "library",
+          "version": "0.10.2"
+        }
+      ],
+      "copyright": "Apache 2.0 baby!",
+      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
+      "description": "This component is awesome",
+      "evidence": {
+        "copyright": [
           {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
+            "text": "Commercial"
           },
           {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
+            "text": "Commercial 2"
           }
         ]
       },
-      "author": "Test Author",
-      "publisher": "CycloneDX",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "description": "This component is awesome",
-      "scope": "required",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "copyright": "Apache 2.0 baby!",
-      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "swid": {
-        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
-        "name": "Test Application",
-        "version": "3.4.5",
-        "text": {
-          "contentType": "text/xml",
-          "encoding": "base64",
-          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
-        }
-      },
+      "name": "setuptools",
       "pedigree": {
         "ancestors": [
           {
-            "type": "library",
-            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
-            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "author": "Test Author",
-            "name": "setuptools",
+            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library"
+          }
+        ],
+        "commits": [
+          {
+            "message": "A commit message",
+            "uid": "a-random-uid"
           }
         ],
         "descendants": [
           {
-            "type": "library",
-            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "author": "Test Author",
-            "name": "setuptools",
+            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library"
           },
           {
-            "type": "library",
             "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa",
-            "name": "toml",
-            "version": "0.10.2",
-            "hashes": [
-              {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-              }
-            ],
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
             "externalReferences": [
               {
-                "url": "https://cyclonedx.org",
                 "comment": "No comment",
-                "type": "distribution",
                 "hashes": [
                   {
                     "alg": "SHA-256",
                     "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
                   }
-                ]
+                ],
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
               }
-            ]
+            ],
+            "hashes": [
+              {
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+              }
+            ],
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
+          }
+        ],
+        "notes": "Some notes here please",
+        "patches": [
+          {
+            "type": "backport"
           }
         ],
         "variants": [
           {
-            "type": "library",
-            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
             "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
-            "name": "toml",
-            "version": "0.10.2",
-            "hashes": [
-              {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-              }
-            ],
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
             "externalReferences": [
               {
-                "url": "https://cyclonedx.org",
                 "comment": "No comment",
-                "type": "distribution",
                 "hashes": [
                   {
                     "alg": "SHA-256",
                     "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
                   }
-                ]
+                ],
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
               }
-            ]
-          }
-        ],
-        "commits": [
-          {
-            "uid": "a-random-uid",
-            "message": "A commit message"
-          }
-        ],
-        "patches": [
-          {
-            "type": "backport"
+            ],
+            "hashes": [
+              {
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+              }
+            ],
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
           }
-        ],
-        "notes": "Some notes here please"
+        ]
       },
-      "externalReferences": [
-        {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ]
-        }
-      ],
       "properties": [
         {
           "name": "key1",
@@ -247,103 +224,30 @@
           "value": "val2"
         }
       ],
-      "components": [
-        {
-          "type": "library",
-          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-          "author": "Test Author",
-          "name": "setuptools",
-          "version": "50.3.2",
-          "licenses": [
-            {
-              "expression": "MIT License"
-            }
-          ],
-          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-        },
-        {
-          "type": "library",
-          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "name": "toml",
-          "version": "0.10.2",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ],
-          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "externalReferences": [
-            {
-              "url": "https://cyclonedx.org",
-              "comment": "No comment",
-              "type": "distribution",
-              "hashes": [
-                {
-                  "alg": "SHA-256",
-                  "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-                }
-              ]
-            }
-          ]
-        }
-      ],
-      "evidence": {
-        "copyright": [
-          {
-            "text": "Commercial"
-          },
-          {
-            "text": "Commercial 2"
-          }
-        ]
-      },
+      "publisher": "CycloneDX",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "releaseNotes": {
-        "type": "major",
-        "title": "Release Notes Title",
-        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
-        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
-        "description": "This release is a test release",
-        "timestamp": "2021-12-31T10:00:00+00:00",
         "aliases": [
           "First Test Release"
         ],
-        "tags": [
-          "alpha",
-          "test"
-        ],
-        "resolves": [
-          {
-            "type": "security",
-            "id": "CVE-2021-44228",
-            "name": "Apache Log3Shell",
-            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
-            "source": {
-              "name": "NVD",
-              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
-            },
-            "references": [
-              "https://central.sonatype.org/news/20211213_log4shell_help",
-              "https://logging.apache.org/log4j/2.x/security.html"
-            ]
-          }
-        ],
+        "description": "This release is a test release",
+        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
         "notes": [
           {
+            "locale": "en-GB",
             "text": {
               "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
               "encoding": "base64"
-            },
-            "locale": "en-GB"
+            }
           },
           {
+            "locale": "en-US",
             "text": {
               "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
               "encoding": "base64"
-            },
-            "locale": "en-US"
+            }
           }
         ],
         "properties": [
@@ -355,52 +259,93 @@
             "name": "key2",
             "value": "val2"
           }
+        ],
+        "resolves": [
+          {
+            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
+            "id": "CVE-2021-44228",
+            "name": "Apache Log3Shell",
+            "references": [
+              "https://central.sonatype.org/news/20211213_log4shell_help",
+              "https://logging.apache.org/log4j/2.x/security.html"
+            ],
+            "source": {
+              "name": "NVD",
+              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
+            },
+            "type": "security"
+          }
+        ],
+        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
+        "tags": [
+          "alpha",
+          "test"
+        ],
+        "timestamp": "2023-08-15T01:23:45.678900+00:00",
+        "title": "Release Notes Title",
+        "type": "major"
+      },
+      "scope": "required",
+      "supplier": {
+        "contact": [
+          {
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          },
+          {
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
+          }
+        ],
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
         ]
-      }
-    },
-    "manufacture": {
-      "name": "CycloneDX",
-      "url": [
-        "https://cyclonedx.org"
-      ],
-      "contact": [
-        {
-          "name": "A N Other",
-          "email": "someone@somewhere.tld",
-          "phone": "+44 (0)1234 567890"
+      },
+      "swid": {
+        "name": "Test Application",
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "text": {
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==",
+          "contentType": "text/xml",
+          "encoding": "base64"
         },
-        {
-          "name": "Paul Horton",
-          "email": "paul.horton@owasp.org"
-        }
-      ]
-    },
-    "supplier": {
-      "name": "Cyclone DX",
-      "url": [
-        "https://cyclonedx.org/"
-      ],
-      "contact": [
-        {
-          "name": "A N Other",
-          "email": "someone@somewhere.tld",
-          "phone": "+44 (0)1234 567890"
-        }
-      ]
+        "version": "3.4.5"
+      },
+      "type": "library",
+      "version": "50.3.2"
     },
     "licenses": [
       {
         "license": {
           "id": "Apache-2.0",
           "text": {
+            "content": "VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE=",
             "contentType": "text/plain",
-            "encoding": "base64",
-            "content": "VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE="
+            "encoding": "base64"
           },
           "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
         }
       }
     ],
+    "manufacture": {
+      "contact": [
+        {
+          "email": "someone@somewhere.tld",
+          "name": "A N Other",
+          "phone": "+44 (0)1234 567890"
+        },
+        {
+          "email": "paul.horton@owasp.org",
+          "name": "Paul Horton"
+        }
+      ],
+      "name": "CycloneDX",
+      "url": [
+        "https://cyclonedx.org"
+      ]
+    },
     "properties": [
       {
         "name": "key1",
@@ -410,11 +355,66 @@
         "name": "key2",
         "value": "val2"
       }
+    ],
+    "supplier": {
+      "contact": [
+        {
+          "email": "someone@somewhere.tld",
+          "name": "A N Other",
+          "phone": "+44 (0)1234 567890"
+        }
+      ],
+      "name": "Cyclone DX",
+      "url": [
+        "https://cyclonedx.org/"
+      ]
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
     ]
   },
-  "dependencies": [
-    {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
-    }
-  ]
-}
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.xml.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.xml.bin
new file mode 100644
index 000000000..98e51691d
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.xml.bin
@@ -0,0 +1,293 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <authors>
+      <author>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </author>
+      <author>
+        <name>Paul Horton</name>
+        <email>paul.horton@owasp.org</email>
+      </author>
+    </authors>
+    <component type="library" bom-ref="my-specific-bom-ref-for-dings">
+      <supplier>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </supplier>
+      <author>Test Author</author>
+      <publisher>CycloneDX</publisher>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <description>This component is awesome</description>
+      <scope>required</scope>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <copyright>Apache 2.0 baby!</copyright>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
+        <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+      </swid>
+      <pedigree>
+        <ancestors>
+          <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+        </ancestors>
+        <descendants>
+          <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+                <hashes>
+                  <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+                </hashes>
+              </reference>
+            </externalReferences>
+          </component>
+        </descendants>
+        <variants>
+          <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+                <hashes>
+                  <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+                </hashes>
+              </reference>
+            </externalReferences>
+          </component>
+        </variants>
+        <commits>
+          <commit>
+            <uid>a-random-uid</uid>
+            <message>A commit message</message>
+          </commit>
+        </commits>
+        <patches>
+          <patch type="backport"/>
+        </patches>
+        <notes>Some notes here please</notes>
+      </pedigree>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+      <components>
+        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+          <author>Test Author</author>
+          <name>setuptools</name>
+          <version>50.3.2</version>
+          <licenses>
+            <expression>MIT License</expression>
+          </licenses>
+          <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+        </component>
+        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+          <name>toml</name>
+          <version>0.10.2</version>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+          <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+          <externalReferences>
+            <reference type="distribution">
+              <url>https://cyclonedx.org</url>
+              <comment>No comment</comment>
+              <hashes>
+                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+              </hashes>
+            </reference>
+          </externalReferences>
+        </component>
+      </components>
+      <evidence>
+        <copyright>
+          <text>Commercial</text>
+          <text>Commercial 2</text>
+        </copyright>
+      </evidence>
+      <releaseNotes>
+        <type>major</type>
+        <title>Release Notes Title</title>
+        <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
+        <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
+        <description>This release is a test release</description>
+        <timestamp>2023-08-15T01:23:45.678900+00:00</timestamp>
+        <aliases>
+          <alias>First Test Release</alias>
+        </aliases>
+        <tags>
+          <tag>alpha</tag>
+          <tag>test</tag>
+        </tags>
+        <resolves>
+          <issue type="security">
+            <id>CVE-2021-44228</id>
+            <name>Apache Log3Shell</name>
+            <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
+            <source>
+              <name>NVD</name>
+              <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
+            </source>
+            <references>
+              <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
+              <url>https://logging.apache.org/log4j/2.x/security.html</url>
+            </references>
+          </issue>
+        </resolves>
+        <notes>
+          <note>
+            <locale>en-GB</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+          <note>
+            <locale>en-US</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+        </notes>
+        <properties>
+          <property name="key1">val1</property>
+          <property name="key2">val2</property>
+        </properties>
+      </releaseNotes>
+    </component>
+    <manufacture>
+      <name>CycloneDX</name>
+      <url>https://cyclonedx.org</url>
+      <contact>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </contact>
+      <contact>
+        <name>Paul Horton</name>
+        <email>paul.horton@owasp.org</email>
+      </contact>
+    </manufacture>
+    <supplier>
+      <name>Cyclone DX</name>
+      <url>https://cyclonedx.org/</url>
+      <contact>
+        <name>A N Other</name>
+        <email>someone@somewhere.tld</email>
+        <phone>+44 (0)1234 567890</phone>
+      </contact>
+    </supplier>
+    <licenses>
+      <license>
+        <id>Apache-2.0</id>
+        <text content-type="text/plain" encoding="base64">VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE=</text>
+        <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      </license>
+    </licenses>
+    <properties>
+      <property name="key1">val1</property>
+      <property name="key2">val2</property>
+    </properties>
+  </metadata>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-dings"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.0.xml.bin
new file mode 100644
index 000000000..961bb4798
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.0.xml.bin
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.1.xml.bin
new file mode 100644
index 000000000..0b33bec2a
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.1.xml.bin
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_setuptools.json b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.json.bin
similarity index 79%
rename from tests/_data/own/json/1.2/bom_setuptools.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.json.bin
index 961c69d90..9d0993c87 100644
--- a/tests/_data/own/json/1.2/bom_setuptools.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.json.bin
@@ -1,37 +1,37 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.xml.bin
new file mode 100644
index 000000000..ce6f3e6c6
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_setuptools.json b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.json.bin
similarity index 79%
rename from tests/_data/own/json/1.3/bom_setuptools.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.json.bin
index 33d6d3992..6e2f630e8 100644
--- a/tests/_data/own/json/1.3/bom_setuptools.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.json.bin
@@ -1,37 +1,37 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.xml.bin
new file mode 100644
index 000000000..39cbf1d85
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/indented_two.json b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.json.bin
similarity index 94%
rename from tests/_data/own/json/1.4/indented_two.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.json.bin
index 8d60c03db..d3c70bb7b 100644
--- a/tests/_data/own/json/1.4/indented_two.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.json.bin
@@ -20,7 +20,7 @@
     }
   ],
   "metadata": {
-    "timestamp": "2021-12-31T10:00:00+00:00",
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
         "externalReferences": [
@@ -63,7 +63,7 @@
       }
     ]
   },
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "version": 1,
   "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
   "bomFormat": "CycloneDX",
diff --git a/tests/_data/own/xml/1.4/indented_two.xml b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.xml.bin
similarity index 94%
rename from tests/_data/own/xml/1.4/indented_two.xml
rename to tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.xml.bin
index ce7e1a87c..bef590f2f 100644
--- a/tests/_data/own/xml/1.4/indented_two.xml
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.xml.bin
@@ -1,7 +1,7 @@
 <?xml version="1.0" ?>
-<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79" version="1">
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
   <metadata>
-    <timestamp>2021-12-31T10:00:00+00:00</timestamp>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
     <tools>
       <tool>
         <vendor>CycloneDX</vendor>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.0.xml.bin
new file mode 100644
index 000000000..dc8f73327
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.0.xml.bin
@@ -0,0 +1,33 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <publisher>CycloneDX</publisher>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <description>This component is awesome</description>
+      <scope>required</scope>
+      <copyright>Apache 2.0 baby!</copyright>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <modified>false</modified>
+      <components>
+        <component type="library">
+          <name>setuptools</name>
+          <version>50.3.2</version>
+          <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          <modified>false</modified>
+        </component>
+        <component type="library">
+          <name>toml</name>
+          <version>0.10.2</version>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+          <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+          <modified>false</modified>
+        </component>
+      </components>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.1.xml.bin
new file mode 100644
index 000000000..cf2184b05
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.1.xml.bin
@@ -0,0 +1,123 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="my-specific-bom-ref-for-dings">
+      <publisher>CycloneDX</publisher>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <description>This component is awesome</description>
+      <scope>required</scope>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <copyright>Apache 2.0 baby!</copyright>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <pedigree>
+        <ancestors>
+          <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+        </ancestors>
+        <descendants>
+          <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+              </reference>
+            </externalReferences>
+          </component>
+        </descendants>
+        <variants>
+          <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+              </reference>
+            </externalReferences>
+          </component>
+        </variants>
+        <commits>
+          <commit>
+            <uid>a-random-uid</uid>
+            <message>A commit message</message>
+          </commit>
+        </commits>
+        <notes>Some notes here please</notes>
+      </pedigree>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+      <components>
+        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+          <name>setuptools</name>
+          <version>50.3.2</version>
+          <licenses>
+            <expression>MIT License</expression>
+          </licenses>
+          <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+        </component>
+        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+          <name>toml</name>
+          <version>0.10.2</version>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+          <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+          <externalReferences>
+            <reference type="distribution">
+              <url>https://cyclonedx.org</url>
+              <comment>No comment</comment>
+            </reference>
+          </externalReferences>
+        </component>
+      </components>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_setuptools_complete.json b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.json.bin
similarity index 80%
rename from tests/_data/own/json/1.2/bom_setuptools_complete.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.json.bin
index 1bfc41dc8..9cf4af5be 100644
--- a/tests/_data/own/json/1.2/bom_setuptools_complete.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.json.bin
@@ -1,223 +1,223 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "df70b5f1-8f53-47a4-be48-669ae78795e6",
-      "supplier": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
-          {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
-          },
-          {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
-          }
-        ]
-      },
       "author": "Test Author",
-      "publisher": "CycloneDX",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "description": "This component is awesome",
-      "scope": "required",
-      "licenses": [
+      "bom-ref": "my-specific-bom-ref-for-dings",
+      "components": [
         {
-          "expression": "MIT License"
+          "author": "Test Author",
+          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "licenses": [
+            {
+              "expression": "MIT License"
+            }
+          ],
+          "name": "setuptools",
+          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "type": "library",
+          "version": "50.3.2"
+        },
+        {
+          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "externalReferences": [
+            {
+              "comment": "No comment",
+              "type": "distribution",
+              "url": "https://cyclonedx.org"
+            }
+          ],
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "name": "toml",
+          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "type": "library",
+          "version": "0.10.2"
         }
       ],
       "copyright": "Apache 2.0 baby!",
       "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "swid": {
-        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
-        "name": "Test Application",
-        "version": "3.4.5",
-        "text": {
-          "contentType": "text/xml",
-          "encoding": "base64",
-          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
+      "description": "This component is awesome",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
-      },
+      ],
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
       "pedigree": {
         "ancestors": [
           {
-            "type": "library",
-            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
-            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "",
+            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library",
+            "version": ""
+          }
+        ],
+        "commits": [
+          {
+            "message": "A commit message",
+            "uid": "a-random-uid"
           }
         ],
         "descendants": [
           {
-            "type": "library",
-            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "",
+            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library",
+            "version": ""
           },
           {
-            "type": "library",
             "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa",
-            "name": "toml",
-            "version": "0.10.2",
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "externalReferences": [
+              {
+                "comment": "No comment",
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
+              }
+            ],
             "hashes": [
               {
                 "alg": "SHA-256",
                 "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
               }
             ],
-            "externalReferences": [
-              {
-                "type": "distribution",
-                "url": "https://cyclonedx.org",
-                "comment": "No comment"
-              }
-            ]
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
+          }
+        ],
+        "notes": "Some notes here please",
+        "patches": [
+          {
+            "type": "backport"
           }
         ],
         "variants": [
           {
-            "type": "library",
-            "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
-            "name": "toml",
-            "version": "0.10.2",
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-            "hashes": [
+            "author": "Test Author",
+            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
+            "licenses": [
               {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+                "expression": "MIT License"
               }
             ],
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
+          },
+          {
+            "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
             "externalReferences": [
               {
+                "comment": "No comment",
                 "type": "distribution",
-                "url": "https://cyclonedx.org",
-                "comment": "No comment"
+                "url": "https://cyclonedx.org"
               }
-            ]
-          },
-          {
-            "type": "library",
-            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
-            "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
-            "licenses": [
+            ],
+            "hashes": [
               {
-                "expression": "MIT License"
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
           }
-        ],
-        "commits": [
+        ]
+      },
+      "publisher": "CycloneDX",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "scope": "required",
+      "supplier": {
+        "contact": [
           {
-            "uid": "a-random-uid",
-            "message": "A commit message"
-          }
-        ],
-        "patches": [
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          },
           {
-            "type": "backport"
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
           }
         ],
-        "notes": "Some notes here please"
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
+        ]
       },
-      "externalReferences": [
-        {
-          "type": "distribution",
-          "url": "https://cyclonedx.org",
-          "comment": "No comment"
-        }
-      ],
-      "components": [
-        {
-          "type": "library",
-          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-          "author": "Test Author",
-          "name": "setuptools",
-          "version": "50.3.2",
-          "licenses": [
-            {
-              "expression": "MIT License"
-            }
-          ],
-          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "swid": {
+        "name": "Test Application",
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "text": {
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==",
+          "contentType": "text/xml",
+          "encoding": "base64"
         },
-        {
-          "type": "library",
-          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "name": "toml",
-          "version": "0.10.2",
-          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ],
-          "externalReferences": [
-            {
-              "type": "distribution",
-              "url": "https://cyclonedx.org",
-              "comment": "No comment"
-            }
-          ]
-        }
-      ]
+        "version": "3.4.5"
+      },
+      "type": "library",
+      "version": "50.3.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "df70b5f1-8f53-47a4-be48-669ae78795e6"
+      "ref": "my-specific-bom-ref-for-dings"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.xml.bin
new file mode 100644
index 000000000..7c9f77b41
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.xml.bin
@@ -0,0 +1,161 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="my-specific-bom-ref-for-dings">
+      <supplier>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </supplier>
+      <author>Test Author</author>
+      <publisher>CycloneDX</publisher>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <description>This component is awesome</description>
+      <scope>required</scope>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <copyright>Apache 2.0 baby!</copyright>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
+        <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+      </swid>
+      <pedigree>
+        <ancestors>
+          <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+        </ancestors>
+        <descendants>
+          <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+              </reference>
+            </externalReferences>
+          </component>
+        </descendants>
+        <variants>
+          <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+              </reference>
+            </externalReferences>
+          </component>
+        </variants>
+        <commits>
+          <commit>
+            <uid>a-random-uid</uid>
+            <message>A commit message</message>
+          </commit>
+        </commits>
+        <patches>
+          <patch type="backport"/>
+        </patches>
+        <notes>Some notes here please</notes>
+      </pedigree>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+      <components>
+        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+          <author>Test Author</author>
+          <name>setuptools</name>
+          <version>50.3.2</version>
+          <licenses>
+            <expression>MIT License</expression>
+          </licenses>
+          <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+        </component>
+        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+          <name>toml</name>
+          <version>0.10.2</version>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+          <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+          <externalReferences>
+            <reference type="distribution">
+              <url>https://cyclonedx.org</url>
+              <comment>No comment</comment>
+            </reference>
+          </externalReferences>
+        </component>
+      </components>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-dings"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_setuptools_complete.json b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.json.bin
similarity index 84%
rename from tests/_data/own/json/1.3/bom_setuptools_complete.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.json.bin
index d32d02004..cf2dc3e1f 100644
--- a/tests/_data/own/json/1.3/bom_setuptools_complete.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.json.bin
@@ -1,267 +1,267 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "df70b5f1-8f53-47a4-be48-669ae78795e6",
-      "supplier": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
+      "author": "Test Author",
+      "bom-ref": "my-specific-bom-ref-for-dings",
+      "components": [
+        {
+          "author": "Test Author",
+          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "licenses": [
+            {
+              "expression": "MIT License"
+            }
+          ],
+          "name": "setuptools",
+          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "type": "library",
+          "version": "50.3.2"
+        },
+        {
+          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "externalReferences": [
+            {
+              "comment": "No comment",
+              "hashes": [
+                {
+                  "alg": "SHA-256",
+                  "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+                }
+              ],
+              "type": "distribution",
+              "url": "https://cyclonedx.org"
+            }
+          ],
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "name": "toml",
+          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "type": "library",
+          "version": "0.10.2"
+        }
+      ],
+      "copyright": "Apache 2.0 baby!",
+      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
+      "description": "This component is awesome",
+      "evidence": {
+        "copyright": [
           {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
+            "text": "Commercial"
           },
           {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
+            "text": "Commercial 2"
           }
         ]
       },
-      "author": "Test Author",
-      "publisher": "CycloneDX",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "description": "This component is awesome",
-      "scope": "required",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "copyright": "Apache 2.0 baby!",
-      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "swid": {
-        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
-        "name": "Test Application",
-        "version": "3.4.5",
-        "text": {
-          "contentType": "text/xml",
-          "encoding": "base64",
-          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
-        }
-      },
+      "name": "setuptools",
       "pedigree": {
         "ancestors": [
           {
-            "type": "library",
-            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
-            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "",
+            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library",
+            "version": ""
+          }
+        ],
+        "commits": [
+          {
+            "message": "A commit message",
+            "uid": "a-random-uid"
           }
         ],
         "descendants": [
           {
-            "type": "library",
-            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "",
+            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library",
+            "version": ""
           },
           {
-            "type": "library",
             "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa",
-            "name": "toml",
-            "version": "0.10.2",
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-            "hashes": [
-              {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-              }
-            ],
             "externalReferences": [
               {
-                "type": "distribution",
-                "url": "https://cyclonedx.org",
                 "comment": "No comment",
                 "hashes": [
                   {
                     "alg": "SHA-256",
                     "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
                   }
-                ]
+                ],
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
               }
-            ]
+            ],
+            "hashes": [
+              {
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+              }
+            ],
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
+          }
+        ],
+        "notes": "Some notes here please",
+        "patches": [
+          {
+            "type": "backport"
           }
         ],
         "variants": [
           {
-            "type": "library",
-            "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
-            "name": "toml",
-            "version": "0.10.2",
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-            "hashes": [
+            "author": "Test Author",
+            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
+            "licenses": [
               {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+                "expression": "MIT License"
               }
             ],
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
+          },
+          {
+            "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
             "externalReferences": [
               {
-                "type": "distribution",
-                "url": "https://cyclonedx.org",
                 "comment": "No comment",
                 "hashes": [
                   {
                     "alg": "SHA-256",
                     "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
                   }
-                ]
+                ],
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
               }
-            ]
-          },
-          {
-            "type": "library",
-            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
-            "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
-            "licenses": [
+            ],
+            "hashes": [
               {
-                "expression": "MIT License"
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-          }
-        ],
-        "commits": [
-          {
-            "uid": "a-random-uid",
-            "message": "A commit message"
-          }
-        ],
-        "patches": [
-          {
-            "type": "backport"
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
           }
-        ],
-        "notes": "Some notes here please"
+        ]
       },
-      "externalReferences": [
-        {
-          "type": "distribution",
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ]
-        }
-      ],
-      "components": [
+      "properties": [
         {
-          "type": "library",
-          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-          "author": "Test Author",
-          "name": "setuptools",
-          "version": "50.3.2",
-          "licenses": [
-            {
-              "expression": "MIT License"
-            }
-          ],
-          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+          "name": "key1",
+          "value": "val1"
         },
         {
-          "type": "library",
-          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "name": "toml",
-          "version": "0.10.2",
-          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ],
-          "externalReferences": [
-            {
-              "type": "distribution",
-              "url": "https://cyclonedx.org",
-              "comment": "No comment",
-              "hashes": [
-                {
-                  "alg": "SHA-256",
-                  "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-                }
-              ]
-            }
-          ]
+          "name": "key2",
+          "value": "val2"
         }
       ],
-      "evidence": {
-        "copyright": [
+      "publisher": "CycloneDX",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "scope": "required",
+      "supplier": {
+        "contact": [
           {
-            "text": "Commercial"
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
           },
           {
-            "text": "Commercial 2"
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
           }
+        ],
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
         ]
       },
-      "properties": [
-        {
-          "name": "key1",
-          "value": "val1"
+      "swid": {
+        "name": "Test Application",
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "text": {
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==",
+          "contentType": "text/xml",
+          "encoding": "base64"
         },
-        {
-          "name": "key2",
-          "value": "val2"
-        }
-      ]
+        "version": "3.4.5"
+      },
+      "type": "library",
+      "version": "50.3.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "df70b5f1-8f53-47a4-be48-669ae78795e6"
+      "ref": "my-specific-bom-ref-for-dings"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.xml.bin
new file mode 100644
index 000000000..316f55629
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.xml.bin
@@ -0,0 +1,183 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="my-specific-bom-ref-for-dings">
+      <supplier>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </supplier>
+      <author>Test Author</author>
+      <publisher>CycloneDX</publisher>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <description>This component is awesome</description>
+      <scope>required</scope>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <copyright>Apache 2.0 baby!</copyright>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
+        <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+      </swid>
+      <pedigree>
+        <ancestors>
+          <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+        </ancestors>
+        <descendants>
+          <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version/>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+                <hashes>
+                  <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+                </hashes>
+              </reference>
+            </externalReferences>
+          </component>
+        </descendants>
+        <variants>
+          <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+                <hashes>
+                  <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+                </hashes>
+              </reference>
+            </externalReferences>
+          </component>
+        </variants>
+        <commits>
+          <commit>
+            <uid>a-random-uid</uid>
+            <message>A commit message</message>
+          </commit>
+        </commits>
+        <patches>
+          <patch type="backport"/>
+        </patches>
+        <notes>Some notes here please</notes>
+      </pedigree>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+      <components>
+        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+          <author>Test Author</author>
+          <name>setuptools</name>
+          <version>50.3.2</version>
+          <licenses>
+            <expression>MIT License</expression>
+          </licenses>
+          <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+        </component>
+        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+          <name>toml</name>
+          <version>0.10.2</version>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+          <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+          <externalReferences>
+            <reference type="distribution">
+              <url>https://cyclonedx.org</url>
+              <comment>No comment</comment>
+              <hashes>
+                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+              </hashes>
+            </reference>
+          </externalReferences>
+        </component>
+      </components>
+      <evidence>
+        <copyright>
+          <text>Commercial</text>
+          <text>Commercial 2</text>
+        </copyright>
+      </evidence>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-dings"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_setuptools_complete.json b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.json.bin
similarity index 84%
rename from tests/_data/own/json/1.4/bom_setuptools_complete.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.json.bin
index ceb5903c2..525c924c4 100644
--- a/tests/_data/own/json/1.4/bom_setuptools_complete.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.json.bin
@@ -1,329 +1,236 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
-        "externalReferences": [
-          {
-            "type": "build-system",
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
-          },
-          {
-            "type": "distribution",
-            "url": "https://pypi.org/project/cyclonedx-python-lib/"
-          },
-          {
-            "type": "documentation",
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
-          },
-          {
-            "type": "issue-tracker",
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
-          },
-          {
-            "type": "license",
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
-          },
-          {
-            "type": "release-notes",
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
-          },
-          {
-            "type": "vcs",
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
-          },
-          {
-            "type": "website",
-            "url": "https://cyclonedx.org"
-          }
-        ]
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "df70b5f1-8f53-47a4-be48-669ae78795e6",
-      "supplier": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
+      "author": "Test Author",
+      "bom-ref": "my-specific-bom-ref-for-dings",
+      "components": [
+        {
+          "author": "Test Author",
+          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "licenses": [
+            {
+              "expression": "MIT License"
+            }
+          ],
+          "name": "setuptools",
+          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "type": "library",
+          "version": "50.3.2"
+        },
+        {
+          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "externalReferences": [
+            {
+              "comment": "No comment",
+              "hashes": [
+                {
+                  "alg": "SHA-256",
+                  "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+                }
+              ],
+              "type": "distribution",
+              "url": "https://cyclonedx.org"
+            }
+          ],
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "name": "toml",
+          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+          "type": "library",
+          "version": "0.10.2"
+        }
+      ],
+      "copyright": "Apache 2.0 baby!",
+      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
+      "description": "This component is awesome",
+      "evidence": {
+        "copyright": [
           {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
+            "text": "Commercial"
           },
           {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
+            "text": "Commercial 2"
           }
         ]
       },
-      "author": "Test Author",
-      "publisher": "CycloneDX",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "description": "This component is awesome",
-      "scope": "required",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "copyright": "Apache 2.0 baby!",
-      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "swid": {
-        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
-        "name": "Test Application",
-        "version": "3.4.5",
-        "text": {
-          "contentType": "text/xml",
-          "encoding": "base64",
-          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg=="
-        }
-      },
+      "name": "setuptools",
       "pedigree": {
         "ancestors": [
           {
-            "type": "library",
-            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
+            "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
           },
           {
-            "type": "library",
-            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "author": "Test Author",
-            "name": "setuptools",
+            "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library"
+          }
+        ],
+        "commits": [
+          {
+            "message": "A commit message",
+            "uid": "a-random-uid"
           }
         ],
         "descendants": [
           {
-            "type": "library",
-            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "author": "Test Author",
-            "name": "setuptools",
+            "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
                 "expression": "MIT License"
               }
             ],
-            "purl": "pkg:pypi/setuptools?extension=tar.gz"
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools?extension=tar.gz",
+            "type": "library"
           },
           {
-            "type": "library",
             "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa",
-            "name": "toml",
-            "version": "0.10.2",
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-            "hashes": [
-              {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-              }
-            ],
             "externalReferences": [
               {
-                "type": "distribution",
-                "url": "https://cyclonedx.org",
                 "comment": "No comment",
                 "hashes": [
                   {
                     "alg": "SHA-256",
                     "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
                   }
-                ]
+                ],
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
               }
-            ]
+            ],
+            "hashes": [
+              {
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+              }
+            ],
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
+          }
+        ],
+        "notes": "Some notes here please",
+        "patches": [
+          {
+            "type": "backport"
           }
         ],
         "variants": [
           {
-            "type": "library",
-            "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
-            "name": "toml",
-            "version": "0.10.2",
-            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-            "hashes": [
+            "author": "Test Author",
+            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
+            "licenses": [
               {
-                "alg": "SHA-256",
-                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+                "expression": "MIT License"
               }
             ],
+            "name": "setuptools",
+            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+            "type": "library",
+            "version": "50.3.2"
+          },
+          {
+            "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66",
             "externalReferences": [
               {
-                "type": "distribution",
-                "url": "https://cyclonedx.org",
                 "comment": "No comment",
                 "hashes": [
                   {
                     "alg": "SHA-256",
                     "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
                   }
-                ]
+                ],
+                "type": "distribution",
+                "url": "https://cyclonedx.org"
               }
-            ]
-          },
-          {
-            "type": "library",
-            "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
-            "author": "Test Author",
-            "name": "setuptools",
-            "version": "50.3.2",
-            "licenses": [
+            ],
+            "hashes": [
               {
-                "expression": "MIT License"
+                "alg": "SHA-256",
+                "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
               }
             ],
-            "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-          }
-        ],
-        "commits": [
-          {
-            "uid": "a-random-uid",
-            "message": "A commit message"
-          }
-        ],
-        "patches": [
-          {
-            "type": "backport"
+            "name": "toml",
+            "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+            "type": "library",
+            "version": "0.10.2"
           }
-        ],
-        "notes": "Some notes here please"
+        ]
       },
-      "externalReferences": [
-        {
-          "type": "distribution",
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ]
-        }
-      ],
-      "components": [
+      "properties": [
         {
-          "type": "library",
-          "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-          "author": "Test Author",
-          "name": "setuptools",
-          "version": "50.3.2",
-          "licenses": [
-            {
-              "expression": "MIT License"
-            }
-          ],
-          "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+          "name": "key1",
+          "value": "val1"
         },
         {
-          "type": "library",
-          "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "name": "toml",
-          "version": "0.10.2",
-          "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ],
-          "externalReferences": [
-            {
-              "type": "distribution",
-              "url": "https://cyclonedx.org",
-              "comment": "No comment",
-              "hashes": [
-                {
-                  "alg": "SHA-256",
-                  "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-                }
-              ]
-            }
-          ]
+          "name": "key2",
+          "value": "val2"
         }
       ],
-      "evidence": {
-        "copyright": [
-          {
-            "text": "Commercial"
-          },
-          {
-            "text": "Commercial 2"
-          }
-        ]
-      },
+      "publisher": "CycloneDX",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "releaseNotes": {
-        "type": "major",
-        "title": "Release Notes Title",
-        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
-        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
-        "description": "This release is a test release",
-        "timestamp": "2021-12-31T10:00:00+00:00",
         "aliases": [
           "First Test Release"
         ],
-        "tags": [
-          "test",
-          "alpha"
-        ],
-        "resolves": [
-          {
-            "type": "security",
-            "id": "CVE-2021-44228",
-            "name": "Apache Log3Shell",
-            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
-            "source": {
-              "name": "NVD",
-              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
-            },
-            "references": [
-              "https://logging.apache.org/log4j/2.x/security.html",
-              "https://central.sonatype.org/news/20211213_log4shell_help"
-            ]
-          }
-        ],
+        "description": "This release is a test release",
+        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
         "notes": [
           {
             "locale": "en-GB",
             "text": {
+              "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
-              "encoding": "base64",
-              "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA=="
+              "encoding": "base64"
             }
           },
           {
             "locale": "en-US",
             "text": {
+              "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
-              "encoding": "base64",
-              "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA=="
+              "encoding": "base64"
             }
           }
         ],
@@ -336,23 +243,116 @@
             "name": "key2",
             "value": "val2"
           }
+        ],
+        "resolves": [
+          {
+            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
+            "id": "CVE-2021-44228",
+            "name": "Apache Log3Shell",
+            "references": [
+              "https://central.sonatype.org/news/20211213_log4shell_help",
+              "https://logging.apache.org/log4j/2.x/security.html"
+            ],
+            "source": {
+              "name": "NVD",
+              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
+            },
+            "type": "security"
+          }
+        ],
+        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
+        "tags": [
+          "alpha",
+          "test"
+        ],
+        "timestamp": "2023-08-15T01:23:45.678900+00:00",
+        "title": "Release Notes Title",
+        "type": "major"
+      },
+      "scope": "required",
+      "supplier": {
+        "contact": [
+          {
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          },
+          {
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
+          }
+        ],
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
         ]
       },
-      "properties": [
-        {
-          "name": "key1",
-          "value": "val1"
+      "swid": {
+        "name": "Test Application",
+        "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1",
+        "text": {
+          "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==",
+          "contentType": "text/xml",
+          "encoding": "base64"
         },
-        {
-          "name": "key2",
-          "value": "val2"
-        }
-      ]
+        "version": "3.4.5"
+      },
+      "type": "library",
+      "version": "50.3.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "df70b5f1-8f53-47a4-be48-669ae78795e6"
+      "ref": "my-specific-bom-ref-for-dings"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.xml.bin
new file mode 100644
index 000000000..24b43c3f0
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.xml.bin
@@ -0,0 +1,251 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="my-specific-bom-ref-for-dings">
+      <supplier>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </supplier>
+      <author>Test Author</author>
+      <publisher>CycloneDX</publisher>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <description>This component is awesome</description>
+      <scope>required</scope>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <copyright>Apache 2.0 baby!</copyright>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <swid tagId="swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1" name="Test Application" version="3.4.5">
+        <text content-type="text/xml" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==</text>
+      </swid>
+      <pedigree>
+        <ancestors>
+          <component type="library" bom-ref="ccc8d7ee-4b9c-4750-aee0-a72585152291">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="8a3893b3-9923-4adb-a1d3-47456636ba0a">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+        </ancestors>
+        <descendants>
+          <component type="library" bom-ref="28b2d8ce-def0-446f-a221-58dee0b44acc">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="555ca729-93c6-48f3-956e-bdaa4a2f0bfa">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+                <hashes>
+                  <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+                </hashes>
+              </reference>
+            </externalReferences>
+          </component>
+        </descendants>
+        <variants>
+          <component type="library" bom-ref="ded1d73e-1fca-4302-b520-f1bc53979958">
+            <author>Test Author</author>
+            <name>setuptools</name>
+            <version>50.3.2</version>
+            <licenses>
+              <expression>MIT License</expression>
+            </licenses>
+            <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+          </component>
+          <component type="library" bom-ref="e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66">
+            <name>toml</name>
+            <version>0.10.2</version>
+            <hashes>
+              <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+            </hashes>
+            <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+            <externalReferences>
+              <reference type="distribution">
+                <url>https://cyclonedx.org</url>
+                <comment>No comment</comment>
+                <hashes>
+                  <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+                </hashes>
+              </reference>
+            </externalReferences>
+          </component>
+        </variants>
+        <commits>
+          <commit>
+            <uid>a-random-uid</uid>
+            <message>A commit message</message>
+          </commit>
+        </commits>
+        <patches>
+          <patch type="backport"/>
+        </patches>
+        <notes>Some notes here please</notes>
+      </pedigree>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+      <components>
+        <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+          <author>Test Author</author>
+          <name>setuptools</name>
+          <version>50.3.2</version>
+          <licenses>
+            <expression>MIT License</expression>
+          </licenses>
+          <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+        </component>
+        <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+          <name>toml</name>
+          <version>0.10.2</version>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+          <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+          <externalReferences>
+            <reference type="distribution">
+              <url>https://cyclonedx.org</url>
+              <comment>No comment</comment>
+              <hashes>
+                <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+              </hashes>
+            </reference>
+          </externalReferences>
+        </component>
+      </components>
+      <evidence>
+        <copyright>
+          <text>Commercial</text>
+          <text>Commercial 2</text>
+        </copyright>
+      </evidence>
+      <releaseNotes>
+        <type>major</type>
+        <title>Release Notes Title</title>
+        <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
+        <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
+        <description>This release is a test release</description>
+        <timestamp>2023-08-15T01:23:45.678900+00:00</timestamp>
+        <aliases>
+          <alias>First Test Release</alias>
+        </aliases>
+        <tags>
+          <tag>alpha</tag>
+          <tag>test</tag>
+        </tags>
+        <resolves>
+          <issue type="security">
+            <id>CVE-2021-44228</id>
+            <name>Apache Log3Shell</name>
+            <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
+            <source>
+              <name>NVD</name>
+              <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
+            </source>
+            <references>
+              <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
+              <url>https://logging.apache.org/log4j/2.x/security.html</url>
+            </references>
+          </issue>
+        </resolves>
+        <notes>
+          <note>
+            <locale>en-GB</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+          <note>
+            <locale>en-US</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+        </notes>
+        <properties>
+          <property name="key1">val1</property>
+          <property name="key2">val2</property>
+        </properties>
+      </releaseNotes>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-dings"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.0.xml.bin
new file mode 100644
index 000000000..19b807ce8
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.0.xml.bin
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>setuptools</name>
+      <version/>
+      <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.1.xml.bin
new file mode 100644
index 000000000..4d6b504d4
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.1.xml.bin
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools?extension=tar.gz">
+      <name>setuptools</name>
+      <version/>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_setuptools_no_version.json b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.json.bin
similarity index 80%
rename from tests/_data/own/json/1.2/bom_setuptools_no_version.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.json.bin
index 8fb2dd782..7bb0d1e15 100644
--- a/tests/_data/own/json/1.2/bom_setuptools_no_version.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.json.bin
@@ -1,37 +1,37 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:77d15ab9-5602-4cca-8ed2-59ae579aafd3",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "",
+      "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "purl": "pkg:pypi/setuptools?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools?extension=tar.gz",
+      "type": "library",
+      "version": ""
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/setuptools?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.xml.bin
new file mode 100644
index 000000000..a993370c3
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version/>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_setuptools_no_version.json b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.json.bin
similarity index 80%
rename from tests/_data/own/json/1.3/bom_setuptools_no_version.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.json.bin
index c59f067e7..1fb453b4a 100644
--- a/tests/_data/own/json/1.3/bom_setuptools_no_version.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.json.bin
@@ -1,37 +1,37 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:77d15ab9-5602-4cca-8ed2-59ae579aafd3",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "",
+      "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "purl": "pkg:pypi/setuptools?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools?extension=tar.gz",
+      "type": "library",
+      "version": ""
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/setuptools?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.xml.bin
new file mode 100644
index 000000000..f12eaf368
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version/>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_setuptools_no_version.json b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.json.bin
similarity index 67%
rename from tests/_data/own/json/1.4/bom_setuptools_no_version.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.json.bin
index ea3bb5d6d..ac80eda9a 100644
--- a/tests/_data/own/json/1.4/bom_setuptools_no_version.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.json.bin
@@ -1,70 +1,70 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:77d15ab9-5602-4cca-8ed2-59ae579aafd3",
-  "version": 1,
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools?extension=tar.gz",
+      "type": "library"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/setuptools?extension=tar.gz"
+    }
+  ],
   "metadata": {
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
         "externalReferences": [
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
           },
           {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
           },
           {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
           },
           {
-            "url": "https://cyclonedx.org",
-            "type": "website"
+            "type": "website",
+            "url": "https://cyclonedx.org"
           }
-        ]
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
       }
     ]
   },
-  "components": [
-    {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
-      "author": "Test Author",
-      "name": "setuptools",
-      "licenses": [
-        {
-          "expression": "MIT License"
-        }
-      ],
-      "purl": "pkg:pypi/setuptools?extension=tar.gz"
-    }
-  ],
-  "dependencies": [
-    {
-      "ref": "pkg:pypi/setuptools?extension=tar.gz"
-    }
-  ]
-}
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.xml.bin
new file mode 100644
index 000000000..a08ce14db
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.xml.bin
@@ -0,0 +1,52 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.0.xml.bin
new file mode 100644
index 000000000..79dbb1afc
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.0.xml.bin
@@ -0,0 +1,12 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.1.xml.bin
new file mode 100644
index 000000000..1ac5e156d
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.1.xml.bin
@@ -0,0 +1,14 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_setuptools_with_cpe.json b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.json.bin
similarity index 80%
rename from tests/_data/own/json/1.2/bom_setuptools_with_cpe.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.json.bin
index 0d7e9b9e2..2dd754f8f 100644
--- a/tests/_data/own/json/1.2/bom_setuptools_with_cpe.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.json.bin
@@ -1,38 +1,38 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.xml.bin
new file mode 100644
index 000000000..7a23d5d11
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.xml.bin
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_setuptools_with_cpe.json b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.json.bin
similarity index 80%
rename from tests/_data/own/json/1.3/bom_setuptools_with_cpe.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.json.bin
index baf80bccb..077f8b253 100644
--- a/tests/_data/own/json/1.3/bom_setuptools_with_cpe.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.json.bin
@@ -1,38 +1,38 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.xml.bin
new file mode 100644
index 000000000..a2d699055
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.xml.bin
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_setuptools_with_cpe.json b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.json.bin
similarity index 68%
rename from tests/_data/own/json/1.4/bom_setuptools_with_cpe.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.json.bin
index 7ad22406a..66f999c5f 100644
--- a/tests/_data/own/json/1.4/bom_setuptools_with_cpe.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.json.bin
@@ -1,72 +1,72 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+    }
+  ],
   "metadata": {
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
         "externalReferences": [
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
           },
           {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
           },
           {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
           },
           {
-            "url": "https://cyclonedx.org",
-            "type": "website"
+            "type": "website",
+            "url": "https://cyclonedx.org"
           }
-        ]
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
       }
     ]
   },
-  "components": [
-    {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "licenses": [
-        {
-          "expression": "MIT License"
-        }
-      ],
-      "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  ],
-  "dependencies": [
-    {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  ]
-}
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.xml.bin
new file mode 100644
index 000000000..a2c30d437
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.xml.bin
@@ -0,0 +1,54 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.0.xml.bin
new file mode 100644
index 000000000..961bb4798
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.0.xml.bin
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.1.xml.bin
new file mode 100644
index 000000000..0b33bec2a
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.1.xml.bin
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.json.bin
new file mode 100644
index 000000000..9d0993c87
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.json.bin
@@ -0,0 +1,37 @@
+{
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+    }
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.xml.bin
new file mode 100644
index 000000000..ce6f3e6c6
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.json.bin
new file mode 100644
index 000000000..6e2f630e8
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.json.bin
@@ -0,0 +1,37 @@
+{
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+    }
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.xml.bin
new file mode 100644
index 000000000..39cbf1d85
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_setuptools_with_release_notes.json b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.json.bin
similarity index 78%
rename from tests/_data/own/json/1.4/bom_setuptools_with_release_notes.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.json.bin
index 492be373e..6eed4f13c 100644
--- a/tests/_data/own/json/1.4/bom_setuptools_with_release_notes.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.json.bin
@@ -1,112 +1,37 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
-        "externalReferences": [
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
-          },
-          {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
-          },
-          {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
-          },
-          {
-            "url": "https://cyclonedx.org",
-            "type": "website"
-          }
-        ]
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
+      "name": "setuptools",
       "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "releaseNotes": {
-        "type": "major",
-        "title": "Release Notes Title",
-        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
-        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
-        "description": "This release is a test release",
-        "timestamp": "2021-12-31T10:00:00+00:00",
         "aliases": [
           "First Test Release"
         ],
-        "tags": [
-          "alpha",
-          "test"
-        ],
-        "resolves": [
-          {
-            "type": "security",
-            "id": "CVE-2021-44228",
-            "name": "Apache Log3Shell",
-            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
-            "source": {
-              "name": "NVD",
-              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
-            },
-            "references": [
-              "https://central.sonatype.org/news/20211213_log4shell_help",
-              "https://logging.apache.org/log4j/2.x/security.html"
-            ]
-          }
-        ],
+        "description": "This release is a test release",
+        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
         "notes": [
           {
+            "locale": "en-GB",
             "text": {
               "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
               "encoding": "base64"
-            },
-            "locale": "en-GB"
+            }
           },
           {
+            "locale": "en-US",
             "text": {
               "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
               "encoding": "base64"
-            },
-            "locale": "en-US"
+            }
           }
         ],
         "properties": [
@@ -118,13 +43,88 @@
             "name": "key2",
             "value": "val2"
           }
-        ]
-      }
+        ],
+        "resolves": [
+          {
+            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
+            "id": "CVE-2021-44228",
+            "name": "Apache Log3Shell",
+            "references": [
+              "https://central.sonatype.org/news/20211213_log4shell_help",
+              "https://logging.apache.org/log4j/2.x/security.html"
+            ],
+            "source": {
+              "name": "NVD",
+              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
+            },
+            "type": "security"
+          }
+        ],
+        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
+        "tags": [
+          "alpha",
+          "test"
+        ],
+        "timestamp": "2023-08-15T01:23:45.678900+00:00",
+        "title": "Release Notes Title",
+        "type": "major"
+      },
+      "type": "library",
+      "version": "50.3.2"
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.xml.bin
new file mode 100644
index 000000000..2d067b43e
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.xml.bin
@@ -0,0 +1,97 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <releaseNotes>
+        <type>major</type>
+        <title>Release Notes Title</title>
+        <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
+        <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
+        <description>This release is a test release</description>
+        <timestamp>2023-08-15T01:23:45.678900+00:00</timestamp>
+        <aliases>
+          <alias>First Test Release</alias>
+        </aliases>
+        <tags>
+          <tag>alpha</tag>
+          <tag>test</tag>
+        </tags>
+        <resolves>
+          <issue type="security">
+            <id>CVE-2021-44228</id>
+            <name>Apache Log3Shell</name>
+            <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
+            <source>
+              <name>NVD</name>
+              <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
+            </source>
+            <references>
+              <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
+              <url>https://logging.apache.org/log4j/2.x/security.html</url>
+            </references>
+          </issue>
+        </resolves>
+        <notes>
+          <note>
+            <locale>en-GB</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+          <note>
+            <locale>en-US</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+        </notes>
+        <properties>
+          <property name="key1">val1</property>
+          <property name="key2">val2</property>
+        </properties>
+      </releaseNotes>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.0.xml.bin
new file mode 100644
index 000000000..961bb4798
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.0.xml.bin
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.1.xml.bin
new file mode 100644
index 000000000..0b33bec2a
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.1.xml.bin
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.json.bin
new file mode 100644
index 000000000..9d0993c87
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.json.bin
@@ -0,0 +1,37 @@
+{
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+    }
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.xml.bin
new file mode 100644
index 000000000..ce6f3e6c6
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.json.bin
new file mode 100644
index 000000000..6e2f630e8
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.json.bin
@@ -0,0 +1,37 @@
+{
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+    }
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.xml.bin
new file mode 100644
index 000000000..39cbf1d85
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_setuptools_with_vulnerabilities.json b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.json.bin
similarity index 77%
rename from tests/_data/own/json/1.4/bom_setuptools_with_vulnerabilities.json
rename to tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.json.bin
index c7c0ed05c..296520bee 100644
--- a/tests/_data/own/json/1.4/bom_setuptools_with_vulnerabilities.json
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.json.bin
@@ -1,121 +1,72 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+    }
+  ],
   "metadata": {
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
         "externalReferences": [
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
           },
           {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
           },
           {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
           },
           {
-            "url": "https://cyclonedx.org",
-            "type": "website"
+            "type": "website",
+            "url": "https://cyclonedx.org"
           }
-        ]
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
       }
     ]
   },
-  "components": [
-    {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "licenses": [
-        {
-          "expression": "MIT License"
-        }
-      ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  ],
-  "dependencies": [
-    {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  ],
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
   "vulnerabilities": [
     {
-      "bom-ref": "my-vuln-ref-1",
-      "id": "CVE-2018-7489",
-      "source": {
-        "name": "NVD",
-        "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-7489"
-      },
-      "references": [
-        {
-          "id": "SOME-OTHER-ID",
-          "source": {
-            "name": "OSS Index",
-            "url": "https://ossindex.sonatype.org/component/pkg:pypi/setuptools"
-          }
-        }
-      ],
-      "ratings": [
-        {
-          "source": {
-            "name": "NVD",
-            "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-7489"
-          },
-          "score": 9.8,
-          "severity": "critical",
-          "method": "CVSSv3",
-          "vector": "AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
-          "justification": "Some justification"
-        },
-        {
-          "source": {
-            "name": "OWASP",
-            "url": "https://owasp.org"
-          },
-          "score": 2.7,
-          "severity": "low",
-          "method": "CVSSv3",
-          "vector": "AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N",
-          "justification": "Some other justification"
-        }
-      ],
-      "cwes": [
-        22,
-        33
-      ],
-      "description": "A description here",
-      "detail": "Some detail here",
-      "recommendation": "Upgrade",
       "advisories": [
         {
           "url": "http://www.securitytracker.com/id/1040693"
@@ -124,62 +75,62 @@
           "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-7489"
         }
       ],
+      "affects": [
+        {
+          "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+          "versions": [
+            {
+              "range": "49.0.0 - 54.0.0",
+              "status": "affected"
+            }
+          ]
+        }
+      ],
+      "analysis": {
+        "detail": "Some extra detail",
+        "justification": "requires_environment",
+        "response": [
+          "can_not_fix"
+        ],
+        "state": "exploitable"
+      },
+      "bom-ref": "my-vuln-ref-1",
       "created": "2021-09-01T10:50:42.051979+00:00",
-      "published": "2021-09-02T10:50:42.051979+00:00",
-      "updated": "2021-09-03T10:50:42.051979+00:00",
       "credits": {
+        "individuals": [
+          {
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          }
+        ],
         "organizations": [
           {
-            "name": "CycloneDX",
-            "url": [
-              "https://cyclonedx.org"
-            ],
             "contact": [
               {
-                "name": "A N Other",
                 "email": "someone@somewhere.tld",
+                "name": "A N Other",
                 "phone": "+44 (0)1234 567890"
               },
               {
-                "name": "Paul Horton",
-                "email": "paul.horton@owasp.org"
+                "email": "paul.horton@owasp.org",
+                "name": "Paul Horton"
               }
+            ],
+            "name": "CycloneDX",
+            "url": [
+              "https://cyclonedx.org"
             ]
           }
-        ],
-        "individuals": [
-          {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
-          }
         ]
       },
-      "tools": [
-        {
-          "vendor": "CycloneDX",
-          "name": "cyclonedx-python-lib"
-        }
-      ],
-      "analysis": {
-        "state": "exploitable",
-        "justification": "requires_environment",
-        "response": [
-          "can_not_fix"
-        ],
-        "detail": "Some extra detail"
-      },
-      "affects": [
-        {
-          "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-          "versions": [
-            {
-              "range": "49.0.0 - 54.0.0",
-              "status": "affected"
-            }
-          ]
-        }
+      "cwes": [
+        22,
+        33
       ],
+      "description": "A description here",
+      "detail": "Some detail here",
+      "id": "CVE-2018-7489",
       "properties": [
         {
           "name": "key1",
@@ -189,7 +140,56 @@
           "name": "key2",
           "value": "val2"
         }
-      ]
+      ],
+      "published": "2021-09-02T10:50:42.051979+00:00",
+      "ratings": [
+        {
+          "justification": "Some justification",
+          "method": "CVSSv3",
+          "score": 9.8,
+          "severity": "critical",
+          "source": {
+            "name": "NVD",
+            "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-7489"
+          },
+          "vector": "AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
+        },
+        {
+          "justification": "Some other justification",
+          "method": "CVSSv3",
+          "score": 2.7,
+          "severity": "low",
+          "source": {
+            "name": "OWASP",
+            "url": "https://owasp.org"
+          },
+          "vector": "AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N"
+        }
+      ],
+      "recommendation": "Upgrade",
+      "references": [
+        {
+          "id": "SOME-OTHER-ID",
+          "source": {
+            "name": "OSS Index",
+            "url": "https://ossindex.sonatype.org/component/pkg:pypi/setuptools"
+          }
+        }
+      ],
+      "source": {
+        "name": "NVD",
+        "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-7489"
+      },
+      "tools": [
+        {
+          "name": "cyclonedx-python-lib",
+          "vendor": "CycloneDX"
+        }
+      ],
+      "updated": "2021-09-03T10:50:42.051979+00:00"
     }
-  ]
-}
+  ],
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.xml.bin
new file mode 100644
index 000000000..7ccc65ebd
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.xml.bin
@@ -0,0 +1,166 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz"/>
+  </dependencies>
+  <vulnerabilities>
+    <vulnerability bom-ref="my-vuln-ref-1">
+      <id>CVE-2018-7489</id>
+      <source>
+        <name>NVD</name>
+        <url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</url>
+      </source>
+      <references>
+        <reference>
+          <id>SOME-OTHER-ID</id>
+          <source>
+            <name>OSS Index</name>
+            <url>https://ossindex.sonatype.org/component/pkg:pypi/setuptools</url>
+          </source>
+        </reference>
+      </references>
+      <ratings>
+        <rating>
+          <source>
+            <name>NVD</name>
+            <url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</url>
+          </source>
+          <score>9.8</score>
+          <severity>critical</severity>
+          <method>CVSSv3</method>
+          <vector>AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H</vector>
+          <justification>Some justification</justification>
+        </rating>
+        <rating>
+          <source>
+            <name>OWASP</name>
+            <url>https://owasp.org</url>
+          </source>
+          <score>2.7</score>
+          <severity>low</severity>
+          <method>CVSSv3</method>
+          <vector>AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N</vector>
+          <justification>Some other justification</justification>
+        </rating>
+      </ratings>
+      <cwes>
+        <cwe>22</cwe>
+        <cwe>33</cwe>
+      </cwes>
+      <description>A description here</description>
+      <detail>Some detail here</detail>
+      <recommendation>Upgrade</recommendation>
+      <advisories>
+        <advisory>
+          <url>http://www.securitytracker.com/id/1040693</url>
+        </advisory>
+        <advisory>
+          <url>https://nvd.nist.gov/vuln/detail/CVE-2018-7489</url>
+        </advisory>
+      </advisories>
+      <created>2021-09-01T10:50:42.051979+00:00</created>
+      <published>2021-09-02T10:50:42.051979+00:00</published>
+      <updated>2021-09-03T10:50:42.051979+00:00</updated>
+      <credits>
+        <organizations>
+          <organization>
+            <name>CycloneDX</name>
+            <url>https://cyclonedx.org</url>
+            <contact>
+              <name>A N Other</name>
+              <email>someone@somewhere.tld</email>
+              <phone>+44 (0)1234 567890</phone>
+            </contact>
+            <contact>
+              <name>Paul Horton</name>
+              <email>paul.horton@owasp.org</email>
+            </contact>
+          </organization>
+        </organizations>
+        <individuals>
+          <individual>
+            <name>A N Other</name>
+            <email>someone@somewhere.tld</email>
+            <phone>+44 (0)1234 567890</phone>
+          </individual>
+        </individuals>
+      </credits>
+      <tools>
+        <tool>
+          <vendor>CycloneDX</vendor>
+          <name>cyclonedx-python-lib</name>
+        </tool>
+      </tools>
+      <analysis>
+        <state>exploitable</state>
+        <justification>requires_environment</justification>
+        <responses>
+          <response>can_not_fix</response>
+        </responses>
+        <detail>Some extra detail</detail>
+      </analysis>
+      <affects>
+        <target>
+          <ref>pkg:pypi/setuptools@50.3.2?extension=tar.gz</ref>
+          <versions>
+            <version>
+              <range>49.0.0 - 54.0.0</range>
+              <status>affected</status>
+            </version>
+          </versions>
+        </target>
+      </affects>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+    </vulnerability>
+  </vulnerabilities>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_toml_1-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_component_toml_1-1.0.xml.bin
new file mode 100644
index 000000000..7355c2cac
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_toml_1-1.0.xml.bin
@@ -0,0 +1,14 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_component_toml_1-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_toml_1-1.1.xml.bin
new file mode 100644
index 000000000..7f5932c19
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_toml_1-1.1.xml.bin
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_toml_1.json b/tests/_data/snapshots/get_bom_with_component_toml_1-1.2.json.bin
similarity index 80%
rename from tests/_data/own/json/1.2/bom_toml_1.json
rename to tests/_data/snapshots/get_bom_with_component_toml_1-1.2.json.bin
index 4180b39b0..8e170b991 100644
--- a/tests/_data/own/json/1.2/bom_toml_1.json
+++ b/tests/_data/snapshots/get_bom_with_component_toml_1-1.2.json.bin
@@ -1,44 +1,44 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:6f266d1c-760f-4552-ae3b-41a9b74232fa",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
       "hashes": [
         {
           "alg": "SHA-256",
           "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
         }
       ],
+      "name": "toml",
       "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "externalReferences": [
-        {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution"
-        }
-      ]
+      "type": "library",
+      "version": "0.10.2"
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_toml_1-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_toml_1-1.2.xml.bin
new file mode 100644
index 000000000..ef97c383d
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_toml_1-1.2.xml.bin
@@ -0,0 +1,32 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_toml_1.json b/tests/_data/snapshots/get_bom_with_component_toml_1-1.3.json.bin
similarity index 85%
rename from tests/_data/own/json/1.3/bom_toml_1.json
rename to tests/_data/snapshots/get_bom_with_component_toml_1-1.3.json.bin
index 2ec922747..aefb94a14 100644
--- a/tests/_data/own/json/1.3/bom_toml_1.json
+++ b/tests/_data/snapshots/get_bom_with_component_toml_1-1.3.json.bin
@@ -1,50 +1,50 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:6f266d1c-760f-4552-ae3b-41a9b74232fa",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
-      "hashes": [
-        {
-          "alg": "SHA-256",
-          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-        }
-      ],
-      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
       "externalReferences": [
         {
-          "url": "https://cyclonedx.org",
           "comment": "No comment",
-          "type": "distribution",
           "hashes": [
             {
               "alg": "SHA-256",
               "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
             }
-          ]
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
-      ]
+      ],
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "name": "toml",
+      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "type": "library",
+      "version": "0.10.2"
     }
   ],
   "dependencies": [
     {
       "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_toml_1-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_toml_1-1.3.xml.bin
new file mode 100644
index 000000000..a9417823f
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_toml_1-1.3.xml.bin
@@ -0,0 +1,35 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_toml_1.json b/tests/_data/snapshots/get_bom_with_component_toml_1-1.4.json.bin
similarity index 72%
rename from tests/_data/own/json/1.4/bom_toml_1.json
rename to tests/_data/snapshots/get_bom_with_component_toml_1-1.4.json.bin
index 80fe0ae3f..1b8835591 100644
--- a/tests/_data/own/json/1.4/bom_toml_1.json
+++ b/tests/_data/snapshots/get_bom_with_component_toml_1-1.4.json.bin
@@ -1,84 +1,84 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:6f266d1c-760f-4552-ae3b-41a9b74232fa",
-  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "name": "toml",
+      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "type": "library",
+      "version": "0.10.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
+    }
+  ],
   "metadata": {
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
         "externalReferences": [
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
           },
           {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
           },
           {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
           },
           {
-            "url": "https://cyclonedx.org",
-            "type": "website"
+            "type": "website",
+            "url": "https://cyclonedx.org"
           }
-        ]
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
       }
     ]
   },
-  "components": [
-    {
-      "type": "library",
-      "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
-      "hashes": [
-        {
-          "alg": "SHA-256",
-          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-        }
-      ],
-      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "externalReferences": [
-        {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ]
-        }
-      ]
-    }
-  ],
-  "dependencies": [
-    {
-      "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
-    }
-  ]
-}
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_component_toml_1-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_toml_1-1.4.xml.bin
new file mode 100644
index 000000000..a17f8a46a
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_component_toml_1-1.4.xml.bin
@@ -0,0 +1,61 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.0.xml.bin
new file mode 100644
index 000000000..d0259a8af
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.0.xml.bin
@@ -0,0 +1,20 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="23">
+  <components>
+    <component type="library">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+    <component type="library">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.1.xml.bin
new file mode 100644
index 000000000..ef886b52b
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.1.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="23">
+  <components>
+    <component type="library" bom-ref="setuptools">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+    <component type="library" bom-ref="toml">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.json.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.json.bin
new file mode 100644
index 000000000..c63b1b817
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.json.bin
@@ -0,0 +1,72 @@
+{
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "setuptools",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    },
+    {
+      "bom-ref": "toml",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "name": "toml",
+      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "type": "library",
+      "version": "0.10.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "root-component"
+    },
+    {
+      "dependsOn": [
+        "toml"
+      ],
+      "ref": "setuptools"
+    },
+    {
+      "ref": "toml"
+    }
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "root-component",
+      "name": "rootComponent",
+      "type": "application",
+      "version": ""
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 23,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.xml.bin
new file mode 100644
index 000000000..3d1ac1fb5
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.xml.bin
@@ -0,0 +1,49 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="23">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="root-component">
+      <name>rootComponent</name>
+      <version/>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="setuptools">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+    <component type="library" bom-ref="toml">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="root-component"/>
+    <dependency ref="setuptools">
+      <dependency ref="toml"/>
+    </dependency>
+    <dependency ref="toml"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_with_dependencies_hanging.json b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.json.bin
similarity index 75%
rename from tests/_data/own/json/1.4/bom_with_dependencies_hanging.json
rename to tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.json.bin
index 92cf9405d..5ccacbb31 100644
--- a/tests/_data/own/json/1.4/bom_with_dependencies_hanging.json
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.json.bin
@@ -1,17 +1,4 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:12345678-395b-41f5-a30f-1234567890ab",
-  "version": 23,
-  "metadata": {
-    "component": {
-      "bom-ref": "root-component",
-      "name": "rootComponent",
-      "type": "application"
-    },
-    "timestamp": "2023-06-01T03:03:07+00:00"
-  },
   "components": [
     {
       "author": "Test Author",
@@ -58,13 +45,34 @@
       "ref": "root-component"
     },
     {
-      "ref": "setuptools",
       "dependsOn": [
         "toml"
-      ]
+      ],
+      "ref": "setuptools"
     },
     {
       "ref": "toml"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "root-component",
+      "name": "rootComponent",
+      "type": "application",
+      "version": ""
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 23,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.xml.bin
new file mode 100644
index 000000000..656e37d0e
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.xml.bin
@@ -0,0 +1,52 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="23">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="root-component">
+      <name>rootComponent</name>
+      <version/>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="setuptools">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+    <component type="library" bom-ref="toml">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="root-component"/>
+    <dependency ref="setuptools">
+      <dependency ref="toml"/>
+    </dependency>
+    <dependency ref="toml"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.json.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.json.bin
new file mode 100644
index 000000000..abe58bd49
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.json.bin
@@ -0,0 +1,111 @@
+{
+  "components": [
+    {
+      "author": "Test Author",
+      "bom-ref": "setuptools",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    },
+    {
+      "bom-ref": "toml",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "name": "toml",
+      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "type": "library",
+      "version": "0.10.2"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "root-component"
+    },
+    {
+      "dependsOn": [
+        "toml"
+      ],
+      "ref": "setuptools"
+    },
+    {
+      "ref": "toml"
+    }
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "root-component",
+      "name": "rootComponent",
+      "type": "application"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 23,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.xml.bin
new file mode 100644
index 000000000..5bea1c052
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.xml.bin
@@ -0,0 +1,77 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="23">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="root-component">
+      <name>rootComponent</name>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="setuptools">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+    <component type="library" bom-ref="toml">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="root-component"/>
+    <dependency ref="setuptools">
+      <dependency ref="toml"/>
+    </dependency>
+    <dependency ref="toml"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.0.xml.bin
new file mode 100644
index 000000000..9d0e55d48
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.0.xml.bin
@@ -0,0 +1,20 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+    <component type="library">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.1.xml.bin
new file mode 100644
index 000000000..2f6897772
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.1.xml.bin
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_dependencies.json b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.json.bin
similarity index 73%
rename from tests/_data/own/json/1.2/bom_dependencies.json
rename to tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.json.bin
index 8f54fe4a1..a9874292d 100644
--- a/tests/_data/own/json/1.2/bom_dependencies.json
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.json.bin
@@ -1,63 +1,63 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:6dc366e9-89eb-48cc-9ae8-49a810ce3dcb",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:45:57.575599+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
     },
     {
-      "type": "library",
       "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
       "hashes": [
         {
           "alg": "SHA-256",
           "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
         }
       ],
+      "name": "toml",
       "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "externalReferences": [
-        {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution"
-        }
-      ]
+      "type": "library",
+      "version": "0.10.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "dependsOn": [
         "pkg:pypi/toml@0.10.2?extension=tar.gz"
-      ]
+      ],
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     },
     {
       "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.xml.bin
new file mode 100644
index 000000000..4fd57d868
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.xml.bin
@@ -0,0 +1,44 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+    </dependency>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_dependencies.json b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.json.bin
similarity index 77%
rename from tests/_data/own/json/1.3/bom_dependencies.json
rename to tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.json.bin
index afd36d07f..a44b69b8c 100644
--- a/tests/_data/own/json/1.3/bom_dependencies.json
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.json.bin
@@ -1,69 +1,69 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:d2ef50e0-27c7-4776-9e6f-9bbb3614d6de",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:45:57.875727+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
     },
     {
-      "type": "library",
       "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
-      "hashes": [
-        {
-          "alg": "SHA-256",
-          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-        }
-      ],
-      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
       "externalReferences": [
         {
-          "url": "https://cyclonedx.org",
           "comment": "No comment",
-          "type": "distribution",
           "hashes": [
             {
               "alg": "SHA-256",
               "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
             }
-          ]
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
-      ]
+      ],
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "name": "toml",
+      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "type": "library",
+      "version": "0.10.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "dependsOn": [
         "pkg:pypi/toml@0.10.2?extension=tar.gz"
-      ]
+      ],
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     },
     {
       "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.xml.bin
new file mode 100644
index 000000000..6a5779c80
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.xml.bin
@@ -0,0 +1,47 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+    </dependency>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_dependencies.json b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.json.bin
similarity index 71%
rename from tests/_data/own/json/1.4/bom_dependencies.json
rename to tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.json.bin
index 02c349606..19e76581e 100644
--- a/tests/_data/own/json/1.4/bom_dependencies.json
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.json.bin
@@ -1,103 +1,103 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
-        "externalReferences": [
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
-          },
-          {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
-          },
-          {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
-          },
-          {
-            "url": "https://cyclonedx.org",
-            "type": "website"
-          }
-        ]
-      }
-    ]
-  },
   "components": [
     {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
           "expression": "MIT License"
         }
       ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
     },
     {
-      "type": "library",
       "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
-      "hashes": [
-        {
-          "alg": "SHA-256",
-          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-        }
-      ],
-      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
       "externalReferences": [
         {
-          "url": "https://cyclonedx.org",
           "comment": "No comment",
-          "type": "distribution",
           "hashes": [
             {
               "alg": "SHA-256",
               "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
             }
-          ]
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
-      ]
+      ],
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "name": "toml",
+      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "type": "library",
+      "version": "0.10.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "dependsOn": [
         "pkg:pypi/toml@0.10.2?extension=tar.gz"
-      ]
+      ],
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     },
     {
       "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.xml.bin
new file mode 100644
index 000000000..64970d15b
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.xml.bin
@@ -0,0 +1,73 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+    </dependency>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_external_references-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_external_references-1.0.xml.bin
new file mode 100644
index 000000000..acb066124
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_external_references-1.0.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_external_references-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_external_references-1.1.xml.bin
new file mode 100644
index 000000000..0a260e819
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_external_references-1.1.xml.bin
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components/>
+  <externalReferences>
+    <reference type="distribution">
+      <url>https://cyclonedx.org</url>
+      <comment>No comment</comment>
+    </reference>
+    <reference type="website">
+      <url>https://cyclonedx.org</url>
+    </reference>
+  </externalReferences>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_external_references.json b/tests/_data/snapshots/get_bom_with_external_references-1.2.json.bin
similarity index 64%
rename from tests/_data/own/json/1.2/bom_external_references.json
rename to tests/_data/snapshots/get_bom_with_external_references-1.2.json.bin
index fb370e06e..0808ac139 100644
--- a/tests/_data/own/json/1.2/bom_external_references.json
+++ b/tests/_data/snapshots/get_bom_with_external_references-1.2.json.bin
@@ -1,28 +1,28 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
+  "externalReferences": [
+    {
+      "comment": "No comment",
+      "type": "distribution",
+      "url": "https://cyclonedx.org"
+    },
+    {
+      "type": "website",
+      "url": "https://cyclonedx.org"
+    }
+  ],
   "metadata": {
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
         "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
         "version": "TESTING"
       }
     ]
   },
-  "externalReferences": [
-    {
-      "url": "https://cyclonedx.org",
-      "comment": "No comment",
-      "type": "distribution"
-    },
-    {
-      "url": "https://cyclonedx.org",
-      "type": "website"
-    }
-  ]
-}
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_external_references-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_external_references-1.2.xml.bin
new file mode 100644
index 000000000..052f94d0b
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_external_references-1.2.xml.bin
@@ -0,0 +1,22 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <externalReferences>
+    <reference type="distribution">
+      <url>https://cyclonedx.org</url>
+      <comment>No comment</comment>
+    </reference>
+    <reference type="website">
+      <url>https://cyclonedx.org</url>
+    </reference>
+  </externalReferences>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_external_references.json b/tests/_data/snapshots/get_bom_with_external_references-1.3.json.bin
similarity index 74%
rename from tests/_data/own/json/1.3/bom_external_references.json
rename to tests/_data/snapshots/get_bom_with_external_references-1.3.json.bin
index a4d4d9fde..4f4556622 100644
--- a/tests/_data/own/json/1.3/bom_external_references.json
+++ b/tests/_data/snapshots/get_bom_with_external_references-1.3.json.bin
@@ -1,34 +1,34 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:44:32.312678+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ]
-  },
   "externalReferences": [
     {
-      "url": "https://cyclonedx.org",
       "comment": "No comment",
-      "type": "distribution",
       "hashes": [
         {
           "alg": "SHA-256",
           "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
         }
-      ]
+      ],
+      "type": "distribution",
+      "url": "https://cyclonedx.org"
     },
     {
-      "url": "https://cyclonedx.org",
-      "type": "website"
+      "type": "website",
+      "url": "https://cyclonedx.org"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_external_references-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_external_references-1.3.xml.bin
new file mode 100644
index 000000000..b82483a08
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_external_references-1.3.xml.bin
@@ -0,0 +1,25 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+  <externalReferences>
+    <reference type="distribution">
+      <url>https://cyclonedx.org</url>
+      <comment>No comment</comment>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+    </reference>
+    <reference type="website">
+      <url>https://cyclonedx.org</url>
+    </reference>
+  </externalReferences>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_external_references.json b/tests/_data/snapshots/get_bom_with_external_references-1.4.json.bin
similarity index 65%
rename from tests/_data/own/json/1.4/bom_external_references.json
rename to tests/_data/snapshots/get_bom_with_external_references-1.4.json.bin
index 2f961c7b4..6608b6373 100644
--- a/tests/_data/own/json/1.4/bom_external_references.json
+++ b/tests/_data/snapshots/get_bom_with_external_references-1.4.json.bin
@@ -1,68 +1,68 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
-  "version": 1,
+  "externalReferences": [
+    {
+      "comment": "No comment",
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "type": "distribution",
+      "url": "https://cyclonedx.org"
+    },
+    {
+      "type": "website",
+      "url": "https://cyclonedx.org"
+    }
+  ],
   "metadata": {
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
         "externalReferences": [
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
           },
           {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
           },
           {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
           },
           {
-            "url": "https://cyclonedx.org",
-            "type": "website"
+            "type": "website",
+            "url": "https://cyclonedx.org"
           }
-        ]
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
       }
     ]
   },
-  "externalReferences": [
-    {
-      "url": "https://cyclonedx.org",
-      "comment": "No comment",
-      "type": "distribution",
-      "hashes": [
-        {
-          "alg": "SHA-256",
-          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-        }
-      ]
-    },
-    {
-      "url": "https://cyclonedx.org",
-      "type": "website"
-    }
-  ]
-}
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_external_references-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_external_references-1.4.xml.bin
new file mode 100644
index 000000000..877f4c951
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_external_references-1.4.xml.bin
@@ -0,0 +1,51 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+  </metadata>
+  <externalReferences>
+    <reference type="distribution">
+      <url>https://cyclonedx.org</url>
+      <comment>No comment</comment>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+    </reference>
+    <reference type="website">
+      <url>https://cyclonedx.org</url>
+    </reference>
+  </externalReferences>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.0.xml.bin
new file mode 100644
index 000000000..7355c2cac
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.0.xml.bin
@@ -0,0 +1,14 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.1.xml.bin
new file mode 100644
index 000000000..7f5932c19
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.1.xml.bin
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_dependencies_component.json b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.json.bin
similarity index 72%
rename from tests/_data/own/json/1.2/bom_dependencies_component.json
rename to tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.json.bin
index dd6b880ee..522592fa2 100644
--- a/tests/_data/own/json/1.2/bom_dependencies_component.json
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.json.bin
@@ -1,63 +1,63 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:fae7d0a5-648d-4058-be92-774ed4f974eb",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:45:57.597300+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "licenses": [
-        {
-          "expression": "MIT License"
-        }
-      ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
       "hashes": [
         {
           "alg": "SHA-256",
           "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
         }
       ],
+      "name": "toml",
       "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "externalReferences": [
-        {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution"
-        }
-      ]
+      "type": "library",
+      "version": "0.10.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "dependsOn": [
         "pkg:pypi/toml@0.10.2?extension=tar.gz"
-      ]
+      ],
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     },
     {
       "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.xml.bin
new file mode 100644
index 000000000..0370a0e36
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.xml.bin
@@ -0,0 +1,44 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+    </dependency>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_dependencies_component.json b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.json.bin
similarity index 76%
rename from tests/_data/own/json/1.3/bom_dependencies_component.json
rename to tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.json.bin
index 1820acbd6..2aae8fac7 100644
--- a/tests/_data/own/json/1.3/bom_dependencies_component.json
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.json.bin
@@ -1,69 +1,69 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:f1ab7398-e797-4ac1-8fdd-f2901bd5059d",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:45:57.901622+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING"
-      }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "licenses": [
-        {
-          "expression": "MIT License"
-        }
-      ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
-      "hashes": [
-        {
-          "alg": "SHA-256",
-          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-        }
-      ],
-      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
       "externalReferences": [
         {
-          "url": "https://cyclonedx.org",
           "comment": "No comment",
-          "type": "distribution",
           "hashes": [
             {
               "alg": "SHA-256",
               "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
             }
-          ]
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
-      ]
+      ],
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "name": "toml",
+      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "type": "library",
+      "version": "0.10.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "dependsOn": [
         "pkg:pypi/toml@0.10.2?extension=tar.gz"
-      ]
+      ],
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     },
     {
       "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.xml.bin
new file mode 100644
index 000000000..1b6501308
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.xml.bin
@@ -0,0 +1,47 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+    </dependency>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_dependencies_component.json b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.json.bin
similarity index 69%
rename from tests/_data/own/json/1.4/bom_dependencies_component.json
rename to tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.json.bin
index df8cc3b77..531d42fcf 100644
--- a/tests/_data/own/json/1.4/bom_dependencies_component.json
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.json.bin
@@ -1,103 +1,103 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:890c2dff-1e2c-4133-a0b1-ee23d93737af",
-  "version": 1,
-  "metadata": {
-    "timestamp": "2023-01-07T13:45:58.782058+00:00",
-    "tools": [
-      {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
-        "externalReferences": [
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
-          },
-          {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
-          },
-          {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
-          },
-          {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
-          },
-          {
-            "url": "https://cyclonedx.org",
-            "type": "website"
-          }
-        ]
-      }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
-      "author": "Test Author",
-      "name": "setuptools",
-      "version": "50.3.2",
-      "licenses": [
-        {
-          "expression": "MIT License"
-        }
-      ],
-      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
-    }
-  },
   "components": [
     {
-      "type": "library",
       "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz",
-      "name": "toml",
-      "version": "0.10.2",
-      "hashes": [
-        {
-          "alg": "SHA-256",
-          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-        }
-      ],
-      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
       "externalReferences": [
         {
-          "url": "https://cyclonedx.org",
           "comment": "No comment",
-          "type": "distribution",
           "hashes": [
             {
               "alg": "SHA-256",
               "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
             }
-          ]
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
-      ]
+      ],
+      "hashes": [
+        {
+          "alg": "SHA-256",
+          "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+        }
+      ],
+      "name": "toml",
+      "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz",
+      "type": "library",
+      "version": "0.10.2"
     }
   ],
   "dependencies": [
     {
-      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "dependsOn": [
         "pkg:pypi/toml@0.10.2?extension=tar.gz"
-      ]
+      ],
+      "ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
     },
     {
       "ref": "pkg:pypi/toml@0.10.2?extension=tar.gz"
     }
-  ]
-}
+  ],
+  "metadata": {
+    "component": {
+      "author": "Test Author",
+      "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "licenses": [
+        {
+          "expression": "MIT License"
+        }
+      ],
+      "name": "setuptools",
+      "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
+      "type": "library",
+      "version": "50.3.2"
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.xml.bin
new file mode 100644
index 000000000..1464249f6
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.xml.bin
@@ -0,0 +1,73 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <author>Test Author</author>
+      <name>setuptools</name>
+      <version>50.3.2</version>
+      <licenses>
+        <expression>MIT License</expression>
+      </licenses>
+      <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="pkg:pypi/toml@0.10.2?extension=tar.gz">
+      <name>toml</name>
+      <version>0.10.2</version>
+      <hashes>
+        <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+      </hashes>
+      <purl>pkg:pypi/toml@0.10.2?extension=tar.gz</purl>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+    </component>
+  </components>
+  <dependencies>
+    <dependency ref="pkg:pypi/setuptools@50.3.2?extension=tar.gz">
+      <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+    </dependency>
+    <dependency ref="pkg:pypi/toml@0.10.2?extension=tar.gz"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.0.xml.bin
new file mode 100644
index 000000000..acb066124
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.0.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.1.xml.bin
new file mode 100644
index 000000000..55ef5cda2
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.1.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_services_nested.json b/tests/_data/snapshots/get_bom_with_nested_services-1.2.json.bin
similarity index 88%
rename from tests/_data/own/json/1.2/bom_services_nested.json
rename to tests/_data/snapshots/get_bom_with_nested_services-1.2.json.bin
index f927f9d7a..ae3197b79 100644
--- a/tests/_data/own/json/1.2/bom_services_nested.json
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.2.json.bin
@@ -1,9 +1,18 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
     "component": {
-      "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789",
+      "bom-ref": "my-specific-bom-ref-for-cpl",
       "name": "cyclonedx-python-lib",
       "type": "library",
       "version": "1.0.0"
@@ -17,7 +26,7 @@
       }
     ]
   },
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
       "authenticated": false,
@@ -49,14 +58,14 @@
       "name": "my-first-service",
       "provider": {
         "contact": [
-          {
-            "email": "paul.horton@owasp.org",
-            "name": "Paul Horton"
-          },
           {
             "email": "someone@somewhere.tld",
             "name": "A N Other",
             "phone": "+44 (0)1234 567890"
+          },
+          {
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
           }
         ],
         "name": "CycloneDX",
@@ -65,10 +74,6 @@
         ]
       },
       "services": [
-        {
-          "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
-          "name": "first-nested-service"
-        },
         {
           "authenticated": true,
           "bom-ref": "my-specific-bom-ref-for-second-nested-service",
@@ -76,14 +81,14 @@
           "name": "second-nested-service",
           "provider": {
             "contact": [
-              {
-                "email": "paul.horton@owasp.org",
-                "name": "Paul Horton"
-              },
               {
                 "email": "someone@somewhere.tld",
                 "name": "A N Other",
                 "phone": "+44 (0)1234 567890"
+              },
+              {
+                "email": "paul.horton@owasp.org",
+                "name": "Paul Horton"
               }
             ],
             "name": "CycloneDX",
@@ -93,29 +98,33 @@
           },
           "version": "3.2.1",
           "x-trust-boundary": false
+        },
+        {
+          "bom-ref": "my-specific-bom-ref-for-first-nested-service",
+          "name": "first-nested-service"
         }
       ],
       "version": "1.2.3",
       "x-trust-boundary": true
     },
     {
-      "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service",
       "services": [
         {
-          "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
+          "bom-ref": "00000000-0000-4000-8000-000000000003",
           "group": "what-group",
           "name": "yet-another-nested-service",
           "provider": {
             "contact": [
-              {
-                "email": "paul.horton@owasp.org",
-                "name": "Paul Horton"
-              },
               {
                 "email": "someone@somewhere.tld",
                 "name": "A N Other",
                 "phone": "+44 (0)1234 567890"
+              },
+              {
+                "email": "paul.horton@owasp.org",
+                "name": "Paul Horton"
               }
             ],
             "name": "CycloneDX",
@@ -132,17 +141,8 @@
       ]
     }
   ],
-  "specVersion": "1.2",
   "version": 1,
-  "dependencies": [
-    {
-      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857"
-    },
-    {
-      "ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
-    },
-    {
-      "ref": "my-specific-bom-ref-for-my-first-service"
-    }
-  ]
-}
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.2.xml.bin
new file mode 100644
index 000000000..e01e6b3ed
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.2.xml.bin
@@ -0,0 +1,112 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <provider>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </provider>
+      <group>a-group</group>
+      <name>my-first-service</name>
+      <version>1.2.3</version>
+      <description>Description goes here</description>
+      <endpoints>
+        <endpoint>/api/thing/1</endpoint>
+        <endpoint>/api/thing/2</endpoint>
+      </endpoints>
+      <authenticated>false</authenticated>
+      <x-trust-boundary>true</x-trust-boundary>
+      <data>
+        <classification flow="outbound">public</classification>
+      </data>
+      <licenses>
+        <expression>Commercial</expression>
+      </licenses>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+      <services>
+        <service bom-ref="my-specific-bom-ref-for-second-nested-service">
+          <provider>
+            <name>CycloneDX</name>
+            <url>https://cyclonedx.org</url>
+            <contact>
+              <name>A N Other</name>
+              <email>someone@somewhere.tld</email>
+              <phone>+44 (0)1234 567890</phone>
+            </contact>
+            <contact>
+              <name>Paul Horton</name>
+              <email>paul.horton@owasp.org</email>
+            </contact>
+          </provider>
+          <group>no-group</group>
+          <name>second-nested-service</name>
+          <version>3.2.1</version>
+          <authenticated>true</authenticated>
+          <x-trust-boundary>false</x-trust-boundary>
+        </service>
+        <service bom-ref="my-specific-bom-ref-for-first-nested-service">
+          <name>first-nested-service</name>
+        </service>
+      </services>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+      <services>
+        <service bom-ref="00000000-0000-4000-8000-000000000003">
+          <provider>
+            <name>CycloneDX</name>
+            <url>https://cyclonedx.org</url>
+            <contact>
+              <name>A N Other</name>
+              <email>someone@somewhere.tld</email>
+              <phone>+44 (0)1234 567890</phone>
+            </contact>
+            <contact>
+              <name>Paul Horton</name>
+              <email>paul.horton@owasp.org</email>
+            </contact>
+          </provider>
+          <group>what-group</group>
+          <name>yet-another-nested-service</name>
+          <version>6.5.4</version>
+        </service>
+        <service bom-ref="my-specific-bom-ref-for-another-nested-service">
+          <name>another-nested-service</name>
+        </service>
+      </services>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_services_nested.json b/tests/_data/snapshots/get_bom_with_nested_services-1.3.json.bin
similarity index 79%
rename from tests/_data/own/json/1.3/bom_services_nested.json
rename to tests/_data/snapshots/get_bom_with_nested_services-1.3.json.bin
index 82e9e1870..9ab746dbf 100644
--- a/tests/_data/own/json/1.3/bom_services_nested.json
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.3.json.bin
@@ -1,146 +1,153 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
+    "component": {
+      "bom-ref": "my-specific-bom-ref-for-cpl",
+      "name": "cyclonedx-python-lib",
+      "type": "library",
+      "version": "1.0.0"
+    },
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
         "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
         "version": "TESTING"
       }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789",
-      "name": "cyclonedx-python-lib",
-      "version": "1.0.0"
-    }
+    ]
   },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
+      "authenticated": false,
       "bom-ref": "my-specific-bom-ref-for-my-first-service",
-      "provider": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
-          {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
-          },
-          {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
-          }
-        ]
-      },
-      "group": "a-group",
-      "name": "my-first-service",
-      "version": "1.2.3",
+      "data": [
+        {
+          "classification": "public",
+          "flow": "outbound"
+        }
+      ],
       "description": "Description goes here",
       "endpoints": [
         "/api/thing/1",
         "/api/thing/2"
       ],
-      "authenticated": false,
-      "x-trust-boundary": true,
-      "data": [
+      "externalReferences": [
         {
-          "flow": "outbound",
-          "classification": "public"
+          "comment": "No comment",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
       ],
+      "group": "a-group",
       "licenses": [
         {
           "expression": "Commercial"
         }
       ],
-      "externalReferences": [
+      "name": "my-first-service",
+      "properties": [
         {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ]
+          "name": "key1",
+          "value": "val1"
+        },
+        {
+          "name": "key2",
+          "value": "val2"
         }
       ],
+      "provider": {
+        "contact": [
+          {
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          },
+          {
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
+          }
+        ],
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
+        ]
+      },
       "services": [
         {
+          "authenticated": true,
           "bom-ref": "my-specific-bom-ref-for-second-nested-service",
+          "group": "no-group",
+          "name": "second-nested-service",
           "provider": {
-            "name": "CycloneDX",
-            "url": [
-              "https://cyclonedx.org"
-            ],
             "contact": [
               {
-                "name": "A N Other",
                 "email": "someone@somewhere.tld",
+                "name": "A N Other",
                 "phone": "+44 (0)1234 567890"
               },
               {
-                "name": "Paul Horton",
-                "email": "paul.horton@owasp.org"
+                "email": "paul.horton@owasp.org",
+                "name": "Paul Horton"
               }
+            ],
+            "name": "CycloneDX",
+            "url": [
+              "https://cyclonedx.org"
             ]
           },
-          "group": "no-group",
-          "name": "second-nested-service",
           "version": "3.2.1",
-          "authenticated": true,
           "x-trust-boundary": false
         },
         {
-          "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+          "bom-ref": "my-specific-bom-ref-for-first-nested-service",
           "name": "first-nested-service"
         }
       ],
-      "properties": [
-        {
-          "name": "key1",
-          "value": "val1"
-        },
-        {
-          "name": "key2",
-          "value": "val2"
-        }
-      ]
+      "version": "1.2.3",
+      "x-trust-boundary": true
     },
     {
-      "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service",
       "services": [
         {
-          "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
+          "bom-ref": "00000000-0000-4000-8000-000000000002",
+          "group": "what-group",
+          "name": "yet-another-nested-service",
           "provider": {
-            "name": "CycloneDX",
-            "url": [
-              "https://cyclonedx.org"
-            ],
             "contact": [
               {
-                "name": "A N Other",
                 "email": "someone@somewhere.tld",
+                "name": "A N Other",
                 "phone": "+44 (0)1234 567890"
               },
               {
-                "name": "Paul Horton",
-                "email": "paul.horton@owasp.org"
+                "email": "paul.horton@owasp.org",
+                "name": "Paul Horton"
               }
+            ],
+            "name": "CycloneDX",
+            "url": [
+              "https://cyclonedx.org"
             ]
           },
-          "group": "what-group",
-          "name": "yet-another-nested-service",
           "version": "6.5.4"
         },
         {
@@ -150,15 +157,8 @@
       ]
     }
   ],
-  "dependencies": [
-    {
-      "ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
-    },
-    {
-      "ref": "my-specific-bom-ref-for-my-first-service"
-    },
-    {
-      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857"
-    }
-  ]
-}
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.3.xml.bin
new file mode 100644
index 000000000..00c1fd2b9
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.3.xml.bin
@@ -0,0 +1,119 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <provider>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </provider>
+      <group>a-group</group>
+      <name>my-first-service</name>
+      <version>1.2.3</version>
+      <description>Description goes here</description>
+      <endpoints>
+        <endpoint>/api/thing/1</endpoint>
+        <endpoint>/api/thing/2</endpoint>
+      </endpoints>
+      <authenticated>false</authenticated>
+      <x-trust-boundary>true</x-trust-boundary>
+      <data>
+        <classification flow="outbound">public</classification>
+      </data>
+      <licenses>
+        <expression>Commercial</expression>
+      </licenses>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+      <services>
+        <service bom-ref="my-specific-bom-ref-for-second-nested-service">
+          <provider>
+            <name>CycloneDX</name>
+            <url>https://cyclonedx.org</url>
+            <contact>
+              <name>A N Other</name>
+              <email>someone@somewhere.tld</email>
+              <phone>+44 (0)1234 567890</phone>
+            </contact>
+            <contact>
+              <name>Paul Horton</name>
+              <email>paul.horton@owasp.org</email>
+            </contact>
+          </provider>
+          <group>no-group</group>
+          <name>second-nested-service</name>
+          <version>3.2.1</version>
+          <authenticated>true</authenticated>
+          <x-trust-boundary>false</x-trust-boundary>
+        </service>
+        <service bom-ref="my-specific-bom-ref-for-first-nested-service">
+          <name>first-nested-service</name>
+        </service>
+      </services>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+      <services>
+        <service bom-ref="00000000-0000-4000-8000-000000000002">
+          <provider>
+            <name>CycloneDX</name>
+            <url>https://cyclonedx.org</url>
+            <contact>
+              <name>A N Other</name>
+              <email>someone@somewhere.tld</email>
+              <phone>+44 (0)1234 567890</phone>
+            </contact>
+            <contact>
+              <name>Paul Horton</name>
+              <email>paul.horton@owasp.org</email>
+            </contact>
+          </provider>
+          <group>what-group</group>
+          <name>yet-another-nested-service</name>
+          <version>6.5.4</version>
+        </service>
+        <service bom-ref="my-specific-bom-ref-for-another-nested-service">
+          <name>another-nested-service</name>
+        </service>
+      </services>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_services_nested.json b/tests/_data/snapshots/get_bom_with_nested_services-1.4.json.bin
similarity index 78%
rename from tests/_data/own/json/1.4/bom_services_nested.json
rename to tests/_data/snapshots/get_bom_with_nested_services-1.4.json.bin
index 3c6746827..be23872da 100644
--- a/tests/_data/own/json/1.4/bom_services_nested.json
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.4.json.bin
@@ -1,190 +1,150 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
+    "component": {
+      "bom-ref": "my-specific-bom-ref-for-cpl",
+      "name": "cyclonedx-python-lib",
+      "type": "library",
+      "version": "1.0.0"
+    },
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
         "externalReferences": [
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
           },
           {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
           },
           {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
           },
           {
-            "url": "https://cyclonedx.org",
-            "type": "website"
+            "type": "website",
+            "url": "https://cyclonedx.org"
           }
-        ]
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
       }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789",
-      "name": "cyclonedx-python-lib",
-      "version": "1.0.0"
-    }
+    ]
   },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
-      "bom-ref": "my-specific-bom-ref-for-my-first-service",
-      "provider": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
-          {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
-          },
-          {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
-          }
-        ]
-      },
-      "group": "a-group",
-      "name": "my-first-service",
-      "version": "1.2.3",
-      "description": "Description goes here",
-      "endpoints": [
-        "/api/thing/1",
-        "/api/thing/2"
-      ],
       "authenticated": false,
-      "x-trust-boundary": true,
+      "bom-ref": "my-specific-bom-ref-for-my-first-service",
       "data": [
         {
-          "flow": "outbound",
-          "classification": "public"
+          "classification": "public",
+          "flow": "outbound"
         }
       ],
-      "licenses": [
-        {
-          "expression": "Commercial"
-        }
+      "description": "Description goes here",
+      "endpoints": [
+        "/api/thing/1",
+        "/api/thing/2"
       ],
       "externalReferences": [
         {
-          "url": "https://cyclonedx.org",
           "comment": "No comment",
-          "type": "distribution",
           "hashes": [
             {
               "alg": "SHA-256",
               "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
             }
-          ]
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
       ],
-      "services": [
+      "group": "a-group",
+      "licenses": [
         {
-          "bom-ref": "my-specific-bom-ref-for-second-nested-service",
-          "provider": {
-            "name": "CycloneDX",
-            "url": [
-              "https://cyclonedx.org"
-            ],
-            "contact": [
-              {
-                "name": "A N Other",
-                "email": "someone@somewhere.tld",
-                "phone": "+44 (0)1234 567890"
-              },
-              {
-                "name": "Paul Horton",
-                "email": "paul.horton@owasp.org"
-              }
-            ]
-          },
-          "group": "no-group",
-          "name": "second-nested-service",
-          "version": "3.2.1",
-          "authenticated": true,
-          "x-trust-boundary": false
+          "expression": "Commercial"
+        }
+      ],
+      "name": "my-first-service",
+      "properties": [
+        {
+          "name": "key1",
+          "value": "val1"
         },
         {
-          "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
-          "name": "first-nested-service"
+          "name": "key2",
+          "value": "val2"
         }
       ],
+      "provider": {
+        "contact": [
+          {
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          },
+          {
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
+          }
+        ],
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
+        ]
+      },
       "releaseNotes": {
-        "type": "major",
-        "title": "Release Notes Title",
-        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
-        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
-        "description": "This release is a test release",
-        "timestamp": "2021-12-31T10:00:00+00:00",
         "aliases": [
           "First Test Release"
         ],
-        "tags": [
-          "alpha",
-          "test"
-        ],
-        "resolves": [
-          {
-            "type": "security",
-            "id": "CVE-2021-44228",
-            "name": "Apache Log3Shell",
-            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
-            "source": {
-              "name": "NVD",
-              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
-            },
-            "references": [
-              "https://central.sonatype.org/news/20211213_log4shell_help",
-              "https://logging.apache.org/log4j/2.x/security.html"
-            ]
-          }
-        ],
+        "description": "This release is a test release",
+        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
         "notes": [
           {
+            "locale": "en-GB",
             "text": {
               "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
               "encoding": "base64"
-            },
-            "locale": "en-GB"
+            }
           },
           {
+            "locale": "en-US",
             "text": {
               "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
               "encoding": "base64"
-            },
-            "locale": "en-US"
+            }
           }
         ],
         "properties": [
@@ -196,44 +156,91 @@
             "name": "key2",
             "value": "val2"
           }
-        ]
+        ],
+        "resolves": [
+          {
+            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
+            "id": "CVE-2021-44228",
+            "name": "Apache Log3Shell",
+            "references": [
+              "https://central.sonatype.org/news/20211213_log4shell_help",
+              "https://logging.apache.org/log4j/2.x/security.html"
+            ],
+            "source": {
+              "name": "NVD",
+              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
+            },
+            "type": "security"
+          }
+        ],
+        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
+        "tags": [
+          "alpha",
+          "test"
+        ],
+        "timestamp": "2023-08-15T01:23:45.678900+00:00",
+        "title": "Release Notes Title",
+        "type": "major"
       },
-      "properties": [
+      "services": [
         {
-          "name": "key1",
-          "value": "val1"
+          "authenticated": true,
+          "bom-ref": "my-specific-bom-ref-for-second-nested-service",
+          "group": "no-group",
+          "name": "second-nested-service",
+          "provider": {
+            "contact": [
+              {
+                "email": "someone@somewhere.tld",
+                "name": "A N Other",
+                "phone": "+44 (0)1234 567890"
+              },
+              {
+                "email": "paul.horton@owasp.org",
+                "name": "Paul Horton"
+              }
+            ],
+            "name": "CycloneDX",
+            "url": [
+              "https://cyclonedx.org"
+            ]
+          },
+          "version": "3.2.1",
+          "x-trust-boundary": false
         },
         {
-          "name": "key2",
-          "value": "val2"
+          "bom-ref": "my-specific-bom-ref-for-first-nested-service",
+          "name": "first-nested-service"
         }
-      ]
+      ],
+      "version": "1.2.3",
+      "x-trust-boundary": true
     },
     {
-      "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service",
       "services": [
         {
-          "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
+          "bom-ref": "00000000-0000-4000-8000-000000000001",
+          "group": "what-group",
+          "name": "yet-another-nested-service",
           "provider": {
-            "name": "CycloneDX",
-            "url": [
-              "https://cyclonedx.org"
-            ],
             "contact": [
               {
-                "name": "A N Other",
                 "email": "someone@somewhere.tld",
+                "name": "A N Other",
                 "phone": "+44 (0)1234 567890"
               },
               {
-                "name": "Paul Horton",
-                "email": "paul.horton@owasp.org"
+                "email": "paul.horton@owasp.org",
+                "name": "Paul Horton"
               }
+            ],
+            "name": "CycloneDX",
+            "url": [
+              "https://cyclonedx.org"
             ]
           },
-          "group": "what-group",
-          "name": "yet-another-nested-service",
           "version": "6.5.4"
         },
         {
@@ -243,15 +250,8 @@
       ]
     }
   ],
-  "dependencies": [
-    {
-      "ref": "my-specific-bom-ref-for-my-first-service"
-    },
-    {
-      "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857"
-    },
-    {
-      "ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789"
-    }
-  ]
-}
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.4.xml.bin
new file mode 100644
index 000000000..986ed1589
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.4.xml.bin
@@ -0,0 +1,189 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <provider>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </provider>
+      <group>a-group</group>
+      <name>my-first-service</name>
+      <version>1.2.3</version>
+      <description>Description goes here</description>
+      <endpoints>
+        <endpoint>/api/thing/1</endpoint>
+        <endpoint>/api/thing/2</endpoint>
+      </endpoints>
+      <authenticated>false</authenticated>
+      <x-trust-boundary>true</x-trust-boundary>
+      <data>
+        <classification flow="outbound">public</classification>
+      </data>
+      <licenses>
+        <expression>Commercial</expression>
+      </licenses>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+      <services>
+        <service bom-ref="my-specific-bom-ref-for-second-nested-service">
+          <provider>
+            <name>CycloneDX</name>
+            <url>https://cyclonedx.org</url>
+            <contact>
+              <name>A N Other</name>
+              <email>someone@somewhere.tld</email>
+              <phone>+44 (0)1234 567890</phone>
+            </contact>
+            <contact>
+              <name>Paul Horton</name>
+              <email>paul.horton@owasp.org</email>
+            </contact>
+          </provider>
+          <group>no-group</group>
+          <name>second-nested-service</name>
+          <version>3.2.1</version>
+          <authenticated>true</authenticated>
+          <x-trust-boundary>false</x-trust-boundary>
+        </service>
+        <service bom-ref="my-specific-bom-ref-for-first-nested-service">
+          <name>first-nested-service</name>
+        </service>
+      </services>
+      <releaseNotes>
+        <type>major</type>
+        <title>Release Notes Title</title>
+        <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
+        <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
+        <description>This release is a test release</description>
+        <timestamp>2023-08-15T01:23:45.678900+00:00</timestamp>
+        <aliases>
+          <alias>First Test Release</alias>
+        </aliases>
+        <tags>
+          <tag>alpha</tag>
+          <tag>test</tag>
+        </tags>
+        <resolves>
+          <issue type="security">
+            <id>CVE-2021-44228</id>
+            <name>Apache Log3Shell</name>
+            <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
+            <source>
+              <name>NVD</name>
+              <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
+            </source>
+            <references>
+              <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
+              <url>https://logging.apache.org/log4j/2.x/security.html</url>
+            </references>
+          </issue>
+        </resolves>
+        <notes>
+          <note>
+            <locale>en-GB</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+          <note>
+            <locale>en-US</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+        </notes>
+        <properties>
+          <property name="key1">val1</property>
+          <property name="key2">val2</property>
+        </properties>
+      </releaseNotes>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+      <services>
+        <service bom-ref="00000000-0000-4000-8000-000000000001">
+          <provider>
+            <name>CycloneDX</name>
+            <url>https://cyclonedx.org</url>
+            <contact>
+              <name>A N Other</name>
+              <email>someone@somewhere.tld</email>
+              <phone>+44 (0)1234 567890</phone>
+            </contact>
+            <contact>
+              <name>Paul Horton</name>
+              <email>paul.horton@owasp.org</email>
+            </contact>
+          </provider>
+          <group>what-group</group>
+          <name>yet-another-nested-service</name>
+          <version>6.5.4</version>
+        </service>
+        <service bom-ref="my-specific-bom-ref-for-another-nested-service">
+          <name>another-nested-service</name>
+        </service>
+      </services>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.0.xml.bin
new file mode 100644
index 000000000..acb066124
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.0.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.1.xml.bin
new file mode 100644
index 000000000..55ef5cda2
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.1.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_services_complex.json b/tests/_data/snapshots/get_bom_with_services_complex-1.2.json.bin
similarity index 82%
rename from tests/_data/own/json/1.2/bom_services_complex.json
rename to tests/_data/snapshots/get_bom_with_services_complex-1.2.json.bin
index 2caa98766..549dc40fc 100644
--- a/tests/_data/own/json/1.2/bom_services_complex.json
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.2.json.bin
@@ -1,38 +1,71 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
+    "component": {
+      "bom-ref": "my-specific-bom-ref-for-cpl",
+      "name": "cyclonedx-python-lib",
+      "type": "library",
+      "version": "1.0.0"
+    },
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
         "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
         "version": "TESTING"
       }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "bb5911d6-1a1d-41c9-b6e0-46e848d16655",
-      "name": "cyclonedx-python-lib",
-      "version": "1.0.0"
-    }
+    ]
   },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
+      "authenticated": false,
       "bom-ref": "my-specific-bom-ref-for-my-first-service",
+      "data": [
+        {
+          "classification": "public",
+          "flow": "outbound"
+        }
+      ],
+      "description": "Description goes here",
+      "endpoints": [
+        "/api/thing/1",
+        "/api/thing/2"
+      ],
+      "externalReferences": [
+        {
+          "comment": "No comment",
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
+        }
+      ],
+      "group": "a-group",
+      "licenses": [
+        {
+          "expression": "Commercial"
+        }
+      ],
+      "name": "my-first-service",
       "provider": {
         "contact": [
-          {
-            "email": "paul.horton@owasp.org",
-            "name": "Paul Horton"
-          },
           {
             "email": "someone@somewhere.tld",
             "name": "A N Other",
             "phone": "+44 (0)1234 567890"
+          },
+          {
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
           }
         ],
         "name": "CycloneDX",
@@ -40,49 +73,16 @@
           "https://cyclonedx.org"
         ]
       },
-      "group": "a-group",
-      "name": "my-first-service",
       "version": "1.2.3",
-      "description": "Description goes here",
-      "endpoints": [
-        "/api/thing/1",
-        "/api/thing/2"
-      ],
-      "authenticated": false,
-      "x-trust-boundary": true,
-      "data": [
-        {
-          "classification": "public",
-          "flow": "outbound"
-        }
-      ],
-      "licenses": [
-        {
-          "expression": "Commercial"
-        }
-      ],
-      "externalReferences": [
-        {
-          "comment": "No comment",
-          "type": "distribution",
-          "url": "https://cyclonedx.org"
-        }
-      ]
+      "x-trust-boundary": true
     },
     {
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service"
     }
   ],
-  "dependencies": [
-    {
-      "ref": "bb5911d6-1a1d-41c9-b6e0-46e848d16655"
-    },
-    {
-      "ref": "my-specific-bom-ref-for-my-first-service"
-    },
-    {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
-    }
-  ]
-}
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.2.xml.bin
new file mode 100644
index 000000000..7e6b4b9f0
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.2.xml.bin
@@ -0,0 +1,64 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <provider>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </provider>
+      <group>a-group</group>
+      <name>my-first-service</name>
+      <version>1.2.3</version>
+      <description>Description goes here</description>
+      <endpoints>
+        <endpoint>/api/thing/1</endpoint>
+        <endpoint>/api/thing/2</endpoint>
+      </endpoints>
+      <authenticated>false</authenticated>
+      <x-trust-boundary>true</x-trust-boundary>
+      <data>
+        <classification flow="outbound">public</classification>
+      </data>
+      <licenses>
+        <expression>Commercial</expression>
+      </licenses>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+        </reference>
+      </externalReferences>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_services_complex.json b/tests/_data/snapshots/get_bom_with_services_complex-1.3.json.bin
similarity index 76%
rename from tests/_data/own/json/1.3/bom_services_complex.json
rename to tests/_data/snapshots/get_bom_with_services_complex-1.3.json.bin
index f222cd505..38ea8bb3f 100644
--- a/tests/_data/own/json/1.3/bom_services_complex.json
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.3.json.bin
@@ -1,79 +1,67 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
+    "component": {
+      "bom-ref": "my-specific-bom-ref-for-cpl",
+      "name": "cyclonedx-python-lib",
+      "type": "library",
+      "version": "1.0.0"
+    },
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
         "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
         "version": "TESTING"
       }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "bb5911d6-1a1d-41c9-b6e0-46e848d16655",
-      "name": "cyclonedx-python-lib",
-      "version": "1.0.0"
-    }
+    ]
   },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
-      "bom-ref": "my-specific-bom-ref-for-my-first-service",
-      "provider": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
-          {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
-          },
-          {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
-          }
-        ]
-      },
-      "group": "a-group",
-      "name": "my-first-service",
-      "version": "1.2.3",
-      "description": "Description goes here",
-      "endpoints": [
-        "/api/thing/1",
-        "/api/thing/2"
-      ],
       "authenticated": false,
-      "x-trust-boundary": true,
+      "bom-ref": "my-specific-bom-ref-for-my-first-service",
       "data": [
         {
-          "flow": "outbound",
-          "classification": "public"
+          "classification": "public",
+          "flow": "outbound"
         }
       ],
-      "licenses": [
-        {
-          "expression": "Commercial"
-        }
+      "description": "Description goes here",
+      "endpoints": [
+        "/api/thing/1",
+        "/api/thing/2"
       ],
       "externalReferences": [
         {
-          "url": "https://cyclonedx.org",
           "comment": "No comment",
-          "type": "distribution",
           "hashes": [
             {
               "alg": "SHA-256",
               "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
             }
-          ]
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
       ],
+      "group": "a-group",
+      "licenses": [
+        {
+          "expression": "Commercial"
+        }
+      ],
+      "name": "my-first-service",
       "properties": [
         {
           "name": "key1",
@@ -83,22 +71,34 @@
           "name": "key2",
           "value": "val2"
         }
-      ]
+      ],
+      "provider": {
+        "contact": [
+          {
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          },
+          {
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
+          }
+        ],
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
+        ]
+      },
+      "version": "1.2.3",
+      "x-trust-boundary": true
     },
     {
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service"
     }
   ],
-  "dependencies": [
-    {
-      "ref": "my-specific-bom-ref-for-my-first-service"
-    },
-    {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
-    },
-    {
-      "ref": "bb5911d6-1a1d-41c9-b6e0-46e848d16655"
-    }
-  ]
-}
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.3.xml.bin
new file mode 100644
index 000000000..3725a7257
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.3.xml.bin
@@ -0,0 +1,71 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <provider>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </provider>
+      <group>a-group</group>
+      <name>my-first-service</name>
+      <version>1.2.3</version>
+      <description>Description goes here</description>
+      <endpoints>
+        <endpoint>/api/thing/1</endpoint>
+        <endpoint>/api/thing/2</endpoint>
+      </endpoints>
+      <authenticated>false</authenticated>
+      <x-trust-boundary>true</x-trust-boundary>
+      <data>
+        <classification flow="outbound">public</classification>
+      </data>
+      <licenses>
+        <expression>Commercial</expression>
+      </licenses>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_services_complex.json b/tests/_data/snapshots/get_bom_with_services_complex-1.4.json.bin
similarity index 76%
rename from tests/_data/own/json/1.4/bom_services_complex.json
rename to tests/_data/snapshots/get_bom_with_services_complex-1.4.json.bin
index d4d80b06d..b4d58520e 100644
--- a/tests/_data/own/json/1.4/bom_services_complex.json
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.4.json.bin
@@ -1,159 +1,150 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
+    "component": {
+      "bom-ref": "my-specific-bom-ref-for-cpl",
+      "name": "cyclonedx-python-lib",
+      "type": "library",
+      "version": "1.0.0"
+    },
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
         "externalReferences": [
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
           },
           {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
           },
           {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
           },
           {
-            "url": "https://cyclonedx.org",
-            "type": "website"
+            "type": "website",
+            "url": "https://cyclonedx.org"
           }
-        ]
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
       }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "bb5911d6-1a1d-41c9-b6e0-46e848d16655",
-      "name": "cyclonedx-python-lib",
-      "version": "1.0.0"
-    }
+    ]
   },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
+      "authenticated": false,
       "bom-ref": "my-specific-bom-ref-for-my-first-service",
-      "provider": {
-        "name": "CycloneDX",
-        "url": [
-          "https://cyclonedx.org"
-        ],
-        "contact": [
-          {
-            "name": "A N Other",
-            "email": "someone@somewhere.tld",
-            "phone": "+44 (0)1234 567890"
-          },
-          {
-            "name": "Paul Horton",
-            "email": "paul.horton@owasp.org"
-          }
-        ]
-      },
-      "group": "a-group",
-      "name": "my-first-service",
-      "version": "1.2.3",
+      "data": [
+        {
+          "classification": "public",
+          "flow": "outbound"
+        }
+      ],
       "description": "Description goes here",
       "endpoints": [
         "/api/thing/1",
         "/api/thing/2"
       ],
-      "authenticated": false,
-      "x-trust-boundary": true,
-      "data": [
+      "externalReferences": [
         {
-          "flow": "outbound",
-          "classification": "public"
+          "comment": "No comment",
+          "hashes": [
+            {
+              "alg": "SHA-256",
+              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+            }
+          ],
+          "type": "distribution",
+          "url": "https://cyclonedx.org"
         }
       ],
+      "group": "a-group",
       "licenses": [
         {
           "expression": "Commercial"
         }
       ],
-      "externalReferences": [
+      "name": "my-first-service",
+      "properties": [
         {
-          "url": "https://cyclonedx.org",
-          "comment": "No comment",
-          "type": "distribution",
-          "hashes": [
-            {
-              "alg": "SHA-256",
-              "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
-            }
-          ]
+          "name": "key1",
+          "value": "val1"
+        },
+        {
+          "name": "key2",
+          "value": "val2"
         }
       ],
+      "provider": {
+        "contact": [
+          {
+            "email": "someone@somewhere.tld",
+            "name": "A N Other",
+            "phone": "+44 (0)1234 567890"
+          },
+          {
+            "email": "paul.horton@owasp.org",
+            "name": "Paul Horton"
+          }
+        ],
+        "name": "CycloneDX",
+        "url": [
+          "https://cyclonedx.org"
+        ]
+      },
       "releaseNotes": {
-        "type": "major",
-        "title": "Release Notes Title",
-        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
-        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
-        "description": "This release is a test release",
-        "timestamp": "2021-12-31T10:00:00+00:00",
         "aliases": [
           "First Test Release"
         ],
-        "tags": [
-          "alpha",
-          "test"
-        ],
-        "resolves": [
-          {
-            "type": "security",
-            "id": "CVE-2021-44228",
-            "name": "Apache Log3Shell",
-            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
-            "source": {
-              "name": "NVD",
-              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
-            },
-            "references": [
-              "https://central.sonatype.org/news/20211213_log4shell_help",
-              "https://logging.apache.org/log4j/2.x/security.html"
-            ]
-          }
-        ],
+        "description": "This release is a test release",
+        "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png",
         "notes": [
           {
+            "locale": "en-GB",
             "text": {
               "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
               "encoding": "base64"
-            },
-            "locale": "en-GB"
+            }
           },
           {
+            "locale": "en-US",
             "text": {
               "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==",
               "contentType": "text/plain; charset=UTF-8",
               "encoding": "base64"
-            },
-            "locale": "en-US"
+            }
           }
         ],
         "properties": [
@@ -165,33 +156,42 @@
             "name": "key2",
             "value": "val2"
           }
-        ]
+        ],
+        "resolves": [
+          {
+            "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...",
+            "id": "CVE-2021-44228",
+            "name": "Apache Log3Shell",
+            "references": [
+              "https://central.sonatype.org/news/20211213_log4shell_help",
+              "https://logging.apache.org/log4j/2.x/security.html"
+            ],
+            "source": {
+              "name": "NVD",
+              "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
+            },
+            "type": "security"
+          }
+        ],
+        "socialImage": "https://cyclonedx.org/cyclonedx-icon.png",
+        "tags": [
+          "alpha",
+          "test"
+        ],
+        "timestamp": "2023-08-15T01:23:45.678900+00:00",
+        "title": "Release Notes Title",
+        "type": "major"
       },
-      "properties": [
-        {
-          "name": "key1",
-          "value": "val1"
-        },
-        {
-          "name": "key2",
-          "value": "val2"
-        }
-      ]
+      "version": "1.2.3",
+      "x-trust-boundary": true
     },
     {
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service"
     }
   ],
-  "dependencies": [
-    {
-      "ref": "bb5911d6-1a1d-41c9-b6e0-46e848d16655"
-    },
-    {
-      "ref": "my-specific-bom-ref-for-my-first-service"
-    },
-    {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
-    }
-  ]
-}
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.4.xml.bin
new file mode 100644
index 000000000..bb4f4a0ff
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.4.xml.bin
@@ -0,0 +1,141 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <provider>
+        <name>CycloneDX</name>
+        <url>https://cyclonedx.org</url>
+        <contact>
+          <name>A N Other</name>
+          <email>someone@somewhere.tld</email>
+          <phone>+44 (0)1234 567890</phone>
+        </contact>
+        <contact>
+          <name>Paul Horton</name>
+          <email>paul.horton@owasp.org</email>
+        </contact>
+      </provider>
+      <group>a-group</group>
+      <name>my-first-service</name>
+      <version>1.2.3</version>
+      <description>Description goes here</description>
+      <endpoints>
+        <endpoint>/api/thing/1</endpoint>
+        <endpoint>/api/thing/2</endpoint>
+      </endpoints>
+      <authenticated>false</authenticated>
+      <x-trust-boundary>true</x-trust-boundary>
+      <data>
+        <classification flow="outbound">public</classification>
+      </data>
+      <licenses>
+        <expression>Commercial</expression>
+      </licenses>
+      <externalReferences>
+        <reference type="distribution">
+          <url>https://cyclonedx.org</url>
+          <comment>No comment</comment>
+          <hashes>
+            <hash alg="SHA-256">806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b</hash>
+          </hashes>
+        </reference>
+      </externalReferences>
+      <properties>
+        <property name="key1">val1</property>
+        <property name="key2">val2</property>
+      </properties>
+      <releaseNotes>
+        <type>major</type>
+        <title>Release Notes Title</title>
+        <featuredImage>https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png</featuredImage>
+        <socialImage>https://cyclonedx.org/cyclonedx-icon.png</socialImage>
+        <description>This release is a test release</description>
+        <timestamp>2023-08-15T01:23:45.678900+00:00</timestamp>
+        <aliases>
+          <alias>First Test Release</alias>
+        </aliases>
+        <tags>
+          <tag>alpha</tag>
+          <tag>test</tag>
+        </tags>
+        <resolves>
+          <issue type="security">
+            <id>CVE-2021-44228</id>
+            <name>Apache Log3Shell</name>
+            <description>Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...</description>
+            <source>
+              <name>NVD</name>
+              <url>https://nvd.nist.gov/vuln/detail/CVE-2021-44228</url>
+            </source>
+            <references>
+              <url>https://central.sonatype.org/news/20211213_log4shell_help</url>
+              <url>https://logging.apache.org/log4j/2.x/security.html</url>
+            </references>
+          </issue>
+        </resolves>
+        <notes>
+          <note>
+            <locale>en-GB</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+          <note>
+            <locale>en-US</locale>
+            <text content-type="text/plain; charset=UTF-8" encoding="base64">U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==</text>
+          </note>
+        </notes>
+        <properties>
+          <property name="key1">val1</property>
+          <property name="key2">val2</property>
+        </properties>
+      </releaseNotes>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_services_simple-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_services_simple-1.0.xml.bin
new file mode 100644
index 000000000..acb066124
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_simple-1.0.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_services_simple-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_services_simple-1.1.xml.bin
new file mode 100644
index 000000000..55ef5cda2
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_simple-1.1.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/own/json/1.2/bom_services_simple.json b/tests/_data/snapshots/get_bom_with_services_simple-1.2.json.bin
similarity index 57%
rename from tests/_data/own/json/1.2/bom_services_simple.json
rename to tests/_data/snapshots/get_bom_with_services_simple-1.2.json.bin
index 198bfadd0..e7562cebe 100644
--- a/tests/_data/own/json/1.2/bom_services_simple.json
+++ b/tests/_data/snapshots/get_bom_with_services_simple-1.2.json.bin
@@ -1,44 +1,44 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.2",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
+    "component": {
+      "bom-ref": "my-specific-bom-ref-for-cpl",
+      "name": "cyclonedx-python-lib",
+      "type": "library",
+      "version": "1.0.0"
+    },
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
         "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
         "version": "TESTING"
       }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "df70b5f1-8f53-47a4-be48-669ae78795e6",
-      "name": "cyclonedx-python-lib",
-      "version": "1.0.0"
-    }
+    ]
   },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "bom-ref": "my-specific-bom-ref-for-my-first-service",
       "name": "my-first-service"
     },
     {
-      "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service"
     }
   ],
-  "dependencies": [
-    {
-      "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
-    },
-    {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
-    },
-    {
-      "ref": "df70b5f1-8f53-47a4-be48-669ae78795e6"
-    }
-  ]
-}
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_services_simple-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_services_simple-1.2.xml.bin
new file mode 100644
index 000000000..60db211e8
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_simple-1.2.xml.bin
@@ -0,0 +1,30 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <name>my-first-service</name>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.3/bom_services_simple.json b/tests/_data/snapshots/get_bom_with_services_simple-1.3.json.bin
similarity index 57%
rename from tests/_data/own/json/1.3/bom_services_simple.json
rename to tests/_data/snapshots/get_bom_with_services_simple-1.3.json.bin
index a18e31cbe..4c2ea8b21 100644
--- a/tests/_data/own/json/1.3/bom_services_simple.json
+++ b/tests/_data/snapshots/get_bom_with_services_simple-1.3.json.bin
@@ -1,44 +1,44 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.3",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
+    "component": {
+      "bom-ref": "my-specific-bom-ref-for-cpl",
+      "name": "cyclonedx-python-lib",
+      "type": "library",
+      "version": "1.0.0"
+    },
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
         "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
         "version": "TESTING"
       }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "df70b5f1-8f53-47a4-be48-669ae78795e6",
-      "name": "cyclonedx-python-lib",
-      "version": "1.0.0"
-    }
+    ]
   },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "bom-ref": "my-specific-bom-ref-for-my-first-service",
       "name": "my-first-service"
     },
     {
-      "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service"
     }
   ],
-  "dependencies": [
-    {
-      "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
-    },
-    {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
-    },
-    {
-      "ref": "df70b5f1-8f53-47a4-be48-669ae78795e6"
-    }
-  ]
-}
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_services_simple-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_services_simple-1.3.xml.bin
new file mode 100644
index 000000000..08fcc576b
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_simple-1.3.xml.bin
@@ -0,0 +1,30 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <name>my-first-service</name>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/own/json/1.4/bom_services_simple.json b/tests/_data/snapshots/get_bom_with_services_simple-1.4.json.bin
similarity index 58%
rename from tests/_data/own/json/1.4/bom_services_simple.json
rename to tests/_data/snapshots/get_bom_with_services_simple-1.4.json.bin
index 38c714228..78ab58482 100644
--- a/tests/_data/own/json/1.4/bom_services_simple.json
+++ b/tests/_data/snapshots/get_bom_with_services_simple-1.4.json.bin
@@ -1,78 +1,78 @@
 {
-  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
-  "bomFormat": "CycloneDX",
-  "specVersion": "1.4",
-  "serialNumber": "urn:uuid:d0b24ba4-102b-497e-b31f-4fdc3f0a3005",
-  "version": 1,
+  "dependencies": [
+    {
+      "ref": "my-specific-bom-ref-for-cpl"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-first-service"
+    },
+    {
+      "ref": "my-specific-bom-ref-for-my-second-service"
+    }
+  ],
   "metadata": {
+    "component": {
+      "bom-ref": "my-specific-bom-ref-for-cpl",
+      "name": "cyclonedx-python-lib",
+      "type": "library",
+      "version": "1.0.0"
+    },
     "timestamp": "2023-01-07T13:44:32.312678+00:00",
     "tools": [
       {
-        "vendor": "CycloneDX",
-        "name": "cyclonedx-python-lib",
-        "version": "TESTING",
         "externalReferences": [
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions",
-            "type": "build-system"
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
           },
           {
-            "url": "https://pypi.org/project/cyclonedx-python-lib/",
-            "type": "distribution"
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
           },
           {
-            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/",
-            "type": "documentation"
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues",
-            "type": "issue-tracker"
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE",
-            "type": "license"
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md",
-            "type": "release-notes"
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
           },
           {
-            "url": "https://github.com/CycloneDX/cyclonedx-python-lib",
-            "type": "vcs"
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
           },
           {
-            "url": "https://cyclonedx.org",
-            "type": "website"
+            "type": "website",
+            "url": "https://cyclonedx.org"
           }
-        ]
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
       }
-    ],
-    "component": {
-      "type": "library",
-      "bom-ref": "df70b5f1-8f53-47a4-be48-669ae78795e6",
-      "name": "cyclonedx-python-lib",
-      "version": "1.0.0"
-    }
+    ]
   },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
   "services": [
     {
-      "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3",
+      "bom-ref": "my-specific-bom-ref-for-my-first-service",
       "name": "my-first-service"
     },
     {
-      "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda",
+      "bom-ref": "my-specific-bom-ref-for-my-second-service",
       "name": "my-second-service"
     }
   ],
-  "dependencies": [
-    {
-      "ref": "df70b5f1-8f53-47a4-be48-669ae78795e6"
-    },
-    {
-      "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3"
-    },
-    {
-      "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"
-    }
-  ]
-}
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_services_simple-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_services_simple-1.4.xml.bin
new file mode 100644
index 000000000..ed0a032df
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_services_simple-1.4.xml.bin
@@ -0,0 +1,56 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="library" bom-ref="my-specific-bom-ref-for-cpl">
+      <name>cyclonedx-python-lib</name>
+      <version>1.0.0</version>
+    </component>
+  </metadata>
+  <services>
+    <service bom-ref="my-specific-bom-ref-for-my-first-service">
+      <name>my-first-service</name>
+    </service>
+    <service bom-ref="my-specific-bom-ref-for-my-second-service">
+      <name>my-second-service</name>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-specific-bom-ref-for-cpl"/>
+    <dependency ref="my-specific-bom-ref-for-my-first-service"/>
+    <dependency ref="my-specific-bom-ref-for-my-second-service"/>
+  </dependencies>
+</bom>
diff --git a/tests/base.py b/tests/base.py
deleted file mode 100644
index 371b53c63..000000000
--- a/tests/base.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# This file is part of CycloneDX Python Lib
-#
-# 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-# Copyright (c) OWASP Foundation. All Rights Reserved.
-
-import json
-import xml.etree.ElementTree
-from datetime import datetime, timezone
-from typing import Any
-from unittest import TestCase
-from uuid import uuid4
-
-from lxml import etree
-from xmldiff import main
-from xmldiff.actions import MoveNode
-
-from cyclonedx.exception import MissingOptionalDependencyException
-from cyclonedx.output import SchemaVersion
-from cyclonedx.validation.json import JsonStrictValidator
-from cyclonedx.validation.xml import XmlValidator
-
-single_uuid: str = 'urn:uuid:{}'.format(uuid4())
-
-
-class BaseJsonTestCase(TestCase):
-
-    def assertValidAgainstSchema(self, bom_json: str, schema_version: SchemaVersion) -> None:
-        try:
-            validation_error = JsonStrictValidator(schema_version).validate_str(bom_json)
-        except MissingOptionalDependencyException:
-            return  # some deps are missing - skip the validation
-        self.assertIsNone(validation_error,
-                          f'Failed to validate SBOM against JSON schema: {str(validation_error)}')
-
-    @staticmethod
-    def _sort_json_dict(item: object) -> Any:
-        if isinstance(item, dict):
-            return sorted((key, BaseJsonTestCase._sort_json_dict(values)) for key, values in item.items())
-        if isinstance(item, list):
-            return sorted(BaseJsonTestCase._sort_json_dict(x) for x in item)
-        else:
-            return item
-
-    def assertEqualJson(self, a: str, b: str) -> None:
-        self.assertEqual(
-            BaseJsonTestCase._sort_json_dict(json.loads(a)),
-            BaseJsonTestCase._sort_json_dict(json.loads(b))
-        )
-
-    def assertEqualJsonBom(self, a: str, b: str) -> None:
-        """
-        Remove UUID before comparison as this will be unique to each generation
-        """
-        ab = json.loads(a)
-        bb = json.loads(b)
-
-        # Null serialNumbers
-        ab['serialNumber'] = single_uuid
-        bb['serialNumber'] = single_uuid
-
-        # Unify timestamps to ensure they will compare
-        now = datetime.now(tz=timezone.utc)
-        if 'metadata' in ab.keys():
-            ab['metadata']['timestamp'] = now.isoformat()
-        if 'metadata' in bb.keys():
-            bb['metadata']['timestamp'] = now.isoformat()
-
-        self.assertEqualJson(json.dumps(ab), json.dumps(bb))
-
-
-class BaseXmlTestCase(TestCase):
-
-    def assertValidAgainstSchema(self, bom_xml: str, schema_version: SchemaVersion) -> None:
-        try:
-            validation_error = XmlValidator(schema_version).validate_str(bom_xml)
-        except MissingOptionalDependencyException:
-            return  # some deps are missing - skip the validation
-        self.assertIsNone(validation_error,
-                          f'Failed to validate Generated SBOM against XSD Schema: {str(validation_error)}')
-
-    def assertEqualXml(self, a: str, b: str) -> None:
-        diff_results = main.diff_texts(a, b, diff_options={'F': 0.5})
-        diff_results = list(filter(lambda o: not isinstance(o, MoveNode), diff_results))
-        self.assertEqual(len(diff_results), 0, f'There are XML differences: {diff_results}\n- {a}\n+ {b}')
-
-    def assertEqualXmlBom(self, a: str, b: str, namespace: str) -> None:
-        """
-        Sanitise some fields such as timestamps which cannot have their values directly compared for equality.
-        """
-        ba = xml.etree.ElementTree.fromstring(a, etree.XMLParser(remove_blank_text=True, remove_comments=True))
-        bb = xml.etree.ElementTree.fromstring(b, etree.XMLParser(remove_blank_text=True, remove_comments=True))
-
-        # Align serialNumbers
-        ba.set('serialNumber', single_uuid)
-        bb.set('serialNumber', single_uuid)
-
-        # Align timestamps in metadata
-        now = datetime.now(tz=timezone.utc)
-        metadata_ts_a = ba.find('./{{{}}}metadata/{{{}}}timestamp'.format(namespace, namespace))
-        if metadata_ts_a is not None:
-            metadata_ts_a.text = now.isoformat()
-        metadata_ts_b = bb.find('./{{{}}}metadata/{{{}}}timestamp'.format(namespace, namespace))
-        if metadata_ts_b is not None:
-            metadata_ts_b.text = now.isoformat()
-
-        self.assertEqualXml(
-            xml.etree.ElementTree.tostring(ba, 'unicode'),
-            xml.etree.ElementTree.tostring(bb, 'unicode')
-        )
diff --git a/tests/test_component.py b/tests/test_component.py
index a344d880c..92c54c8c7 100644
--- a/tests/test_component.py
+++ b/tests/test_component.py
@@ -23,10 +23,8 @@
 
 from cyclonedx.model import sha1sum
 from cyclonedx.model.component import Component
-from tests import TESTDATA_DIRECTORY
-from tests.data import get_component_setuptools_simple
-
-RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml', '1.4')
+from tests import OWN_DATA_DIRECTORY
+from tests._data.models import get_component_setuptools_simple
 
 
 class TestComponent(TestCase):
@@ -64,8 +62,8 @@ def test_purl_incorrect_name(self) -> None:
         self.assertEqual(purl.version, '50.3.2')
         self.assertEqual(purl.qualifiers, {'extension': 'tar.gz'})
 
-    def test_from_file_with_path_for_bom(self) -> None:
-        test_file = join(RELEVANT_TESTDATA_DIRECTORY, 'bom_setuptools.xml')
+    def test_from_xml_file_with_path_for_bom(self) -> None:
+        test_file = join(OWN_DATA_DIRECTORY, 'xml', '1.4', 'bom_setuptools.xml')
         c = Component.for_file(absolute_file_path=test_file, path_for_bom='fixtures/bom_setuptools.xml')
         sha1_hash: str = sha1sum(filename=test_file)
         expected_version = '0.0.0-{}'.format(sha1_hash[0:12])
diff --git a/tests/test_deserialize_json.py b/tests/test_deserialize_json.py
index 1f07252fb..fe9ff1776 100644
--- a/tests/test_deserialize_json.py
+++ b/tests/test_deserialize_json.py
@@ -15,418 +15,31 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
-import json
-from datetime import datetime
-from os.path import join
-from typing import cast
-from unittest.mock import Mock, patch
-from uuid import UUID
 
-from cyclonedx.model.bom import Bom
-from cyclonedx.output import LATEST_SUPPORTED_SCHEMA_VERSION, OutputFormat, SchemaVersion, get_instance
-from tests import TESTDATA_DIRECTORY
-from tests.base import BaseJsonTestCase
-from tests.data import (
-    MOCK_BOM_UUID_1,
-    MOCK_BOM_UUID_2,
-    MOCK_UUID_1,
-    MOCK_UUID_2,
-    MOCK_UUID_3,
-    MOCK_UUID_4,
-    MOCK_UUID_5,
-    MOCK_UUID_6,
-    MOCK_UUID_7,
-    MOCK_UUID_8,
-    TEST_UUIDS,
-    get_bom_just_complete_metadata,
-    get_bom_with_component_setuptools_basic,
-    get_bom_with_component_setuptools_complete,
-    get_bom_with_component_setuptools_no_component_version,
-    get_bom_with_component_setuptools_with_cpe,
-    get_bom_with_component_setuptools_with_release_notes,
-    get_bom_with_component_setuptools_with_vulnerability,
-    get_bom_with_component_toml_1,
-    get_bom_with_dependencies_valid,
-    get_bom_with_external_references,
-    get_bom_with_nested_services,
-    get_bom_with_services_complex,
-    get_bom_with_services_simple,
-)
-
-RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'json')
-
-
-def fixed_date_time() -> datetime:
-    return datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
-
-
-@patch('cyclonedx.model.ThisTool._version', 'TESTING')
-@patch('cyclonedx.model.bom.get_now_utc', fixed_date_time)
-class TestOutputJson(BaseJsonTestCase):
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_external_references_v1_4(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_external_references.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_external_references_v1_3(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_external_references.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_external_references_v1_2(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_external_references.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_4(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_3(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_2(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_4_with_cpe(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_cpe.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_3_with_cpe(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_with_cpe.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_2_with_cpe(self, mock_uuid: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_with_cpe.json'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_4_full_component(self, mock1: Mock, mock2: Mock) -> None:
-        self.maxDiff = None
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_complete.json'
-        )
-        mock1.assert_called()
-        mock2.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_3_full_component(self, mock1: Mock, mock2: Mock) -> None:
-        self.maxDiff = None
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_complete.json'
-        )
-        mock1.assert_called()
-        mock2.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_2_full_component(self, mock1: Mock, mock2: Mock) -> None:
-        self.maxDiff = None
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_complete.json'
-        )
-        mock1.assert_called()
-        mock2.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_UUID_7)
-    def test_bom_v1_4_component_hashes_external_references(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_toml_1.json'
-        )
-        mock_1.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_UUID_7)
-    def test_bom_v1_3_component_hashes_external_references(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_toml_1.json'
-        )
-        mock_1.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_UUID_7)
-    def test_bom_v1_2_component_hashes_external_references(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_toml_1.json'
-        )
-        mock_1.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_UUID_8)
-    def test_bom_v1_4_no_component_version(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_no_version.json'
-        )
-        mock_1.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_UUID_8)
-    def test_bom_v1_3_no_component_version(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_no_version.json'
-        )
-        mock_1.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_UUID_8)
-    def test_bom_v1_2_no_component_version(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_no_version.json'
-        )
-        mock_1.assert_called()
+from json import loads as json_loads
+from typing import Any, Callable
+from unittest import TestCase
+from unittest.mock import patch
 
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_component_with_release_notes(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_release_notes(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_release_notes.json'
-        )
-        mock_1.assert_called()
+from ddt import ddt, named_data
 
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_component_with_release_notes(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_release_notes(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.json'
-        )
-        mock_1.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_component_with_vulnerability(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_vulnerabilities.json'
-        )
-        mock_1.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_component_with_vulnerability(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.json'
-        )
-        mock_1.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_1))
-    def test_bom_v1_4_with_metadata_component(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_with_full_metadata.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_2))
-    def test_bom_v1_3_with_metadata_component(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_with_full_metadata.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    def test_bom_v1_2_with_metadata_component(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_with_full_metadata.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_simple(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_simple.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_simple(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_simple.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_simple(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_simple.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_5))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_complex(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_complex.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_5))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_complex(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_complex.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_5))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_complex(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_complex.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_nested(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_nested.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_nested(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_nested.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_2)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_nested(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_nested.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_dependencies(self, mock_1: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_dependencies.json'
-        )
-        mock_1.assert_called()
-    # --
-
-    # Helper methods
-    def _validate_json_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
-        bom.metadata.timestamp = fixed_date_time()
-        bom.validate()
-
-        if schema_version != LATEST_SUPPORTED_SCHEMA_VERSION:
-            # Rewind the BOM to only have data supported by the SchemaVersion in question
-            outputter = get_instance(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
-            bom = cast(Bom, Bom.from_json(data=json.loads(outputter.output_as_string())))
-
-        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as input_json:
-            deserialized_bom = cast(Bom, Bom.from_json(data=json.loads(input_json.read())))
-
-            self.assertEqual(bom.metadata, deserialized_bom.metadata)
-
-            # This comparison fails for Dependencies despite the SortedSet's being identical
-            # self.assertEqual(bom.dependencies, deserialized_bom.dependencies)
-            self.assertSetEqual(set(bom.dependencies), set(deserialized_bom.dependencies))
-
-            self.assertEqual(bom.vulnerabilities, deserialized_bom.vulnerabilities)
-
-            self.assertEqual(bom, deserialized_bom)
+from cyclonedx.model.bom import Bom
+from cyclonedx.schema import OutputFormat, SchemaVersion
+from tests import DeepCompareMixin, SnapshotMixin, mksname, uuid_generator
+from tests._data.models import all_get_bom_funct_valid, all_get_bom_funct_with_incomplete_deps
+
+
+@ddt
+class TestDeserializeJson(TestCase, SnapshotMixin, DeepCompareMixin):
+
+    @named_data(*all_get_bom_funct_valid)
+    @patch('cyclonedx.model.ThisTool._version', 'TESTING')
+    @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
+    def test(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
+        # only latest schema will have all data populated in serialized form
+        snapshot_name = mksname(get_bom, SchemaVersion.V1_4, OutputFormat.JSON)
+        expected = get_bom()
+        json = json_loads(self.readSnapshot(snapshot_name))
+        bom = Bom.from_json(json)
+        self.assertBomDeepEqual(expected, bom,
+                                fuzzy_deps=get_bom in all_get_bom_funct_with_incomplete_deps)
diff --git a/tests/test_deserialize_xml.py b/tests/test_deserialize_xml.py
index 2b32ed95b..3b2652d81 100644
--- a/tests/test_deserialize_xml.py
+++ b/tests/test_deserialize_xml.py
@@ -15,688 +15,30 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
-from datetime import datetime
-from io import StringIO
-from os.path import join
-from typing import cast
-from unittest.mock import Mock, patch
-from uuid import UUID
 
-from cyclonedx.model.bom import Bom
-from cyclonedx.output import LATEST_SUPPORTED_SCHEMA_VERSION, SchemaVersion, get_instance
-from cyclonedx.schema import OutputFormat
-from tests import TESTDATA_DIRECTORY
-from tests.base import BaseXmlTestCase
-from tests.data import (
-    MOCK_BOM_UUID_1,
-    MOCK_UUID_2,
-    MOCK_UUID_3,
-    MOCK_UUID_4,
-    MOCK_UUID_5,
-    MOCK_UUID_6,
-    TEST_UUIDS,
-    get_bom_for_issue_275_components,
-    get_bom_just_complete_metadata,
-    get_bom_with_component_setuptools_basic,
-    get_bom_with_component_setuptools_complete,
-    get_bom_with_component_setuptools_no_component_version,
-    get_bom_with_component_setuptools_with_cpe,
-    get_bom_with_component_setuptools_with_release_notes,
-    get_bom_with_component_setuptools_with_vulnerability,
-    get_bom_with_component_toml_1,
-    get_bom_with_dependencies_valid,
-    get_bom_with_external_references,
-    get_bom_with_metadata_component_and_dependencies,
-    get_bom_with_nested_services,
-    get_bom_with_services_complex,
-    get_bom_with_services_simple,
-)
-
-RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
-
-
-def fixed_date_time() -> datetime:
-    return datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
-
-
-@patch('cyclonedx.model.ThisTool._version', 'TESTING')
-@patch('cyclonedx.model.bom.get_now_utc', fixed_date_time)
-class TestDeserializeXml(BaseXmlTestCase):
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_external_references_v1_4(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_external_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_external_references_v1_3(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_external_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_external_references_v1_2(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_external_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_external_references_v1_1(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_external_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_external_references_v1_0(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_empty.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_4(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_3(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_2(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_1(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_0(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_4_with_cpe(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_3_with_cpe(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_2_with_cpe(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_1_with_cpe(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_simple_bom_v1_0_with_cpe(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    def test_bom_v1_4_full_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_bom_uuid.assert_called()
-        mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    def test_bom_v1_3_full_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_bom_uuid.assert_called()
-        mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_2))
-    def test_bom_v1_2_full_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_bom_uuid.assert_called()
-        mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    def test_bom_v1_1_full_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_bom_uuid.assert_called()
-        mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    def test_bom_v1_0_full_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_bom_uuid.assert_called()
-        mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_component_hashes_external_references(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_component_hashes_external_references(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_2_component_hashes_external_references(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_1_component_hashes_external_references(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_0_component_hashes_external_references(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_no_component_version(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_no_version.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_no_component_version(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_no_version.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_2_no_component_version(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_no_version.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_1_no_component_version(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools_no_version.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_0_no_component_version(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools_no_version.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_component_with_release_notes(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_release_notes(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_release_notes.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_component_with_release_notes(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_release_notes(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_component_with_vulnerability(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_vulnerabilities.xml'
-        )
-        mock_uuid.assert_called()
+from typing import Any, Callable
+from unittest import TestCase
+from unittest.mock import patch
 
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_component_with_vulnerability(self, mock_uuid: Mock) -> None:
-        with self.assertRaises(ValueError):
-            self._validate_xml_bom(
-                bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_setuptools_with_vulnerabilities.xml'
-            )
-            mock_uuid.assert_called()
+from ddt import ddt, named_data
 
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_2_component_with_vulnerability(self, mock_uuid: Mock) -> None:
-        with self.assertRaises(ValueError):
-            self._validate_xml_bom(
-                bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_setuptools_with_vulnerabilities.xml'
-            )
-            mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_1_component_with_vulnerability(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_0_component_with_vulnerability(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_4_with_metadata_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_with_full_metadata.xml'
-            )
-            mock_bom_uuid.assert_called()
-            mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_5))
-    def test_bom_v1_3_with_metadata_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_with_full_metadata.xml'
-            )
-            mock_bom_uuid.assert_called()
-            mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    def test_bom_v1_2_with_metadata_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_with_full_metadata.xml'
-            )
-            mock_bom_uuid.assert_called()
-            mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_1_with_metadata_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_1,
-                fixture='bom_empty.xml'
-            )
-            mock_bom_uuid.assert_called()
-            mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_0_with_metadata_component(self, mock_bom_uuid: Mock, mock_bom_ref_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_0,
-                fixture='bom_empty.xml'
-            )
-            mock_bom_uuid.assert_called()
-            mock_bom_ref_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_simple(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_simple.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_simple(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_simple.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_simple(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_simple.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_1_services_simple(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_1,
-                fixture='bom_empty.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_0_services_simple(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_0,
-                fixture='bom_empty.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_complex(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_complex.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_complex(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_complex.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_complex(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_complex.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_1_services_complex(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_1,
-                fixture='bom_empty.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_nested(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_nested.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_nested(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_nested.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_nested(self, mock_1: Mock, mock_2: Mock, mock_3: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_nested.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-            mock_3.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_dependencies(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_dependencies.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_dependencies(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_dependencies.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_2_dependencies(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_dependencies.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_1_dependencies(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_dependencies.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_dependencies_for_bom_component(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_dependencies_component.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_dependencies_for_bom_component(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_dependencies_component.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_2_dependencies_for_bom_component(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_dependencies_component.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_4_issue_275_components(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_issue_275_components.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_3_issue_275_components(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_issue_275_components.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_2_issue_275_components(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_issue_275_components.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_1_issue_275_components(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_issue_275_components.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=MOCK_BOM_UUID_1)
-    def test_bom_v1_0_issue_275_components(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_issue_275_components.xml'
-        )
-        mock_uuid.assert_called()
-
-    # Helper methods
-    def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
-        bom.metadata.timestamp = fixed_date_time()
-        bom.validate()
-
-        if schema_version != LATEST_SUPPORTED_SCHEMA_VERSION:
-            # Rewind the BOM to only have data supported by the SchemaVersion in question
-            outputter = get_instance(bom=bom, output_format=OutputFormat.XML, schema_version=schema_version)
-            bom = cast(Bom, Bom.from_xml(StringIO(outputter.output_as_string())))
-
-        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as input_xml:
-            deserialized_bom = cast(Bom, Bom.from_xml(input_xml))
-
-            self.assertEqual(bom.metadata, deserialized_bom.metadata)
-
-            # This comparison fails for Dependencies despite the SortedSet's being identical
-            # print(bom.dependencies.difference(deserialized_bom.dependencies))
-            # self.assertEqual(bom.dependencies, deserialized_bom.dependencies)
-            # self.assertSetEqual(set(bom.dependencies), set(deserialized_bom.dependencies))
-
-            self.assertEqual(bom.vulnerabilities, deserialized_bom.vulnerabilities)
-            self.assertEqual(bom, deserialized_bom)
+from cyclonedx.model.bom import Bom
+from cyclonedx.schema import OutputFormat, SchemaVersion
+from tests import DeepCompareMixin, SnapshotMixin, mksname, uuid_generator
+from tests._data.models import all_get_bom_funct_valid, all_get_bom_funct_with_incomplete_deps
+
+
+@ddt
+class TestDeserializeXml(TestCase, SnapshotMixin, DeepCompareMixin):
+
+    @named_data(*all_get_bom_funct_valid)
+    @patch('cyclonedx.model.ThisTool._version', 'TESTING')
+    @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
+    def test(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
+        # only latest schema will have all data populated in serialized form
+        snapshot_name = mksname(get_bom, SchemaVersion.V1_4, OutputFormat.XML)
+        expected = get_bom()
+        with open(self.getSnapshotFile(snapshot_name), 'r') as s:
+            bom = Bom.from_xml(s)
+        self.assertBomDeepEqual(expected, bom,
+                                fuzzy_deps=get_bom in all_get_bom_funct_with_incomplete_deps)
diff --git a/tests/test_e2e_environment.py b/tests/test_e2e_environment.py
index 3a7460ea2..78b918075 100644
--- a/tests/test_e2e_environment.py
+++ b/tests/test_e2e_environment.py
@@ -18,10 +18,10 @@
 import json
 from unittest import TestCase
 
-import pkg_resources
 from lxml import etree
 from packageurl import PackageURL
 
+from cyclonedx import __version__ as OUR_PACKAGE_VERSION
 from cyclonedx.model.bom import Bom
 from cyclonedx.model.component import Component
 from cyclonedx.output import OutputFormat, get_instance
@@ -29,7 +29,6 @@
 from cyclonedx.output.xml import Xml
 
 OUR_PACKAGE_NAME: str = 'cyclonedx-python-lib'
-OUR_PACKAGE_VERSION: str = pkg_resources.get_distribution(OUR_PACKAGE_NAME).version
 OUR_PACKAGE_AUTHOR: str = 'Paul Horton'
 
 
diff --git a/tests/test_model.py b/tests/test_model.py
index 8459af3bd..af4e8ae81 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -45,7 +45,7 @@
     XsUri,
 )
 from cyclonedx.model.issue import IssueClassification, IssueType, IssueTypeSource
-from tests.data import reorder
+from tests import reorder
 
 
 class DummyStringEnum(str, Enum):
diff --git a/tests/test_model_bom.py b/tests/test_model_bom.py
index 50897ef42..0eb62d6c5 100644
--- a/tests/test_model_bom.py
+++ b/tests/test_model_bom.py
@@ -35,7 +35,7 @@
 from cyclonedx.model.bom import Bom, BomMetaData
 from cyclonedx.model.bom_ref import BomRef
 from cyclonedx.model.component import Component, ComponentType
-from tests.data import (
+from tests._data.models import (
     get_bom_component_licenses_invalid,
     get_bom_component_nested_licenses_invalid,
     get_bom_for_issue_275_components,
diff --git a/tests/test_model_bom_ref.py b/tests/test_model_bom_ref.py
index 955469bc3..40c7cef18 100644
--- a/tests/test_model_bom_ref.py
+++ b/tests/test_model_bom_ref.py
@@ -18,7 +18,7 @@
 from unittest import TestCase
 
 from cyclonedx.model.bom_ref import BomRef
-from tests.data import reorder
+from tests import reorder
 
 
 class TestBomRef(TestCase):
diff --git a/tests/test_model_component.py b/tests/test_model_component.py
index c48bb630c..ccee271e0 100644
--- a/tests/test_model_component.py
+++ b/tests/test_model_component.py
@@ -16,9 +16,9 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 import datetime
-from typing import List
+from typing import Any, List
 from unittest import TestCase
-from unittest.mock import Mock, patch
+from unittest.mock import patch
 
 from cyclonedx.exception.model import NoPropertiesProvidedException
 from cyclonedx.model import (
@@ -42,8 +42,8 @@
     Pedigree,
 )
 from cyclonedx.model.issue import IssueClassification, IssueType
-from tests.data import (
-    MOCK_UUID_7,
+from tests import reorder, uuid_generator
+from tests._data.models import (
     get_component_setuptools_simple,
     get_component_setuptools_simple_no_version,
     get_component_toml_with_hashes_with_references,
@@ -52,7 +52,6 @@
     get_pedigree_1,
     get_swid_1,
     get_swid_2,
-    reorder,
 )
 
 
@@ -105,14 +104,13 @@ def test_sort(self) -> None:
 
 class TestModelComponent(TestCase):
 
-    @patch('cyclonedx.model.component.uuid4', return_value=MOCK_UUID_7)
-    def test_empty_basic_component(self, mock_uuid: Mock) -> None:
+    @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(version=4))
+    def test_empty_basic_component(self, *_: Any, **__: Any) -> None:
         c = Component(name='test-component')
-        mock_uuid.assert_called()
         self.assertEqual(c.name, 'test-component')
         self.assertEqual(c.type, ComponentType.LIBRARY)
         self.assertIsNone(c.mime_type)
-        self.assertEqual(str(c.bom_ref), '6f266d1c-760f-4552-ae3b-41a9b74232fa')
+        self.assertEqual(str(c.bom_ref), '00000000-0000-4000-8000-000000000001')
         self.assertIsNone(c.supplier)
         self.assertIsNone(c.author)
         self.assertIsNone(c.publisher)
@@ -130,8 +128,7 @@ def test_empty_basic_component(self, mock_uuid: Mock) -> None:
         self.assertEqual(len(c.components), 0)
         self.assertEqual(len(c.get_all_nested_components(include_self=True)), 1)
 
-    @patch('cyclonedx.model.component.uuid4', return_value=MOCK_UUID_7)
-    def test_multiple_basic_components(self, mock_uuid: Mock) -> None:
+    def test_multiple_basic_components(self) -> None:
         c1 = Component(name='test-component')
         self.assertEqual(c1.name, 'test-component')
         self.assertIsNone(c1.version)
@@ -148,8 +145,6 @@ def test_multiple_basic_components(self, mock_uuid: Mock) -> None:
 
         self.assertNotEqual(c1, c2)
 
-        mock_uuid.assert_called()
-
     def test_external_references(self) -> None:
         c = Component(name='test-component')
         c.external_references.add(ExternalReference(
diff --git a/tests/test_model_dependency.py b/tests/test_model_dependency.py
index 165bcfca8..4439d6aa0 100644
--- a/tests/test_model_dependency.py
+++ b/tests/test_model_dependency.py
@@ -19,7 +19,7 @@
 
 from cyclonedx.model.bom_ref import BomRef
 from cyclonedx.model.dependency import Dependency
-from tests.data import reorder
+from tests import reorder
 
 
 class TestDependency(TestCase):
diff --git a/tests/test_model_issue.py b/tests/test_model_issue.py
index bc156169d..b7a127ae6 100644
--- a/tests/test_model_issue.py
+++ b/tests/test_model_issue.py
@@ -20,7 +20,8 @@
 from cyclonedx.exception.model import NoPropertiesProvidedException
 from cyclonedx.model import XsUri
 from cyclonedx.model.issue import IssueClassification, IssueType, IssueTypeSource
-from tests.data import get_issue_1, get_issue_2, reorder
+from tests import reorder
+from tests._data.models import get_issue_1, get_issue_2
 
 
 class TestModelIssueType(TestCase):
diff --git a/tests/test_model_service.py b/tests/test_model_service.py
index 588cf2d53..3b677961f 100644
--- a/tests/test_model_service.py
+++ b/tests/test_model_service.py
@@ -14,22 +14,22 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
-
+from typing import Any
 from unittest import TestCase
 from unittest.mock import Mock, patch
 
 from cyclonedx.model.service import Service
-from tests.data import MOCK_UUID_8, MOCK_UUID_9, reorder
+from tests import reorder, uuid_generator
 
 
 class TestModelService(TestCase):
 
-    @patch('cyclonedx.model.service.uuid4', return_value=MOCK_UUID_8)
+    @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(version=4))
     def test_minimal_service(self, mock_uuid: Mock) -> None:
         s = Service(name='my-test-service')
         mock_uuid.assert_called()
         self.assertEqual(s.name, 'my-test-service')
-        self.assertEqual(str(s.bom_ref), str(MOCK_UUID_8))
+        self.assertEqual(str(s.bom_ref), '00000000-0000-4000-8000-000000000001')
         self.assertIsNone(s.provider)
         self.assertIsNone(s.group)
         self.assertIsNone(s.version)
@@ -44,16 +44,15 @@ def test_minimal_service(self, mock_uuid: Mock) -> None:
         self.assertFalse(s.release_notes)
         self.assertFalse(s.properties)
 
-    @patch('cyclonedx.model.service.uuid4', return_value=MOCK_UUID_9)
-    def test_service_with_services(self, mock_uuid: Mock) -> None:
+    @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(version=4))
+    def test_service_with_services(self, *_: Any, **__: Any) -> None:
         parent_service = Service(name='parent-service')
         parent_service.services = [
             Service(name='child-service-1'),
-            Service(name='child-service-2')
+            Service(name='child-service-2'),
         ]
-        mock_uuid.assert_called()
         self.assertEqual(parent_service.name, 'parent-service')
-        self.assertEqual(str(parent_service.bom_ref), str(MOCK_UUID_9))
+        self.assertEqual(str(parent_service.bom_ref), '00000000-0000-4000-8000-000000000001')
         self.assertIsNone(parent_service.provider)
         self.assertIsNone(parent_service.group)
         self.assertIsNone(parent_service.version)
diff --git a/tests/test_model_vulnerability.py b/tests/test_model_vulnerability.py
index 257b82a8b..50a6c03f5 100644
--- a/tests/test_model_vulnerability.py
+++ b/tests/test_model_vulnerability.py
@@ -17,8 +17,9 @@
 
 from datetime import datetime, timedelta
 from decimal import Decimal
+from typing import Any
 from unittest import TestCase
-from unittest.mock import Mock, patch
+from unittest.mock import patch
 
 from cyclonedx.model import XsUri
 from cyclonedx.model.impact_analysis import ImpactAnalysisAffectedStatus
@@ -33,7 +34,7 @@
     VulnerabilitySeverity,
     VulnerabilitySource,
 )
-from tests.data import MOCK_UUID_10, reorder
+from tests import reorder, uuid_generator
 
 
 class TestModelVulnerability(TestCase):
@@ -167,11 +168,10 @@ def test_v_source_get_localised_vector_other_2(self) -> None:
             'SOMETHING_OR_OTHER'
         )
 
-    @patch('cyclonedx.model.vulnerability.uuid4', return_value=MOCK_UUID_10)
-    def test_empty_vulnerability(self, mock_uuid: Mock) -> None:
+    @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(version=4))
+    def test_empty_vulnerability(self, *_: Any, **__: Any) -> None:
         v = Vulnerability()
-        mock_uuid.assert_called()
-        self.assertEqual(str(v.bom_ref), str(MOCK_UUID_10))
+        self.assertEqual(str(v.bom_ref), '00000000-0000-4000-8000-000000000001')
         self.assertIsNone(v.id)
         self.assertIsNone(v.source)
         self.assertFalse(v.references)
diff --git a/tests/test_output_json.py b/tests/test_output_json.py
index f40802625..0a291fa27 100644
--- a/tests/test_output_json.py
+++ b/tests/test_output_json.py
@@ -14,428 +14,71 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
-from os.path import join
-from typing import Optional, Union
+
+from typing import Any, Callable
 from unittest import TestCase
 from unittest.mock import Mock, patch
-from uuid import UUID
 
-from ddt import ddt, idata, named_data
+from ddt import data, ddt, idata, named_data, unpack
 
+from cyclonedx.exception import CycloneDxException, MissingOptionalDependencyException
+from cyclonedx.exception.model import LicenseExpressionAlongWithOthersException, UnknownComponentDependencyException
 from cyclonedx.exception.output import FormatNotSupportedException
 from cyclonedx.model.bom import Bom
-from cyclonedx.output import get_instance as get_outputter
 from cyclonedx.output.json import BY_SCHEMA_VERSION, Json
 from cyclonedx.schema import OutputFormat, SchemaVersion
-from tests import TESTDATA_DIRECTORY
-from tests.base import BaseJsonTestCase
-from tests.data import (
-    MOCK_BOM_UUID_1,
-    MOCK_TIMESTAMP,
-    MOCK_UUID_1,
-    MOCK_UUID_2,
-    MOCK_UUID_3,
-    MOCK_UUID_4,
-    MOCK_UUID_5,
-    MOCK_UUID_6,
-    TEST_UUIDS,
-    get_bom_for_issue_275_components,
-    get_bom_just_complete_metadata,
-    get_bom_with_component_setuptools_basic,
-    get_bom_with_component_setuptools_complete,
-    get_bom_with_component_setuptools_no_component_version,
-    get_bom_with_component_setuptools_with_cpe,
-    get_bom_with_component_setuptools_with_release_notes,
-    get_bom_with_component_setuptools_with_vulnerability,
-    get_bom_with_component_toml_1,
-    get_bom_with_dependencies_hanging,
-    get_bom_with_dependencies_valid,
-    get_bom_with_external_references,
-    get_bom_with_metadata_component_and_dependencies,
-    get_bom_with_nested_services,
-    get_bom_with_services_complex,
-    get_bom_with_services_simple,
-)
+from cyclonedx.validation.json import JsonStrictValidator
+from tests import SnapshotMixin, mksname, uuid_generator
+from tests._data.models import all_get_bom_funct_invalid, all_get_bom_funct_valid
 
-RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'json')
+UNSUPPORTED_SV = frozenset((SchemaVersion.V1_1, SchemaVersion.V1_0,))
 
 
 @ddt
-@patch('cyclonedx.model.ThisTool._version', 'TESTING')
-class TestOutputJson(BaseJsonTestCase):
-
-    def test_bom_external_references_v1_4(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_external_references.json'
-        )
-
-    def test_bom_external_references_v1_3(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_external_references.json'
-        )
-
-    def test_bom_external_references_v1_2(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_external_references.json'
-        )
-
-    def test_simple_bom_v1_4(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools.json'
-        )
-
-    def test_simple_bom_v1_3(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.json'
-        )
-
-    def test_simple_bom_v1_2(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools.json'
-        )
-
-    def test_simple_bom_v1_1(self) -> None:
-        self._validate_json_bom_not_supported(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_1
-        )
-
-    def test_simple_bom_v1_0(self) -> None:
-        self._validate_json_bom_not_supported(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_0
-        )
-
-    def test_simple_bom_v1_4_with_cpe(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_cpe.json'
-        )
-
-    def test_simple_bom_v1_3_with_cpe(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_with_cpe.json'
-        )
-
-    def test_simple_bom_v1_2_with_cpe(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_with_cpe.json'
-        )
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_4_full_component(self, mock: Mock) -> None:
-        self.maxDiff = None
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_complete.json'
-        )
-        mock.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_3_full_component(self, mock: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_complete.json'
-        )
-        mock.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_2_full_component(self, mock: Mock) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_complete.json'
-        )
-        mock.assert_called()
-
-    def test_bom_v1_4_component_hashes_external_references(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_toml_1.json'
-        )
-
-    def test_bom_v1_3_component_hashes_external_references(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_toml_1.json'
-        )
-
-    def test_bom_v1_2_component_hashes_external_references(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_toml_1.json'
-        )
-
-    def test_bom_v1_1_component_hashes_external_references(self) -> None:
-        self._validate_json_bom_not_supported(bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_1)
-
-    def test_bom_v1_0_component_hashes_external_references(self) -> None:
-        self._validate_json_bom_not_supported(bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_0)
-
-    def test_bom_v1_4_no_component_version(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_no_version.json'
-        )
-
-    def test_bom_v1_3_no_component_version(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_no_version.json'
-        )
-
-    def test_bom_v1_4_component_with_release_notes(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_release_notes(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_release_notes.json'
-        )
-
-    def test_bom_v1_3_component_with_release_notes(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_release_notes(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.json'
-        )
-
-    def test_bom_v1_4_component_with_vulnerability(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_vulnerabilities.json'
-        )
-
-    def test_bom_v1_3_component_with_vulnerability(self) -> None:
-        # Vulnerabilities not support in JSON < 1.4
-        self._validate_json_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.json'
-        )
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_1))
-    def test_bom_v1_4_with_metadata_component(self, mock_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_with_full_metadata.json'
-            )
-            mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_2))
-    def test_bom_v1_3_with_metadata_component(self, mock_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_with_full_metadata.json'
-            )
-            mock_uuid.assert_called()
+class TestOutputJson(TestCase, SnapshotMixin):
 
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    def test_bom_v1_2_with_metadata_component(self, mock_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_with_full_metadata.json'
-            )
-            mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_simple(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_simple.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_simple(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_simple.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_simple(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_simple.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_5))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_complex(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_complex.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_5))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_complex(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_complex.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_5))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_complex(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_complex.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_nested(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_nested.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_nested(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_nested.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_nested(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_json_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_nested.json'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    def test_bom_v1_4_dependencies(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_dependencies.json'
-        )
-
-    def test_bom_v1_3_dependencies(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_dependencies.json'
-        )
-
-    def test_bom_v1_2_dependencies(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_dependencies.json'
-        )
-
-    def test_bom_v1_4_dependencies_for_bom_component(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_dependencies_component.json'
-        )
-
-    def test_bom_v1_3_dependencies_for_bom_component(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_dependencies_component.json'
-        )
-
-    def test_bom_v1_2_dependencies_for_bom_component(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_dependencies_component.json'
-        )
-
-    def test_bom_v1_4_issue_275_components(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_issue_275_components.json'
-        )
-
-    def test_bom_v1_3_issue_275_components(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_issue_275_components.json'
-        )
-
-    def test_bom_v1_2_issue_275_components(self) -> None:
-        self._validate_json_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_issue_275_components.json'
-        )
-
-    def test_bom_v1_4_warn_dependencies(self) -> None:
-        with self.assertWarns(UserWarning):
-            # this data set is expected to throw this UserWarning.
-            # that is the while point of this test!
-            self._validate_json_bom(
-                bom=get_bom_with_dependencies_hanging(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_with_dependencies_hanging.json'
-            )
-
-    @named_data(
-        ('None', 'None', None),
-        ('two', 'two', 2),
-        ('4spaces', '4spaces', '    '),
-        ('tab', 'tab', '\t')
-    )
-    def test_indent(self, name: str, indent: Optional[Union[str, int]]) -> None:
-        bom = get_bom_with_component_setuptools_basic()
-        bom.serial_number = MOCK_BOM_UUID_1
-        bom.metadata.timestamp = MOCK_TIMESTAMP
-        schema_version = SchemaVersion.V1_4
-        outputter = get_outputter(bom=bom, schema_version=schema_version, output_format=OutputFormat.JSON)
-        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), f'indented_{name}.json')
-                  ) as expected_xml:
-            bom_json = outputter.output_as_string(indent=indent)
-            self.assertEqual(expected_xml.read(), bom_json)
-            self.assertValidAgainstSchema(bom_json=bom_json, schema_version=schema_version)
-
-    # region Helper methods
-
-    def _validate_json_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
-        outputter = get_outputter(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
-        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as expected_json:
-            output_as_string = outputter.output_as_string()
-            self.assertValidAgainstSchema(bom_json=output_as_string, schema_version=schema_version)
-            self.assertEqualJsonBom(expected_json.read(), output_as_string)
-
-    def _validate_json_bom_not_supported(self, bom: Bom, schema_version: SchemaVersion) -> None:
+    @data(*UNSUPPORTED_SV)
+    def test_unsupported_schema_raises(self, sv: SchemaVersion) -> None:
+        outputterClass = BY_SCHEMA_VERSION[sv]
+        self.assertTrue(issubclass(outputterClass, Json))
+        outputter = outputterClass(Mock(spec=Bom))
         with self.assertRaises(FormatNotSupportedException):
-            outputter = get_outputter(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version)
             outputter.output_as_string()
 
-    # endregion Helper methods
+    @named_data(*((f'{n}-{sv.to_version()}', gb, sv)
+                  for n, gb in all_get_bom_funct_valid
+                  for sv in SchemaVersion
+                  if sv not in UNSUPPORTED_SV))
+    @unpack
+    @patch('cyclonedx.model.ThisTool._version', 'TESTING')
+    @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
+    def test_valid(self, get_bom: Callable[[], Bom], sv: SchemaVersion, *_: Any, **__: Any) -> None:
+        snapshot_name = mksname(get_bom, sv, OutputFormat.JSON)
+        bom = get_bom()
+        json = BY_SCHEMA_VERSION[sv](bom).output_as_string(indent=2)
+        try:
+            errors = JsonStrictValidator(sv).validate_str(json)
+        except MissingOptionalDependencyException:
+            errors = None  # skipped validation
+        self.assertIsNone(errors)
+        self.assertEqualSnapshot(json, snapshot_name)
+
+    @named_data(*((f'{n}-{sv.to_version()}', gb, sv)
+                  for n, gb in all_get_bom_funct_invalid
+                  for sv in SchemaVersion
+                  if sv not in UNSUPPORTED_SV))
+    @unpack
+    def test_invalid(self, get_bom: Callable[[], Bom], sv: SchemaVersion) -> None:
+        bom = get_bom()
+        outputter = BY_SCHEMA_VERSION[sv](bom)
+        with self.assertRaises(CycloneDxException) as error:
+            outputter.output_as_string()
+        if isinstance(error.exception, (
+            LicenseExpressionAlongWithOthersException,
+            UnknownComponentDependencyException,
+        )):
+            return None  # expected
+        raise error.exception
 
 
 @ddt
diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py
index 5303cb9f0..c78a87551 100644
--- a/tests/test_output_xml.py
+++ b/tests/test_output_xml.py
@@ -14,555 +14,59 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
-from os.path import join
-from typing import Optional, Union
+
+
+from typing import Any, Callable
 from unittest import TestCase
 from unittest.mock import Mock, patch
-from uuid import UUID
 
-from ddt import ddt, idata, named_data
+from ddt import ddt, idata, named_data, unpack
 
+from cyclonedx.exception import CycloneDxException, MissingOptionalDependencyException
+from cyclonedx.exception.model import LicenseExpressionAlongWithOthersException, UnknownComponentDependencyException
 from cyclonedx.model.bom import Bom
-from cyclonedx.output import get_instance as get_outputter
 from cyclonedx.output.xml import BY_SCHEMA_VERSION, Xml
 from cyclonedx.schema import OutputFormat, SchemaVersion
-from tests import TESTDATA_DIRECTORY
-from tests.base import BaseXmlTestCase
-from tests.data import (
-    MOCK_BOM_UUID_1,
-    MOCK_TIMESTAMP,
-    MOCK_UUID_1,
-    MOCK_UUID_2,
-    MOCK_UUID_3,
-    MOCK_UUID_4,
-    MOCK_UUID_5,
-    MOCK_UUID_6,
-    TEST_UUIDS,
-    get_bom_for_issue_275_components,
-    get_bom_just_complete_metadata,
-    get_bom_with_component_setuptools_basic,
-    get_bom_with_component_setuptools_complete,
-    get_bom_with_component_setuptools_no_component_version,
-    get_bom_with_component_setuptools_with_cpe,
-    get_bom_with_component_setuptools_with_release_notes,
-    get_bom_with_component_setuptools_with_vulnerability,
-    get_bom_with_component_toml_1,
-    get_bom_with_dependencies_hanging,
-    get_bom_with_dependencies_valid,
-    get_bom_with_external_references,
-    get_bom_with_metadata_component_and_dependencies,
-    get_bom_with_nested_services,
-    get_bom_with_services_complex,
-    get_bom_with_services_simple,
-)
-
-RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
+from cyclonedx.validation.xml import XmlValidator
+from tests import SnapshotMixin, mksname, uuid_generator
+from tests._data.models import all_get_bom_funct_invalid, all_get_bom_funct_valid
 
 
 @ddt
-@patch('cyclonedx.model.ThisTool._version', 'TESTING')
-class TestOutputXml(BaseXmlTestCase):
-
-    def test_bom_external_references_v1_4(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_external_references.xml'
-        )
-
-    def test_bom_external_references_v1_3(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_external_references.xml'
-        )
-
-    def test_bom_external_references_v1_2(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_external_references.xml'
-        )
-
-    def test_bom_external_references_v1_1(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_external_references.xml'
-        )
-
-    def test_bom_external_references_v1_0(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_external_references(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_empty.xml'
-        )
-
-    def test_simple_bom_v1_4(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools.xml'
-        )
-
-    def test_simple_bom_v1_3(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.xml'
-        )
-
-    def test_simple_bom_v1_2(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools.xml'
-        )
-
-    def test_simple_bom_v1_1(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools.xml'
-        )
-
-    def test_simple_bom_v1_0(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_basic(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools.xml'
-        )
-
-    def test_simple_bom_v1_4_with_cpe(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-
-    def test_simple_bom_v1_3_with_cpe(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-
-    def test_simple_bom_v1_2_with_cpe(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-
-    def test_simple_bom_v1_1_with_cpe(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-
-    def test_simple_bom_v1_0_with_cpe(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_cpe(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools_with_cpe.xml'
-        )
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    def test_bom_v1_4_full_component(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    def test_bom_v1_3_full_component(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_2))
-    def test_bom_v1_2_full_component(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_1))
-    def test_bom_v1_1_full_component(self, mock_uuid: Mock) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools_complete.xml'
-        )
-        mock_uuid.assert_called()
-
-    def test_bom_v1_0_full_component(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools_complete.xml'
-        )
-
-    def test_bom_v1_4_component_hashes_external_references(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-
-    def test_bom_v1_3_component_hashes_external_references(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-
-    def test_bom_v1_2_component_hashes_external_references(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-
-    def test_bom_v1_1_component_hashes_external_references(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-
-    def test_bom_v1_0_component_hashes_external_references(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_toml_1(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_toml_hashes_and_references.xml'
-        )
-
-    def test_bom_v1_4_no_component_version(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_no_version.xml'
-        )
-
-    def test_bom_v1_3_no_component_version(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools_no_version.xml'
-        )
-
-    def test_bom_v1_2_no_component_version(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_setuptools_no_version.xml'
-        )
-
-    def test_bom_v1_1_no_component_version(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_setuptools_no_version.xml'
-        )
-
-    def test_bom_v1_0_no_component_version(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_no_component_version(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools_no_version.xml'
-        )
-
-    def test_bom_v1_4_component_with_release_notes(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_release_notes(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_release_notes.xml'
-        )
-
-    def test_bom_v1_3_component_with_release_notes(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_release_notes(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_setuptools.xml'
-        )
-
-    def test_bom_v1_4_component_with_vulnerability(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_setuptools_with_vulnerabilities.xml'
-        )
-
-    def test_bom_v1_0_component_with_vulnerability(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_component_setuptools_with_vulnerability(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_setuptools.xml'
-        )
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    def test_bom_v1_4_with_metadata_component(self, mock_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_with_full_metadata.xml'
-            )
-            mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_5))
-    def test_bom_v1_3_with_metadata_component(self, mock_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_with_full_metadata.xml'
-            )
-            mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    def test_bom_v1_2_with_metadata_component(self, mock_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_with_full_metadata.xml'
-            )
-            mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=UUID(MOCK_UUID_1))
-    def test_bom_v1_1_with_metadata_component(self, mock_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_1,
-                fixture='bom_empty.xml'
-            )
-            mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.bom.uuid4', return_value=UUID(MOCK_UUID_1))
-    def test_bom_v1_0_with_metadata_component(self, mock_uuid: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_0,
-                fixture='bom_empty.xml'
-            )
-            mock_uuid.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_simple(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_simple.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_simple(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_simple.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_simple(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_simple.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_1_services_simple(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_1,
-                fixture='bom_empty.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_3))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_0_services_simple(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_0,
-                fixture='bom_empty.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_complex(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_complex.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_complex(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_complex.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_4))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_complex(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_complex.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_2))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_1_services_complex(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_1,
-                fixture='bom_empty.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_4_services_nested(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_services_nested.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_3_services_nested(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_3,
-                fixture='bom_services_nested.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    @patch('cyclonedx.model.component.uuid4', return_value=UUID(MOCK_UUID_6))
-    @patch('cyclonedx.model.service.uuid4', side_effect=TEST_UUIDS)
-    def test_bom_v1_2_services_nested(self, mock_1: Mock, mock_2: Mock) -> None:
-        with self.assertWarns(UserWarning):
-            self._validate_xml_bom(
-                bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_2,
-                fixture='bom_services_nested.xml'
-            )
-            mock_1.assert_called()
-            mock_2.assert_called()
-
-    def test_bom_v1_4_dependencies(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_dependencies.xml'
-        )
-
-    def test_bom_v1_3_dependencies(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_dependencies.xml'
-        )
-
-    def test_bom_v1_2_dependencies(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_dependencies.xml'
-        )
-
-    def test_bom_v1_1_dependencies(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_dependencies_valid(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_dependencies.xml'
-        )
-
-    def test_bom_v1_4_dependencies_for_bom_component(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_dependencies_component.xml'
-        )
-
-    def test_bom_v1_3_dependencies_for_bom_component(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_dependencies_component.xml'
-        )
-
-    def test_bom_v1_2_dependencies_for_bom_component(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_with_metadata_component_and_dependencies(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_dependencies_component.xml'
-        )
-
-    def test_bom_v1_4_issue_275_components(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_4,
-            fixture='bom_issue_275_components.xml'
-        )
-
-    def test_bom_v1_3_issue_275_components(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_3,
-            fixture='bom_issue_275_components.xml'
-        )
-
-    def test_bom_v1_2_issue_275_components(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_2,
-            fixture='bom_issue_275_components.xml'
-        )
-
-    def test_bom_v1_1_issue_275_components(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_1,
-            fixture='bom_issue_275_components.xml'
-        )
-
-    def test_bom_v1_0_issue_275_components(self) -> None:
-        self._validate_xml_bom(
-            bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_0,
-            fixture='bom_issue_275_components.xml'
-        )
-
-    def test_bom_v1_4_warn_dependencies(self) -> None:
-        with self.assertWarns(UserWarning):
-            # this data set is expected to throw this UserWarning.
-            # that is the while point of this test!
-            self._validate_xml_bom(
-                bom=get_bom_with_dependencies_hanging(), schema_version=SchemaVersion.V1_4,
-                fixture='bom_with_dependencies_hanging.xml'
-            )
-
-    @named_data(
-        ('None', 'None', None),
-        ('two', 'two', 2),
-        ('4spaces', '4spaces', '    '),
-        ('tab', 'tab', '\t')
-    )
-    def test_indent(self, name: str, indent: Optional[Union[str, int]]) -> None:
-        bom = get_bom_with_component_setuptools_basic()
-        bom.serial_number = MOCK_BOM_UUID_1
-        bom.metadata.timestamp = MOCK_TIMESTAMP
-        schema_version = SchemaVersion.V1_4
-        outputter = get_outputter(bom=bom, schema_version=schema_version, output_format=OutputFormat.XML)
-        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), f'indented_{name}.xml')
-                  ) as expected_xml:
-            bom_xml = outputter.output_as_string(indent=indent)
-            self.assertEqual(expected_xml.read(), bom_xml)
-            self.assertValidAgainstSchema(bom_xml=bom_xml, schema_version=schema_version)
-
-    # region Helper methods
-
-    def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None:
-        outputter = get_outputter(bom=bom, schema_version=schema_version)
-        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as expected_xml:
-            output_as_string = outputter.output_as_string()
-            self.assertValidAgainstSchema(bom_xml=output_as_string, schema_version=schema_version)
-            self.assertEqualXmlBom(
-                expected_xml.read(), output_as_string, namespace=outputter.get_target_namespace()
-            )
-
-    # endregion Helper methods
+class TestOutputXml(TestCase, SnapshotMixin):
+
+    @named_data(*(
+        (f'{n}-{sv.to_version()}', gb, sv) for n, gb in all_get_bom_funct_valid for sv in SchemaVersion
+    ))
+    @unpack
+    @patch('cyclonedx.model.ThisTool._version', 'TESTING')
+    @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
+    def test_valid(self, get_bom: Callable[[], Bom], sv: SchemaVersion, *_: Any, **__: Any) -> None:
+        snapshot_name = mksname(get_bom, sv, OutputFormat.XML)
+        bom = get_bom()
+        xml = BY_SCHEMA_VERSION[sv](bom).output_as_string(indent=2)
+        try:
+            errors = XmlValidator(sv).validate_str(xml)
+        except MissingOptionalDependencyException:
+            errors = None  # skipped validation
+        self.assertIsNone(errors)
+        self.assertEqualSnapshot(xml, snapshot_name)
+
+    @named_data(*(
+        (f'{n}-{sv.to_version()}', gb, sv) for n, gb in all_get_bom_funct_invalid for sv in SchemaVersion
+    ))
+    @unpack
+    def test_invalid(self, get_bom: Callable[[], Bom], sv: SchemaVersion) -> None:
+        bom = get_bom()
+        outputter = BY_SCHEMA_VERSION[sv](bom)
+        with self.assertRaises(CycloneDxException) as error:
+            outputter.output_as_string()
+        if isinstance(error.exception, (
+            LicenseExpressionAlongWithOthersException,
+            UnknownComponentDependencyException,
+        )):
+            return None  # expected
+        raise error.exception
 
 
 @ddt
diff --git a/tests/test_real_world_examples.py b/tests/test_real_world_examples.py
index 795e38f4c..c3351909f 100644
--- a/tests/test_real_world_examples.py
+++ b/tests/test_real_world_examples.py
@@ -18,29 +18,17 @@
 import unittest
 from datetime import datetime
 from os.path import join
-from typing import cast
+from typing import Any
 from unittest.mock import patch
 
 from cyclonedx.model.bom import Bom
-from cyclonedx.schema import SchemaVersion
-from tests import TESTDATA_DIRECTORY
-
-RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'own', 'xml')
-
-
-def fixed_date_time() -> datetime:
-    return datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
+from tests import OWN_DATA_DIRECTORY
 
 
 @patch('cyclonedx.model.ThisTool._version', 'TESTING')
-@patch('cyclonedx.model.bom.get_now_utc', fixed_date_time)
+@patch('cyclonedx.model.bom.get_now_utc', return_value=datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00'))
 class TestDeserializeeRealWorldExamples(unittest.TestCase):
 
-    def test_webgoat_6_1(self) -> None:
-        self._attempt_load_example(
-            schema_version=SchemaVersion.V1_4, fixture='webgoat-6.1.xml'
-        )
-
-    def _attempt_load_example(self, schema_version: SchemaVersion, fixture: str) -> None:
-        with open(join(RELEVANT_TESTDATA_DIRECTORY, schema_version.to_version(), fixture)) as input_xml:
-            cast(Bom, Bom.from_xml(input_xml))
+    def test_webgoat_6_1(self, *_: Any, **__: Any) -> None:
+        with open(join(OWN_DATA_DIRECTORY, 'xml', '1.4', 'webgoat-6.1.xml')) as input_xml:
+            Bom.from_xml(input_xml)
diff --git a/tests/test_validation_json.py b/tests/test_validation_json.py
index 45f06179e..db639a1f3 100644
--- a/tests/test_validation_json.py
+++ b/tests/test_validation_json.py
@@ -25,17 +25,15 @@
 from cyclonedx.exception import MissingOptionalDependencyException
 from cyclonedx.schema import OutputFormat, SchemaVersion
 from cyclonedx.validation.json import JsonStrictValidator, JsonValidator
-from tests import TESTDATA_DIRECTORY
+from tests import SCHEMA_TESTDATA_DIRECTORY
 
-RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'schemaTestData')
-
-UNSUPPORTED_SCHEMA_VERSIONS = (SchemaVersion.V1_0, SchemaVersion.V1_1,)
+UNSUPPORTED_SCHEMA_VERSIONS = {SchemaVersion.V1_0, SchemaVersion.V1_1, }
 
 
 def _dp(prefix: str) -> Generator:
     return (
         (sv, tf) for sv in SchemaVersion if sv not in UNSUPPORTED_SCHEMA_VERSIONS
-        for tf in iglob(join(RELEVANT_TESTDATA_DIRECTORY, sv.to_version(), f'{prefix}-*.json'))
+        for tf in iglob(join(SCHEMA_TESTDATA_DIRECTORY, sv.to_version(), f'{prefix}-*.json'))
     )
 
 
diff --git a/tests/test_validation_xml.py b/tests/test_validation_xml.py
index a08c932d7..c97ee6f7e 100644
--- a/tests/test_validation_xml.py
+++ b/tests/test_validation_xml.py
@@ -25,9 +25,7 @@
 from cyclonedx.exception import MissingOptionalDependencyException
 from cyclonedx.schema import OutputFormat, SchemaVersion
 from cyclonedx.validation.xml import XmlValidator
-from tests import TESTDATA_DIRECTORY
-
-RELEVANT_TESTDATA_DIRECTORY = join(TESTDATA_DIRECTORY, 'schemaTestData')
+from tests import SCHEMA_TESTDATA_DIRECTORY
 
 UNSUPPORTED_SCHEMA_VERSIONS = set()
 
@@ -35,7 +33,7 @@
 def _dp(prefix: str) -> Generator:
     return (
         (sv, tf) for sv in SchemaVersion if sv not in UNSUPPORTED_SCHEMA_VERSIONS
-        for tf in iglob(join(RELEVANT_TESTDATA_DIRECTORY, sv.to_version(), f'{prefix}-*.xml'))
+        for tf in iglob(join(SCHEMA_TESTDATA_DIRECTORY, sv.to_version(), f'{prefix}-*.xml'))
     )
 
 

From 1e963bd3d7e6c7d9437e41a34ecd622e0d32f3d8 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Mon, 9 Oct 2023 10:32:47 +0200
Subject: [PATCH 24/42] chore: revisit license headers

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/__init__.py               | 2 ++
 cyclonedx/exception/__init__.py     | 3 ++-
 cyclonedx/exception/factory.py      | 3 ++-
 cyclonedx/exception/model.py        | 3 ++-
 cyclonedx/exception/output.py       | 3 ++-
 cyclonedx/model/bom.py              | 2 ++
 cyclonedx/output/__init__.py        | 2 ++
 cyclonedx/parser/__init__.py        | 2 ++
 cyclonedx/schema/__init__.py        | 2 ++
 cyclonedx/schema/_res/__init__.py   | 2 ++
 cyclonedx/serialization/__init__.py | 2 ++
 cyclonedx/spdx.py                   | 2 ++
 cyclonedx/validation/__init__.py    | 2 ++
 cyclonedx/validation/json.py        | 2 ++
 cyclonedx/validation/xml.py         | 2 ++
 typings/sortedcontainers.pyi        | 5 ++---
 16 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/cyclonedx/__init__.py b/cyclonedx/__init__.py
index 449a92d85..d51cb1fac 100644
--- a/cyclonedx/__init__.py
+++ b/cyclonedx/__init__.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 """
 Python library for generating and representing CycloneDX software bill-of-materials.
diff --git a/cyclonedx/exception/__init__.py b/cyclonedx/exception/__init__.py
index 72752a732..868373fda 100644
--- a/cyclonedx/exception/__init__.py
+++ b/cyclonedx/exception/__init__.py
@@ -11,7 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
-#
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 """
 Exceptions that are specific to the CycloneDX library implementation.
diff --git a/cyclonedx/exception/factory.py b/cyclonedx/exception/factory.py
index 5211f9e83..322e1fc37 100644
--- a/cyclonedx/exception/factory.py
+++ b/cyclonedx/exception/factory.py
@@ -11,7 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
-#
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 """
 Exceptions relating to specific conditions that occur when factoring a model.
diff --git a/cyclonedx/exception/model.py b/cyclonedx/exception/model.py
index 5481983c9..05633e245 100644
--- a/cyclonedx/exception/model.py
+++ b/cyclonedx/exception/model.py
@@ -11,7 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
-#
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 """
 Exceptions relating to specific conditions that occur when modelling CycloneDX BOM.
diff --git a/cyclonedx/exception/output.py b/cyclonedx/exception/output.py
index 7bdf45ce1..c3109f13b 100644
--- a/cyclonedx/exception/output.py
+++ b/cyclonedx/exception/output.py
@@ -11,7 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
-#
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 """
 Exceptions that are for specific error scenarios during the output of a Model to a SBOM.
diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
index a46708572..f3c2a840e 100644
--- a/cyclonedx/model/bom.py
+++ b/cyclonedx/model/bom.py
@@ -14,6 +14,8 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
+
+
 import warnings
 from datetime import datetime
 from itertools import chain
diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index fde15bc1d..72126fbd3 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 """
 Set of classes and methods for outputting our libraries internal Bom model to CycloneDX documents in varying formats
diff --git a/cyclonedx/parser/__init__.py b/cyclonedx/parser/__init__.py
index c69cdf1c2..6fdded1eb 100644
--- a/cyclonedx/parser/__init__.py
+++ b/cyclonedx/parser/__init__.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 """
 Set of classes and methods which allow for quick creation of a Bom instance from your environment or Python project.
diff --git a/cyclonedx/schema/__init__.py b/cyclonedx/schema/__init__.py
index ef2a696fe..f0e38b05b 100644
--- a/cyclonedx/schema/__init__.py
+++ b/cyclonedx/schema/__init__.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 from enum import Enum, auto, unique
 from typing import Any, Type, TypeVar
diff --git a/cyclonedx/schema/_res/__init__.py b/cyclonedx/schema/_res/__init__.py
index 8089d9432..d33cf6955 100644
--- a/cyclonedx/schema/_res/__init__.py
+++ b/cyclonedx/schema/_res/__init__.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 from os.path import dirname, join
 from typing import Dict, Optional
diff --git a/cyclonedx/serialization/__init__.py b/cyclonedx/serialization/__init__.py
index 925dd4d45..094b57f83 100644
--- a/cyclonedx/serialization/__init__.py
+++ b/cyclonedx/serialization/__init__.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 """
 Set of helper classes for use with ``serializable`` when conducting (de-)serialization.
diff --git a/cyclonedx/spdx.py b/cyclonedx/spdx.py
index b7dfe0522..98808d690 100644
--- a/cyclonedx/spdx.py
+++ b/cyclonedx/spdx.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 __all__ = [
     'is_supported_id', 'fixup_id',
diff --git a/cyclonedx/validation/__init__.py b/cyclonedx/validation/__init__.py
index 87f183354..fe0c34324 100644
--- a/cyclonedx/validation/__init__.py
+++ b/cyclonedx/validation/__init__.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 from abc import ABC, abstractmethod
 from importlib import import_module
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
index 721dd5d7d..3e6b38cbb 100644
--- a/cyclonedx/validation/json.py
+++ b/cyclonedx/validation/json.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 __all__ = ['JsonValidator', 'JsonStrictValidator']
 
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index 6da23b2a7..0c65ffd10 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -11,6 +11,8 @@
 # limitations under the License.
 #
 # SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
 
 __all__ = ['XmlValidator']
 
diff --git a/typings/sortedcontainers.pyi b/typings/sortedcontainers.pyi
index b8e8b6f6c..c91678374 100644
--- a/typings/sortedcontainers.pyi
+++ b/typings/sortedcontainers.pyi
@@ -1,9 +1,9 @@
 # Correct as of 27 May 2022
 # sortedcontainers does not have PEP561 type hints, and there are no published typeshed hints.
-# The contents of this file were obtained from 
+# The contents of this file were obtained from
 #  https://github.com/althonos/python-sortedcontainers/blob/d0a225d7fd0fb4c54532b8798af3cbeebf97e2d5/sortedcontainers/sortedset.pyi
 
-from typing import (  # Iterator,; Tuple,; Type,
+from typing import (  # Iterator,; Tuple,; Type, Set
     Any,
     Callable,
     Hashable,
@@ -12,7 +12,6 @@ from typing import (  # Iterator,; Tuple,; Type,
     MutableSet,
     Optional,
     Sequence,
-    Set,
     TypeVar,
     Union,
     overload,

From 67707864ac0f1b27bac166a8fd537ea38523fe6f Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Tue, 10 Oct 2023 19:43:36 +0200
Subject: [PATCH 25/42] fix: multiple licenses issue #365 (#466)

breaking changes
------------------
* Reworked license related models and collections
* API
  * Removed class `factory.license.LicenseChoiceFactory`
    The old functionality was integrated into `factory.license.LicenseFactory`.
  * Method `factory.license.LicenseFactory.make_from_string()`'s parameter `name_or_spdx` was renamed to `value`
  * Method `factory.license.LicenseFactory.make_from_string()`'s return value can also be a `LicenseExpression`
    The behavior imitates the old `factory.license.LicenseChoiceFactory.make_from_string()`
  * Renamed class `module.License` to `module.license.DisjunctliveLicense`
  * Removed class `module.LicenseChoice`
    Use dedicated classes `module.license.DisjunctliveLicense` and `module.license.LicenseExpression` instead
  * All occurrences of `models.LicenseChoice` were replaced by `models.licenses.License`
  * All occurrences of `SortedSet[LicenseChoice]` were specialized to `models.license.LicenseRepository`


fixes
------------------
* serialization of multy-licenses #365

added
------------------
* API
  * Method `factory.license.LicenseFactory.make_with_expression()`
  * Class `model.license.DisjunctiveLicense`
  * Class `model.license.LicenseExpression`
  * Class `model.license.LicenseRepository`
  * Class `serialization.LicenseRepositoryHelper`

tests
------------------
* added regression test for bug #365

misc
------------------
* raised dependency `py-serializable@^9.15`



----

fixes #365

~~BLOCKED by a feature request to serializer: <https://github.com/madpah/serializable/pull/32>~~


---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/factory/license.py                  |  91 +++----
 cyclonedx/model/__init__.py                   | 184 +-------------
 cyclonedx/model/bom.py                        |  27 +--
 cyclonedx/model/component.py                  |  26 +-
 cyclonedx/model/dependency.py                 |   4 +-
 cyclonedx/model/license.py                    | 224 ++++++++++++++++++
 cyclonedx/model/service.py                    |  23 +-
 cyclonedx/schema/_res/__init__.py             |  11 +-
 cyclonedx/serialization/__init__.py           |  85 ++++++-
 docs/conf.py                                  |   2 +-
 examples/complex.py                           |   4 +-
 pyproject.toml                                |   2 +-
 tests/_data/models.py                         |  90 +++++--
 ...et_bom_just_complete_metadata-1.2.json.bin |  24 +-
 ...get_bom_just_complete_metadata-1.2.xml.bin |  24 +-
 ...et_bom_just_complete_metadata-1.3.json.bin |  24 +-
 ...get_bom_just_complete_metadata-1.3.xml.bin |  24 +-
 ...et_bom_just_complete_metadata-1.4.json.bin |  24 +-
 ...get_bom_just_complete_metadata-1.4.xml.bin |  24 +-
 ...ith_component_setuptools_basic-1.1.xml.bin |   4 +-
 ...th_component_setuptools_basic-1.2.json.bin |   4 +-
 ...ith_component_setuptools_basic-1.2.xml.bin |   4 +-
 ...th_component_setuptools_basic-1.3.json.bin |   4 +-
 ...ith_component_setuptools_basic-1.3.xml.bin |   4 +-
 ...th_component_setuptools_basic-1.4.json.bin |   4 +-
 ...ith_component_setuptools_basic-1.4.xml.bin |   4 +-
 ..._component_setuptools_complete-1.1.xml.bin |  24 +-
 ...component_setuptools_complete-1.2.json.bin |  24 +-
 ..._component_setuptools_complete-1.2.xml.bin |  24 +-
 ...component_setuptools_complete-1.3.json.bin |  24 +-
 ..._component_setuptools_complete-1.3.xml.bin |  24 +-
 ...component_setuptools_complete-1.4.json.bin |  24 +-
 ..._component_setuptools_complete-1.4.xml.bin |  24 +-
 ...etuptools_no_component_version-1.1.xml.bin |   4 +-
 ...tuptools_no_component_version-1.2.json.bin |   4 +-
 ...etuptools_no_component_version-1.2.xml.bin |   4 +-
 ...tuptools_no_component_version-1.3.json.bin |   4 +-
 ...etuptools_no_component_version-1.3.xml.bin |   4 +-
 ...tuptools_no_component_version-1.4.json.bin |   4 +-
 ...etuptools_no_component_version-1.4.xml.bin |   4 +-
 ..._component_setuptools_with_cpe-1.1.xml.bin |   4 +-
 ...component_setuptools_with_cpe-1.2.json.bin |   4 +-
 ..._component_setuptools_with_cpe-1.2.xml.bin |   4 +-
 ...component_setuptools_with_cpe-1.3.json.bin |   4 +-
 ..._component_setuptools_with_cpe-1.3.xml.bin |   4 +-
 ...component_setuptools_with_cpe-1.4.json.bin |   4 +-
 ..._component_setuptools_with_cpe-1.4.xml.bin |   4 +-
 ..._setuptools_with_release_notes-1.1.xml.bin |   4 +-
 ...setuptools_with_release_notes-1.2.json.bin |   4 +-
 ..._setuptools_with_release_notes-1.2.xml.bin |   4 +-
 ...setuptools_with_release_notes-1.3.json.bin |   4 +-
 ..._setuptools_with_release_notes-1.3.xml.bin |   4 +-
 ...setuptools_with_release_notes-1.4.json.bin |   4 +-
 ..._setuptools_with_release_notes-1.4.xml.bin |   4 +-
 ..._setuptools_with_vulnerability-1.1.xml.bin |   4 +-
 ...setuptools_with_vulnerability-1.2.json.bin |   4 +-
 ..._setuptools_with_vulnerability-1.2.xml.bin |   4 +-
 ...setuptools_with_vulnerability-1.3.json.bin |   4 +-
 ..._setuptools_with_vulnerability-1.3.xml.bin |   4 +-
 ...setuptools_with_vulnerability-1.4.json.bin |   4 +-
 ..._setuptools_with_vulnerability-1.4.xml.bin |   4 +-
 ..._bom_with_dependencies_hanging-1.1.xml.bin |   4 +-
 ...bom_with_dependencies_hanging-1.2.json.bin |   4 +-
 ..._bom_with_dependencies_hanging-1.2.xml.bin |   4 +-
 ...bom_with_dependencies_hanging-1.3.json.bin |   4 +-
 ..._bom_with_dependencies_hanging-1.3.xml.bin |   4 +-
 ...bom_with_dependencies_hanging-1.4.json.bin |   4 +-
 ..._bom_with_dependencies_hanging-1.4.xml.bin |   4 +-
 ...et_bom_with_dependencies_valid-1.1.xml.bin |   4 +-
 ...t_bom_with_dependencies_valid-1.2.json.bin |   4 +-
 ...et_bom_with_dependencies_valid-1.2.xml.bin |   4 +-
 ...t_bom_with_dependencies_valid-1.3.json.bin |   4 +-
 ...et_bom_with_dependencies_valid-1.3.xml.bin |   4 +-
 ...t_bom_with_dependencies_valid-1.4.json.bin |   4 +-
 ...et_bom_with_dependencies_valid-1.4.xml.bin |   4 +-
 .../get_bom_with_licenses-1.0.xml.bin         |  20 ++
 .../get_bom_with_licenses-1.1.xml.bin         |  30 +++
 .../get_bom_with_licenses-1.2.json.bin        | 125 ++++++++++
 .../get_bom_with_licenses-1.2.xml.bin         |  82 +++++++
 .../get_bom_with_licenses-1.3.json.bin        | 132 +++++++++++
 .../get_bom_with_licenses-1.3.xml.bin         |  87 +++++++
 .../get_bom_with_licenses-1.4.json.bin        | 162 +++++++++++++
 .../get_bom_with_licenses-1.4.xml.bin         | 109 +++++++++
 ...t_bom_with_licenses_expression-1.0.xml.bin |   4 +
 ...t_bom_with_licenses_expression-1.1.xml.bin |   4 +
 ..._bom_with_licenses_expression-1.2.json.bin |  17 ++
 ...t_bom_with_licenses_expression-1.2.xml.bin |  13 +
 ..._bom_with_licenses_expression-1.3.json.bin |  22 ++
 ...t_bom_with_licenses_expression-1.3.xml.bin |  16 ++
 ..._bom_with_licenses_expression-1.4.json.bin |  56 +++++
 ...t_bom_with_licenses_expression-1.4.xml.bin |  42 ++++
 ...ta_component_and_dependencies-1.2.json.bin |   4 +-
 ...ata_component_and_dependencies-1.2.xml.bin |   4 +-
 ...ta_component_and_dependencies-1.3.json.bin |   4 +-
 ...ata_component_and_dependencies-1.3.xml.bin |   4 +-
 ...ta_component_and_dependencies-1.4.json.bin |   4 +-
 ...ata_component_and_dependencies-1.4.xml.bin |   4 +-
 ...get_bom_with_multiple_licenses-1.0.xml.bin |  10 +
 ...get_bom_with_multiple_licenses-1.1.xml.bin |  17 ++
 ...et_bom_with_multiple_licenses-1.2.json.bin |  84 +++++++
 ...get_bom_with_multiple_licenses-1.2.xml.bin |  57 +++++
 ...et_bom_with_multiple_licenses-1.3.json.bin |  96 ++++++++
 ...get_bom_with_multiple_licenses-1.3.xml.bin |  65 +++++
 ...et_bom_with_multiple_licenses-1.4.json.bin | 128 ++++++++++
 ...get_bom_with_multiple_licenses-1.4.xml.bin |  89 +++++++
 .../get_bom_with_nested_services-1.2.json.bin |   4 +-
 .../get_bom_with_nested_services-1.2.xml.bin  |   4 +-
 .../get_bom_with_nested_services-1.3.json.bin |   4 +-
 .../get_bom_with_nested_services-1.3.xml.bin  |   4 +-
 .../get_bom_with_nested_services-1.4.json.bin |   4 +-
 .../get_bom_with_nested_services-1.4.xml.bin  |   4 +-
 ...get_bom_with_services_complex-1.2.json.bin |   4 +-
 .../get_bom_with_services_complex-1.2.xml.bin |   4 +-
 ...get_bom_with_services_complex-1.3.json.bin |   4 +-
 .../get_bom_with_services_complex-1.3.xml.bin |   4 +-
 ...get_bom_with_services_complex-1.4.json.bin |   4 +-
 .../get_bom_with_services_complex-1.4.xml.bin |   4 +-
 tests/test_factory_license.py                 | 109 +++------
 tests/test_model.py                           |  37 ---
 tests/test_model_bom.py                       |  15 +-
 tests/test_model_license.py                   | 117 +++++++++
 121 files changed, 2504 insertions(+), 594 deletions(-)
 create mode 100644 cyclonedx/model/license.py
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses-1.1.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses-1.2.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses-1.2.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses-1.3.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses-1.3.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses-1.4.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses_expression-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses_expression-1.1.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses_expression-1.2.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses_expression-1.2.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses_expression-1.3.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses_expression-1.3.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses_expression-1.4.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_licenses_expression-1.4.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_multiple_licenses-1.0.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_multiple_licenses-1.1.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_multiple_licenses-1.2.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_multiple_licenses-1.2.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_multiple_licenses-1.3.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_multiple_licenses-1.3.xml.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_multiple_licenses-1.4.json.bin
 create mode 100644 tests/_data/snapshots/get_bom_with_multiple_licenses-1.4.xml.bin
 create mode 100644 tests/test_model_license.py

diff --git a/cyclonedx/factory/license.py b/cyclonedx/factory/license.py
index 9974c0462..d6446569a 100644
--- a/cyclonedx/factory/license.py
+++ b/cyclonedx/factory/license.py
@@ -13,76 +13,59 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
-from typing import Optional
+from typing import TYPE_CHECKING, Optional
 
 from ..exception.factory import InvalidLicenseExpressionException, InvalidSpdxLicenseException
-from ..model import AttachedText, License, LicenseChoice, XsUri
+from ..model.license import DisjunctiveLicense, LicenseExpression
 from ..spdx import fixup_id as spdx_fixup, is_compound_expression as is_spdx_compound_expression
 
+if TYPE_CHECKING:  # pragma: no cover
+    from ..model import AttachedText, XsUri
+    from ..model.license import License
 
-class LicenseFactory:
-    """Factory for :class:`cyclonedx.model.License`."""
-
-    def make_from_string(self, name_or_spdx: str, *,
-                         license_text: Optional[AttachedText] = None,
-                         license_url: Optional[XsUri] = None) -> License:
-        """Make a :class:`cyclonedx.model.License` from a string."""
-        try:
-            return self.make_with_id(name_or_spdx, text=license_text, url=license_url)
-        except InvalidSpdxLicenseException:
-            return self.make_with_name(name_or_spdx, text=license_text, url=license_url)
-
-    def make_with_id(self, spdx_id: str, *, text: Optional[AttachedText] = None,
-                     url: Optional[XsUri] = None) -> License:
-        """Make a :class:`cyclonedx.model.License` from an SPDX-ID.
-
-        :raises InvalidSpdxLicenseException: if `spdx_id` was not known/supported SPDX-ID
-        """
-        spdx_license_id = spdx_fixup(spdx_id)
-        if spdx_license_id is None:
-            raise InvalidSpdxLicenseException(spdx_id)
-        return License(id=spdx_license_id, text=text, url=url)
-
-    def make_with_name(self, name: str, *, text: Optional[AttachedText] = None, url: Optional[XsUri] = None) -> License:
-        """Make a :class:`cyclonedx.model.License` with a name."""
-        return License(name=name, text=text, url=url)
 
+class LicenseFactory:
+    """Factory for :class:`cyclonedx.model.license.License`."""
 
-class LicenseChoiceFactory:
-    """Factory for :class:`cyclonedx.model.LicenseChoice`."""
-
-    def __init__(self, *, license_factory: LicenseFactory) -> None:
-        self.license_factory = license_factory
-
-    def make_from_string(self, expression_or_name_or_spdx: str) -> LicenseChoice:
-        """Make a :class:`cyclonedx.model.LicenseChoice` from a string.
-
-        Priority: SPDX license ID, SPDX license expression, named license
-        """
+    def make_from_string(self, value: str, *,
+                         license_text: Optional['AttachedText'] = None,
+                         license_url: Optional['XsUri'] = None) -> 'License':
+        """Make a :class:`cyclonedx.model.license.License` from a string."""
         try:
-            return LicenseChoice(license=self.license_factory.make_with_id(expression_or_name_or_spdx))
+            return self.make_with_id(value, text=license_text, url=license_url)
         except InvalidSpdxLicenseException:
             pass
         try:
-            return self.make_with_compound_expression(expression_or_name_or_spdx)
+            return self.make_with_expression(value)
         except InvalidLicenseExpressionException:
             pass
-        return LicenseChoice(license=self.license_factory.make_with_name(expression_or_name_or_spdx))
+        return self.make_with_name(value, text=license_text, url=license_url)
 
-    def make_with_compound_expression(self, compound_expression: str) -> LicenseChoice:
-        """Make a :class:`cyclonedx.model.LicenseChoice` with a compound expression.
+    def make_with_expression(self, expression: str) -> LicenseExpression:
+        """Make a :class:`cyclonedx.model.license.LicenseExpression` with a compound expression.
 
         Utilizes :func:`cyclonedx.spdx.is_compound_expression`.
 
-        :raises InvalidLicenseExpressionException: if `expression` is not known/supported license expression
+        :raises InvalidLicenseExpressionException: if param `value` is not known/supported license expression
         """
-        if is_spdx_compound_expression(compound_expression):
-            return LicenseChoice(expression=compound_expression)
-        raise InvalidLicenseExpressionException(compound_expression)
+        if is_spdx_compound_expression(expression):
+            return LicenseExpression(expression)
+        raise InvalidLicenseExpressionException(expression)
+
+    def make_with_id(self, spdx_id: str, *,
+                     text: Optional['AttachedText'] = None,
+                     url: Optional['XsUri'] = None) -> DisjunctiveLicense:
+        """Make a :class:`cyclonedx.model.license.DisjunctiveLicense` from an SPDX-ID.
+
+        :raises InvalidSpdxLicenseException: if param `spdx_id` was not known/supported SPDX-ID
+        """
+        spdx_license_id = spdx_fixup(spdx_id)
+        if spdx_license_id is None:
+            raise InvalidSpdxLicenseException(spdx_id)
+        return DisjunctiveLicense(id=spdx_license_id, text=text, url=url)
 
-    def make_with_license(self, name_or_spdx: str, *,
-                          license_text: Optional[AttachedText] = None,
-                          license_url: Optional[XsUri] = None) -> LicenseChoice:
-        """Make a :class:`cyclonedx.model.LicenseChoice` with a license (name or SPDX-ID)."""
-        return LicenseChoice(license=self.license_factory.make_from_string(
-            name_or_spdx, license_text=license_text, license_url=license_url))
+    def make_with_name(self, name: str, *,
+                       text: Optional['AttachedText'] = None,
+                       url: Optional['XsUri'] = None) -> DisjunctiveLicense:
+        """Make a :class:`cyclonedx.model.license.DisjunctiveLicense` with a name."""
+        return DisjunctiveLicense(name=name, text=text, url=url)
diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
index 68ce6dc84..d30ad9613 100644
--- a/cyclonedx/model/__init__.py
+++ b/cyclonedx/model/__init__.py
@@ -15,7 +15,6 @@
 
 import hashlib
 import re
-import warnings
 from datetime import datetime, timezone
 from enum import Enum
 from itertools import zip_longest
@@ -28,7 +27,6 @@
 from ..exception.model import (
     InvalidLocaleTypeException,
     InvalidUriException,
-    MutuallyExclusivePropertiesException,
     NoPropertiesProvidedException,
     UnknownHashTypeException,
 )
@@ -444,20 +442,19 @@ def uri(self) -> str:
         return self._uri
 
     @classmethod
-    def serialize(cls, o: object) -> str:
+    def serialize(cls, o: Any) -> str:
         if isinstance(o, XsUri):
             return str(o)
-
         raise ValueError(f'Attempt to serialize a non-XsUri: {o.__class__}')
 
     @classmethod
-    def deserialize(cls, o: object) -> 'XsUri':
+    def deserialize(cls, o: Any) -> 'XsUri':
         try:
             return XsUri(uri=str(o))
         except ValueError:
             raise ValueError(f'XsUri string supplied ({o}) does not parse!')
 
-    def __eq__(self, other: object) -> bool:
+    def __eq__(self, other: Any) -> bool:
         if isinstance(other, XsUri):
             return hash(other) == hash(self)
         return False
@@ -579,181 +576,6 @@ def __repr__(self) -> str:
         return f'<ExternalReference {self.type.name}, {self.url}>'
 
 
-@serializable.serializable_class
-class License:
-    """
-    This is our internal representation of `licenseType` complex type that can be used in multiple places within
-    a CycloneDX BOM document.
-
-    .. note::
-        See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_licenseType
-    """
-
-    def __init__(self, *, id: Optional[str] = None, name: Optional[str] = None,
-                 text: Optional[AttachedText] = None, url: Optional[XsUri] = None) -> None:
-        if not id and not name:
-            raise MutuallyExclusivePropertiesException('Either `id` or `name` MUST be supplied')
-        if id and name:
-            warnings.warn(
-                'Both `id` and `name` have been supplied - `name` will be ignored!',
-                RuntimeWarning
-            )
-        self.id = id
-        if not id:
-            self.name = name
-        else:
-            self.name = None
-        self.text = text
-        self.url = url
-
-    @property
-    def id(self) -> Optional[str]:
-        """
-        A valid SPDX license ID
-
-        Returns:
-            `str` or `None`
-        """
-        return self._id
-
-    @id.setter
-    def id(self, id: Optional[str]) -> None:
-        self._id = id
-
-    @property
-    def name(self) -> Optional[str]:
-        """
-        If SPDX does not define the license used, this field may be used to provide the license name.
-
-        Returns:
-            `str` or `None`
-        """
-        return self._name
-
-    @name.setter
-    def name(self, name: Optional[str]) -> None:
-        self._name = name
-
-    @property
-    def text(self) -> Optional[AttachedText]:
-        """
-        Specifies the optional full text of the attachment
-
-        Returns:
-            `AttachedText` else `None`
-        """
-        return self._text
-
-    @text.setter
-    def text(self, text: Optional[AttachedText]) -> None:
-        self._text = text
-
-    @property
-    def url(self) -> Optional[XsUri]:
-        """
-        The URL to the attachment file. If the attachment is a license or BOM, an externalReference should also be
-        specified for completeness.
-
-        Returns:
-            `XsUri` or `None`
-        """
-        return self._url
-
-    @url.setter
-    def url(self, url: Optional[XsUri]) -> None:
-        self._url = url
-
-    def __eq__(self, other: object) -> bool:
-        if isinstance(other, License):
-            return hash(other) == hash(self)
-        return False
-
-    def __lt__(self, other: Any) -> bool:
-        if isinstance(other, License):
-            return ComparableTuple((self.id, self.name)) < ComparableTuple((other.id, other.name))
-        return NotImplemented
-
-    def __hash__(self) -> int:
-        return hash((self.id, self.name, self.text, self.url))
-
-    def __repr__(self) -> str:
-        return f'<License id={self.id}, name={self.name}>'
-
-
-@serializable.serializable_class
-class LicenseChoice:
-    """
-    This is our internal representation of `licenseChoiceType` complex type that can be used in multiple places within
-    a CycloneDX BOM document.
-
-    .. note::
-        See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_licenseChoiceType
-    """
-
-    def __init__(self, *, license: Optional[License] = None, expression: Optional[str] = None) -> None:
-        if not license and not expression:
-            raise NoPropertiesProvidedException(
-                'One of `license` or `expression` must be supplied - neither supplied'
-            )
-        if license and expression:
-            warnings.warn(
-                'Both `license` and `expression` have been supplied - `license` will take precedence',
-                RuntimeWarning
-            )
-        self.license = license
-        if not license:
-            self.expression = expression
-        else:
-            self.expression = None
-
-    @property
-    def license(self) -> Optional[License]:
-        """
-        License definition
-
-        Returns:
-            `License` or `None`
-        """
-        return self._license
-
-    @license.setter
-    def license(self, license: Optional[License]) -> None:
-        self._license = license
-
-    @property
-    def expression(self) -> Optional[str]:
-        """
-        A valid SPDX license expression (not enforced).
-
-        Refer to https://spdx.org/specifications for syntax requirements.
-
-        Returns:
-            `str` or `None`
-        """
-        return self._expression
-
-    @expression.setter
-    def expression(self, expression: Optional[str]) -> None:
-        self._expression = expression
-
-    def __eq__(self, other: object) -> bool:
-        if isinstance(other, LicenseChoice):
-            return hash(other) == hash(self)
-        return False
-
-    def __lt__(self, other: Any) -> bool:
-        if isinstance(other, LicenseChoice):
-            return ComparableTuple((self.license, self.expression)) < ComparableTuple(
-                (other.license, other.expression))
-        return NotImplemented
-
-    def __hash__(self) -> int:
-        return hash((self.license, self.expression))
-
-    def __repr__(self) -> str:
-        return f'<LicenseChoice license={self.license}, expression={self.expression}>'
-
-
 @serializable.serializable_class
 class Property:
     """
diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
index f3c2a840e..16c0d6c0c 100644
--- a/cyclonedx/model/bom.py
+++ b/cyclonedx/model/bom.py
@@ -25,8 +25,6 @@
 import serializable
 from sortedcontainers import SortedSet
 
-from cyclonedx.serialization import UrnUuidHelper
-
 from ..exception.model import LicenseExpressionAlongWithOthersException, UnknownComponentDependencyException
 from ..parser import BaseParser
 from ..schema.schema import (
@@ -36,19 +34,12 @@
     SchemaVersion1Dot3,
     SchemaVersion1Dot4,
 )
-from . import (
-    ExternalReference,
-    LicenseChoice,
-    OrganizationalContact,
-    OrganizationalEntity,
-    Property,
-    ThisTool,
-    Tool,
-    get_now_utc,
-)
+from ..serialization import LicenseRepositoryHelper, UrnUuidHelper
+from . import ExternalReference, OrganizationalContact, OrganizationalEntity, Property, ThisTool, Tool, get_now_utc
 from .bom_ref import BomRef
 from .component import Component
 from .dependency import Dependable, Dependency
+from .license import License, LicenseExpression, LicenseRepository
 from .service import Service
 from .vulnerability import Vulnerability
 
@@ -69,7 +60,7 @@ def __init__(self, *, tools: Optional[Iterable[Tool]] = None,
                  authors: Optional[Iterable[OrganizationalContact]] = None, component: Optional[Component] = None,
                  manufacture: Optional[OrganizationalEntity] = None,
                  supplier: Optional[OrganizationalEntity] = None,
-                 licenses: Optional[Iterable[LicenseChoice]] = None,
+                 licenses: Optional[Iterable[License]] = None,
                  properties: Optional[Iterable[Property]] = None,
                  timestamp: Optional[datetime] = None) -> None:
         self.timestamp = timestamp or get_now_utc()
@@ -196,9 +187,9 @@ def supplier(self, supplier: Optional[OrganizationalEntity]) -> None:
     @property
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
-    @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'licenses')
+    @serializable.type_mapping(LicenseRepositoryHelper)
     @serializable.xml_sequence(7)
-    def licenses(self) -> "SortedSet[LicenseChoice]":
+    def licenses(self) -> LicenseRepository:
         """
         A optional list of statements about how this BOM is licensed.
 
@@ -208,8 +199,8 @@ def licenses(self) -> "SortedSet[LicenseChoice]":
         return self._licenses
 
     @licenses.setter
-    def licenses(self, licenses: Iterable[LicenseChoice]) -> None:
-        self._licenses = SortedSet(licenses)
+    def licenses(self, licenses: Iterable[License]) -> None:
+        self._licenses = LicenseRepository(licenses)
 
     @property
     @serializable.view(SchemaVersion1Dot3)
@@ -585,7 +576,7 @@ def validate(self) -> bool:
             chain.from_iterable(c.get_all_nested_components(include_self=True) for c in self.components),
             self.services
         ):
-            if len(elem.licenses) > 1 and any(li.expression for li in elem.licenses):
+            if len(elem.licenses) > 1 and any(isinstance(li, LicenseExpression) for li in elem.licenses):
                 raise LicenseExpressionAlongWithOthersException(
                     f'Found LicenseExpression along with others licenses in: {elem!r}')
 
diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py
index 29e51eed5..bf8501a90 100644
--- a/cyclonedx/model/component.py
+++ b/cyclonedx/model/component.py
@@ -33,7 +33,7 @@
     SchemaVersion1Dot3,
     SchemaVersion1Dot4,
 )
-from ..serialization import BomRefHelper, PackageUrl
+from ..serialization import BomRefHelper, LicenseRepositoryHelper, PackageUrl
 from . import (
     AttachedText,
     ComparableTuple,
@@ -42,7 +42,6 @@
     HashAlgorithm,
     HashType,
     IdentifiableAction,
-    LicenseChoice,
     OrganizationalEntity,
     Property,
     XsUri,
@@ -51,6 +50,7 @@
 from .bom_ref import BomRef
 from .dependency import Dependable
 from .issue import IssueType
+from .license import License, LicenseExpression, LicenseRepository
 from .release_note import ReleaseNotes
 
 
@@ -182,7 +182,7 @@ class ComponentEvidence:
         See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_componentEvidenceType
     """
 
-    def __init__(self, *, licenses: Optional[Iterable[LicenseChoice]] = None,
+    def __init__(self, *, licenses: Optional[Iterable[License]] = None,
                  copyright: Optional[Iterable[Copyright]] = None) -> None:
         if not licenses and not copyright:
             raise NoPropertiesProvidedException(
@@ -193,8 +193,8 @@ def __init__(self, *, licenses: Optional[Iterable[LicenseChoice]] = None,
         self.copyright = copyright or []  # type: ignore
 
     @property
-    @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'license')
-    def licenses(self) -> "SortedSet[LicenseChoice]":
+    @serializable.type_mapping(LicenseRepositoryHelper)
+    def licenses(self) -> LicenseRepository:
         """
         Optional list of licenses obtained during analysis.
 
@@ -204,8 +204,8 @@ def licenses(self) -> "SortedSet[LicenseChoice]":
         return self._licenses
 
     @licenses.setter
-    def licenses(self, licenses: Iterable[LicenseChoice]) -> None:
-        self._licenses = SortedSet(licenses)
+    def licenses(self, licenses: Iterable[License]) -> None:
+        self._licenses = LicenseRepository(licenses)
 
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'text')
@@ -753,7 +753,7 @@ def __init__(self, *, name: str, type: ComponentType = ComponentType.LIBRARY,
                  supplier: Optional[OrganizationalEntity] = None, author: Optional[str] = None,
                  publisher: Optional[str] = None, group: Optional[str] = None, version: Optional[str] = None,
                  description: Optional[str] = None, scope: Optional[ComponentScope] = None,
-                 hashes: Optional[Iterable[HashType]] = None, licenses: Optional[Iterable[LicenseChoice]] = None,
+                 hashes: Optional[Iterable[HashType]] = None, licenses: Optional[Iterable[License]] = None,
                  copyright: Optional[str] = None, purl: Optional[PackageURL] = None,
                  external_references: Optional[Iterable[ExternalReference]] = None,
                  properties: Optional[Iterable[Property]] = None, release_notes: Optional[ReleaseNotes] = None,
@@ -806,7 +806,7 @@ def __init__(self, *, name: str, type: ComponentType = ComponentType.LIBRARY,
                 'standard', DeprecationWarning
             )
             if not licenses:
-                self.licenses = [LicenseChoice(expression=license_str)]  # type: ignore
+                self.licenses = LicenseRepository([LicenseExpression(license_str)])
 
     @property
     @serializable.xml_attribute()
@@ -1027,9 +1027,9 @@ def hashes(self, hashes: Iterable[HashType]) -> None:
     @serializable.view(SchemaVersion1Dot2)
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
-    @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'licenses')
+    @serializable.type_mapping(LicenseRepositoryHelper)
     @serializable.xml_sequence(10)
-    def licenses(self) -> "SortedSet[LicenseChoice]":
+    def licenses(self) -> LicenseRepository:
         """
         A optional list of statements about how this Component is licensed.
 
@@ -1039,8 +1039,8 @@ def licenses(self) -> "SortedSet[LicenseChoice]":
         return self._licenses
 
     @licenses.setter
-    def licenses(self, licenses: Iterable[LicenseChoice]) -> None:
-        self._licenses = SortedSet(licenses)
+    def licenses(self, licenses: Iterable[License]) -> None:
+        self._licenses = LicenseRepository(licenses)
 
     @property
     @serializable.xml_sequence(11)
diff --git a/cyclonedx/model/dependency.py b/cyclonedx/model/dependency.py
index 317de1613..ee40fa6d0 100644
--- a/cyclonedx/model/dependency.py
+++ b/cyclonedx/model/dependency.py
@@ -30,14 +30,14 @@
 class DependencyDependencies(serializable.BaseHelper):  # type: ignore
 
     @classmethod
-    def serialize(cls, o: object) -> List[str]:
+    def serialize(cls, o: Any) -> List[str]:
         if isinstance(o, SortedSet):
             return list(map(lambda i: str(i.ref), o))
 
         raise ValueError(f'Attempt to serialize a non-Dependency: {o.__class__}')
 
     @classmethod
-    def deserialize(cls, o: object) -> Set["Dependency"]:
+    def deserialize(cls, o: Any) -> Set["Dependency"]:
         dependencies: Set["Dependency"] = set()
         if isinstance(o, list):
             for v in o:
diff --git a/cyclonedx/model/license.py b/cyclonedx/model/license.py
new file mode 100644
index 000000000..70b76a8c1
--- /dev/null
+++ b/cyclonedx/model/license.py
@@ -0,0 +1,224 @@
+# encoding: utf-8
+
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+import warnings
+from typing import TYPE_CHECKING, Any, Optional, Union
+
+import serializable
+from sortedcontainers import SortedSet
+
+from ..exception.model import MutuallyExclusivePropertiesException
+from . import AttachedText, ComparableTuple, XsUri
+
+"""
+License related things
+"""
+
+
+@serializable.serializable_class(name='license')
+class DisjunctiveLicense:
+    """
+    This is our internal representation of `licenseType` complex type that can be used in multiple places within
+    a CycloneDX BOM document.
+
+    .. note::
+        See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_licenseType
+    """
+
+    def __init__(self, *, id: Optional[str] = None, name: Optional[str] = None,
+                 text: Optional[AttachedText] = None, url: Optional[XsUri] = None) -> None:
+        if not id and not name:
+            raise MutuallyExclusivePropertiesException('Either `id` or `name` MUST be supplied')
+        if id and name:
+            warnings.warn(
+                'Both `id` and `name` have been supplied - `name` will be ignored!',
+                RuntimeWarning
+            )
+        self._id = id
+        self._name = name if not id else None
+        self._text = text
+        self._url = url
+
+    @property
+    @serializable.xml_sequence(1)
+    def id(self) -> Optional[str]:
+        """
+        A valid SPDX license ID
+
+        Returns:
+            `str` or `None`
+        """
+        return self._id
+
+    @id.setter
+    def id(self, id: Optional[str]) -> None:
+        self._id = id
+        if id is not None:
+            self._name = None
+
+    @property
+    @serializable.xml_sequence(1)
+    def name(self) -> Optional[str]:
+        """
+        If SPDX does not define the license used, this field may be used to provide the license name.
+
+        Returns:
+            `str` or `None`
+        """
+        return self._name
+
+    @name.setter
+    def name(self, name: Optional[str]) -> None:
+        self._name = name
+        if name is not None:
+            self._id = None
+
+    @property
+    @serializable.xml_sequence(2)
+    def text(self) -> Optional[AttachedText]:
+        """
+        Specifies the optional full text of the attachment
+
+        Returns:
+            `AttachedText` else `None`
+        """
+        return self._text
+
+    @text.setter
+    def text(self, text: Optional[AttachedText]) -> None:
+        self._text = text
+
+    @property
+    @serializable.xml_sequence(3)
+    def url(self) -> Optional[XsUri]:
+        """
+        The URL to the attachment file. If the attachment is a license or BOM, an externalReference should also be
+        specified for completeness.
+
+        Returns:
+            `XsUri` or `None`
+        """
+        return self._url
+
+    @url.setter
+    def url(self, url: Optional[XsUri]) -> None:
+        self._url = url
+
+    def __eq__(self, other: object) -> bool:
+        if isinstance(other, DisjunctiveLicense):
+            return hash(other) == hash(self)
+        return False
+
+    def __lt__(self, other: Any) -> bool:
+        if isinstance(other, DisjunctiveLicense):
+            return ComparableTuple((self._id, self._name)) < ComparableTuple((other._id, other._name))
+        if isinstance(other, LicenseExpression):
+            return False  # self after any LicenseExpression
+        return NotImplemented
+
+    def __hash__(self) -> int:
+        return hash((self._id, self._name, self._text, self._url))
+
+    def __repr__(self) -> str:
+        return f'<License id={self._id!r}, name={self._name!r}>'
+
+
+@serializable.serializable_class(name='expression')
+class LicenseExpression:
+    """
+    This is our internal representation of `licenseType`'s  expression type that can be used in multiple places within
+    a CycloneDX BOM document.
+
+    .. note::
+        See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_licenseType
+    """
+
+    def __init__(self, value: str) -> None:
+        self._value = value
+
+    @property
+    @serializable.xml_name('.')
+    @serializable.json_name('expression')
+    def value(self) -> str:
+        """
+        Value of this LicenseExpression.
+
+        Returns:
+             `str`
+        """
+        return self._value
+
+    @value.setter
+    def value(self, value: str) -> None:
+        self._value = value
+
+    def __hash__(self) -> int:
+        return hash(self._value)
+
+    def __eq__(self, other: object) -> bool:
+        if isinstance(other, LicenseExpression):
+            return self._value == other._value
+        return False
+
+    def __lt__(self, other: Any) -> bool:
+        if isinstance(other, LicenseExpression):
+            return self._value < other._value
+        if isinstance(other, DisjunctiveLicense):
+            return True  # self before any DisjunctiveLicense
+        return NotImplemented
+
+    def __repr__(self) -> str:
+        return f'<LicenseExpression value={self._value!r}>'
+
+
+License = Union[LicenseExpression, DisjunctiveLicense]
+"""TypeAlias for a union of supported license models.
+
+- :class:`LicenseExpression`
+- :class:`DisjunctiveLicense`
+"""
+
+if TYPE_CHECKING:  # pragma: no cover
+    # workaround for https://github.com/python/mypy/issues/5264
+    # this code path is taken when static code analysis or documentation tools runs through.
+    class LicenseRepository(SortedSet[License]):
+        """Collection of :class:`License`.
+
+        This is a `set`, not a `list`.  Order MUST NOT matter here.
+        If you wanted a certain order, then you should also express whether the items are concat by `AND` or `OR`.
+        If you wanted to do so, you should use :class:`LicenseExpression`.
+
+        As a model, this MUST accept multiple :class:`LicenseExpression` along with
+        multiple :class:`DisjunctiveLicense`, as this was an accepted in CycloneDX JSON before v1.5.
+        So for modeling purposes, this is supported.
+        Denormalizers/deserializers will be thankful.
+        The normalization/serialization process SHOULD take care of these facts and do what is needed.
+        """
+else:
+    class LicenseRepository(SortedSet):
+        """Collection of :class:`License`.
+
+        This is a `set`, not a `list`.  Order MUST NOT matter here.
+        If you wanted a certain order, then you should also express whether the items are concat by `AND` or `OR`.
+        If you wanted to do so, you should use :class:`LicenseExpression`.
+
+        As a model, this MUST accept multiple :class:`LicenseExpression` along with
+        multiple :class:`DisjunctiveLicense`, as this was an accepted in CycloneDX JSON before v1.5.
+        So for modeling purposes, this is supported.
+        Denormalizers/deserializers will be thankful.
+        The normalization/serialization process SHOULD take care of these facts and do what is needed.
+        """
diff --git a/cyclonedx/model/service.py b/cyclonedx/model/service.py
index f681659a1..b00b0714a 100644
--- a/cyclonedx/model/service.py
+++ b/cyclonedx/model/service.py
@@ -18,20 +18,13 @@
 import serializable
 from sortedcontainers import SortedSet
 
-from cyclonedx.serialization import BomRefHelper
+from cyclonedx.serialization import BomRefHelper, LicenseRepositoryHelper
 
 from ..schema.schema import SchemaVersion1Dot3, SchemaVersion1Dot4
-from . import (
-    ComparableTuple,
-    DataClassification,
-    ExternalReference,
-    LicenseChoice,
-    OrganizationalEntity,
-    Property,
-    XsUri,
-)
+from . import ComparableTuple, DataClassification, ExternalReference, OrganizationalEntity, Property, XsUri
 from .bom_ref import BomRef
 from .dependency import Dependable
+from .license import License, LicenseRepository
 from .release_note import ReleaseNotes
 
 """
@@ -56,7 +49,7 @@ def __init__(self, *, name: str, bom_ref: Optional[Union[str, BomRef]] = None,
                  group: Optional[str] = None, version: Optional[str] = None, description: Optional[str] = None,
                  endpoints: Optional[Iterable[XsUri]] = None, authenticated: Optional[bool] = None,
                  x_trust_boundary: Optional[bool] = None, data: Optional[Iterable[DataClassification]] = None,
-                 licenses: Optional[Iterable[LicenseChoice]] = None,
+                 licenses: Optional[Iterable[License]] = None,
                  external_references: Optional[Iterable[ExternalReference]] = None,
                  properties: Optional[Iterable[Property]] = None,
                  services: Optional[Iterable['Service']] = None,
@@ -245,9 +238,9 @@ def data(self, data: Iterable[DataClassification]) -> None:
         self._data = SortedSet(data)
 
     @property
-    @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'licenses')
+    @serializable.type_mapping(LicenseRepositoryHelper)
     @serializable.xml_sequence(10)
-    def licenses(self) -> "SortedSet[LicenseChoice]":
+    def licenses(self) -> LicenseRepository:
         """
         A optional list of statements about how this Service is licensed.
 
@@ -257,8 +250,8 @@ def licenses(self) -> "SortedSet[LicenseChoice]":
         return self._licenses
 
     @licenses.setter
-    def licenses(self, licenses: Iterable[LicenseChoice]) -> None:
-        self._licenses = SortedSet(licenses)
+    def licenses(self, licenses: Iterable[License]) -> None:
+        self._licenses = LicenseRepository(licenses)
 
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
diff --git a/cyclonedx/schema/_res/__init__.py b/cyclonedx/schema/_res/__init__.py
index d33cf6955..2a672d036 100644
--- a/cyclonedx/schema/_res/__init__.py
+++ b/cyclonedx/schema/_res/__init__.py
@@ -14,16 +14,17 @@
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
 
-from os.path import dirname, join
-from typing import Dict, Optional
-
-from .. import SchemaVersion
-
 """
 Content in here is internal, not for public use.
 Breaking changes without notice may happen.
 """
 
+
+from os.path import dirname, join
+from typing import Dict, Optional
+
+from .. import SchemaVersion
+
 __DIR = dirname(__file__)
 
 BOM_XML: Dict[SchemaVersion, Optional[str]] = {
diff --git a/cyclonedx/serialization/__init__.py b/cyclonedx/serialization/__init__.py
index 094b57f83..7c5475866 100644
--- a/cyclonedx/serialization/__init__.py
+++ b/cyclonedx/serialization/__init__.py
@@ -18,26 +18,33 @@
 Set of helper classes for use with ``serializable`` when conducting (de-)serialization.
 """
 
+from json import loads as json_loads
+from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type
 from uuid import UUID
+from xml.etree.ElementTree import Element
 
 # See https://github.com/package-url/packageurl-python/issues/65
 from packageurl import PackageURL
 from serializable.helpers import BaseHelper
 
 from ..model.bom_ref import BomRef
+from ..model.license import DisjunctiveLicense, LicenseExpression, LicenseRepository
+
+if TYPE_CHECKING:  # pragma: no cover
+    from serializable import ViewType
 
 
 class BomRefHelper(BaseHelper):
 
     @classmethod
-    def serialize(cls, o: object) -> str:
+    def serialize(cls, o: Any) -> str:
         if isinstance(o, BomRef):
             return o.value
 
         raise ValueError(f'Attempt to serialize a non-BomRef: {o.__class__}')
 
     @classmethod
-    def deserialize(cls, o: object) -> BomRef:
+    def deserialize(cls, o: Any) -> BomRef:
         try:
             return BomRef(value=str(o))
         except ValueError:
@@ -47,14 +54,14 @@ def deserialize(cls, o: object) -> BomRef:
 class PackageUrl(BaseHelper):
 
     @classmethod
-    def serialize(cls, o: object) -> str:
+    def serialize(cls, o: Any, ) -> str:
         if isinstance(o, PackageURL):
             return str(o.to_string())
 
         raise ValueError(f'Attempt to serialize a non-PackageURL: {o.__class__}')
 
     @classmethod
-    def deserialize(cls, o: object) -> PackageURL:
+    def deserialize(cls, o: Any) -> PackageURL:
         try:
             return PackageURL.from_string(purl=str(o))
         except ValueError:
@@ -64,15 +71,81 @@ def deserialize(cls, o: object) -> PackageURL:
 class UrnUuidHelper(BaseHelper):
 
     @classmethod
-    def serialize(cls, o: object) -> str:
+    def serialize(cls, o: Any) -> str:
         if isinstance(o, UUID):
             return o.urn
 
         raise ValueError(f'Attempt to serialize a non-UUID: {o.__class__}')
 
     @classmethod
-    def deserialize(cls, o: object) -> UUID:
+    def deserialize(cls, o: Any) -> UUID:
         try:
             return UUID(str(o))
         except ValueError:
             raise ValueError(f'UUID string supplied ({o}) does not parse!')
+
+
+class LicenseRepositoryHelper(BaseHelper):
+    @classmethod
+    def json_normalize(cls, o: LicenseRepository, *,
+                       view: Optional[Type['ViewType']],
+                       **__: Any) -> Any:
+        if len(o) == 0:
+            return None
+        expression = next((li for li in o if isinstance(li, LicenseExpression)), None)
+        if expression:
+            # mixed license expression and license? this is an invalid constellation according to schema!
+            # see https://github.com/CycloneDX/specification/pull/205
+            # but models need to allow it for backwards compatibility with JSON CDX < 1.5
+            return [{'expression': str(expression.value)}]
+        return [{'license': json_loads(li.as_json(  # type:ignore[union-attr]
+            view_=view))} for li in o]
+
+    @classmethod
+    def json_denormalize(cls, o: List[Dict[str, Any]],
+                         **__: Any) -> LicenseRepository:
+        repo = LicenseRepository()
+        for li in o:
+            if 'license' in li:
+                repo.add(DisjunctiveLicense.from_json(  # type:ignore[attr-defined]
+                    li['license']))
+            elif 'expression' in li:
+                repo.add(LicenseExpression(li['expression']))
+        return repo
+
+    @classmethod
+    def xml_normalize(cls, o: LicenseRepository, *,
+                      element_name: str,
+                      view: Optional[Type['ViewType']],
+                      xmlns: Optional[str],
+                      **__: Any) -> Optional[Element]:
+        if len(o) == 0:
+            return None
+        elem = Element(element_name)
+        expression = next((li for li in o if isinstance(li, LicenseExpression)), None)
+        if expression:
+            # mixed license expression and license? this is an invalid constellation according to schema!
+            # see https://github.com/CycloneDX/specification/pull/205
+            # but models need to allow it for backwards compatibility with JSON CDX < 1.5
+            elem.append(expression.as_xml(  # type:ignore[attr-defined]
+                view, as_string=False, element_name='expression', xmlns=xmlns))
+        else:
+            for li in o:
+                elem.append(li.as_xml(  # type:ignore[union-attr]
+                    view, as_string=False, element_name='license', xmlns=xmlns))
+        return elem
+
+    @classmethod
+    def xml_denormalize(cls, o: Element,
+                        default_ns: Optional[str],
+                        **__: Any) -> LicenseRepository:
+        repo = LicenseRepository()
+        for li in o:
+            tag = li.tag if default_ns is None else li.tag.replace(f'{{{default_ns}}}', '')
+            if tag == 'license':
+                repo.add(DisjunctiveLicense.from_xml(  # type:ignore[attr-defined]
+                    li, default_ns))
+            elif tag == 'expression':
+                repo.add(LicenseExpression.from_xml(  # type:ignore[attr-defined]
+                    li, default_ns))
+        return repo
diff --git a/docs/conf.py b/docs/conf.py
index f6672dbc5..4225ce4ea 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -50,7 +50,7 @@
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.venv']
 
 # -- Options for HTML output -------------------------------------------------
 
diff --git a/examples/complex.py b/examples/complex.py
index 641c2ed2c..e167d0af3 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -20,7 +20,7 @@
 from packageurl import PackageURL
 
 from cyclonedx.exception import MissingOptionalDependencyException
-from cyclonedx.factory.license import LicenseChoiceFactory, LicenseFactory
+from cyclonedx.factory.license import LicenseFactory
 from cyclonedx.model import OrganizationalEntity, XsUri
 from cyclonedx.model.bom import Bom
 from cyclonedx.model.component import Component, ComponentType
@@ -38,7 +38,7 @@
     from cyclonedx.validation.xml import XmlValidator
 
 
-lc_factory = LicenseChoiceFactory(license_factory=LicenseFactory())
+lc_factory = LicenseFactory()
 
 # region build the BOM
 
diff --git a/pyproject.toml b/pyproject.toml
index dbe4a8743..e80454138 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -61,7 +61,7 @@ keywords = [
 # ATTENTION: keep `deps.lowest.r` file in sync
 python = "^3.8"
 packageurl-python = ">= 0.11"
-py-serializable =  "^0.14.1"
+py-serializable =  "^0.15"
 sortedcontainers = "^2.4.0"
 license-expression = "^30"
 jsonschema = { version = "^4.18", extras=['format'], optional=true }
diff --git a/tests/_data/models.py b/tests/_data/models.py
index d1e6e2ba7..6a1e178c1 100644
--- a/tests/_data/models.py
+++ b/tests/_data/models.py
@@ -35,8 +35,6 @@
     ExternalReference,
     ExternalReferenceType,
     HashType,
-    License,
-    LicenseChoice,
     Note,
     NoteText,
     OrganizationalContact,
@@ -66,6 +64,7 @@
     ImpactAnalysisState,
 )
 from cyclonedx.model.issue import IssueClassification, IssueType, IssueTypeSource
+from cyclonedx.model.license import DisjunctiveLicense, License, LicenseExpression
 from cyclonedx.model.release_note import ReleaseNotes
 from cyclonedx.model.service import Service
 from cyclonedx.model.vulnerability import (
@@ -104,7 +103,6 @@
     'a3f4096d-4211-4d68-9d2b-13973c86aca9',
 )
 
-
 BOM_SERIAL_NUMBER = UUID('1441d33a-e0fc-45b5-af3b-61ee52a88bac')
 BOM_TIMESTAMP = datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
 
@@ -269,11 +267,14 @@ def get_bom_just_complete_metadata() -> Bom:
     bom.metadata.component = get_component_setuptools_complete()
     bom.metadata.manufacture = get_org_entity_1()
     bom.metadata.supplier = get_org_entity_2()
-    bom.metadata.licenses = [LicenseChoice(license=License(
-        id='Apache-2.0', text=AttachedText(
-            content='VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE=', encoding=Encoding.BASE_64
-        ), url=XsUri('https://www.apache.org/licenses/LICENSE-2.0.txt')
-    ))]
+    bom.metadata.licenses = [DisjunctiveLicense(
+        id='Apache-2.0',
+        url=XsUri('https://www.apache.org/licenses/LICENSE-2.0.txt'),
+        text=AttachedText(
+            encoding=Encoding.BASE_64,
+            content='VGVzdCBjb250ZW50IC0gdGhpcyBpcyBub3QgdGhlIEFwYWNoZSAyLjAgbGljZW5zZSE='
+        )
+    )]
     bom.metadata.properties = get_properties_1()
     return bom
 
@@ -309,9 +310,7 @@ def get_bom_with_services_complex() -> Bom:
             authenticated=False, x_trust_boundary=True, data=[
                 DataClassification(flow=DataFlow.OUTBOUND, classification='public')
             ],
-            licenses=[
-                LicenseChoice(expression='Commercial')
-            ],
+            licenses=[DisjunctiveLicense(name='Commercial')],
             external_references=[
                 get_external_reference_1()
             ],
@@ -339,9 +338,7 @@ def get_bom_with_nested_services() -> Bom:
             authenticated=False, x_trust_boundary=True, data=[
                 DataClassification(flow=DataFlow.OUTBOUND, classification='public')
             ],
-            licenses=[
-                LicenseChoice(expression='Commercial')
-            ],
+            licenses=[DisjunctiveLicense(name='Commercial')],
             external_references=[
                 get_external_reference_1()
             ],
@@ -480,7 +477,7 @@ def get_component_setuptools_simple(
         purl=PackageURL(
             type='pypi', name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'
         ),
-        licenses=[LicenseChoice(expression='MIT License')],
+        licenses=[DisjunctiveLicense(id='MIT')],
         author='Test Author'
     )
 
@@ -491,7 +488,7 @@ def get_component_setuptools_simple_no_version(bom_ref: Optional[str] = None) ->
         purl=PackageURL(
             type='pypi', name='setuptools', qualifiers='extension=tar.gz'
         ),
-        licenses=[LicenseChoice(expression='MIT License')],
+        licenses=[DisjunctiveLicense(id='MIT')],
         author='Test Author'
     )
 
@@ -664,21 +661,43 @@ def get_vulnerability_source_owasp() -> VulnerabilitySource:
     return VulnerabilitySource(name='OWASP', url=XsUri('https://owasp.org'))
 
 
+def get_bom_with_licenses() -> Bom:
+    return _makeBom(
+        metadata=BomMetaData(
+            licenses=[DisjunctiveLicense(id='CC-BY-1.0')],
+            component=Component(name='app', type=ComponentType.APPLICATION, bom_ref='my-app',
+                                licenses=[DisjunctiveLicense(name='proprietary')])
+        ),
+        components=[
+            Component(name='c-with-expression', type=ComponentType.LIBRARY, bom_ref='C1',
+                      licenses=[LicenseExpression(value='Apache-2.0 OR MIT')]),
+            Component(name='c-with-SPDX', type=ComponentType.LIBRARY, bom_ref='C2',
+                      licenses=[DisjunctiveLicense(id='Apache-2.0')]),
+            Component(name='c-with-name', type=ComponentType.LIBRARY, bom_ref='C3',
+                      licenses=[DisjunctiveLicense(name='(c) ACME Inc.')]),
+        ],
+        services=[
+            Service(name='s-with-expression', bom_ref='S1',
+                    licenses=[LicenseExpression(value='Apache-2.0 OR MIT')]),
+            Service(name='s-with-SPDX', bom_ref='S2',
+                    licenses=[DisjunctiveLicense(id='Apache-2.0')]),
+            Service(name='s-with-name', bom_ref='S3',
+                    licenses=[DisjunctiveLicense(name='(c) ACME Inc.')]),
+        ])
+
+
 def get_bom_metadata_licenses_invalid() -> Bom:
-    return Bom(metadata=BomMetaData(licenses=[
-        LicenseChoice(expression='Apache-2.0 OR MIT'),
-        LicenseChoice(license=License(id='MIT')),
-    ]))
+    return Bom(metadata=BomMetaData(licenses=get_invalid_license_repository()))
 
 
-def get_invalid_license_repository() -> List[LicenseChoice]:
+def get_invalid_license_repository() -> List[License]:
     """
     license expression and a license -- this is an invalid constellation according to schema
     see https://github.com/CycloneDX/specification/pull/205
     """
     return [
-        LicenseChoice(expression='Apache-2.0 OR MIT'),
-        LicenseChoice(license=License(id='GPL-2.0-only')),
+        LicenseExpression(value='Apache-2.0 OR MIT'),
+        DisjunctiveLicense(id='GPL-2.0-only'),
     ]
 
 
@@ -717,6 +736,27 @@ def get_bom_service_licenses_invalid() -> Bom:
     ])
 
 
+def get_bom_with_multiple_licenses() -> Bom:
+    multi_licenses = (
+        DisjunctiveLicense(id='MIT'),
+        DisjunctiveLicense(name='foo license'),
+    )
+    return _makeBom(
+        metadata=BomMetaData(
+            licenses=multi_licenses,
+            component=Component(name='app', type=ComponentType.APPLICATION, bom_ref='my-app',
+                                licenses=multi_licenses)
+        ),
+        components=[Component(name='comp', type=ComponentType.LIBRARY, bom_ref='my-compo',
+                              licenses=multi_licenses)],
+        services=[Service(name='serv', bom_ref='my-serv',
+                          licenses=multi_licenses)]
+    )
+
+
+# ---
+
+
 all_get_bom_funct_valid = tuple(
     (n, f) for n, f in getmembers(sys.modules[__name__], isfunction)
     if n.startswith('get_bom_') and not n.endswith('_invalid')
@@ -728,6 +768,8 @@ def get_bom_service_licenses_invalid() -> Bom:
 )
 
 all_get_bom_funct_with_incomplete_deps = {
+    # List of functions that return BOM with an incomplte dependency graph.
+    # It is expected that some process auto-fixes this before actual serialization takes place.
     get_bom_just_complete_metadata,
     get_bom_with_component_setuptools_basic,
     get_bom_with_component_setuptools_complete,
@@ -741,4 +783,6 @@ def get_bom_service_licenses_invalid() -> Bom:
     get_bom_with_nested_services,
     get_bom_with_services_complex,
     get_bom_with_services_simple,
+    get_bom_with_licenses,
+    get_bom_with_multiple_licenses,
 }
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.json.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.json.bin
index 7233c3c12..4d1842129 100644
--- a/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.json.bin
@@ -25,7 +25,9 @@
           "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
           "licenses": [
             {
-              "expression": "MIT License"
+              "license": {
+                "id": "MIT"
+              }
             }
           ],
           "name": "setuptools",
@@ -66,7 +68,9 @@
       ],
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
@@ -77,7 +81,9 @@
             "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -90,7 +96,9 @@
             "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -111,7 +119,9 @@
             "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -152,7 +162,9 @@
             "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.xml.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.xml.bin
index 75b6733e3..9e4a71e06 100644
--- a/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.2.xml.bin
@@ -41,7 +41,9 @@
       <description>This component is awesome</description>
       <scope>required</scope>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <copyright>Apache 2.0 baby!</copyright>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
@@ -56,7 +58,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -65,7 +69,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -76,7 +82,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -101,7 +109,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -143,7 +153,9 @@
           <name>setuptools</name>
           <version>50.3.2</version>
           <licenses>
-            <expression>MIT License</expression>
+            <license>
+              <id>MIT</id>
+            </license>
           </licenses>
           <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
         </component>
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.json.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.json.bin
index 1a720cf21..4028367c1 100644
--- a/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.json.bin
@@ -25,7 +25,9 @@
           "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
           "licenses": [
             {
-              "expression": "MIT License"
+              "license": {
+                "id": "MIT"
+              }
             }
           ],
           "name": "setuptools",
@@ -88,7 +90,9 @@
       ],
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
@@ -99,7 +103,9 @@
             "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -112,7 +118,9 @@
             "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -133,7 +141,9 @@
             "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -180,7 +190,9 @@
             "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.xml.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.xml.bin
index 4b03243b0..a657ab399 100644
--- a/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.3.xml.bin
@@ -41,7 +41,9 @@
       <description>This component is awesome</description>
       <scope>required</scope>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <copyright>Apache 2.0 baby!</copyright>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
@@ -56,7 +58,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -65,7 +69,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -76,7 +82,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -104,7 +112,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -156,7 +166,9 @@
           <name>setuptools</name>
           <version>50.3.2</version>
           <licenses>
-            <expression>MIT License</expression>
+            <license>
+              <id>MIT</id>
+            </license>
           </licenses>
           <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
         </component>
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.json.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.json.bin
index 60b9249af..1c5a5e402 100644
--- a/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.json.bin
@@ -25,7 +25,9 @@
           "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
           "licenses": [
             {
-              "expression": "MIT License"
+              "license": {
+                "id": "MIT"
+              }
             }
           ],
           "name": "setuptools",
@@ -88,7 +90,9 @@
       ],
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
@@ -99,7 +103,9 @@
             "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -112,7 +118,9 @@
             "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -132,7 +140,9 @@
             "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -178,7 +188,9 @@
             "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.xml.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.xml.bin
index 98e51691d..886b439ac 100644
--- a/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.4.xml.bin
@@ -67,7 +67,9 @@
       <description>This component is awesome</description>
       <scope>required</scope>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <copyright>Apache 2.0 baby!</copyright>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
@@ -82,7 +84,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -90,7 +94,9 @@
             <author>Test Author</author>
             <name>setuptools</name>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -100,7 +106,9 @@
             <author>Test Author</author>
             <name>setuptools</name>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -128,7 +136,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -180,7 +190,9 @@
           <name>setuptools</name>
           <version>50.3.2</version>
           <licenses>
-            <expression>MIT License</expression>
+            <license>
+              <id>MIT</id>
+            </license>
           </licenses>
           <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
         </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.1.xml.bin
index 0b33bec2a..ba1ca960c 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.1.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.1.xml.bin
@@ -5,7 +5,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.json.bin
index 9d0993c87..2f1464461 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.xml.bin
index ce6f3e6c6..cb29e5bad 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.2.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.json.bin
index 6e2f630e8..a075deb22 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.xml.bin
index 39cbf1d85..76ce40a00 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.3.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.json.bin
index d3c70bb7b..70616689f 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.xml.bin
index bef590f2f..586abf6ae 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_basic-1.4.xml.bin
@@ -42,7 +42,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.1.xml.bin
index cf2184b05..851c9d9b8 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.1.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.1.xml.bin
@@ -8,7 +8,9 @@
       <description>This component is awesome</description>
       <scope>required</scope>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <copyright>Apache 2.0 baby!</copyright>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
@@ -19,7 +21,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -27,7 +31,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -37,7 +43,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -61,7 +69,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -99,7 +109,9 @@
           <name>setuptools</name>
           <version>50.3.2</version>
           <licenses>
-            <expression>MIT License</expression>
+            <license>
+              <id>MIT</id>
+            </license>
           </licenses>
           <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
         </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.json.bin
index 9cf4af5be..952801f93 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.json.bin
@@ -9,7 +9,9 @@
           "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
           "licenses": [
             {
-              "expression": "MIT License"
+              "license": {
+                "id": "MIT"
+              }
             }
           ],
           "name": "setuptools",
@@ -50,7 +52,9 @@
       ],
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
@@ -61,7 +65,9 @@
             "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -74,7 +80,9 @@
             "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -95,7 +103,9 @@
             "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -136,7 +146,9 @@
             "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.xml.bin
index 7c9f77b41..ab648c164 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.2.xml.bin
@@ -32,7 +32,9 @@
       <description>This component is awesome</description>
       <scope>required</scope>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <copyright>Apache 2.0 baby!</copyright>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
@@ -47,7 +49,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -56,7 +60,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -67,7 +73,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -92,7 +100,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -134,7 +144,9 @@
           <name>setuptools</name>
           <version>50.3.2</version>
           <licenses>
-            <expression>MIT License</expression>
+            <license>
+              <id>MIT</id>
+            </license>
           </licenses>
           <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
         </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.json.bin
index cf2dc3e1f..d974b1953 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.json.bin
@@ -9,7 +9,9 @@
           "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
           "licenses": [
             {
-              "expression": "MIT License"
+              "license": {
+                "id": "MIT"
+              }
             }
           ],
           "name": "setuptools",
@@ -72,7 +74,9 @@
       ],
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
@@ -83,7 +87,9 @@
             "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -96,7 +102,9 @@
             "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -117,7 +125,9 @@
             "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -164,7 +174,9 @@
             "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.xml.bin
index 316f55629..27861fd17 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.3.xml.bin
@@ -32,7 +32,9 @@
       <description>This component is awesome</description>
       <scope>required</scope>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <copyright>Apache 2.0 baby!</copyright>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
@@ -47,7 +49,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -56,7 +60,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -67,7 +73,9 @@
             <name>setuptools</name>
             <version/>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -95,7 +103,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -147,7 +157,9 @@
           <name>setuptools</name>
           <version>50.3.2</version>
           <licenses>
-            <expression>MIT License</expression>
+            <license>
+              <id>MIT</id>
+            </license>
           </licenses>
           <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
         </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.json.bin
index 525c924c4..c19e9908a 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.json.bin
@@ -9,7 +9,9 @@
           "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
           "licenses": [
             {
-              "expression": "MIT License"
+              "license": {
+                "id": "MIT"
+              }
             }
           ],
           "name": "setuptools",
@@ -72,7 +74,9 @@
       ],
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
@@ -83,7 +87,9 @@
             "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -96,7 +102,9 @@
             "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -116,7 +124,9 @@
             "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
@@ -162,7 +172,9 @@
             "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958",
             "licenses": [
               {
-                "expression": "MIT License"
+                "license": {
+                  "id": "MIT"
+                }
               }
             ],
             "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.xml.bin
index 24b43c3f0..026761404 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_complete-1.4.xml.bin
@@ -58,7 +58,9 @@
       <description>This component is awesome</description>
       <scope>required</scope>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <copyright>Apache 2.0 baby!</copyright>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
@@ -73,7 +75,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -81,7 +85,9 @@
             <author>Test Author</author>
             <name>setuptools</name>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -91,7 +97,9 @@
             <author>Test Author</author>
             <name>setuptools</name>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
           </component>
@@ -119,7 +127,9 @@
             <name>setuptools</name>
             <version>50.3.2</version>
             <licenses>
-              <expression>MIT License</expression>
+              <license>
+                <id>MIT</id>
+              </license>
             </licenses>
             <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
           </component>
@@ -171,7 +181,9 @@
           <name>setuptools</name>
           <version>50.3.2</version>
           <licenses>
-            <expression>MIT License</expression>
+            <license>
+              <id>MIT</id>
+            </license>
           </licenses>
           <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
         </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.1.xml.bin
index 4d6b504d4..5bc27d5b3 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.1.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.1.xml.bin
@@ -5,7 +5,9 @@
       <name>setuptools</name>
       <version/>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.json.bin
index 7bb0d1e15..556f871e3 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.xml.bin
index a993370c3..39e16bf4f 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.2.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version/>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.json.bin
index 1fb453b4a..0d3f35477 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.xml.bin
index f12eaf368..b1198c98f 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.3.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version/>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.json.bin
index ac80eda9a..a8f2ac878 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.xml.bin
index a08ce14db..558c9be77 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_no_component_version-1.4.xml.bin
@@ -41,7 +41,9 @@
       <author>Test Author</author>
       <name>setuptools</name>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.1.xml.bin
index 1ac5e156d..21439ea9b 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.1.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.1.xml.bin
@@ -5,7 +5,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.json.bin
index 2dd754f8f..f92821171 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.json.bin
@@ -6,7 +6,9 @@
       "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.xml.bin
index 7a23d5d11..f8b4fd27d 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.2.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.json.bin
index 077f8b253..8ad7c7667 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.json.bin
@@ -6,7 +6,9 @@
       "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.xml.bin
index a2d699055..457d800bf 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.3.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.json.bin
index 66f999c5f..177998685 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.json.bin
@@ -6,7 +6,9 @@
       "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.xml.bin
index a2c30d437..1cf91295b 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_cpe-1.4.xml.bin
@@ -42,7 +42,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <cpe>cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*</cpe>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.1.xml.bin
index 0b33bec2a..ba1ca960c 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.1.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.1.xml.bin
@@ -5,7 +5,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.json.bin
index 9d0993c87..2f1464461 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.xml.bin
index ce6f3e6c6..cb29e5bad 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.2.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.json.bin
index 6e2f630e8..a075deb22 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.xml.bin
index 39cbf1d85..76ce40a00 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.3.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.json.bin
index 6eed4f13c..492ecc0b2 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.xml.bin
index 2d067b43e..708524422 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_release_notes-1.4.xml.bin
@@ -42,7 +42,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
       <releaseNotes>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.1.xml.bin
index 0b33bec2a..ba1ca960c 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.1.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.1.xml.bin
@@ -5,7 +5,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.json.bin
index 9d0993c87..2f1464461 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.xml.bin
index ce6f3e6c6..cb29e5bad 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.2.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.json.bin
index 6e2f630e8..a075deb22 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.xml.bin
index 39cbf1d85..76ce40a00 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.3.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.json.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.json.bin
index 296520bee..c1b42b963 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.xml.bin
index 7ccc65ebd..3326f3f97 100644
--- a/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_component_setuptools_with_vulnerability-1.4.xml.bin
@@ -42,7 +42,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.1.xml.bin
index ef886b52b..2a2038c30 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.1.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.1.xml.bin
@@ -5,7 +5,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.json.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.json.bin
index c63b1b817..6dc68f3d4 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "setuptools",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.xml.bin
index 3d1ac1fb5..39df1a3b2 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.2.xml.bin
@@ -20,7 +20,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.json.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.json.bin
index 5ccacbb31..20919e4f5 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "setuptools",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.xml.bin
index 656e37d0e..cb19113f7 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.3.xml.bin
@@ -20,7 +20,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.json.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.json.bin
index abe58bd49..e860d1fb7 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "setuptools",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.xml.bin
index 5bea1c052..d13eaf18e 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_hanging-1.4.xml.bin
@@ -45,7 +45,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.1.xml.bin
index 2f6897772..9d446f67d 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.1.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.1.xml.bin
@@ -5,7 +5,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.json.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.json.bin
index a9874292d..44bde82bc 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.xml.bin
index 4fd57d868..45734322c 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.2.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.json.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.json.bin
index a44b69b8c..945582d85 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.xml.bin
index 6a5779c80..0ac9a56b5 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.3.xml.bin
@@ -16,7 +16,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.json.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.json.bin
index 19e76581e..4c0d4031f 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.json.bin
@@ -5,7 +5,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.xml.bin
index 64970d15b..10868becf 100644
--- a/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_dependencies_valid-1.4.xml.bin
@@ -42,7 +42,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_licenses-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_licenses-1.0.xml.bin
new file mode 100644
index 000000000..1b308eafe
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses-1.0.xml.bin
@@ -0,0 +1,20 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>c-with-SPDX</name>
+      <version/>
+      <modified>false</modified>
+    </component>
+    <component type="library">
+      <name>c-with-expression</name>
+      <version/>
+      <modified>false</modified>
+    </component>
+    <component type="library">
+      <name>c-with-name</name>
+      <version/>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_licenses-1.1.xml.bin
new file mode 100644
index 000000000..97aa8eb37
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses-1.1.xml.bin
@@ -0,0 +1,30 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="C2">
+      <name>c-with-SPDX</name>
+      <version/>
+      <licenses>
+        <license>
+          <id>Apache-2.0</id>
+        </license>
+      </licenses>
+    </component>
+    <component type="library" bom-ref="C1">
+      <name>c-with-expression</name>
+      <version/>
+      <licenses>
+        <expression>Apache-2.0 OR MIT</expression>
+      </licenses>
+    </component>
+    <component type="library" bom-ref="C3">
+      <name>c-with-name</name>
+      <version/>
+      <licenses>
+        <license>
+          <name>(c) ACME Inc.</name>
+        </license>
+      </licenses>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses-1.2.json.bin b/tests/_data/snapshots/get_bom_with_licenses-1.2.json.bin
new file mode 100644
index 000000000..848073cdf
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses-1.2.json.bin
@@ -0,0 +1,125 @@
+{
+  "components": [
+    {
+      "bom-ref": "C2",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "name": "c-with-SPDX",
+      "type": "library",
+      "version": ""
+    },
+    {
+      "bom-ref": "C1",
+      "licenses": [
+        {
+          "expression": "Apache-2.0 OR MIT"
+        }
+      ],
+      "name": "c-with-expression",
+      "type": "library",
+      "version": ""
+    },
+    {
+      "bom-ref": "C3",
+      "licenses": [
+        {
+          "license": {
+            "name": "(c) ACME Inc."
+          }
+        }
+      ],
+      "name": "c-with-name",
+      "type": "library",
+      "version": ""
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "C1"
+    },
+    {
+      "ref": "C2"
+    },
+    {
+      "ref": "C3"
+    },
+    {
+      "ref": "S1"
+    },
+    {
+      "ref": "S2"
+    },
+    {
+      "ref": "S3"
+    },
+    {
+      "ref": "my-app"
+    }
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-app",
+      "licenses": [
+        {
+          "license": {
+            "name": "proprietary"
+          }
+        }
+      ],
+      "name": "app",
+      "type": "application",
+      "version": ""
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "services": [
+    {
+      "bom-ref": "S2",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "name": "s-with-SPDX"
+    },
+    {
+      "bom-ref": "S1",
+      "licenses": [
+        {
+          "expression": "Apache-2.0 OR MIT"
+        }
+      ],
+      "name": "s-with-expression"
+    },
+    {
+      "bom-ref": "S3",
+      "licenses": [
+        {
+          "license": {
+            "name": "(c) ACME Inc."
+          }
+        }
+      ],
+      "name": "s-with-name"
+    }
+  ],
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_licenses-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_licenses-1.2.xml.bin
new file mode 100644
index 000000000..3f67d83c5
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses-1.2.xml.bin
@@ -0,0 +1,82 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-app">
+      <name>app</name>
+      <version/>
+      <licenses>
+        <license>
+          <name>proprietary</name>
+        </license>
+      </licenses>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="C2">
+      <name>c-with-SPDX</name>
+      <version/>
+      <licenses>
+        <license>
+          <id>Apache-2.0</id>
+        </license>
+      </licenses>
+    </component>
+    <component type="library" bom-ref="C1">
+      <name>c-with-expression</name>
+      <version/>
+      <licenses>
+        <expression>Apache-2.0 OR MIT</expression>
+      </licenses>
+    </component>
+    <component type="library" bom-ref="C3">
+      <name>c-with-name</name>
+      <version/>
+      <licenses>
+        <license>
+          <name>(c) ACME Inc.</name>
+        </license>
+      </licenses>
+    </component>
+  </components>
+  <services>
+    <service bom-ref="S2">
+      <name>s-with-SPDX</name>
+      <licenses>
+        <license>
+          <id>Apache-2.0</id>
+        </license>
+      </licenses>
+    </service>
+    <service bom-ref="S1">
+      <name>s-with-expression</name>
+      <licenses>
+        <expression>Apache-2.0 OR MIT</expression>
+      </licenses>
+    </service>
+    <service bom-ref="S3">
+      <name>s-with-name</name>
+      <licenses>
+        <license>
+          <name>(c) ACME Inc.</name>
+        </license>
+      </licenses>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="C1"/>
+    <dependency ref="C2"/>
+    <dependency ref="C3"/>
+    <dependency ref="S1"/>
+    <dependency ref="S2"/>
+    <dependency ref="S3"/>
+    <dependency ref="my-app"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses-1.3.json.bin b/tests/_data/snapshots/get_bom_with_licenses-1.3.json.bin
new file mode 100644
index 000000000..143c48bad
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses-1.3.json.bin
@@ -0,0 +1,132 @@
+{
+  "components": [
+    {
+      "bom-ref": "C2",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "name": "c-with-SPDX",
+      "type": "library",
+      "version": ""
+    },
+    {
+      "bom-ref": "C1",
+      "licenses": [
+        {
+          "expression": "Apache-2.0 OR MIT"
+        }
+      ],
+      "name": "c-with-expression",
+      "type": "library",
+      "version": ""
+    },
+    {
+      "bom-ref": "C3",
+      "licenses": [
+        {
+          "license": {
+            "name": "(c) ACME Inc."
+          }
+        }
+      ],
+      "name": "c-with-name",
+      "type": "library",
+      "version": ""
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "C1"
+    },
+    {
+      "ref": "C2"
+    },
+    {
+      "ref": "C3"
+    },
+    {
+      "ref": "S1"
+    },
+    {
+      "ref": "S2"
+    },
+    {
+      "ref": "S3"
+    },
+    {
+      "ref": "my-app"
+    }
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-app",
+      "licenses": [
+        {
+          "license": {
+            "name": "proprietary"
+          }
+        }
+      ],
+      "name": "app",
+      "type": "application",
+      "version": ""
+    },
+    "licenses": [
+      {
+        "license": {
+          "id": "CC-BY-1.0"
+        }
+      }
+    ],
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "services": [
+    {
+      "bom-ref": "S2",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "name": "s-with-SPDX"
+    },
+    {
+      "bom-ref": "S1",
+      "licenses": [
+        {
+          "expression": "Apache-2.0 OR MIT"
+        }
+      ],
+      "name": "s-with-expression"
+    },
+    {
+      "bom-ref": "S3",
+      "licenses": [
+        {
+          "license": {
+            "name": "(c) ACME Inc."
+          }
+        }
+      ],
+      "name": "s-with-name"
+    }
+  ],
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_licenses-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_licenses-1.3.xml.bin
new file mode 100644
index 000000000..897922111
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses-1.3.xml.bin
@@ -0,0 +1,87 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-app">
+      <name>app</name>
+      <version/>
+      <licenses>
+        <license>
+          <name>proprietary</name>
+        </license>
+      </licenses>
+    </component>
+    <licenses>
+      <license>
+        <id>CC-BY-1.0</id>
+      </license>
+    </licenses>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="C2">
+      <name>c-with-SPDX</name>
+      <version/>
+      <licenses>
+        <license>
+          <id>Apache-2.0</id>
+        </license>
+      </licenses>
+    </component>
+    <component type="library" bom-ref="C1">
+      <name>c-with-expression</name>
+      <version/>
+      <licenses>
+        <expression>Apache-2.0 OR MIT</expression>
+      </licenses>
+    </component>
+    <component type="library" bom-ref="C3">
+      <name>c-with-name</name>
+      <version/>
+      <licenses>
+        <license>
+          <name>(c) ACME Inc.</name>
+        </license>
+      </licenses>
+    </component>
+  </components>
+  <services>
+    <service bom-ref="S2">
+      <name>s-with-SPDX</name>
+      <licenses>
+        <license>
+          <id>Apache-2.0</id>
+        </license>
+      </licenses>
+    </service>
+    <service bom-ref="S1">
+      <name>s-with-expression</name>
+      <licenses>
+        <expression>Apache-2.0 OR MIT</expression>
+      </licenses>
+    </service>
+    <service bom-ref="S3">
+      <name>s-with-name</name>
+      <licenses>
+        <license>
+          <name>(c) ACME Inc.</name>
+        </license>
+      </licenses>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="C1"/>
+    <dependency ref="C2"/>
+    <dependency ref="C3"/>
+    <dependency ref="S1"/>
+    <dependency ref="S2"/>
+    <dependency ref="S3"/>
+    <dependency ref="my-app"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses-1.4.json.bin b/tests/_data/snapshots/get_bom_with_licenses-1.4.json.bin
new file mode 100644
index 000000000..a4965e690
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses-1.4.json.bin
@@ -0,0 +1,162 @@
+{
+  "components": [
+    {
+      "bom-ref": "C2",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "name": "c-with-SPDX",
+      "type": "library"
+    },
+    {
+      "bom-ref": "C1",
+      "licenses": [
+        {
+          "expression": "Apache-2.0 OR MIT"
+        }
+      ],
+      "name": "c-with-expression",
+      "type": "library"
+    },
+    {
+      "bom-ref": "C3",
+      "licenses": [
+        {
+          "license": {
+            "name": "(c) ACME Inc."
+          }
+        }
+      ],
+      "name": "c-with-name",
+      "type": "library"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "C1"
+    },
+    {
+      "ref": "C2"
+    },
+    {
+      "ref": "C3"
+    },
+    {
+      "ref": "S1"
+    },
+    {
+      "ref": "S2"
+    },
+    {
+      "ref": "S3"
+    },
+    {
+      "ref": "my-app"
+    }
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-app",
+      "licenses": [
+        {
+          "license": {
+            "name": "proprietary"
+          }
+        }
+      ],
+      "name": "app",
+      "type": "application"
+    },
+    "licenses": [
+      {
+        "license": {
+          "id": "CC-BY-1.0"
+        }
+      }
+    ],
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "services": [
+    {
+      "bom-ref": "S2",
+      "licenses": [
+        {
+          "license": {
+            "id": "Apache-2.0"
+          }
+        }
+      ],
+      "name": "s-with-SPDX"
+    },
+    {
+      "bom-ref": "S1",
+      "licenses": [
+        {
+          "expression": "Apache-2.0 OR MIT"
+        }
+      ],
+      "name": "s-with-expression"
+    },
+    {
+      "bom-ref": "S3",
+      "licenses": [
+        {
+          "license": {
+            "name": "(c) ACME Inc."
+          }
+        }
+      ],
+      "name": "s-with-name"
+    }
+  ],
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_licenses-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_licenses-1.4.xml.bin
new file mode 100644
index 000000000..2afc522a7
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses-1.4.xml.bin
@@ -0,0 +1,109 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-app">
+      <name>app</name>
+      <licenses>
+        <license>
+          <name>proprietary</name>
+        </license>
+      </licenses>
+    </component>
+    <licenses>
+      <license>
+        <id>CC-BY-1.0</id>
+      </license>
+    </licenses>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="C2">
+      <name>c-with-SPDX</name>
+      <licenses>
+        <license>
+          <id>Apache-2.0</id>
+        </license>
+      </licenses>
+    </component>
+    <component type="library" bom-ref="C1">
+      <name>c-with-expression</name>
+      <licenses>
+        <expression>Apache-2.0 OR MIT</expression>
+      </licenses>
+    </component>
+    <component type="library" bom-ref="C3">
+      <name>c-with-name</name>
+      <licenses>
+        <license>
+          <name>(c) ACME Inc.</name>
+        </license>
+      </licenses>
+    </component>
+  </components>
+  <services>
+    <service bom-ref="S2">
+      <name>s-with-SPDX</name>
+      <licenses>
+        <license>
+          <id>Apache-2.0</id>
+        </license>
+      </licenses>
+    </service>
+    <service bom-ref="S1">
+      <name>s-with-expression</name>
+      <licenses>
+        <expression>Apache-2.0 OR MIT</expression>
+      </licenses>
+    </service>
+    <service bom-ref="S3">
+      <name>s-with-name</name>
+      <licenses>
+        <license>
+          <name>(c) ACME Inc.</name>
+        </license>
+      </licenses>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="C1"/>
+    <dependency ref="C2"/>
+    <dependency ref="C3"/>
+    <dependency ref="S1"/>
+    <dependency ref="S2"/>
+    <dependency ref="S3"/>
+    <dependency ref="my-app"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses_expression-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_licenses_expression-1.0.xml.bin
new file mode 100644
index 000000000..acb066124
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses_expression-1.0.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses_expression-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_licenses_expression-1.1.xml.bin
new file mode 100644
index 000000000..55ef5cda2
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses_expression-1.1.xml.bin
@@ -0,0 +1,4 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components/>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses_expression-1.2.json.bin b/tests/_data/snapshots/get_bom_with_licenses_expression-1.2.json.bin
new file mode 100644
index 000000000..1165e037a
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses_expression-1.2.json.bin
@@ -0,0 +1,17 @@
+{
+  "metadata": {
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_licenses_expression-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_licenses_expression-1.2.xml.bin
new file mode 100644
index 000000000..bc36ede08
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses_expression-1.2.xml.bin
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+  </metadata>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses_expression-1.3.json.bin b/tests/_data/snapshots/get_bom_with_licenses_expression-1.3.json.bin
new file mode 100644
index 000000000..1d765cdb1
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses_expression-1.3.json.bin
@@ -0,0 +1,22 @@
+{
+  "metadata": {
+    "licenses": [
+      {
+        "expression": "Apache-2.0 OR MIT"
+      }
+    ],
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_licenses_expression-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_licenses_expression-1.3.xml.bin
new file mode 100644
index 000000000..bb16ef4fb
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses_expression-1.3.xml.bin
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <licenses>
+      <expression>Apache-2.0 OR MIT</expression>
+    </licenses>
+  </metadata>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_licenses_expression-1.4.json.bin b/tests/_data/snapshots/get_bom_with_licenses_expression-1.4.json.bin
new file mode 100644
index 000000000..d484276f7
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses_expression-1.4.json.bin
@@ -0,0 +1,56 @@
+{
+  "metadata": {
+    "licenses": [
+      {
+        "expression": "Apache-2.0 OR MIT"
+      }
+    ],
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_licenses_expression-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_licenses_expression-1.4.xml.bin
new file mode 100644
index 000000000..0361c11f5
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_licenses_expression-1.4.xml.bin
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <licenses>
+      <expression>Apache-2.0 OR MIT</expression>
+    </licenses>
+  </metadata>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.json.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.json.bin
index 522592fa2..8e1ad38b9 100644
--- a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.json.bin
@@ -38,7 +38,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.xml.bin
index 0370a0e36..9f181dd39 100644
--- a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.2.xml.bin
@@ -14,7 +14,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.json.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.json.bin
index 2aae8fac7..44d8a5732 100644
--- a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.json.bin
@@ -44,7 +44,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.xml.bin
index 1b6501308..6a0e37c38 100644
--- a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.3.xml.bin
@@ -14,7 +14,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.json.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.json.bin
index 531d42fcf..6852fd3b8 100644
--- a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.json.bin
@@ -44,7 +44,9 @@
       "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz",
       "licenses": [
         {
-          "expression": "MIT License"
+          "license": {
+            "id": "MIT"
+          }
         }
       ],
       "name": "setuptools",
diff --git a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.xml.bin
index 1464249f6..38c9e4796 100644
--- a/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_metadata_component_and_dependencies-1.4.xml.bin
@@ -40,7 +40,9 @@
       <name>setuptools</name>
       <version>50.3.2</version>
       <licenses>
-        <expression>MIT License</expression>
+        <license>
+          <id>MIT</id>
+        </license>
       </licenses>
       <purl>pkg:pypi/setuptools@50.3.2?extension=tar.gz</purl>
     </component>
diff --git a/tests/_data/snapshots/get_bom_with_multiple_licenses-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.0.xml.bin
new file mode 100644
index 000000000..13a20245d
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.0.xml.bin
@@ -0,0 +1,10 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
+  <components>
+    <component type="library">
+      <name>comp</name>
+      <version/>
+      <modified>false</modified>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_multiple_licenses-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.1.xml.bin
new file mode 100644
index 000000000..27b2bce0f
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.1.xml.bin
@@ -0,0 +1,17 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <components>
+    <component type="library" bom-ref="my-compo">
+      <name>comp</name>
+      <version/>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </component>
+  </components>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_multiple_licenses-1.2.json.bin b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.2.json.bin
new file mode 100644
index 000000000..19aadbf12
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.2.json.bin
@@ -0,0 +1,84 @@
+{
+  "components": [
+    {
+      "bom-ref": "my-compo",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "comp",
+      "type": "library",
+      "version": ""
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "my-app"
+    },
+    {
+      "ref": "my-compo"
+    },
+    {
+      "ref": "my-serv"
+    }
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-app",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "app",
+      "type": "application",
+      "version": ""
+    },
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "services": [
+    {
+      "bom-ref": "my-serv",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "serv"
+    }
+  ],
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.2"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_multiple_licenses-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.2.xml.bin
new file mode 100644
index 000000000..df26741d5
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.2.xml.bin
@@ -0,0 +1,57 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-app">
+      <name>app</name>
+      <version/>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </component>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="my-compo">
+      <name>comp</name>
+      <version/>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </component>
+  </components>
+  <services>
+    <service bom-ref="my-serv">
+      <name>serv</name>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-app"/>
+    <dependency ref="my-compo"/>
+    <dependency ref="my-serv"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_multiple_licenses-1.3.json.bin b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.3.json.bin
new file mode 100644
index 000000000..1a6eba500
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.3.json.bin
@@ -0,0 +1,96 @@
+{
+  "components": [
+    {
+      "bom-ref": "my-compo",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "comp",
+      "type": "library",
+      "version": ""
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "my-app"
+    },
+    {
+      "ref": "my-compo"
+    },
+    {
+      "ref": "my-serv"
+    }
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-app",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "app",
+      "type": "application",
+      "version": ""
+    },
+    "licenses": [
+      {
+        "license": {
+          "id": "MIT"
+        }
+      },
+      {
+        "license": {
+          "name": "foo license"
+        }
+      }
+    ],
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "services": [
+    {
+      "bom-ref": "my-serv",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "serv"
+    }
+  ],
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.3"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_multiple_licenses-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.3.xml.bin
new file mode 100644
index 000000000..1bb3e0ab1
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.3.xml.bin
@@ -0,0 +1,65 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-app">
+      <name>app</name>
+      <version/>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </component>
+    <licenses>
+      <license>
+        <id>MIT</id>
+      </license>
+      <license>
+        <name>foo license</name>
+      </license>
+    </licenses>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="my-compo">
+      <name>comp</name>
+      <version/>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </component>
+  </components>
+  <services>
+    <service bom-ref="my-serv">
+      <name>serv</name>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-app"/>
+    <dependency ref="my-compo"/>
+    <dependency ref="my-serv"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_multiple_licenses-1.4.json.bin b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.4.json.bin
new file mode 100644
index 000000000..b8751bb05
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.4.json.bin
@@ -0,0 +1,128 @@
+{
+  "components": [
+    {
+      "bom-ref": "my-compo",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "comp",
+      "type": "library"
+    }
+  ],
+  "dependencies": [
+    {
+      "ref": "my-app"
+    },
+    {
+      "ref": "my-compo"
+    },
+    {
+      "ref": "my-serv"
+    }
+  ],
+  "metadata": {
+    "component": {
+      "bom-ref": "my-app",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "app",
+      "type": "application"
+    },
+    "licenses": [
+      {
+        "license": {
+          "id": "MIT"
+        }
+      },
+      {
+        "license": {
+          "name": "foo license"
+        }
+      }
+    ],
+    "timestamp": "2023-01-07T13:44:32.312678+00:00",
+    "tools": [
+      {
+        "externalReferences": [
+          {
+            "type": "build-system",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
+          },
+          {
+            "type": "distribution",
+            "url": "https://pypi.org/project/cyclonedx-python-lib/"
+          },
+          {
+            "type": "documentation",
+            "url": "https://cyclonedx.github.io/cyclonedx-python-lib/"
+          },
+          {
+            "type": "issue-tracker",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
+          },
+          {
+            "type": "license",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
+          },
+          {
+            "type": "release-notes",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
+          },
+          {
+            "type": "vcs",
+            "url": "https://github.com/CycloneDX/cyclonedx-python-lib"
+          },
+          {
+            "type": "website",
+            "url": "https://cyclonedx.org"
+          }
+        ],
+        "name": "cyclonedx-python-lib",
+        "vendor": "CycloneDX",
+        "version": "TESTING"
+      }
+    ]
+  },
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "services": [
+    {
+      "bom-ref": "my-serv",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        },
+        {
+          "license": {
+            "name": "foo license"
+          }
+        }
+      ],
+      "name": "serv"
+    }
+  ],
+  "version": 1,
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4"
+}
\ No newline at end of file
diff --git a/tests/_data/snapshots/get_bom_with_multiple_licenses-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.4.xml.bin
new file mode 100644
index 000000000..7afbd2d73
--- /dev/null
+++ b/tests/_data/snapshots/get_bom_with_multiple_licenses-1.4.xml.bin
@@ -0,0 +1,89 @@
+<?xml version="1.0" ?>
+<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
+  <metadata>
+    <timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
+    <tools>
+      <tool>
+        <vendor>CycloneDX</vendor>
+        <name>cyclonedx-python-lib</name>
+        <version>TESTING</version>
+        <externalReferences>
+          <reference type="build-system">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
+          </reference>
+          <reference type="distribution">
+            <url>https://pypi.org/project/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="documentation">
+            <url>https://cyclonedx.github.io/cyclonedx-python-lib/</url>
+          </reference>
+          <reference type="issue-tracker">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
+          </reference>
+          <reference type="license">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
+          </reference>
+          <reference type="release-notes">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
+          </reference>
+          <reference type="vcs">
+            <url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
+          </reference>
+          <reference type="website">
+            <url>https://cyclonedx.org</url>
+          </reference>
+        </externalReferences>
+      </tool>
+    </tools>
+    <component type="application" bom-ref="my-app">
+      <name>app</name>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </component>
+    <licenses>
+      <license>
+        <id>MIT</id>
+      </license>
+      <license>
+        <name>foo license</name>
+      </license>
+    </licenses>
+  </metadata>
+  <components>
+    <component type="library" bom-ref="my-compo">
+      <name>comp</name>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </component>
+  </components>
+  <services>
+    <service bom-ref="my-serv">
+      <name>serv</name>
+      <licenses>
+        <license>
+          <id>MIT</id>
+        </license>
+        <license>
+          <name>foo license</name>
+        </license>
+      </licenses>
+    </service>
+  </services>
+  <dependencies>
+    <dependency ref="my-app"/>
+    <dependency ref="my-compo"/>
+    <dependency ref="my-serv"/>
+  </dependencies>
+</bom>
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.2.json.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.2.json.bin
index ae3197b79..e5ca79e97 100644
--- a/tests/_data/snapshots/get_bom_with_nested_services-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.2.json.bin
@@ -52,7 +52,9 @@
       "group": "a-group",
       "licenses": [
         {
-          "expression": "Commercial"
+          "license": {
+            "name": "Commercial"
+          }
         }
       ],
       "name": "my-first-service",
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.2.xml.bin
index e01e6b3ed..84fd1409e 100644
--- a/tests/_data/snapshots/get_bom_with_nested_services-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.2.xml.bin
@@ -43,7 +43,9 @@
         <classification flow="outbound">public</classification>
       </data>
       <licenses>
-        <expression>Commercial</expression>
+        <license>
+          <name>Commercial</name>
+        </license>
       </licenses>
       <externalReferences>
         <reference type="distribution">
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.3.json.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.3.json.bin
index 9ab746dbf..9b89174d3 100644
--- a/tests/_data/snapshots/get_bom_with_nested_services-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.3.json.bin
@@ -58,7 +58,9 @@
       "group": "a-group",
       "licenses": [
         {
-          "expression": "Commercial"
+          "license": {
+            "name": "Commercial"
+          }
         }
       ],
       "name": "my-first-service",
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.3.xml.bin
index 00c1fd2b9..29b5d27b1 100644
--- a/tests/_data/snapshots/get_bom_with_nested_services-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.3.xml.bin
@@ -43,7 +43,9 @@
         <classification flow="outbound">public</classification>
       </data>
       <licenses>
-        <expression>Commercial</expression>
+        <license>
+          <name>Commercial</name>
+        </license>
       </licenses>
       <externalReferences>
         <reference type="distribution">
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.4.json.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.4.json.bin
index be23872da..f11014a59 100644
--- a/tests/_data/snapshots/get_bom_with_nested_services-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.4.json.bin
@@ -92,7 +92,9 @@
       "group": "a-group",
       "licenses": [
         {
-          "expression": "Commercial"
+          "license": {
+            "name": "Commercial"
+          }
         }
       ],
       "name": "my-first-service",
diff --git a/tests/_data/snapshots/get_bom_with_nested_services-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_nested_services-1.4.xml.bin
index 986ed1589..78c93eed3 100644
--- a/tests/_data/snapshots/get_bom_with_nested_services-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_nested_services-1.4.xml.bin
@@ -69,7 +69,9 @@
         <classification flow="outbound">public</classification>
       </data>
       <licenses>
-        <expression>Commercial</expression>
+        <license>
+          <name>Commercial</name>
+        </license>
       </licenses>
       <externalReferences>
         <reference type="distribution">
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.2.json.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.2.json.bin
index 549dc40fc..d66fe485c 100644
--- a/tests/_data/snapshots/get_bom_with_services_complex-1.2.json.bin
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.2.json.bin
@@ -52,7 +52,9 @@
       "group": "a-group",
       "licenses": [
         {
-          "expression": "Commercial"
+          "license": {
+            "name": "Commercial"
+          }
         }
       ],
       "name": "my-first-service",
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.2.xml.bin
index 7e6b4b9f0..d03f661e3 100644
--- a/tests/_data/snapshots/get_bom_with_services_complex-1.2.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.2.xml.bin
@@ -43,7 +43,9 @@
         <classification flow="outbound">public</classification>
       </data>
       <licenses>
-        <expression>Commercial</expression>
+        <license>
+          <name>Commercial</name>
+        </license>
       </licenses>
       <externalReferences>
         <reference type="distribution">
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.3.json.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.3.json.bin
index 38ea8bb3f..a48276143 100644
--- a/tests/_data/snapshots/get_bom_with_services_complex-1.3.json.bin
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.3.json.bin
@@ -58,7 +58,9 @@
       "group": "a-group",
       "licenses": [
         {
-          "expression": "Commercial"
+          "license": {
+            "name": "Commercial"
+          }
         }
       ],
       "name": "my-first-service",
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.3.xml.bin
index 3725a7257..136d59a1b 100644
--- a/tests/_data/snapshots/get_bom_with_services_complex-1.3.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.3.xml.bin
@@ -43,7 +43,9 @@
         <classification flow="outbound">public</classification>
       </data>
       <licenses>
-        <expression>Commercial</expression>
+        <license>
+          <name>Commercial</name>
+        </license>
       </licenses>
       <externalReferences>
         <reference type="distribution">
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.4.json.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.4.json.bin
index b4d58520e..52ae938d2 100644
--- a/tests/_data/snapshots/get_bom_with_services_complex-1.4.json.bin
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.4.json.bin
@@ -92,7 +92,9 @@
       "group": "a-group",
       "licenses": [
         {
-          "expression": "Commercial"
+          "license": {
+            "name": "Commercial"
+          }
         }
       ],
       "name": "my-first-service",
diff --git a/tests/_data/snapshots/get_bom_with_services_complex-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_services_complex-1.4.xml.bin
index bb4f4a0ff..3c9b6dbed 100644
--- a/tests/_data/snapshots/get_bom_with_services_complex-1.4.xml.bin
+++ b/tests/_data/snapshots/get_bom_with_services_complex-1.4.xml.bin
@@ -69,7 +69,9 @@
         <classification flow="outbound">public</classification>
       </data>
       <licenses>
-        <expression>Commercial</expression>
+        <license>
+          <name>Commercial</name>
+        </license>
       </licenses>
       <externalReferences>
         <reference type="distribution">
diff --git a/tests/test_factory_license.py b/tests/test_factory_license.py
index 022f6ac25..7d21a1d32 100644
--- a/tests/test_factory_license.py
+++ b/tests/test_factory_license.py
@@ -19,8 +19,9 @@
 import unittest.mock
 
 from cyclonedx.exception.factory import InvalidLicenseExpressionException, InvalidSpdxLicenseException
-from cyclonedx.factory.license import LicenseChoiceFactory, LicenseFactory
-from cyclonedx.model import AttachedText, License, LicenseChoice, XsUri
+from cyclonedx.factory.license import LicenseFactory
+from cyclonedx.model import AttachedText, XsUri
+from cyclonedx.model.license import DisjunctiveLicense, LicenseExpression
 
 
 class TestFactoryLicense(unittest.TestCase):
@@ -28,27 +29,38 @@ class TestFactoryLicense(unittest.TestCase):
     def test_make_from_string_with_id(self) -> None:
         text = unittest.mock.NonCallableMock(spec=AttachedText)
         url = unittest.mock.NonCallableMock(spec=XsUri)
-        expected = License(id='bar', text=text, url=url)
+        expected = DisjunctiveLicense(id='bar', text=text, url=url)
 
-        with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value='bar'):
-            actual = LicenseFactory().make_from_string(name_or_spdx='foo', license_text=text, license_url=url)
+        with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value='bar'), \
+                unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=True):
+            actual = LicenseFactory().make_from_string('foo', license_text=text, license_url=url)
 
         self.assertEqual(expected, actual)
 
     def test_make_from_string_with_name(self) -> None:
         text = unittest.mock.NonCallableMock(spec=AttachedText)
         url = unittest.mock.NonCallableMock(spec=XsUri)
-        expected = License(name='foo', text=text, url=url)
+        expected = DisjunctiveLicense(name='foo', text=text, url=url)
 
-        with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value=None):
-            actual = LicenseFactory().make_from_string(name_or_spdx='foo', license_text=text, license_url=url)
+        with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value=None), \
+                unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=False):
+            actual = LicenseFactory().make_from_string('foo', license_text=text, license_url=url)
+
+        self.assertEqual(expected, actual)
+
+    def test_make_from_string_with_expression(self) -> None:
+        expected = LicenseExpression('foo')
+
+        with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value=None), \
+                unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=True):
+            actual = LicenseFactory().make_from_string('foo')
 
         self.assertEqual(expected, actual)
 
     def test_make_with_id(self) -> None:
         text = unittest.mock.NonCallableMock(spec=AttachedText)
         url = unittest.mock.NonCallableMock(spec=XsUri)
-        expected = License(id='bar', text=text, url=url)
+        expected = DisjunctiveLicense(id='bar', text=text, url=url)
 
         with unittest.mock.patch('cyclonedx.factory.license.spdx_fixup', return_value='bar'):
             actual = LicenseFactory().make_with_id(spdx_id='foo', text=text, url=url)
@@ -63,80 +75,17 @@ def test_make_with_id_raises(self) -> None:
     def test_make_with_name(self) -> None:
         text = unittest.mock.NonCallableMock(spec=AttachedText)
         url = unittest.mock.NonCallableMock(spec=XsUri)
-        expected = License(name='foo', text=text, url=url)
+        expected = DisjunctiveLicense(name='foo', text=text, url=url)
         actual = LicenseFactory().make_with_name(name='foo', text=text, url=url)
         self.assertEqual(expected, actual)
 
-
-class TestFactoryLicenseChoice(unittest.TestCase):
-
-    def test_make_from_string_with_license_id(self) -> None:
-        license_ = unittest.mock.NonCallableMock(spec=License)
-        expected = LicenseChoice(license=license_)
-        license_factory = unittest.mock.MagicMock(spec=LicenseFactory)
-        license_factory.make_with_id.return_value = license_
-        factory = LicenseChoiceFactory(license_factory=license_factory)
-
-        actual = factory.make_from_string('foo')
-
-        self.assertEqual(expected, actual)
-        self.assertIs(license_, actual.license)
-        license_factory.make_with_id.assert_called_once_with('foo')
-
-    def test_make_from_string_with_compound_expression(self) -> None:
-        expected = LicenseChoice(expression='foo')
-        license_factory = unittest.mock.MagicMock(spec=LicenseFactory)
-        license_factory.make_with_id.side_effect = InvalidSpdxLicenseException('foo')
-        factory = LicenseChoiceFactory(license_factory=license_factory)
-
-        with unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=True):
-            actual = factory.make_from_string('foo')
-
-        self.assertEqual(expected, actual)
-        license_factory.make_with_id.assert_called_once_with('foo')
-
-    def test_make_from_string_with_license_name(self) -> None:
-        license_ = unittest.mock.NonCallableMock(spec=License)
-        expected = LicenseChoice(license=license_)
-        license_factory = unittest.mock.MagicMock(spec=LicenseFactory)
-        license_factory.make_with_id.side_effect = InvalidSpdxLicenseException('foo')
-        license_factory.make_with_name.return_value = license_
-        factory = LicenseChoiceFactory(license_factory=license_factory)
-
-        with unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=False):
-            actual = factory.make_from_string('foo')
-
-        self.assertEqual(expected, actual)
-        self.assertIs(license_, actual.license)
-        license_factory.make_with_id.assert_called_once_with('foo')
-        license_factory.make_with_name.assert_called_once_with('foo')
-
-    def test_make_with_compound_expression(self) -> None:
-        expected = LicenseChoice(expression='foo')
-        factory = LicenseChoiceFactory(license_factory=unittest.mock.MagicMock(spec=LicenseFactory))
-
+    def test_make_with_expression(self) -> None:
+        expected = LicenseExpression('foo')
         with unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=True):
-            actual = factory.make_with_compound_expression('foo')
-
+            actual = LicenseFactory().make_with_expression(expression='foo')
         self.assertEqual(expected, actual)
 
-    def test_make_with_compound_expression_raises(self) -> None:
-        factory = LicenseChoiceFactory(license_factory=unittest.mock.MagicMock(spec=LicenseFactory))
-        with unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=False):
-            with self.assertRaises(InvalidLicenseExpressionException, msg='foo'):
-                factory.make_with_compound_expression('foo')
-
-    def test_make_with_license(self) -> None:
-        text = unittest.mock.NonCallableMock(spec=AttachedText)
-        url = unittest.mock.NonCallableMock(spec=XsUri)
-        license_ = unittest.mock.NonCallableMock(spec=License)
-        expected = LicenseChoice(license=license_)
-        license_factory = unittest.mock.MagicMock(spec=LicenseFactory)
-        license_factory.make_from_string.return_value = license_
-        factory = LicenseChoiceFactory(license_factory=license_factory)
-
-        actual = factory.make_with_license('foo', license_text=text, license_url=url)
-
-        self.assertEqual(expected, actual)
-        self.assertIs(license_, actual.license)
-        license_factory.make_from_string.assert_called_once_with('foo', license_text=text, license_url=url)
+    def test_make_with_expression_raises(self) -> None:
+        with self.assertRaises(InvalidLicenseExpressionException, msg='foo'):
+            with unittest.mock.patch('cyclonedx.factory.license.is_spdx_compound_expression', return_value=False):
+                LicenseFactory().make_with_expression('foo')
diff --git a/tests/test_model.py b/tests/test_model.py
index af4e8ae81..97ffc4a9e 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -35,8 +35,6 @@
     HashAlgorithm,
     HashType,
     IdentifiableAction,
-    License,
-    LicenseChoice,
     Note,
     NoteText,
     OrganizationalContact,
@@ -157,41 +155,6 @@ def test_compare_enum_then_none(self) -> None:
         self.assertNotEqual(tuple2, tuple1)
 
 
-class TestModelLicense(TestCase):
-
-    def test_sort(self) -> None:
-        # expected sort order: ([id], [name])
-        expected_order = [1, 0, 3, 2]
-        licenses = [
-            License(id='MIT'),
-            License(id='Apache-2.0'),
-            License(name='MIT'),
-            License(name='Apache-2.0'),
-        ]
-        sorted_licenses = sorted(licenses)
-        expected_licenses = reorder(licenses, expected_order)
-        self.assertListEqual(sorted_licenses, expected_licenses)
-
-
-class TestModelLicenseChoice(TestCase):
-
-    def test_sort(self) -> None:
-        license_a = License(id='Apache-2.0')
-        license_b = License(id='MIT')
-
-        # expected sort order: ([license], [expression])
-        expected_order = [1, 0, 3, 2]
-        licenses = [
-            LicenseChoice(license=license_b),
-            LicenseChoice(license=license_a),
-            LicenseChoice(expression='MIT'),
-            LicenseChoice(expression='Apache-2.0'),
-        ]
-        sorted_licenses = sorted(licenses)
-        expected_licenses = reorder(licenses, expected_order)
-        self.assertListEqual(sorted_licenses, expected_licenses)
-
-
 class TestModelCopyright(TestCase):
 
     def test_same(self) -> None:
diff --git a/tests/test_model_bom.py b/tests/test_model_bom.py
index 0eb62d6c5..8336f58e0 100644
--- a/tests/test_model_bom.py
+++ b/tests/test_model_bom.py
@@ -23,18 +23,11 @@
 from ddt import ddt, named_data
 
 from cyclonedx.exception.model import LicenseExpressionAlongWithOthersException
-from cyclonedx.model import (
-    License,
-    LicenseChoice,
-    OrganizationalContact,
-    OrganizationalEntity,
-    Property,
-    ThisTool,
-    Tool,
-)
+from cyclonedx.model import OrganizationalContact, OrganizationalEntity, Property, ThisTool, Tool
 from cyclonedx.model.bom import Bom, BomMetaData
 from cyclonedx.model.bom_ref import BomRef
 from cyclonedx.model.component import Component, ComponentType
+from cyclonedx.model.license import DisjunctiveLicense
 from tests._data.models import (
     get_bom_component_licenses_invalid,
     get_bom_component_nested_licenses_invalid,
@@ -76,8 +69,8 @@ def test_basic_bom_metadata(self) -> None:
         manufacturer = OrganizationalEntity(name='test_manufacturer')
         supplier = OrganizationalEntity(name='test_supplier')
         licenses = [
-            LicenseChoice(license=License(id='MIT')),
-            LicenseChoice(license=License(id='Apache-2.0')),
+            DisjunctiveLicense(id='MIT'),
+            DisjunctiveLicense(id='Apache-2.0'),
         ]
         properties = [
             Property(name='property_1', value='value_1'),
diff --git a/tests/test_model_license.py b/tests/test_model_license.py
new file mode 100644
index 000000000..1ccfa534e
--- /dev/null
+++ b/tests/test_model_license.py
@@ -0,0 +1,117 @@
+# This file is part of CycloneDX Python Lib
+#
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+
+from random import shuffle
+from unittest import TestCase
+from unittest.mock import MagicMock
+
+from cyclonedx.exception.model import MutuallyExclusivePropertiesException
+from cyclonedx.model import AttachedText, XsUri
+from cyclonedx.model.license import DisjunctiveLicense, LicenseExpression
+from tests import reorder
+
+
+class TestModelDisjunctiveLicense(TestCase):
+    def test_create_complete_id(self) -> None:
+        text = MagicMock(spec=AttachedText)
+        url = MagicMock(spec=XsUri)
+        license = DisjunctiveLicense(id='foo', text=text, url=url)
+        self.assertEqual('foo', license.id)
+        self.assertIsNone(license.name)
+        self.assertIs(text, license.text)
+        self.assertIs(url, license.url)
+
+    def test_update_id_name(self) -> None:
+        license = DisjunctiveLicense(id='foo')
+        self.assertEqual('foo', license.id)
+        self.assertIsNone(license.name)
+        license.name = 'bar'
+        self.assertIsNone(license.id)
+        self.assertEqual('bar', license.name)
+
+    def test_create_complete_named(self) -> None:
+        text = MagicMock(spec=AttachedText)
+        url = MagicMock(spec=XsUri)
+        license = DisjunctiveLicense(name='foo', text=text, url=url)
+        self.assertIsNone(license.id)
+        self.assertEqual('foo', license.name)
+        self.assertIs(text, license.text)
+        self.assertIs(url, license.url)
+
+    def test_update_name_id(self) -> None:
+        license = DisjunctiveLicense(name='foo')
+        self.assertEqual('foo', license.name)
+        self.assertIsNone(license.id)
+        license.id = 'bar'
+        self.assertIsNone(license.name)
+        self.assertEqual('bar', license.id)
+
+    def test_throws_when_no_id_nor_name(self) -> None:
+        with self.assertRaises(MutuallyExclusivePropertiesException):
+            DisjunctiveLicense(id=None, name=None)
+
+    def test_prefers_id_over_name(self) -> None:
+        with self.assertWarnsRegex(
+                RuntimeWarning,
+                'Both `id` and `name` have been supplied - `name` will be ignored!'):
+            license = DisjunctiveLicense(id='foo', name='bar')
+        self.assertEqual('foo', license.id)
+        self.assertEqual(None, license.name)
+
+    def test_equal(self) -> None:
+        a = DisjunctiveLicense(id='foo', name='bar')
+        b = DisjunctiveLicense(id='foo', name='bar')
+        c = DisjunctiveLicense(id='bar', name='foo')
+        self.assertEqual(a, b)
+        self.assertNotEqual(a, c)
+        self.assertNotEqual(a, 'foo')
+
+
+class TestModelLicenseExpression(TestCase):
+    def test_create(self) -> None:
+        license = LicenseExpression('foo')
+        self.assertEqual('foo', license.value)
+
+    def test_update(self) -> None:
+        license = LicenseExpression('foo')
+        self.assertEqual('foo', license.value)
+        license.value = 'bar'
+        self.assertEqual('bar', license.value)
+
+    def test_equal(self) -> None:
+        a = LicenseExpression('foo')
+        b = LicenseExpression('foo')
+        c = LicenseExpression('bar')
+        self.assertEqual(a, b)
+        self.assertNotEqual(a, c)
+        self.assertNotEqual(a, 'foo')
+
+
+class TestModelLicense(TestCase):
+
+    def test_sort_mixed(self) -> None:
+        expected_order = [1, 2, 0]
+        licenses = [
+            DisjunctiveLicense(name='my license'),
+            LicenseExpression(value='MIT or Apache-2.0'),
+            DisjunctiveLicense(id='MIT'),
+        ]
+        expected_licenses = reorder(licenses, expected_order)
+        shuffle(licenses)
+        sorted_licenses = sorted(licenses)
+        self.assertListEqual(sorted_licenses, expected_licenses)

From 4c2ef14017467980509bdb69f937b5098d8c0965 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Wed, 11 Oct 2023 11:10:04 +0200
Subject: [PATCH 26/42] tests for backwards compatibility of #365 (#467)

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .../own/json/1.2/bom_with_mixed_licenses.json | 47 +++++++++++++++++++
 .../own/json/1.3/bom_with_mixed_licenses.json | 47 +++++++++++++++++++
 .../own/json/1.4/bom_with_mixed_licenses.json | 47 +++++++++++++++++++
 tests/test_deserialize_json.py                | 35 ++++++++++++--
 tests/test_deserialize_xml.py                 |  2 +-
 5 files changed, 174 insertions(+), 4 deletions(-)
 create mode 100644 tests/_data/own/json/1.2/bom_with_mixed_licenses.json
 create mode 100644 tests/_data/own/json/1.3/bom_with_mixed_licenses.json
 create mode 100644 tests/_data/own/json/1.4/bom_with_mixed_licenses.json

diff --git a/tests/_data/own/json/1.2/bom_with_mixed_licenses.json b/tests/_data/own/json/1.2/bom_with_mixed_licenses.json
new file mode 100644
index 000000000..da4d3c54f
--- /dev/null
+++ b/tests/_data/own/json/1.2/bom_with_mixed_licenses.json
@@ -0,0 +1,47 @@
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "metadata": {
+    "component": {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"expression": "MIT OR Apache-2.0"},
+        {"license": {"id": "MIT"}},
+        {"license": {"name": "foo license"}}
+      ],
+      "name": "app",
+      "type": "application"
+    },
+    "licenses": [
+      {"license": {"name": "foo license"}},
+      {"license": {"id": "MIT"}},
+      {"expression": "MIT OR Apache-2.0"}
+    ]
+  },
+  "components": [
+    {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"license": {"id": "MIT"}},
+        {"license": {"name": "foo license"}},
+        {"expression": "MIT OR Apache-2.0"}
+      ],
+      "name": "comp",
+      "type": "library"
+    }
+  ],
+  "services": [
+    {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"license": {"name": "foo license"}},
+        {"expression": "MIT OR Apache-2.0"},
+        {"license": {"id": "MIT"}}
+      ],
+      "name": "serv"
+    }
+  ],
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1337
+}
diff --git a/tests/_data/own/json/1.3/bom_with_mixed_licenses.json b/tests/_data/own/json/1.3/bom_with_mixed_licenses.json
new file mode 100644
index 000000000..da4d3c54f
--- /dev/null
+++ b/tests/_data/own/json/1.3/bom_with_mixed_licenses.json
@@ -0,0 +1,47 @@
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "metadata": {
+    "component": {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"expression": "MIT OR Apache-2.0"},
+        {"license": {"id": "MIT"}},
+        {"license": {"name": "foo license"}}
+      ],
+      "name": "app",
+      "type": "application"
+    },
+    "licenses": [
+      {"license": {"name": "foo license"}},
+      {"license": {"id": "MIT"}},
+      {"expression": "MIT OR Apache-2.0"}
+    ]
+  },
+  "components": [
+    {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"license": {"id": "MIT"}},
+        {"license": {"name": "foo license"}},
+        {"expression": "MIT OR Apache-2.0"}
+      ],
+      "name": "comp",
+      "type": "library"
+    }
+  ],
+  "services": [
+    {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"license": {"name": "foo license"}},
+        {"expression": "MIT OR Apache-2.0"},
+        {"license": {"id": "MIT"}}
+      ],
+      "name": "serv"
+    }
+  ],
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1337
+}
diff --git a/tests/_data/own/json/1.4/bom_with_mixed_licenses.json b/tests/_data/own/json/1.4/bom_with_mixed_licenses.json
new file mode 100644
index 000000000..da4d3c54f
--- /dev/null
+++ b/tests/_data/own/json/1.4/bom_with_mixed_licenses.json
@@ -0,0 +1,47 @@
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "metadata": {
+    "component": {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"expression": "MIT OR Apache-2.0"},
+        {"license": {"id": "MIT"}},
+        {"license": {"name": "foo license"}}
+      ],
+      "name": "app",
+      "type": "application"
+    },
+    "licenses": [
+      {"license": {"name": "foo license"}},
+      {"license": {"id": "MIT"}},
+      {"expression": "MIT OR Apache-2.0"}
+    ]
+  },
+  "components": [
+    {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"license": {"id": "MIT"}},
+        {"license": {"name": "foo license"}},
+        {"expression": "MIT OR Apache-2.0"}
+      ],
+      "name": "comp",
+      "type": "library"
+    }
+  ],
+  "services": [
+    {
+      "description": "before CDX 1.5 it was allowed to mix `expression` and `license`",
+      "licenses": [
+        {"license": {"name": "foo license"}},
+        {"expression": "MIT OR Apache-2.0"},
+        {"license": {"id": "MIT"}}
+      ],
+      "name": "serv"
+    }
+  ],
+  "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
+  "version": 1337
+}
diff --git a/tests/test_deserialize_json.py b/tests/test_deserialize_json.py
index fe9ff1776..c3b670d04 100644
--- a/tests/test_deserialize_json.py
+++ b/tests/test_deserialize_json.py
@@ -17,15 +17,17 @@
 
 
 from json import loads as json_loads
+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 ddt import data, ddt, named_data
 
 from cyclonedx.model.bom import Bom
+from cyclonedx.model.license import DisjunctiveLicense, LicenseExpression, LicenseRepository
 from cyclonedx.schema import OutputFormat, SchemaVersion
-from tests import DeepCompareMixin, SnapshotMixin, mksname, uuid_generator
+from tests import OWN_DATA_DIRECTORY, DeepCompareMixin, SnapshotMixin, mksname, uuid_generator
 from tests._data.models import all_get_bom_funct_valid, all_get_bom_funct_with_incomplete_deps
 
 
@@ -35,7 +37,7 @@ class TestDeserializeJson(TestCase, SnapshotMixin, DeepCompareMixin):
     @named_data(*all_get_bom_funct_valid)
     @patch('cyclonedx.model.ThisTool._version', 'TESTING')
     @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
-    def test(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
+    def test_prepared(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
         # only latest schema will have all data populated in serialized form
         snapshot_name = mksname(get_bom, SchemaVersion.V1_4, OutputFormat.JSON)
         expected = get_bom()
@@ -43,3 +45,30 @@ def test(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
         bom = Bom.from_json(json)
         self.assertBomDeepEqual(expected, bom,
                                 fuzzy_deps=get_bom in all_get_bom_funct_with_incomplete_deps)
+
+    @data(SchemaVersion.V1_4, SchemaVersion.V1_3, SchemaVersion.V1_2)
+    def test_mixed_licenses_before15(self, sv: SchemaVersion) -> None:
+        # before CDX 1.5 it was allowed to mix `expression` and `license`
+        def test(ls: LicenseRepository) -> None:
+            self.assertEqual(3, len(ls))
+            expression: LicenseExpression = next((
+                li for li in ls if isinstance(li, LicenseExpression)
+            ), None)
+            with_id: DisjunctiveLicense = next((
+                li for li in ls if isinstance(li, DisjunctiveLicense) and li.id is not None
+            ), None)
+            with_name: DisjunctiveLicense = next((
+                li for li in ls if isinstance(li, DisjunctiveLicense) and li.name is not None
+            ), None)
+            self.assertEqual('MIT OR Apache-2.0', expression.value)
+            self.assertEqual('MIT', with_id.id)
+            self.assertEqual('foo license', with_name.name)
+
+        json_file = join(OWN_DATA_DIRECTORY, 'json', sv.to_version(), 'bom_with_mixed_licenses.json')
+        with open(json_file) as f:
+            json = json_loads(f.read())
+        bom: Bom = Bom.from_json(json)
+        test(bom.metadata.licenses)
+        test(bom.metadata.component.licenses)
+        test(list(bom.components)[0].licenses)
+        test(list(bom.services)[0].licenses)
diff --git a/tests/test_deserialize_xml.py b/tests/test_deserialize_xml.py
index 3b2652d81..d4c5688af 100644
--- a/tests/test_deserialize_xml.py
+++ b/tests/test_deserialize_xml.py
@@ -34,7 +34,7 @@ class TestDeserializeXml(TestCase, SnapshotMixin, DeepCompareMixin):
     @named_data(*all_get_bom_funct_valid)
     @patch('cyclonedx.model.ThisTool._version', 'TESTING')
     @patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
-    def test(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
+    def test_prepared(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
         # only latest schema will have all data populated in serialized form
         snapshot_name = mksname(get_bom, SchemaVersion.V1_4, OutputFormat.XML)
         expected = get_bom()

From bae8a84e7aa329780f91f49212c15f4d8c13ddcb Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Wed, 11 Oct 2023 11:55:12 +0200
Subject: [PATCH 27/42] chore!: bump major version to v5

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 pyproject.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyproject.toml b/pyproject.toml
index e80454138..33762aee2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
 [tool.poetry]
 name = "cyclonedx-python-lib"
 # !! version is managed by semantic_release
-version = "5.0.0-alpha.1"
+version = "5.0.0-rc.0"
 description = "A library for producing CycloneDX SBOM (Software Bill of Materials) files."
 authors = [
   "Paul Horton <phorton@sonatype.com>",

From 4d65b10b7a3da192a00fbde7180a445febe9baf4 Mon Sep 17 00:00:00 2001
From: semantic-release <semantic-release>
Date: Wed, 11 Oct 2023 10:03:51 +0000
Subject: [PATCH 28/42] chore(release): 5.0.0-rc.1

Automatically generated by python-semantic-release

Signed-off-by: semantic-release <semantic-release>
---
 CHANGELOG.md          | 240 ++++++++++++++++++++++++++++++++++++++++++
 cyclonedx/__init__.py |   2 +-
 docs/conf.py          |   2 +-
 pyproject.toml        |   2 +-
 4 files changed, 243 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d27fe25f3..10b9d20bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,246 @@
 
 
 
+## v5.0.0-rc.1 (2023-10-11)
+
+### Breaking
+
+* chore!: bump major version to v5
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`bae8a84`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/bae8a84e7aa329780f91f49212c15f4d8c13ddcb))
+
+### Chore
+
+* chore: revisit license headers
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1e963bd`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1e963bd3d7e6c7d9437e41a34ecd622e0d32f3d8))
+
+* chore: clean deps
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`ac6ad0e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/ac6ad0ed5b5933f03d1132c3bbce0ada1915fc40))
+
+* chore: remove encoding hint (#459)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`37219c3`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/37219c321ac7ce5b507a0c0a74776f8204b400bf))
+
+* chore: Update CONTRIBUTING.md
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`0ebaa21`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0ebaa216d43a1389362dbdb33f9b49f43a21ab66))
+
+* chore: config sem-release
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`839fe11`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/839fe114bafac6117879175eb54a8759b7ef8963))
+
+* chore: sem-release config
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`18b4eca`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/18b4eca2c0fe2a2b4f1ca79976719c1afa0816bc))
+
+* chore: absolute tet imports
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`39e0eb9`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/39e0eb9af29a13e1cad6a073e5eb20955e492484))
+
+* chore(build): test before release
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5cb695e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5cb695ebf9989f9bdefaa6823f5814d5c2fe9998))
+
+* chore: init 5.0.0-dev
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`0a3ae26`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0a3ae26f8fe50e1dc03fb72fb7fdba51654c7f8b))
+
+### Ci
+
+* ci: publish coverage report to codacy (#439)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`0012a82`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0012a82382f9f33831a80aa0e26c0cbb7fd8984b))
+
+### Documentation
+
+* docs: fix hilighter
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`9d49280`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/9d49280b680a4f8a7c4b8795f35928584e29baee))
+
+* docs: fix typo
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`6adc98f`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/6adc98f66da94b7bac987bc5b25da7099498fe3a))
+
+### Feature
+
+* feat: support python 3.12 (#460)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`eaba7a0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/eaba7a048de190bce0797fb9ce40c4e2de49c5d9))
+
+* feat: options for beautiful output (#458)
+
+add indention to outputters. this may come at a cost!
+
+
+Breaking Changes
+------------------
+* abstract Method `output.BaseOutput.output_as_string()` got new optional kwarg `indent`
+* abstract Method `output.BaseOutput.output_as_string()` accepts arbitrary kwargs
+
+Changed
+----------
+* XML output uses a default namespace, which makes results smaller.
+
+
+Added
+------------------
+* All outputters&#39; method `output_as_string()` got new optional kwarg `indent`
+* All outputters&#39; method `output_as_string()` accepts arbitrary kwargs
+* All outputters&#39; method `output_to_file()` got new optional kwarg `indent`
+* All outputters&#39; method `output_to_file()` accepts arbitrary kwargs
+
+-----
+
+- [x] implementation
+- [x] tests (snapshot binary compare; structural equal compare) 
+
+-----
+
+enables https://github.com/CycloneDX/cyclonedx-python/issues/424
+fixes #437
+fixes #438
+supersedes #449
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`3bcd9e9`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/3bcd9e99a58b74c9dc1fc474b468e67fc92fb7c4))
+
+* feat: easy access validators (#448)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1c9ea9e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1c9ea9e22e53933347a8f366c5fc06febe811757))
+
+* feat: add CycloneDX document validators to public API (#433)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a4f5ec5`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a4f5ec5d63d576c04bcef5c0b6641f6c47164cfb))
+
+### Fix
+
+* fix: multiple licenses issue #365 (#466)
+
+breaking changes
+------------------
+* Reworked license related models and collections
+* API
+  * Removed class `factory.license.LicenseChoiceFactory`  
+    The old functionality was integrated into `factory.license.LicenseFactory`.
+  * Method `factory.license.LicenseFactory.make_from_string()`&#39;s parameter `name_or_spdx` was renamed to `value`
+  * Method `factory.license.LicenseFactory.make_from_string()`&#39;s return value can also be a `LicenseExpression`
+    The behavior imitates the old `factory.license.LicenseChoiceFactory.make_from_string()`
+  * Renamed class `module.License` to `module.license.DisjunctliveLicense`
+  * Removed class `module.LicenseChoice`
+    Use dedicated classes `module.license.DisjunctliveLicense` and `module.license.LicenseExpression` instead
+  * All occurrences of `models.LicenseChoice` were replaced by `models.licenses.License`
+  * All occurrences of `SortedSet[LicenseChoice]` were specialized to `models.license.LicenseRepository`
+
+
+fixes
+------------------
+* serialization of multy-licenses #365
+
+added
+------------------
+* API
+  * Method `factory.license.LicenseFactory.make_with_expression()`
+  * Class `model.license.DisjunctiveLicense`
+  * Class `model.license.LicenseExpression`
+  * Class `model.license.LicenseRepository`
+  * Class `serialization.LicenseRepositoryHelper`
+
+tests
+------------------
+* added regression test for bug #365
+
+misc
+------------------
+* raised dependency `py-serializable@^9.15`
+
+
+
+----
+
+fixes #365
+
+~~BLOCKED by a feature request to serializer: &lt;https://github.com/madpah/serializable/pull/32&gt;~~
+
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`6770786`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/67707864ac0f1b27bac166a8fd537ea38523fe6f))
+
+* fix: typing for `kwargs` (#462)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`2240b4d`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/2240b4dda824c13bc563bce1574dffe563016ac2))
+
+* fix: tuple stuff (#461)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`84c6504`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/84c6504fc92d1207135f7719b6b6477fae7950cb))
+
+* fix: `bom.validate()` detects invalid license constellations (#452)
+
+
+
+If a LicenseExpression is set, then there must be no other license.
+
+fixes #453
+
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`16843b2`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/16843b29086d8f871a7239c33beb930543cfde45))
+
+### Performance
+
+* perf: make validation more secure
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5d7b86c`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5d7b86c0ba84fe17becc53b2ccf4385113f90905))
+
+### Unknown
+
+* tests for backwards compatibility of #365 (#467)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`4c2ef14`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/4c2ef14017467980509bdb69f937b5098d8c0965))
+
+* tests: snapshots and complete deep comparison, instead of pseudo-compare (#464)
+
+part of https://github.com/CycloneDX/cyclonedx-python-lib/issues/437
+also fixed a bug: unused first level dependencies were not detected. now they are.
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`7543789`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/75437896c04e352b51d83e6e52cf94874347f4a6))
+
+* Feat: typing, typehints, &amp; overload (#463)
+
+also: bump `py-serializable@^0.14.0`
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a68ae24`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a68ae2464539d07ed0fc037aa1e315e5ccda054a))
+
+* Merge branch &#39;main&#39; into 5.0.0-dev ([`c8c2183`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/c8c218366298ccc340e769fa180204e79a9a0f3e))
+
+* tests: use internal json strict validation
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`7186b52`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/7186b52a540e478196799ef7a3580f48f77544e9))
+
+* proper enums (#447)
+
+fixes #442
+part of #446
+
+BREAKING CHANGE
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`06b5eb0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/06b5eb03d479e9908b9b62bcee48d23a873dd4ba))
+
+* typo
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`3de2493`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/3de24936533a51c0cbf61de4b19785ee7407526c))
+
+* Drop py37 (#441)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1571d21`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1571d21057b11f11cb81e74a5a702f7f30582b09))
+
+
 ## v4.2.2 (2023-09-14)
 
 ### Chore
diff --git a/cyclonedx/__init__.py b/cyclonedx/__init__.py
index d51cb1fac..6ff0623a9 100644
--- a/cyclonedx/__init__.py
+++ b/cyclonedx/__init__.py
@@ -20,4 +20,4 @@
 
 # !! version is managed by semantic_release
 # do not use typing here, or else `semantic_release` might have issues finding the variable
-__version__ = "5.0.0-alpha.1"
+__version__ = "5.0.0-rc.1"
diff --git a/docs/conf.py b/docs/conf.py
index 4225ce4ea..9bc5732eb 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -20,7 +20,7 @@
 
 # The full version, including alpha/beta/rc tags
 # !! version is managed by semantic_release
-release = '5.0.0-alpha.1'
+release = '5.0.0-rc.1'
 
 # -- General configuration ---------------------------------------------------
 
diff --git a/pyproject.toml b/pyproject.toml
index 33762aee2..223f10356 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
 [tool.poetry]
 name = "cyclonedx-python-lib"
 # !! version is managed by semantic_release
-version = "5.0.0-rc.0"
+version = "5.0.0-rc.1"
 description = "A library for producing CycloneDX SBOM (Software Bill of Materials) files."
 authors = [
   "Paul Horton <phorton@sonatype.com>",

From a911106d09a7b5538e5ae77edf4fc4c2122f1f8b Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Wed, 11 Oct 2023 12:56:25 +0200
Subject: [PATCH 29/42] chore: revert changelog

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 CHANGELOG.md | 240 ---------------------------------------------------
 1 file changed, 240 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10b9d20bc..d27fe25f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,246 +2,6 @@
 
 
 
-## v5.0.0-rc.1 (2023-10-11)
-
-### Breaking
-
-* chore!: bump major version to v5
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`bae8a84`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/bae8a84e7aa329780f91f49212c15f4d8c13ddcb))
-
-### Chore
-
-* chore: revisit license headers
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1e963bd`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1e963bd3d7e6c7d9437e41a34ecd622e0d32f3d8))
-
-* chore: clean deps
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`ac6ad0e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/ac6ad0ed5b5933f03d1132c3bbce0ada1915fc40))
-
-* chore: remove encoding hint (#459)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`37219c3`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/37219c321ac7ce5b507a0c0a74776f8204b400bf))
-
-* chore: Update CONTRIBUTING.md
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`0ebaa21`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0ebaa216d43a1389362dbdb33f9b49f43a21ab66))
-
-* chore: config sem-release
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`839fe11`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/839fe114bafac6117879175eb54a8759b7ef8963))
-
-* chore: sem-release config
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`18b4eca`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/18b4eca2c0fe2a2b4f1ca79976719c1afa0816bc))
-
-* chore: absolute tet imports
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`39e0eb9`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/39e0eb9af29a13e1cad6a073e5eb20955e492484))
-
-* chore(build): test before release
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5cb695e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5cb695ebf9989f9bdefaa6823f5814d5c2fe9998))
-
-* chore: init 5.0.0-dev
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`0a3ae26`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0a3ae26f8fe50e1dc03fb72fb7fdba51654c7f8b))
-
-### Ci
-
-* ci: publish coverage report to codacy (#439)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`0012a82`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0012a82382f9f33831a80aa0e26c0cbb7fd8984b))
-
-### Documentation
-
-* docs: fix hilighter
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`9d49280`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/9d49280b680a4f8a7c4b8795f35928584e29baee))
-
-* docs: fix typo
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`6adc98f`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/6adc98f66da94b7bac987bc5b25da7099498fe3a))
-
-### Feature
-
-* feat: support python 3.12 (#460)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`eaba7a0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/eaba7a048de190bce0797fb9ce40c4e2de49c5d9))
-
-* feat: options for beautiful output (#458)
-
-add indention to outputters. this may come at a cost!
-
-
-Breaking Changes
-------------------
-* abstract Method `output.BaseOutput.output_as_string()` got new optional kwarg `indent`
-* abstract Method `output.BaseOutput.output_as_string()` accepts arbitrary kwargs
-
-Changed
-----------
-* XML output uses a default namespace, which makes results smaller.
-
-
-Added
-------------------
-* All outputters&#39; method `output_as_string()` got new optional kwarg `indent`
-* All outputters&#39; method `output_as_string()` accepts arbitrary kwargs
-* All outputters&#39; method `output_to_file()` got new optional kwarg `indent`
-* All outputters&#39; method `output_to_file()` accepts arbitrary kwargs
-
------
-
-- [x] implementation
-- [x] tests (snapshot binary compare; structural equal compare) 
-
------
-
-enables https://github.com/CycloneDX/cyclonedx-python/issues/424
-fixes #437
-fixes #438
-supersedes #449
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`3bcd9e9`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/3bcd9e99a58b74c9dc1fc474b468e67fc92fb7c4))
-
-* feat: easy access validators (#448)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1c9ea9e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1c9ea9e22e53933347a8f366c5fc06febe811757))
-
-* feat: add CycloneDX document validators to public API (#433)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a4f5ec5`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a4f5ec5d63d576c04bcef5c0b6641f6c47164cfb))
-
-### Fix
-
-* fix: multiple licenses issue #365 (#466)
-
-breaking changes
-------------------
-* Reworked license related models and collections
-* API
-  * Removed class `factory.license.LicenseChoiceFactory`  
-    The old functionality was integrated into `factory.license.LicenseFactory`.
-  * Method `factory.license.LicenseFactory.make_from_string()`&#39;s parameter `name_or_spdx` was renamed to `value`
-  * Method `factory.license.LicenseFactory.make_from_string()`&#39;s return value can also be a `LicenseExpression`
-    The behavior imitates the old `factory.license.LicenseChoiceFactory.make_from_string()`
-  * Renamed class `module.License` to `module.license.DisjunctliveLicense`
-  * Removed class `module.LicenseChoice`
-    Use dedicated classes `module.license.DisjunctliveLicense` and `module.license.LicenseExpression` instead
-  * All occurrences of `models.LicenseChoice` were replaced by `models.licenses.License`
-  * All occurrences of `SortedSet[LicenseChoice]` were specialized to `models.license.LicenseRepository`
-
-
-fixes
-------------------
-* serialization of multy-licenses #365
-
-added
-------------------
-* API
-  * Method `factory.license.LicenseFactory.make_with_expression()`
-  * Class `model.license.DisjunctiveLicense`
-  * Class `model.license.LicenseExpression`
-  * Class `model.license.LicenseRepository`
-  * Class `serialization.LicenseRepositoryHelper`
-
-tests
-------------------
-* added regression test for bug #365
-
-misc
-------------------
-* raised dependency `py-serializable@^9.15`
-
-
-
-----
-
-fixes #365
-
-~~BLOCKED by a feature request to serializer: &lt;https://github.com/madpah/serializable/pull/32&gt;~~
-
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`6770786`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/67707864ac0f1b27bac166a8fd537ea38523fe6f))
-
-* fix: typing for `kwargs` (#462)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`2240b4d`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/2240b4dda824c13bc563bce1574dffe563016ac2))
-
-* fix: tuple stuff (#461)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`84c6504`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/84c6504fc92d1207135f7719b6b6477fae7950cb))
-
-* fix: `bom.validate()` detects invalid license constellations (#452)
-
-
-
-If a LicenseExpression is set, then there must be no other license.
-
-fixes #453
-
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`16843b2`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/16843b29086d8f871a7239c33beb930543cfde45))
-
-### Performance
-
-* perf: make validation more secure
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5d7b86c`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5d7b86c0ba84fe17becc53b2ccf4385113f90905))
-
-### Unknown
-
-* tests for backwards compatibility of #365 (#467)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`4c2ef14`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/4c2ef14017467980509bdb69f937b5098d8c0965))
-
-* tests: snapshots and complete deep comparison, instead of pseudo-compare (#464)
-
-part of https://github.com/CycloneDX/cyclonedx-python-lib/issues/437
-also fixed a bug: unused first level dependencies were not detected. now they are.
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`7543789`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/75437896c04e352b51d83e6e52cf94874347f4a6))
-
-* Feat: typing, typehints, &amp; overload (#463)
-
-also: bump `py-serializable@^0.14.0`
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a68ae24`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a68ae2464539d07ed0fc037aa1e315e5ccda054a))
-
-* Merge branch &#39;main&#39; into 5.0.0-dev ([`c8c2183`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/c8c218366298ccc340e769fa180204e79a9a0f3e))
-
-* tests: use internal json strict validation
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`7186b52`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/7186b52a540e478196799ef7a3580f48f77544e9))
-
-* proper enums (#447)
-
-fixes #442
-part of #446
-
-BREAKING CHANGE
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`06b5eb0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/06b5eb03d479e9908b9b62bcee48d23a873dd4ba))
-
-* typo
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`3de2493`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/3de24936533a51c0cbf61de4b19785ee7407526c))
-
-* Drop py37 (#441)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1571d21`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1571d21057b11f11cb81e74a5a702f7f30582b09))
-
-
 ## v4.2.2 (2023-09-14)
 
 ### Chore

From 65e79cfeb4fed3e31f85a4ec6d06215988a3a6d1 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Sat, 14 Oct 2023 01:00:30 +0200
Subject: [PATCH 30/42] refactor: schema based validator (#468)

- restructured validators, to enable possible non-schema-based validation.
- optimized `validation.schema.get_instance()`
- optimized `output.get_instance()`

---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/output/__init__.py                  | 26 ++++----
 cyclonedx/validation/__init__.py              | 51 ++--------------
 cyclonedx/validation/json.py                  |  8 +--
 cyclonedx/validation/model.py                 | 20 ++++++
 cyclonedx/validation/schema.py                | 61 +++++++++++++++++++
 cyclonedx/validation/xml.py                   |  6 +-
 examples/complex.py                           |  2 +-
 tests/test_output.py                          |  4 +-
 tests/test_validation_json.py                 |  4 +-
 ...alidation.py => test_validation_schema.py} |  6 +-
 10 files changed, 115 insertions(+), 73 deletions(-)
 create mode 100644 cyclonedx/validation/model.py
 create mode 100644 cyclonedx/validation/schema.py
 rename tests/{test_validation.py => test_validation_schema.py} (86%)

diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index 72126fbd3..21ad0a860 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -21,8 +21,7 @@
 
 import os
 from abc import ABC, abstractmethod
-from importlib import import_module
-from typing import TYPE_CHECKING, Any, Iterable, Literal, Optional, Type, Union, overload
+from typing import TYPE_CHECKING, Any, Iterable, Literal, Mapping, Optional, Type, Union, overload
 
 from ..schema import OutputFormat, SchemaVersion
 
@@ -130,15 +129,16 @@ def get_instance(bom: 'Bom', output_format: OutputFormat = OutputFormat.XML,
     :return: BaseOutput
     """
     # all exceptions are undocumented, as they are pure functional, and should be prevented by correct typing...
-    if not isinstance(output_format, OutputFormat):
-        raise TypeError(f"unexpected output_format: {output_format!r}")
-    if not isinstance(schema_version, SchemaVersion):
-        raise TypeError(f"unexpected schema_version: {schema_version!r}")
-    try:
-        module = import_module(f'.{output_format.name.lower()}', __package__)
-    except ImportError as error:
-        raise ValueError(f'Unknown output_format: {output_format.name}') from error
-    klass: Optional[Type[BaseOutput]] = module.BY_SCHEMA_VERSION.get(schema_version, None)
+    if TYPE_CHECKING:  # pragma: no cover
+        BY_SCHEMA_VERSION: Mapping[SchemaVersion, Type[BaseOutput]]
+    if OutputFormat.JSON is output_format:
+        from .json import BY_SCHEMA_VERSION
+    elif OutputFormat.XML is output_format:
+        from .xml import BY_SCHEMA_VERSION
+    else:
+        raise ValueError(f"Unexpected output_format: {output_format!r}")
+
+    klass = BY_SCHEMA_VERSION.get(schema_version, None)
     if klass is None:
-        raise ValueError(f'Unknown {output_format.name}/schema_version: {schema_version.name}')
-    return klass(bom=bom)
+        raise ValueError(f'Unknown {output_format.name}/schema_version: {schema_version!r}')
+    return klass(bom)
diff --git a/cyclonedx/validation/__init__.py b/cyclonedx/validation/__init__.py
index fe0c34324..83cd19491 100644
--- a/cyclonedx/validation/__init__.py
+++ b/cyclonedx/validation/__init__.py
@@ -15,15 +15,12 @@
 
 
 from abc import ABC, abstractmethod
-from importlib import import_module
-from typing import TYPE_CHECKING, Any, Literal, Optional, Protocol, Type, Union, overload
+from typing import TYPE_CHECKING, Any, Optional, Protocol
 
 from ..schema import OutputFormat
 
 if TYPE_CHECKING:  # pragma: no cover
     from ..schema import SchemaVersion
-    from .json import JsonValidator
-    from .xml import XmlValidator
 
 
 class ValidationError:
@@ -44,8 +41,8 @@ def __str__(self) -> str:
         return str(self.data)
 
 
-class Validator(Protocol):
-    """Validator protocol"""
+class SchemaBasedValidator(Protocol):
+    """Schema based Validator protocol"""
 
     def validate_str(self, data: str) -> Optional[ValidationError]:
         """Validate a string
@@ -58,13 +55,13 @@ def validate_str(self, data: str) -> Optional[ValidationError]:
         ...
 
 
-class BaseValidator(ABC, Validator):
-    """BaseValidator"""
+class BaseSchemaBasedValidator(ABC, SchemaBasedValidator):
+    """Base Schema based Validator"""
 
     def __init__(self, schema_version: 'SchemaVersion') -> None:
         self.__schema_version = schema_version
         if not self._schema_file:
-            raise ValueError(f'unsupported schema_version: {schema_version}')
+            raise ValueError(f'Unsupported schema_version: {schema_version!r}')
 
     @property
     def schema_version(self) -> 'SchemaVersion':
@@ -82,39 +79,3 @@ def output_format(self) -> OutputFormat:
     def _schema_file(self) -> Optional[str]:
         """get the schema file according to schema version."""
         ...
-
-
-@overload
-def get_instance(output_format: Literal[OutputFormat.JSON], schema_version: 'SchemaVersion'
-                 ) -> 'JsonValidator':
-    ...
-
-
-@overload
-def get_instance(output_format: Literal[OutputFormat.XML], schema_version: 'SchemaVersion'
-                 ) -> 'XmlValidator':
-    ...
-
-
-@overload
-def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion'
-                 ) -> Union['JsonValidator', 'XmlValidator']:
-    ...
-
-
-def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion') -> BaseValidator:
-    """get the default validator for a certain `OutputFormat`
-
-    Raises error when no instance could be built.
-    """
-    # all exceptions are undocumented, as they are pure functional, and should be prevented by correct typing...
-    if not isinstance(output_format, OutputFormat):
-        raise TypeError(f"unexpected output_format: {output_format!r}")
-    try:
-        module = import_module(f'.{output_format.name.lower()}', __package__)
-    except ImportError as error:
-        raise ValueError(f'Unknown output_format: {output_format.name}') from error
-    klass: Optional[Type[BaseValidator]] = getattr(module, f'{output_format.name.capitalize()}Validator', None)
-    if klass is None:
-        raise ValueError(f'Missing Validator for {output_format.name}')
-    return klass(schema_version)
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
index 3e6b38cbb..0770b2d39 100644
--- a/cyclonedx/validation/json.py
+++ b/cyclonedx/validation/json.py
@@ -27,7 +27,7 @@
 
 from ..exception import MissingOptionalDependencyException
 from ..schema._res import BOM_JSON as _S_BOM, BOM_JSON_STRICT as _S_BOM_STRICT, JSF as _S_JSF, SPDX_JSON as _S_SPDX
-from . import BaseValidator, ValidationError, Validator
+from . import BaseSchemaBasedValidator, SchemaBasedValidator, ValidationError
 
 _missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
 try:
@@ -45,7 +45,7 @@
     ), err
 
 
-class _BaseJsonValidator(BaseValidator, ABC):
+class _BaseJsonValidator(BaseSchemaBasedValidator, ABC):
     @property
     def output_format(self) -> Literal[OutputFormat.JSON]:
         return OutputFormat.JSON
@@ -98,7 +98,7 @@ def __make_validator_registry() -> Registry[Any]:
                 ])
 
 
-class JsonValidator(_BaseJsonValidator, Validator):
+class JsonValidator(_BaseJsonValidator, BaseSchemaBasedValidator, SchemaBasedValidator):
     """Validator for CycloneDX documents in JSON format."""
 
     @property
@@ -106,7 +106,7 @@ def _schema_file(self) -> Optional[str]:
         return _S_BOM.get(self.schema_version)
 
 
-class JsonStrictValidator(_BaseJsonValidator, Validator):
+class JsonStrictValidator(_BaseJsonValidator, BaseSchemaBasedValidator, SchemaBasedValidator):
     """Strict validator for CycloneDX documents in JSON format.
 
     In contrast to :class:`~JsonValidator`,
diff --git a/cyclonedx/validation/model.py b/cyclonedx/validation/model.py
new file mode 100644
index 000000000..c427e60fb
--- /dev/null
+++ b/cyclonedx/validation/model.py
@@ -0,0 +1,20 @@
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+
+# nothing here, yet.
+# in the future this could be the place where model validation is done.
+# like the current `model.bom.Bom.validate()`
+# see also: https://github.com/CycloneDX/cyclonedx-python-lib/issues/455
diff --git a/cyclonedx/validation/schema.py b/cyclonedx/validation/schema.py
new file mode 100644
index 000000000..357e7d7ee
--- /dev/null
+++ b/cyclonedx/validation/schema.py
@@ -0,0 +1,61 @@
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) OWASP Foundation. All Rights Reserved.
+
+
+from typing import TYPE_CHECKING, Literal, Union, overload
+
+from ..schema import OutputFormat
+
+if TYPE_CHECKING:  # pragma: no cover
+    from ..schema import SchemaVersion
+    from . import BaseSchemaBasedValidator
+    from .json import JsonValidator
+    from .xml import XmlValidator
+
+
+@overload
+def get_instance(output_format: Literal[OutputFormat.JSON], schema_version: 'SchemaVersion'
+                 ) -> 'JsonValidator':
+    ...
+
+
+@overload
+def get_instance(output_format: Literal[OutputFormat.XML], schema_version: 'SchemaVersion'
+                 ) -> 'XmlValidator':
+    ...
+
+
+@overload
+def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion'
+                 ) -> Union['JsonValidator', 'XmlValidator']:
+    ...
+
+
+def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion') -> 'BaseSchemaBasedValidator':
+    """get the default schema-based validator for a certain `OutputFormat`
+
+    Raises error when no instance could be built.
+    """
+    # all exceptions are undocumented, as they are pure functional, and should be prevented by correct typing...
+    if TYPE_CHECKING:  # pragma: no cover
+        from typing import Type
+        Validator: Type[BaseSchemaBasedValidator]
+    if OutputFormat.JSON is output_format:
+        from .json import JsonValidator as Validator
+    elif OutputFormat.XML is output_format:
+        from .xml import XmlValidator as Validator
+    else:
+        raise ValueError(f'Unexpected output_format: {output_format!r}')
+    return Validator(schema_version)
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index 0c65ffd10..75221adf3 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -22,7 +22,7 @@
 from ..exception import MissingOptionalDependencyException
 from ..schema import OutputFormat
 from ..schema._res import BOM_XML as _S_BOM
-from . import BaseValidator, ValidationError, Validator
+from . import BaseSchemaBasedValidator, SchemaBasedValidator, ValidationError
 
 if TYPE_CHECKING:  # pragma: no cover
     from ..schema import SchemaVersion
@@ -37,7 +37,7 @@
     ), err
 
 
-class _BaseXmlValidator(BaseValidator, ABC):
+class _BaseXmlValidator(BaseSchemaBasedValidator, ABC):
 
     @property
     def output_format(self) -> Literal[OutputFormat.XML]:
@@ -86,7 +86,7 @@ def _validator(self) -> 'XMLSchema':
             return self.__validator
 
 
-class XmlValidator(_BaseXmlValidator, Validator):
+class XmlValidator(_BaseXmlValidator, BaseSchemaBasedValidator, SchemaBasedValidator):
     """Validator for CycloneDX documents in XML format."""
 
     @property
diff --git a/examples/complex.py b/examples/complex.py
index e167d0af3..c38029b6c 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -28,7 +28,7 @@
 from cyclonedx.output.json import JsonV1Dot4
 from cyclonedx.schema import SchemaVersion, OutputFormat
 from cyclonedx.validation.json import JsonStrictValidator
-from cyclonedx.validation import get_instance as get_validator
+from cyclonedx.validation.schema import get_instance as get_validator
 
 from typing import TYPE_CHECKING
 
diff --git a/tests/test_output.py b/tests/test_output.py
index 71a1b995b..3861a7ae2 100644
--- a/tests/test_output.py
+++ b/tests/test_output.py
@@ -41,8 +41,8 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
         self.assertIs(outputter.schema_version, sv)
 
     @data(
-        *((of, 'foo', (TypeError, "unexpected schema_version: 'foo'")) for of in OutputFormat),
-        *(('foo', sv, (TypeError, "unexpected output_format: 'foo'")) for sv in SchemaVersion),
+        *((of, 'foo', (ValueError, f"Unknown {of.name}/schema_version: 'foo'")) for of in OutputFormat),
+        *(('foo', sv, (ValueError, "Unexpected output_format: 'foo'")) for sv in SchemaVersion),
     )
     @unpack
     def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
diff --git a/tests/test_validation_json.py b/tests/test_validation_json.py
index db639a1f3..6e99acb76 100644
--- a/tests/test_validation_json.py
+++ b/tests/test_validation_json.py
@@ -48,7 +48,7 @@ def test_validator_as_expected(self, schema_version: SchemaVersion) -> None:
 
     @idata(UNSUPPORTED_SCHEMA_VERSIONS)
     def test_throws_with_unsupported_schema_version(self, schema_version: SchemaVersion) -> None:
-        with self.assertRaisesRegex(ValueError, f'unsupported schema_version: {schema_version}'):
+        with self.assertRaisesRegex(ValueError, 'Unsupported schema_version'):
             JsonValidator(schema_version)
 
     @idata(_dp('valid'))
@@ -82,7 +82,7 @@ class TestJsonStrictValidator(TestCase):
 
     @data(*UNSUPPORTED_SCHEMA_VERSIONS)
     def test_throws_with_unsupported_schema_version(self, schema_version: SchemaVersion) -> None:
-        with self.assertRaisesRegex(ValueError, f'unsupported schema_version: {schema_version}'):
+        with self.assertRaisesRegex(ValueError, 'Unsupported schema_version'):
             JsonStrictValidator(schema_version)
 
     @idata(_dp('valid'))
diff --git a/tests/test_validation.py b/tests/test_validation_schema.py
similarity index 86%
rename from tests/test_validation.py
rename to tests/test_validation_schema.py
index eae92c930..cd6ced45c 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation_schema.py
@@ -23,7 +23,7 @@
 from ddt import data, ddt, named_data, unpack
 
 from cyclonedx.schema import OutputFormat, SchemaVersion
-from cyclonedx.validation import get_instance as get_validator
+from cyclonedx.validation.schema import get_instance as get_validator
 
 UNDEFINED_FORMAT_VERSION = {
     (OutputFormat.JSON, SchemaVersion.V1_1),
@@ -45,8 +45,8 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
         self.assertIs(validator.schema_version, sv)
 
     @data(
-        *(('foo', sv, (TypeError, "unexpected output_format: 'foo'")) for sv in SchemaVersion),
-        *((f, v, (ValueError, f'unsupported schema_version: {v}')) for f, v in UNDEFINED_FORMAT_VERSION)
+        *(('foo', sv, (ValueError, 'Unexpected output_format')) for sv in SchemaVersion),
+        *((f, v, (ValueError, 'Unsupported schema_version')) for f, v in UNDEFINED_FORMAT_VERSION)
     )
     @unpack
     def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:

From 2a2b2dd509100eea5ec3153e1ec10ff5dda6f269 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Sat, 14 Oct 2023 11:14:14 +0200
Subject: [PATCH 31/42] refactor(DX): rename `get_instance()` (#469)

- deprecate function `output.get_instance()`
- add function `outout.make_outputter()`
- rename function `validation.get_instance()` -> `validation.make_schemabased_validator()`
- rename function `validation.schema.get_instance()` -> `validation.make_schemabased_validator()`

---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/output/__init__.py                  | 35 ++++----
 cyclonedx/validation/__init__.py              | 48 +++++++++--
 cyclonedx/validation/json.py                  |  8 +-
 cyclonedx/validation/schema.py                | 61 --------------
 cyclonedx/validation/xml.py                   |  6 +-
 examples/complex.py                           |  9 ++-
 tests/test_e2e_environment.py                 | 79 -------------------
 tests/test_output.py                          |  6 +-
 tests/test_output_generic.py                  | 10 +--
 ...alidation_schema.py => test_validation.py} |  8 +-
 10 files changed, 86 insertions(+), 184 deletions(-)
 delete mode 100644 cyclonedx/validation/schema.py
 delete mode 100644 tests/test_e2e_environment.py
 rename tests/{test_validation_schema.py => test_validation.py} (89%)

diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index 21ad0a860..1be6e50ab 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -20,6 +20,7 @@
 """
 
 import os
+import warnings
 from abc import ABC, abstractmethod
 from typing import TYPE_CHECKING, Any, Iterable, Literal, Mapping, Optional, Type, Union, overload
 
@@ -41,11 +42,6 @@ def __init__(self, bom: 'Bom', **kwargs: int) -> None:
         self._bom = bom
         self._generated: bool = False
 
-    def _chained_components(self, container: Union['Bom', 'Component']) -> Iterable['Component']:
-        for component in container.components:
-            yield component
-            yield from self._chained_components(component)
-
     @property
     @abstractmethod
     def schema_version(self) -> SchemaVersion:
@@ -95,40 +91,37 @@ def output_to_file(self, filename: str, allow_overwrite: bool = False, *,
 
 
 @overload
-def get_instance(bom: 'Bom', output_format: Literal[OutputFormat.JSON],
-                 schema_version: SchemaVersion = ...) -> 'JsonOutputter':
+def make_outputter(bom: 'Bom', output_format: Literal[OutputFormat.JSON],
+                   schema_version: SchemaVersion) -> 'JsonOutputter':
     ...
 
 
 @overload
-def get_instance(bom: 'Bom', output_format: Literal[OutputFormat.XML] = ...,
-                 schema_version: SchemaVersion = ...) -> 'XmlOutputter':
+def make_outputter(bom: 'Bom', output_format: Literal[OutputFormat.XML],
+                   schema_version: SchemaVersion) -> 'XmlOutputter':
     ...
 
 
 @overload
-def get_instance(bom: 'Bom', output_format: OutputFormat = ...,
-                 schema_version: SchemaVersion = ...
-                 ) -> Union['XmlOutputter', 'JsonOutputter']:
+def make_outputter(bom: 'Bom', output_format: OutputFormat,
+                   schema_version: SchemaVersion) -> Union['XmlOutputter', 'JsonOutputter']:
     ...
 
 
-def get_instance(bom: 'Bom', output_format: OutputFormat = OutputFormat.XML,
-                 schema_version: SchemaVersion = LATEST_SUPPORTED_SCHEMA_VERSION) -> BaseOutput:
+def make_outputter(bom: 'Bom', output_format: OutputFormat, schema_version: SchemaVersion) -> BaseOutput:
     """
     Helper method to quickly get the correct output class/formatter.
 
     Pass in your BOM and optionally an output format and schema version (defaults to XML and latest schema version).
 
 
-    Raises error when no instance could be built.
+    Raises error when no instance could be made.
 
     :param bom: Bom
     :param output_format: OutputFormat
     :param schema_version: SchemaVersion
     :return: BaseOutput
     """
-    # all exceptions are undocumented, as they are pure functional, and should be prevented by correct typing...
     if TYPE_CHECKING:  # pragma: no cover
         BY_SCHEMA_VERSION: Mapping[SchemaVersion, Type[BaseOutput]]
     if OutputFormat.JSON is output_format:
@@ -142,3 +135,13 @@ def get_instance(bom: 'Bom', output_format: OutputFormat = OutputFormat.XML,
     if klass is None:
         raise ValueError(f'Unknown {output_format.name}/schema_version: {schema_version!r}')
     return klass(bom)
+
+
+def get_instance(bom: 'Bom', output_format: OutputFormat = OutputFormat.XML,
+                 schema_version: SchemaVersion = LATEST_SUPPORTED_SCHEMA_VERSION) -> BaseOutput:
+    """DEPRECATED. use :func:`make_outputter` instead!"""
+    warnings.warn(
+        'function `get_instance()` is deprecated, use `make_outputter()` instead.',
+        DeprecationWarning
+    )
+    return make_outputter(bom, output_format, schema_version)
diff --git a/cyclonedx/validation/__init__.py b/cyclonedx/validation/__init__.py
index 83cd19491..e66c13449 100644
--- a/cyclonedx/validation/__init__.py
+++ b/cyclonedx/validation/__init__.py
@@ -15,12 +15,14 @@
 
 
 from abc import ABC, abstractmethod
-from typing import TYPE_CHECKING, Any, Optional, Protocol
+from typing import TYPE_CHECKING, Any, Literal, Optional, Protocol, Union, overload
 
 from ..schema import OutputFormat
 
 if TYPE_CHECKING:  # pragma: no cover
     from ..schema import SchemaVersion
+    from .json import JsonValidator
+    from .xml import XmlValidator
 
 
 class ValidationError:
@@ -41,8 +43,8 @@ def __str__(self) -> str:
         return str(self.data)
 
 
-class SchemaBasedValidator(Protocol):
-    """Schema based Validator protocol"""
+class SchemabasedValidator(Protocol):
+    """Schema-based Validator protocol"""
 
     def validate_str(self, data: str) -> Optional[ValidationError]:
         """Validate a string
@@ -55,8 +57,8 @@ def validate_str(self, data: str) -> Optional[ValidationError]:
         ...
 
 
-class BaseSchemaBasedValidator(ABC, SchemaBasedValidator):
-    """Base Schema based Validator"""
+class BaseSchemabasedValidator(ABC, SchemabasedValidator):
+    """Base Schema-based Validator"""
 
     def __init__(self, schema_version: 'SchemaVersion') -> None:
         self.__schema_version = schema_version
@@ -79,3 +81,39 @@ def output_format(self) -> OutputFormat:
     def _schema_file(self) -> Optional[str]:
         """get the schema file according to schema version."""
         ...
+
+
+@overload
+def make_schemabased_validator(output_format: Literal[OutputFormat.JSON], schema_version: 'SchemaVersion'
+                               ) -> 'JsonValidator':
+    ...
+
+
+@overload
+def make_schemabased_validator(output_format: Literal[OutputFormat.XML], schema_version: 'SchemaVersion'
+                               ) -> 'XmlValidator':
+    ...
+
+
+@overload
+def make_schemabased_validator(output_format: OutputFormat, schema_version: 'SchemaVersion'
+                               ) -> Union['JsonValidator', 'XmlValidator']:
+    ...
+
+
+def make_schemabased_validator(output_format: OutputFormat, schema_version: 'SchemaVersion'
+                               ) -> 'BaseSchemabasedValidator':
+    """get the default Schema-based Validator for a certain :class:``OutputFormat``.
+
+    Raises error when no instance could be made.
+    """
+    if TYPE_CHECKING:  # pragma: no cover
+        from typing import Type
+        Validator: Type[BaseSchemabasedValidator]
+    if OutputFormat.JSON is output_format:
+        from .json import JsonValidator as Validator
+    elif OutputFormat.XML is output_format:
+        from .xml import XmlValidator as Validator
+    else:
+        raise ValueError(f'Unexpected output_format: {output_format!r}')
+    return Validator(schema_version)
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
index 0770b2d39..797bd3b9e 100644
--- a/cyclonedx/validation/json.py
+++ b/cyclonedx/validation/json.py
@@ -27,7 +27,7 @@
 
 from ..exception import MissingOptionalDependencyException
 from ..schema._res import BOM_JSON as _S_BOM, BOM_JSON_STRICT as _S_BOM_STRICT, JSF as _S_JSF, SPDX_JSON as _S_SPDX
-from . import BaseSchemaBasedValidator, SchemaBasedValidator, ValidationError
+from . import BaseSchemabasedValidator, SchemabasedValidator, ValidationError
 
 _missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
 try:
@@ -45,7 +45,7 @@
     ), err
 
 
-class _BaseJsonValidator(BaseSchemaBasedValidator, ABC):
+class _BaseJsonValidator(BaseSchemabasedValidator, ABC):
     @property
     def output_format(self) -> Literal[OutputFormat.JSON]:
         return OutputFormat.JSON
@@ -98,7 +98,7 @@ def __make_validator_registry() -> Registry[Any]:
                 ])
 
 
-class JsonValidator(_BaseJsonValidator, BaseSchemaBasedValidator, SchemaBasedValidator):
+class JsonValidator(_BaseJsonValidator, BaseSchemabasedValidator, SchemabasedValidator):
     """Validator for CycloneDX documents in JSON format."""
 
     @property
@@ -106,7 +106,7 @@ def _schema_file(self) -> Optional[str]:
         return _S_BOM.get(self.schema_version)
 
 
-class JsonStrictValidator(_BaseJsonValidator, BaseSchemaBasedValidator, SchemaBasedValidator):
+class JsonStrictValidator(_BaseJsonValidator, BaseSchemabasedValidator, SchemabasedValidator):
     """Strict validator for CycloneDX documents in JSON format.
 
     In contrast to :class:`~JsonValidator`,
diff --git a/cyclonedx/validation/schema.py b/cyclonedx/validation/schema.py
deleted file mode 100644
index 357e7d7ee..000000000
--- a/cyclonedx/validation/schema.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-# Copyright (c) OWASP Foundation. All Rights Reserved.
-
-
-from typing import TYPE_CHECKING, Literal, Union, overload
-
-from ..schema import OutputFormat
-
-if TYPE_CHECKING:  # pragma: no cover
-    from ..schema import SchemaVersion
-    from . import BaseSchemaBasedValidator
-    from .json import JsonValidator
-    from .xml import XmlValidator
-
-
-@overload
-def get_instance(output_format: Literal[OutputFormat.JSON], schema_version: 'SchemaVersion'
-                 ) -> 'JsonValidator':
-    ...
-
-
-@overload
-def get_instance(output_format: Literal[OutputFormat.XML], schema_version: 'SchemaVersion'
-                 ) -> 'XmlValidator':
-    ...
-
-
-@overload
-def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion'
-                 ) -> Union['JsonValidator', 'XmlValidator']:
-    ...
-
-
-def get_instance(output_format: OutputFormat, schema_version: 'SchemaVersion') -> 'BaseSchemaBasedValidator':
-    """get the default schema-based validator for a certain `OutputFormat`
-
-    Raises error when no instance could be built.
-    """
-    # all exceptions are undocumented, as they are pure functional, and should be prevented by correct typing...
-    if TYPE_CHECKING:  # pragma: no cover
-        from typing import Type
-        Validator: Type[BaseSchemaBasedValidator]
-    if OutputFormat.JSON is output_format:
-        from .json import JsonValidator as Validator
-    elif OutputFormat.XML is output_format:
-        from .xml import XmlValidator as Validator
-    else:
-        raise ValueError(f'Unexpected output_format: {output_format!r}')
-    return Validator(schema_version)
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index 75221adf3..2fae6692e 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -22,7 +22,7 @@
 from ..exception import MissingOptionalDependencyException
 from ..schema import OutputFormat
 from ..schema._res import BOM_XML as _S_BOM
-from . import BaseSchemaBasedValidator, SchemaBasedValidator, ValidationError
+from . import BaseSchemabasedValidator, SchemabasedValidator, ValidationError
 
 if TYPE_CHECKING:  # pragma: no cover
     from ..schema import SchemaVersion
@@ -37,7 +37,7 @@
     ), err
 
 
-class _BaseXmlValidator(BaseSchemaBasedValidator, ABC):
+class _BaseXmlValidator(BaseSchemabasedValidator, ABC):
 
     @property
     def output_format(self) -> Literal[OutputFormat.XML]:
@@ -86,7 +86,7 @@ def _validator(self) -> 'XMLSchema':
             return self.__validator
 
 
-class XmlValidator(_BaseXmlValidator, BaseSchemaBasedValidator, SchemaBasedValidator):
+class XmlValidator(_BaseXmlValidator, BaseSchemabasedValidator, SchemabasedValidator):
     """Validator for CycloneDX documents in XML format."""
 
     @property
diff --git a/examples/complex.py b/examples/complex.py
index c38029b6c..1b9b068f5 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -24,11 +24,11 @@
 from cyclonedx.model import OrganizationalEntity, XsUri
 from cyclonedx.model.bom import Bom
 from cyclonedx.model.component import Component, ComponentType
-from cyclonedx.output import get_instance as get_outputter
+from cyclonedx.output import make_outputter, LATEST_SUPPORTED_SCHEMA_VERSION
 from cyclonedx.output.json import JsonV1Dot4
 from cyclonedx.schema import SchemaVersion, OutputFormat
 from cyclonedx.validation.json import JsonStrictValidator
-from cyclonedx.validation.schema import get_instance as get_validator
+from cyclonedx.validation import make_schemabased_validator
 
 from typing import TYPE_CHECKING
 
@@ -99,10 +99,11 @@
 # region XML
 """demo with implicit instructions for SchemaVersion, outputter and validator. TypeCheckers will catch errors."""
 
-my_xml_outputter: 'XmlOutputter' = get_outputter(bom, OutputFormat.XML)
+my_xml_outputter: 'XmlOutputter' = make_outputter(bom, OutputFormat.XML, LATEST_SUPPORTED_SCHEMA_VERSION)
 serialized_xml = my_xml_outputter.output_as_string(indent=2)
 print(serialized_xml)
-my_xml_validator: 'XmlValidator' = get_validator(my_xml_outputter.output_format, my_xml_outputter.schema_version)
+my_xml_validator: 'XmlValidator' = make_schemabased_validator(
+    my_xml_outputter.output_format, my_xml_outputter.schema_version)
 try:
     validation_errors = my_xml_validator.validate_str(serialized_xml)
     if validation_errors:
diff --git a/tests/test_e2e_environment.py b/tests/test_e2e_environment.py
deleted file mode 100644
index 78b918075..000000000
--- a/tests/test_e2e_environment.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# This file is part of CycloneDX Python Lib
-#
-# 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-# Copyright (c) OWASP Foundation. All Rights Reserved.
-
-import json
-from unittest import TestCase
-
-from lxml import etree
-from packageurl import PackageURL
-
-from cyclonedx import __version__ as OUR_PACKAGE_VERSION
-from cyclonedx.model.bom import Bom
-from cyclonedx.model.component import Component
-from cyclonedx.output import OutputFormat, get_instance
-from cyclonedx.output.json import Json
-from cyclonedx.output.xml import Xml
-
-OUR_PACKAGE_NAME: str = 'cyclonedx-python-lib'
-OUR_PACKAGE_AUTHOR: str = 'Paul Horton'
-
-
-class TestE2EEnvironment(TestCase):
-
-    @classmethod
-    def setUpClass(cls) -> None:
-        cls.bom: Bom = Bom()
-        cls.bom.components.add(
-            Component(
-                name=OUR_PACKAGE_NAME, author=OUR_PACKAGE_AUTHOR, version=OUR_PACKAGE_VERSION,
-                purl=PackageURL(type='pypi', name=OUR_PACKAGE_NAME, version=OUR_PACKAGE_VERSION)
-            )
-        )
-
-    def test_json_defaults(self) -> None:
-        outputter: Json = get_instance(bom=TestE2EEnvironment.bom, output_format=OutputFormat.JSON)
-        bom_json = json.loads(outputter.output_as_string())
-        self.assertTrue('metadata' in bom_json)
-        self.assertFalse('component' in bom_json['metadata'])
-        component_this_library = next(
-            (x for x in bom_json['components'] if
-             x['purl'] == 'pkg:pypi/{}@{}'.format(OUR_PACKAGE_NAME, OUR_PACKAGE_VERSION)), None
-        )
-
-        self.assertTrue('author' in component_this_library.keys(), 'author is missing from JSON BOM')
-        self.assertEqual(component_this_library['author'], OUR_PACKAGE_AUTHOR)
-        self.assertEqual(component_this_library['name'], OUR_PACKAGE_NAME)
-        self.assertEqual(component_this_library['version'], OUR_PACKAGE_VERSION)
-
-    def test_xml_defaults(self) -> None:
-        outputter: Xml = get_instance(bom=TestE2EEnvironment.bom)
-
-        # Check we have cyclonedx-python-lib with Author, Name and Version
-        bom_xml_e: etree.ElementTree = etree.fromstring(bytes(outputter.output_as_string(), encoding='utf-8'))
-        component_this_library: etree.Element = bom_xml_e.xpath(
-            '/cdx:bom/cdx:components/cdx:component',
-            namespaces={
-                'cdx': outputter.get_target_namespace()
-            }
-        )[0]
-        for a in component_this_library:
-            if a.tag == 'author':
-                self.assertEqual(a.text, OUR_PACKAGE_AUTHOR)
-            if a.tag == 'name':
-                self.assertEqual(a.text, OUR_PACKAGE_NAME)
-            if a.tag == 'version':
-                self.assertEqual(a.text, OUR_PACKAGE_VERSION)
diff --git a/tests/test_output.py b/tests/test_output.py
index 3861a7ae2..aade691b5 100644
--- a/tests/test_output.py
+++ b/tests/test_output.py
@@ -24,7 +24,7 @@
 from ddt import data, ddt, named_data, unpack
 
 from cyclonedx.model.bom import Bom
-from cyclonedx.output import get_instance as get_outputter
+from cyclonedx.output import make_outputter
 from cyclonedx.schema import OutputFormat, SchemaVersion
 
 
@@ -35,7 +35,7 @@ class TestTestGetInstance(TestCase):
     @unpack
     def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
         bom = Mock(spec=Bom)
-        outputter = get_outputter(bom, of, sv)
+        outputter = make_outputter(bom, of, sv)
         self.assertIs(outputter.get_bom(), bom)
         self.assertIs(outputter.output_format, of)
         self.assertIs(outputter.schema_version, sv)
@@ -48,4 +48,4 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
     def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
         bom = Mock(spec=Bom)
         with self.assertRaisesRegex(*raisesRegex):
-            get_outputter(bom, of, sv)
+            make_outputter(bom, of, sv)
diff --git a/tests/test_output_generic.py b/tests/test_output_generic.py
index c664e50f8..073ad642e 100644
--- a/tests/test_output_generic.py
+++ b/tests/test_output_generic.py
@@ -24,7 +24,7 @@
 from cyclonedx.schema import OutputFormat, SchemaVersion
 
 
-class TestOutputGeneric(TestCase):
+class TestGetInstanceGeneric(TestCase):
 
     @classmethod
     def setUpClass(cls) -> None:
@@ -32,17 +32,17 @@ def setUpClass(cls) -> None:
         cls._bom.components.add(Component(name='setuptools'))
 
     def test_get_instance_default(self) -> None:
-        i = get_instance(bom=TestOutputGeneric._bom)
+        i = get_instance(self._bom)
         self.assertIsInstance(i, XmlV1Dot4)
 
     def test_get_instance_xml_default(self) -> None:
-        i = get_instance(bom=TestOutputGeneric._bom, output_format=OutputFormat.XML)
+        i = get_instance(bom=self._bom, output_format=OutputFormat.XML)
         self.assertIsInstance(i, XmlV1Dot4)
 
     def test_get_instance_xml_v1_3(self) -> None:
-        i = get_instance(bom=TestOutputGeneric._bom, output_format=OutputFormat.XML, schema_version=SchemaVersion.V1_3)
+        i = get_instance(bom=self._bom, output_format=OutputFormat.XML, schema_version=SchemaVersion.V1_3)
         self.assertIsInstance(i, XmlV1Dot3)
 
     def test_component_no_version_v1_3(self) -> None:
-        i = get_instance(bom=TestOutputGeneric._bom, schema_version=SchemaVersion.V1_3)
+        i = get_instance(bom=self._bom, schema_version=SchemaVersion.V1_3)
         self.assertIsInstance(i, XmlV1Dot3)
diff --git a/tests/test_validation_schema.py b/tests/test_validation.py
similarity index 89%
rename from tests/test_validation_schema.py
rename to tests/test_validation.py
index cd6ced45c..567dff316 100644
--- a/tests/test_validation_schema.py
+++ b/tests/test_validation.py
@@ -23,7 +23,7 @@
 from ddt import data, ddt, named_data, unpack
 
 from cyclonedx.schema import OutputFormat, SchemaVersion
-from cyclonedx.validation.schema import get_instance as get_validator
+from cyclonedx.validation import make_schemabased_validator
 
 UNDEFINED_FORMAT_VERSION = {
     (OutputFormat.JSON, SchemaVersion.V1_1),
@@ -32,7 +32,7 @@
 
 
 @ddt
-class TestGetInstance(TestCase):
+class TestGetSchemabasedValidator(TestCase):
 
     @named_data(*([f'{f.name} {v.name}', f, v]
                   for f, v
@@ -40,7 +40,7 @@ class TestGetInstance(TestCase):
                   if (f, v) not in UNDEFINED_FORMAT_VERSION))
     @unpack
     def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
-        validator = get_validator(of, sv)
+        validator = make_schemabased_validator(of, sv)
         self.assertIs(validator.output_format, of)
         self.assertIs(validator.schema_version, sv)
 
@@ -51,4 +51,4 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
     @unpack
     def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
         with self.assertRaisesRegex(*raisesRegex):
-            get_validator(of, sv)
+            make_schemabased_validator(of, sv)

From 6316f094552e8bbd38777bc66a17c5546f2b7d14 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Mon, 16 Oct 2023 20:11:09 +0200
Subject: [PATCH 32/42] tidy

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/output/__init__.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index 1be6e50ab..8c590daea 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -22,13 +22,12 @@
 import os
 import warnings
 from abc import ABC, abstractmethod
-from typing import TYPE_CHECKING, Any, Iterable, Literal, Mapping, Optional, Type, Union, overload
+from typing import TYPE_CHECKING, Any, Literal, Mapping, Optional, Type, Union, overload
 
 from ..schema import OutputFormat, SchemaVersion
 
 if TYPE_CHECKING:  # pragma: no cover
     from ..model.bom import Bom
-    from ..model.component import Component
     from .json import Json as JsonOutputter
     from .xml import Xml as XmlOutputter
 

From 9373afc1b94542680c324bacbc59e7b3a015f721 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Wed, 18 Oct 2023 14:33:22 +0200
Subject: [PATCH 33/42] docs: update title

Signed-off-by: Jan Kowalleck <jan.kowalleck@owasp.org>
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 980cb80b6..42c396449 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Python Library for generating CycloneDX
+# CycloneDX Python Library
 
 [![shield_pypi-version]][link_pypi]
 [![shield_conda-forge-version]][link_conda-forge]

From 2967f284cf7e5ab4da69406d599d890b07e62ce1 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Thu, 19 Oct 2023 10:28:29 +0200
Subject: [PATCH 34/42] ci: revisit coverage reporting

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .github/workflows/python.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index dd4799f98..d0d379738 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -134,12 +134,12 @@ jobs:
       - name: Run tox
         run: poetry run tox run -e py${{ matrix.toxenv-factors }} -s false
       - name: Generate coverage reports
+        if: ${{ failure() || success() }}
         shell: bash
         run: |
           set -eux
-          poetry run coverage report
-          poetry run coverage xml -o "$REPORTS_DIR/coverage.${{ matrix.os }}_py${{ matrix.python-version }}_${{ matrix.toxenv-factors }}.cobertura.xml"
-          # poetry run coverage lcov -o "$REPORTS_DIR/coverage.${{ matrix.os }}_py${{ matrix.python-version }}_${{ matrix.toxenv-factors }}.lcov.xml"
+          poetry run coverage report -m
+          poetry run coverage xml -o '${{ env.REPORTS_DIR }}/coverage/${{ matrix.os }}_py${{ matrix.python-version }}_${{ matrix.toxenv-factors }}.cobertura.xml'
       - name: Artifact reports
         if: ${{ ! cancelled() }}
         # see https://github.com/actions/upload-artifact
@@ -169,7 +169,7 @@ jobs:
         uses: codacy/codacy-coverage-reporter-action@v1
         with:
           project-token: ${{ env.CODACY_PROJECT_TOKEN }}
-          coverage-reports: ${{ env.REPORTS_DIR }}/coverage.*
+          coverage-reports: ${{ env.REPORTS_DIR }}/coverage/*.cobertura.xml
 
   examples:
     name: Examples E:${{ matrix.install-extras || '<none>' }}

From bc8e30b32163db3ffd31a7c96460a907637b1794 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Thu, 19 Oct 2023 11:01:03 +0200
Subject: [PATCH 35/42] ci: revisit coverage reporting

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .github/workflows/python.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index d0d379738..b2a3ca237 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -169,7 +169,7 @@ jobs:
         uses: codacy/codacy-coverage-reporter-action@v1
         with:
           project-token: ${{ env.CODACY_PROJECT_TOKEN }}
-          coverage-reports: ${{ env.REPORTS_DIR }}/coverage/*.cobertura.xml
+          coverage-reports: ${{ env.REPORTS_DIR }}/coverage/*
 
   examples:
     name: Examples E:${{ matrix.install-extras || '<none>' }}

From d09ac3685dda97a054be7e0655e95c5b6356057d Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Fri, 20 Oct 2023 10:19:41 +0200
Subject: [PATCH 36/42] reduce imports

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 cyclonedx/model/__init__.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
index d30ad9613..695f3d281 100644
--- a/cyclonedx/model/__init__.py
+++ b/cyclonedx/model/__init__.py
@@ -13,10 +13,10 @@
 # SPDX-License-Identifier: Apache-2.0
 # Copyright (c) OWASP Foundation. All Rights Reserved.
 
-import hashlib
 import re
 from datetime import datetime, timezone
 from enum import Enum
+from hashlib import sha1
 from itertools import zip_longest
 from typing import Any, Iterable, Optional, Tuple, TypeVar
 
@@ -55,7 +55,7 @@ def sha1sum(filename: str) -> str:
     Returns:
         SHA-1 hash
     """
-    h = hashlib.sha1()
+    h = sha1()
     with open(filename, 'rb') as f:
         for byte_block in iter(lambda: f.read(4096), b""):
             h.update(byte_block)

From bb0f7a5d3610ffcd035ea0b89742225dea5abce9 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@owasp.org>
Date: Fri, 20 Oct 2023 12:19:09 +0200
Subject: [PATCH 37/42] style: streamline code quality (#472)

- raised some dev tools
- added more quality checkers and rules
- documented and applied additional code standards

---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .flake8                          | 20 +++++++++++
 .isort.cfg                       |  2 +-
 CONTRIBUTING.md                  |  4 +++
 cyclonedx/__init__.py            |  1 +
 cyclonedx/exception/__init__.py  |  4 +--
 cyclonedx/model/__init__.py      | 34 +++++++++----------
 cyclonedx/model/bom.py           | 22 ++++++------
 cyclonedx/model/component.py     | 40 +++++++++++-----------
 cyclonedx/model/dependency.py    | 10 +++---
 cyclonedx/model/issue.py         |  2 +-
 cyclonedx/model/license.py       |  2 +-
 cyclonedx/model/release_note.py  | 10 +++---
 cyclonedx/model/service.py       |  8 ++---
 cyclonedx/model/vulnerability.py | 35 ++++++++++---------
 cyclonedx/output/__init__.py     |  6 ++--
 cyclonedx/parser/__init__.py     |  2 +-
 cyclonedx/validation/__init__.py |  2 +-
 cyclonedx/validation/json.py     |  6 ++--
 cyclonedx/validation/xml.py      |  2 +-
 examples/complex.py              |  4 +--
 pyproject.toml                   |  9 ++---
 tests/__init__.py                | 36 +++++++++++---------
 tests/_data/models.py            | 58 ++++++++++++++++----------------
 tests/test_component.py          |  2 +-
 tests/test_model.py              |  8 ++---
 tests/test_model_component.py    | 20 +++++------
 tests/test_model_dependency.py   | 14 ++++----
 tests/test_model_issue.py        |  8 ++---
 tests/test_model_release_note.py | 10 +++---
 tests/test_output.py             |  4 +--
 tests/test_output_json.py        | 12 +++----
 tests/test_output_xml.py         |  6 ++--
 tests/test_validation.py         |  4 +--
 tools/schema-downloader.py       | 32 +++++++++---------
 tox.ini                          | 17 ----------
 35 files changed, 237 insertions(+), 219 deletions(-)
 create mode 100644 .flake8

diff --git a/.flake8 b/.flake8
new file mode 100644
index 000000000..b35235263
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,20 @@
+[flake8]
+## https://flake8.pycqa.org/en/latest/user/configuration.html
+## keep in sync with isort config - in `isort.cfg` file
+
+exclude =
+    build,dist,__pycache__,.eggs,*.egg-info*,
+    *_cache,*.cache,
+    .git,.tox,.venv,venv,.venv*,venv*,
+    _OLD,_TEST,
+    docs
+
+max-line-length = 120
+
+max-complexity = 20
+
+ignore =
+    # ignore `self`, `cls` markers of flake8-annotations>=2.0
+    ANN101,ANN102
+    # ignore ANN401 for dynamically typed *args and **kwargs
+    ANN401
diff --git a/.isort.cfg b/.isort.cfg
index 7a30df968..85e125dcc 100644
--- a/.isort.cfg
+++ b/.isort.cfg
@@ -1,6 +1,6 @@
 [settings]
 ## read the docs: https://pycqa.github.io/isort/docs/configuration/options.html
-## keep in sync with flake8 config - in `tox.ini` file
+## keep in sync with flake8 config - in `.flake8` file
 known_first_party = cyclonedx
 skip_gitignore = false
 skip_glob =
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7d2008a99..8b8a5a2a9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,6 +26,10 @@ poetry run isort .
 poetry run autopep8 -ir cyclonedx/ tests/ typings/ examples/
 ```
 
+This project prefers `f'strings'` over `'string'.format()`.  
+This project prefers `'single quotes'` over `"double quotes"`.  
+This project prefers `lower_snake_case` variable names.  
+
 ## Documentation
 
 This project uses [Sphinx] to generate documentation which is automatically published to [readthedocs.io].
diff --git a/cyclonedx/__init__.py b/cyclonedx/__init__.py
index 6ff0623a9..feb796167 100644
--- a/cyclonedx/__init__.py
+++ b/cyclonedx/__init__.py
@@ -20,4 +20,5 @@
 
 # !! version is managed by semantic_release
 # do not use typing here, or else `semantic_release` might have issues finding the variable
+# flake8: noqa
 __version__ = "5.0.0-rc.1"
diff --git a/cyclonedx/exception/__init__.py b/cyclonedx/exception/__init__.py
index 868373fda..ef1ce340b 100644
--- a/cyclonedx/exception/__init__.py
+++ b/cyclonedx/exception/__init__.py
@@ -19,13 +19,13 @@
 """
 
 
-class CycloneDxException(Exception):
+class CycloneDxException(Exception):  # noqa: N818
     """
     Root exception thrown by this library.
     """
     pass
 
 
-class MissingOptionalDependencyException(CycloneDxException):
+class MissingOptionalDependencyException(CycloneDxException):  # noqa: N818
     """Validation did not happen, due to missing dependencies."""
     pass
diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
index 695f3d281..5b5b0d8b8 100644
--- a/cyclonedx/model/__init__.py
+++ b/cyclonedx/model/__init__.py
@@ -23,7 +23,7 @@
 import serializable
 from sortedcontainers import SortedSet
 
-from .. import __version__ as __ThisToolVersion
+from .. import __version__ as __ThisToolVersion  # noqa: N812
 from ..exception.model import (
     InvalidLocaleTypeException,
     InvalidUriException,
@@ -57,7 +57,7 @@ def sha1sum(filename: str) -> str:
     """
     h = sha1()
     with open(filename, 'rb') as f:
-        for byte_block in iter(lambda: f.read(4096), b""):
+        for byte_block in iter(lambda: f.read(4096), b''):
             h.update(byte_block)
     return h.hexdigest()
 
@@ -102,10 +102,10 @@ class DataFlow(str, Enum):
     .. note::
         See the CycloneDX Schema: https://cyclonedx.org/docs/1.4/xml/#type_dataFlowType
     """
-    INBOUND = "inbound"
-    OUTBOUND = "outbound"
-    BI_DIRECTIONAL = "bi-directional"
-    UNKNOWN = "unknown"
+    INBOUND = 'inbound'
+    OUTBOUND = 'outbound'
+    BI_DIRECTIONAL = 'bi-directional'
+    UNKNOWN = 'unknown'
 
 
 @serializable.serializable_class
@@ -325,16 +325,16 @@ def from_composite_str(composite_hash: str) -> 'HashType':
             )
         elif algorithm_prefix[0:3] == 'sha':
             return HashType(
-                alg=getattr(HashAlgorithm, 'SHA_{}'.format(algorithm_prefix[3:])),
+                alg=getattr(HashAlgorithm, f'SHA_{algorithm_prefix[3:]}'),
                 content=parts[1].lower()
             )
         elif algorithm_prefix[0:6] == 'blake2':
             return HashType(
-                alg=getattr(HashAlgorithm, 'BLAKE2b_{}'.format(algorithm_prefix[6:])),
+                alg=getattr(HashAlgorithm, f'BLAKE2b_{algorithm_prefix[6:]}'),
                 content=parts[1].lower()
             )
 
-        raise UnknownHashTypeException(f"Unable to determine hash type from '{composite_hash}'")
+        raise UnknownHashTypeException(f'Unable to determine hash type from {composite_hash!r}')
 
     def __init__(self, *, alg: HashAlgorithm, content: str) -> None:
         self.alg = alg
@@ -542,7 +542,7 @@ def type(self, type: ExternalReferenceType) -> None:
     @serializable.view(SchemaVersion1Dot3)
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'hash')
-    def hashes(self) -> "SortedSet[HashType]":
+    def hashes(self) -> 'SortedSet[HashType]':
         """
         The hashes of the external reference (if applicable).
 
@@ -779,9 +779,9 @@ def locale(self, locale: Optional[str]) -> None:
             if not re.search(Note._LOCALE_TYPE_REGEX, locale):
                 self._locale = None
                 raise InvalidLocaleTypeException(
-                    f"Supplied locale '{locale}' is not a valid locale. "
-                    f"Locale string should be formatted as the ISO-639 (or higher) language code and optional "
-                    f"ISO-3166 (or higher) country code. according to ISO-639 format. Examples include: 'en', 'en-US'."
+                    f'Supplied locale {locale!r} is not a valid locale.'
+                    ' Locale string should be formatted as the ISO-639 (or higher) language code and optional'
+                    " ISO-3166 (or higher) country code. according to ISO-639 format. Examples include: 'en', 'en-US'."
                 )
 
     def __eq__(self, other: object) -> bool:
@@ -922,7 +922,7 @@ def name(self, name: Optional[str]) -> None:
     @serializable.json_name('url')
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'url')
     @serializable.xml_sequence(2)
-    def urls(self) -> "SortedSet[XsUri]":
+    def urls(self) -> 'SortedSet[XsUri]':
         """
         Get a list of URLs of the organization. Multiple URLs are allowed.
 
@@ -939,7 +939,7 @@ def urls(self, urls: Iterable[XsUri]) -> None:
     @serializable.json_name('contact')
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'contact')
     @serializable.xml_sequence(3)
-    def contacts(self) -> "SortedSet[OrganizationalContact]":
+    def contacts(self) -> 'SortedSet[OrganizationalContact]':
         """
         Get a list of contact person at the organization. Multiple contacts are allowed.
 
@@ -1037,7 +1037,7 @@ def version(self, version: Optional[str]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'hash')
     @serializable.xml_sequence(4)
-    def hashes(self) -> "SortedSet[HashType]":
+    def hashes(self) -> 'SortedSet[HashType]':
         """
         The hashes of the tool (if applicable).
 
@@ -1054,7 +1054,7 @@ def hashes(self, hashes: Iterable[HashType]) -> None:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
     @serializable.xml_sequence(5)
-    def external_references(self) -> "SortedSet[ExternalReference]":
+    def external_references(self) -> 'SortedSet[ExternalReference]':
         """
         External References provide a way to document systems, sites, and information that may be relevant but which
         are not included with the BOM.
diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
index 16c0d6c0c..f1e642dbc 100644
--- a/cyclonedx/model/bom.py
+++ b/cyclonedx/model/bom.py
@@ -94,7 +94,7 @@ def timestamp(self, timestamp: datetime) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'tool')
     @serializable.xml_sequence(2)
-    def tools(self) -> "SortedSet[Tool]":
+    def tools(self) -> 'SortedSet[Tool]':
         """
         Tools used to create this BOM.
 
@@ -110,7 +110,7 @@ def tools(self, tools: Iterable[Tool]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'author')
     @serializable.xml_sequence(3)
-    def authors(self) -> "SortedSet[OrganizationalContact]":
+    def authors(self) -> 'SortedSet[OrganizationalContact]':
         """
         The person(s) who created the BOM.
 
@@ -207,7 +207,7 @@ def licenses(self, licenses: Iterable[License]) -> None:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
     @serializable.xml_sequence(8)
-    def properties(self) -> "SortedSet[Property]":
+    def properties(self) -> 'SortedSet[Property]':
         """
         Provides the ability to document properties in a key/value store. This provides flexibility to include data not
         officially supported in the standard without having to use additional namespaces or create extensions.
@@ -335,7 +335,7 @@ def metadata(self, metadata: BomMetaData) -> None:
     @serializable.include_none(SchemaVersion1Dot1)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'component')
     @serializable.xml_sequence(2)
-    def components(self) -> "SortedSet[Component]":
+    def components(self) -> 'SortedSet[Component]':
         """
         Get all the Components currently in this Bom.
 
@@ -348,7 +348,7 @@ def components(self) -> "SortedSet[Component]":
     def components(self, components: Iterable[Component]) -> None:
         self._components = SortedSet(components)
 
-    def get_component_by_purl(self, purl: Optional["PackageURL"]) -> Optional[Component]:
+    def get_component_by_purl(self, purl: Optional['PackageURL']) -> Optional[Component]:
         """
         Get a Component already in the Bom by its PURL
 
@@ -394,7 +394,7 @@ def has_component(self, component: Component) -> bool:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'service')
     @serializable.xml_sequence(3)
-    def services(self) -> "SortedSet[Service]":
+    def services(self) -> 'SortedSet[Service]':
         """
         Get all the Services currently in this Bom.
 
@@ -414,7 +414,7 @@ def services(self, services: Iterable[Service]) -> None:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
     @serializable.xml_sequence(4)
-    def external_references(self) -> "SortedSet[ExternalReference]":
+    def external_references(self) -> 'SortedSet[ExternalReference]':
         """
         Provides the ability to document external references related to the BOM or to the project the BOM describes.
 
@@ -438,7 +438,7 @@ def _get_all_components(self) -> Set[Component]:
 
         return components
 
-    def get_vulnerabilities_for_bom_ref(self, bom_ref: BomRef) -> "SortedSet[Vulnerability]":
+    def get_vulnerabilities_for_bom_ref(self, bom_ref: BomRef) -> 'SortedSet[Vulnerability]':
         """
         Get all known Vulnerabilities that affect the supplied bom_ref.
 
@@ -469,7 +469,7 @@ def has_vulnerabilities(self) -> bool:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'vulnerability')
     @serializable.xml_sequence(8)
-    def vulnerabilities(self) -> "SortedSet[Vulnerability]":
+    def vulnerabilities(self) -> 'SortedSet[Vulnerability]':
         """
         Get all the Vulnerabilities in this BOM.
 
@@ -497,7 +497,7 @@ def version(self, version: int) -> None:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'dependency')
     @serializable.xml_sequence(5)
-    def dependencies(self) -> "SortedSet[Dependency]":
+    def dependencies(self) -> 'SortedSet[Dependency]':
         return self._dependencies
 
     @dependencies.setter
@@ -564,7 +564,7 @@ def validate(self) -> bool:
                 f'The Component this BOM is describing {self.metadata.component.purl} has no defined dependencies '
                 f'which means the Dependency Graph is incomplete - you should add direct dependencies to this '
                 f'"root" Component to complete the Dependency Graph data.',
-                UserWarning
+                category=UserWarning, stacklevel=1
             )
 
         # 3. If a LicenseExpression is set, then there must be no other license.
diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py
index bf8501a90..5aefa706e 100644
--- a/cyclonedx/model/component.py
+++ b/cyclonedx/model/component.py
@@ -209,7 +209,7 @@ def licenses(self, licenses: Iterable[License]) -> None:
 
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'text')
-    def copyright(self) -> "SortedSet[Copyright]":
+    def copyright(self) -> 'SortedSet[Copyright]':
         """
         Optional list of copyright statements.
 
@@ -388,7 +388,7 @@ def diff(self, diff: Optional[Diff]) -> None:
 
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'issue')
-    def resolves(self) -> "SortedSet[IssueType]":
+    def resolves(self) -> 'SortedSet[IssueType]':
         """
         Optional list of issues resolved by this patch.
 
@@ -510,7 +510,7 @@ def variants(self, variants: Iterable['Component']) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'commit')
     @serializable.xml_sequence(4)
-    def commits(self) -> "SortedSet[Commit]":
+    def commits(self) -> 'SortedSet[Commit]':
         """
         A list of zero or more commits which provide a trail describing how the component deviates from an ancestor,
         descendant, or variant.
@@ -530,7 +530,7 @@ def commits(self, commits: Iterable[Commit]) -> None:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'patch')
     @serializable.xml_sequence(5)
-    def patches(self) -> "SortedSet[Patch]":
+    def patches(self) -> 'SortedSet[Patch]':
         """
         A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant.
         Patches may be complimentary to commits or may be used in place of commits.
@@ -733,18 +733,18 @@ def for_file(absolute_file_path: str, path_for_bom: Optional[str]) -> 'Component
             `Component` representing the supplied file
         """
         if not exists(absolute_file_path):
-            raise FileExistsError('Supplied file path \'{}\' does not exist'.format(absolute_file_path))
+            raise FileExistsError(f'Supplied file path {absolute_file_path!r} does not exist')
 
         sha1_hash: str = sha1sum(filename=absolute_file_path)
         return Component(
             name=path_for_bom if path_for_bom else absolute_file_path,
-            version='0.0.0-{}'.format(sha1_hash[0:12]),
+            version=f'0.0.0-{sha1_hash[0:12]}',
             hashes=[
                 HashType(alg=HashAlgorithm.SHA_1, content=sha1_hash)
             ],
             type=ComponentType.FILE, purl=PackageURL(
                 type='generic', name=path_for_bom if path_for_bom else absolute_file_path,
-                version='0.0.0-{}'.format(sha1_hash[0:12])
+                version=f'0.0.0-{sha1_hash[0:12]}'
             )
         )
 
@@ -795,15 +795,16 @@ def __init__(self, *, name: str, type: ComponentType = ComponentType.LIBRARY,
         if namespace:
             warnings.warn(
                 '`namespace` is deprecated and has been replaced with `group` to align with the CycloneDX standard',
-                DeprecationWarning
+                category=DeprecationWarning, stacklevel=1
             )
             if not group:
                 self.group = namespace
 
         if license_str:
             warnings.warn(
-                '`license_str` is deprecated and has been replaced with `licenses` to align with the CycloneDX '
-                'standard', DeprecationWarning
+                '`license_str` is deprecated and has been'
+                ' replaced with `licenses` to align with the CycloneDX standard',
+                category=DeprecationWarning, stacklevel=1
             )
             if not licenses:
                 self.licenses = LicenseRepository([LicenseExpression(license_str)])
@@ -953,10 +954,10 @@ def name(self, name: str) -> None:
         self._name = name
 
     @property
-    @serializable.include_none(SchemaVersion1Dot0, "")
-    @serializable.include_none(SchemaVersion1Dot1, "")
-    @serializable.include_none(SchemaVersion1Dot2, "")
-    @serializable.include_none(SchemaVersion1Dot3, "")
+    @serializable.include_none(SchemaVersion1Dot0, '')
+    @serializable.include_none(SchemaVersion1Dot1, '')
+    @serializable.include_none(SchemaVersion1Dot2, '')
+    @serializable.include_none(SchemaVersion1Dot3, '')
     @serializable.xml_sequence(6)
     def version(self) -> Optional[str]:
         """
@@ -1009,7 +1010,7 @@ def scope(self, scope: Optional[ComponentScope]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'hash')
     @serializable.xml_sequence(9)
-    def hashes(self) -> "SortedSet[HashType]":
+    def hashes(self) -> 'SortedSet[HashType]':
         """
         Optional list of hashes that help specify the integrity of this Component.
 
@@ -1148,7 +1149,7 @@ def pedigree(self, pedigree: Optional[Pedigree]) -> None:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
     @serializable.xml_sequence(17)
-    def external_references(self) -> "SortedSet[ExternalReference]":
+    def external_references(self) -> 'SortedSet[ExternalReference]':
         """
         Provides the ability to document external references related to the component or to the project the component
         describes.
@@ -1167,7 +1168,7 @@ def external_references(self, external_references: Iterable[ExternalReference])
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
     @serializable.xml_sequence(18)
-    def properties(self) -> "SortedSet[Property]":
+    def properties(self) -> 'SortedSet[Property]':
         """
         Provides the ability to document properties in a key/value store. This provides flexibility to include data not
         officially supported in the standard without having to use additional namespaces or create extensions.
@@ -1232,7 +1233,7 @@ def release_notes(self) -> Optional[ReleaseNotes]:
     def release_notes(self, release_notes: Optional[ReleaseNotes]) -> None:
         self._release_notes = release_notes
 
-    def get_all_nested_components(self, include_self: bool = False) -> Set["Component"]:
+    def get_all_nested_components(self, include_self: bool = False) -> Set['Component']:
         components = set()
         if include_self:
             components.add(self)
@@ -1279,5 +1280,6 @@ def get_namespace(self) -> Optional[str]:
         Returns:
             Declared namespace of this Component as `str` if declared, else `None`.
         """
-        warnings.warn('`Component.get_namespace()` is deprecated - use `Component.group`', DeprecationWarning)
+        warnings.warn('`Component.get_namespace()` is deprecated - use `Component.group`',
+                      category=DeprecationWarning, stacklevel=1)
         return self._group
diff --git a/cyclonedx/model/dependency.py b/cyclonedx/model/dependency.py
index ee40fa6d0..51c13d93c 100644
--- a/cyclonedx/model/dependency.py
+++ b/cyclonedx/model/dependency.py
@@ -37,8 +37,8 @@ def serialize(cls, o: Any) -> List[str]:
         raise ValueError(f'Attempt to serialize a non-Dependency: {o.__class__}')
 
     @classmethod
-    def deserialize(cls, o: Any) -> Set["Dependency"]:
-        dependencies: Set["Dependency"] = set()
+    def deserialize(cls, o: Any) -> Set['Dependency']:
+        dependencies: Set['Dependency'] = set()
         if isinstance(o, list):
             for v in o:
                 dependencies.add(Dependency(ref=BomRef(value=v)))
@@ -54,7 +54,7 @@ class Dependency:
         See https://cyclonedx.org/docs/1.4/xml/#type_dependencyType
     """
 
-    def __init__(self, ref: BomRef, dependencies: Optional[Iterable["Dependency"]] = None) -> None:
+    def __init__(self, ref: BomRef, dependencies: Optional[Iterable['Dependency']] = None) -> None:
         self.ref = ref
         self.dependencies = SortedSet(dependencies or [])
 
@@ -72,11 +72,11 @@ def ref(self, ref: BomRef) -> None:
     @serializable.json_name('dependsOn')
     @serializable.type_mapping(DependencyDependencies)
     @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'dependency')
-    def dependencies(self) -> "SortedSet[Dependency]":
+    def dependencies(self) -> 'SortedSet[Dependency]':
         return self._dependencies
 
     @dependencies.setter
-    def dependencies(self, dependencies: Iterable["Dependency"]) -> None:
+    def dependencies(self, dependencies: Iterable['Dependency']) -> None:
         self._dependencies = SortedSet(dependencies)
 
     def dependencies_as_bom_refs(self) -> Set[BomRef]:
diff --git a/cyclonedx/model/issue.py b/cyclonedx/model/issue.py
index 722cb5b65..03709b4fb 100644
--- a/cyclonedx/model/issue.py
+++ b/cyclonedx/model/issue.py
@@ -196,7 +196,7 @@ def source(self, source: Optional[IssueTypeSource]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'url')
     @serializable.xml_sequence(5)
-    def references(self) -> "SortedSet[XsUri]":
+    def references(self) -> 'SortedSet[XsUri]':
         """
         Any reference URLs related to this issue.
 
diff --git a/cyclonedx/model/license.py b/cyclonedx/model/license.py
index 70b76a8c1..f091f698d 100644
--- a/cyclonedx/model/license.py
+++ b/cyclonedx/model/license.py
@@ -46,7 +46,7 @@ def __init__(self, *, id: Optional[str] = None, name: Optional[str] = None,
         if id and name:
             warnings.warn(
                 'Both `id` and `name` have been supplied - `name` will be ignored!',
-                RuntimeWarning
+                category=RuntimeWarning, stacklevel=1
             )
         self._id = id
         self._name = name if not id else None
diff --git a/cyclonedx/model/release_note.py b/cyclonedx/model/release_note.py
index 4464f587f..371c20a37 100644
--- a/cyclonedx/model/release_note.py
+++ b/cyclonedx/model/release_note.py
@@ -141,7 +141,7 @@ def timestamp(self, timestamp: Optional[datetime]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'alias')
     @serializable.xml_sequence(7)
-    def aliases(self) -> "SortedSet[str]":
+    def aliases(self) -> 'SortedSet[str]':
         """
         One or more alternate names the release may be referred to. This may include unofficial terms used by
         development and marketing teams (e.g. code names).
@@ -158,7 +158,7 @@ def aliases(self, aliases: Iterable[str]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'tag')
     @serializable.xml_sequence(8)
-    def tags(self) -> "SortedSet[str]":
+    def tags(self) -> 'SortedSet[str]':
         """
         One or more tags that may aid in search or retrieval of the release note.
 
@@ -174,7 +174,7 @@ def tags(self, tags: Iterable[str]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'issue')
     @serializable.xml_sequence(9)
-    def resolves(self) -> "SortedSet[IssueType]":
+    def resolves(self) -> 'SortedSet[IssueType]':
         """
         A collection of issues that have been resolved.
 
@@ -190,7 +190,7 @@ def resolves(self, resolves: Iterable[IssueType]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'note')
     @serializable.xml_sequence(10)
-    def notes(self) -> "SortedSet[Note]":
+    def notes(self) -> 'SortedSet[Note]':
         """
         Zero or more release notes containing the locale and content. Multiple note elements may be specified to support
         release notes in a wide variety of languages.
@@ -207,7 +207,7 @@ def notes(self, notes: Iterable[Note]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
     @serializable.xml_sequence(11)
-    def properties(self) -> "SortedSet[Property]":
+    def properties(self) -> 'SortedSet[Property]':
         """
         Provides the ability to document properties in a name-value store. This provides flexibility to include data not
         officially supported in the standard without having to use additional namespaces or create extensions. Unlike
diff --git a/cyclonedx/model/service.py b/cyclonedx/model/service.py
index b00b0714a..708e874b1 100644
--- a/cyclonedx/model/service.py
+++ b/cyclonedx/model/service.py
@@ -170,7 +170,7 @@ def description(self, description: Optional[str]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'endpoint')
     @serializable.xml_sequence(6)
-    def endpoints(self) -> "SortedSet[XsUri]":
+    def endpoints(self) -> 'SortedSet[XsUri]':
         """
         A list of endpoints URI's this service provides.
 
@@ -224,7 +224,7 @@ def x_trust_boundary(self, x_trust_boundary: Optional[bool]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'classification')
     @serializable.xml_sequence(9)
-    def data(self) -> "SortedSet[DataClassification]":
+    def data(self) -> 'SortedSet[DataClassification]':
         """
         Specifies the data classification.
 
@@ -256,7 +256,7 @@ def licenses(self, licenses: Iterable[License]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
     @serializable.xml_sequence(11)
-    def external_references(self) -> "SortedSet[ExternalReference]":
+    def external_references(self) -> 'SortedSet[ExternalReference]':
         """
         Provides the ability to document external references related to the Service.
 
@@ -310,7 +310,7 @@ def release_notes(self, release_notes: Optional[ReleaseNotes]) -> None:
     @serializable.view(SchemaVersion1Dot4)
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
     @serializable.xml_sequence(12)
-    def properties(self) -> "SortedSet[Property]":
+    def properties(self) -> 'SortedSet[Property]':
         """
         Provides the ability to document properties in a key/value store. This provides flexibility to include data not
         officially supported in the standard without having to use additional namespaces or create extensions.
diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py
index 53bcf453a..b17fc1174 100644
--- a/cyclonedx/model/vulnerability.py
+++ b/cyclonedx/model/vulnerability.py
@@ -108,7 +108,7 @@ def range(self, range: Optional[str]) -> None:
     def status(self) -> Optional[ImpactAnalysisAffectedStatus]:
         """
         The vulnerability status for the version or range of versions.
-        """""
+        """
         return self._status
 
     @status.setter
@@ -166,7 +166,7 @@ def ref(self, ref: str) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'version')
     @serializable.xml_sequence(2)
-    def versions(self) -> "SortedSet[BomTargetVersionRange]":
+    def versions(self) -> 'SortedSet[BomTargetVersionRange]':
         """
         Zero or more individual versions or range of versions.
 
@@ -253,7 +253,7 @@ def justification(self, justification: Optional[ImpactAnalysisJustification]) ->
     @serializable.json_name('response')
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'response')
     @serializable.xml_sequence(3)
-    def responses(self) -> "SortedSet[ImpactAnalysisResponse]":
+    def responses(self) -> 'SortedSet[ImpactAnalysisResponse]':
         """
         A list of responses to the vulnerability by the manufacturer, supplier, or project responsible for the
         affected component or service. More than one response is allowed. Responses are strongly encouraged for
@@ -631,10 +631,11 @@ def __init__(self, *, source: Optional[VulnerabilitySource] = None, score: Optio
         self.justification = justification
 
         if score_base:
-            warnings.warn('`score_base` is deprecated - use `score`', DeprecationWarning)
+            warnings.warn('`score_base` is deprecated - use `score`',
+                          category=DeprecationWarning, stacklevel=1)
             if score:
                 warnings.warn('Both `score` and `score_base` supplied - the deprecated `score_base` will be discarded',
-                              DeprecationWarning)
+                              category=DeprecationWarning, stacklevel=1)
             else:
                 self.score = Decimal(score_base)
 
@@ -761,7 +762,7 @@ def __init__(self, *, organizations: Optional[Iterable[OrganizationalEntity]] =
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'organization')
     @serializable.xml_sequence(1)
-    def organizations(self) -> "SortedSet[OrganizationalEntity]":
+    def organizations(self) -> 'SortedSet[OrganizationalEntity]':
         """
         The organizations credited with vulnerability discovery.
 
@@ -777,7 +778,7 @@ def organizations(self, organizations: Iterable[OrganizationalEntity]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'individual')
     @serializable.xml_sequence(2)
-    def individuals(self) -> "SortedSet[OrganizationalContact]":
+    def individuals(self) -> 'SortedSet[OrganizationalContact]':
         """
         The individuals, not associated with organizations, that are credited with vulnerability discovery.
 
@@ -856,12 +857,14 @@ def __init__(self, *, bom_ref: Optional[Union[str, BomRef]] = None, id: Optional
         self.properties = properties or []  # type: ignore
 
         if source_name or source_url:
-            warnings.warn('`source_name` and `source_url` are deprecated - use `source`', DeprecationWarning)
+            warnings.warn('`source_name` and `source_url` are deprecated - use `source`',
+                          category=DeprecationWarning, stacklevel=1)
             if not source:
                 self.source = VulnerabilitySource(name=source_name, url=XsUri(source_url) if source_url else None)
 
         if recommendations:
-            warnings.warn('`recommendations` is deprecated - use `recommendation`', DeprecationWarning)
+            warnings.warn('`recommendations` is deprecated - use `recommendation`',
+                          category=DeprecationWarning, stacklevel=1)
             if not recommendation:
                 self.recommendation = next(iter(recommendations))
 
@@ -914,7 +917,7 @@ def source(self, source: Optional[VulnerabilitySource]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
     @serializable.xml_sequence(3)
-    def references(self) -> "SortedSet[VulnerabilityReference]":
+    def references(self) -> 'SortedSet[VulnerabilityReference]':
         """
         Zero or more pointers to vulnerabilities that are the equivalent of the vulnerability specified. Often times,
         the same vulnerability may exist in multiple sources of vulnerability intelligence, but have different
@@ -933,7 +936,7 @@ def references(self, references: Iterable[VulnerabilityReference]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'rating')
     @serializable.xml_sequence(4)
-    def ratings(self) -> "SortedSet[VulnerabilityRating]":
+    def ratings(self) -> 'SortedSet[VulnerabilityRating]':
         """
         List of vulnerability ratings.
 
@@ -949,7 +952,7 @@ def ratings(self, ratings: Iterable[VulnerabilityRating]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'cwe')
     @serializable.xml_sequence(5)
-    def cwes(self) -> "SortedSet[int]":
+    def cwes(self) -> 'SortedSet[int]':
         """
         A list of CWE (Common Weakness Enumeration) identifiers.
 
@@ -1014,7 +1017,7 @@ def recommendation(self, recommendation: Optional[str]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'advisory')
     @serializable.xml_sequence(9)
-    def advisories(self) -> "SortedSet[VulnerabilityAdvisory]":
+    def advisories(self) -> 'SortedSet[VulnerabilityAdvisory]':
         """
         Advisories relating to the Vulnerability.
 
@@ -1093,7 +1096,7 @@ def credits(self, credits: Optional[VulnerabilityCredits]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'tool')
     @serializable.xml_sequence(14)
-    def tools(self) -> "SortedSet[Tool]":
+    def tools(self) -> 'SortedSet[Tool]':
         """
         The tool(s) used to identify, confirm, or score the vulnerability.
 
@@ -1124,7 +1127,7 @@ def analysis(self, analysis: Optional[VulnerabilityAnalysis]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'target')
     @serializable.xml_sequence(16)
-    def affects(self) -> "SortedSet[BomTarget]":
+    def affects(self) -> 'SortedSet[BomTarget]':
         """
         The components or services that are affected by the vulnerability.
 
@@ -1140,7 +1143,7 @@ def affects(self, affects_targets: Iterable[BomTarget]) -> None:
     @property
     @serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
     @serializable.xml_sequence(17)
-    def properties(self) -> "SortedSet[Property]":
+    def properties(self) -> 'SortedSet[Property]':
         """
         Provides the ability to document properties in a key/value store. This provides flexibility to include data not
         officially supported in the standard without having to use additional namespaces or create extensions.
diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
index 8c590daea..f8245743f 100644
--- a/cyclonedx/output/__init__.py
+++ b/cyclonedx/output/__init__.py
@@ -122,13 +122,13 @@ def make_outputter(bom: 'Bom', output_format: OutputFormat, schema_version: Sche
     :return: BaseOutput
     """
     if TYPE_CHECKING:  # pragma: no cover
-        BY_SCHEMA_VERSION: Mapping[SchemaVersion, Type[BaseOutput]]
+        BY_SCHEMA_VERSION: Mapping[SchemaVersion, Type[BaseOutput]]  # noqa:N806
     if OutputFormat.JSON is output_format:
         from .json import BY_SCHEMA_VERSION
     elif OutputFormat.XML is output_format:
         from .xml import BY_SCHEMA_VERSION
     else:
-        raise ValueError(f"Unexpected output_format: {output_format!r}")
+        raise ValueError(f'Unexpected output_format: {output_format!r}')
 
     klass = BY_SCHEMA_VERSION.get(schema_version, None)
     if klass is None:
@@ -141,6 +141,6 @@ def get_instance(bom: 'Bom', output_format: OutputFormat = OutputFormat.XML,
     """DEPRECATED. use :func:`make_outputter` instead!"""
     warnings.warn(
         'function `get_instance()` is deprecated, use `make_outputter()` instead.',
-        DeprecationWarning
+        category=DeprecationWarning, stacklevel=1
     )
     return make_outputter(bom, output_format, schema_version)
diff --git a/cyclonedx/parser/__init__.py b/cyclonedx/parser/__init__.py
index 6fdded1eb..06990d47c 100644
--- a/cyclonedx/parser/__init__.py
+++ b/cyclonedx/parser/__init__.py
@@ -40,7 +40,7 @@ def get_warning_message(self) -> str:
         return self._warning
 
     def __repr__(self) -> str:
-        return f'<ParserWarning item=\'{self._item}\'>'
+        return f'<ParserWarning item={self._item!r}>'
 
 
 class BaseParser:
diff --git a/cyclonedx/validation/__init__.py b/cyclonedx/validation/__init__.py
index e66c13449..b7dda3f13 100644
--- a/cyclonedx/validation/__init__.py
+++ b/cyclonedx/validation/__init__.py
@@ -109,7 +109,7 @@ def make_schemabased_validator(output_format: OutputFormat, schema_version: 'Sch
     """
     if TYPE_CHECKING:  # pragma: no cover
         from typing import Type
-        Validator: Type[BaseSchemabasedValidator]
+        Validator: Type[BaseSchemabasedValidator]  # noqa:N806
     if OutputFormat.JSON is output_format:
         from .json import JsonValidator as Validator
     elif OutputFormat.XML is output_format:
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
index 797bd3b9e..f1ab46c10 100644
--- a/cyclonedx/validation/json.py
+++ b/cyclonedx/validation/json.py
@@ -31,13 +31,13 @@
 
 _missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
 try:
-    from jsonschema.exceptions import ValidationError as JsonValidationError  # type: ignore[import]
-    from jsonschema.validators import Draft7Validator  # type: ignore[import]
+    from jsonschema.exceptions import ValidationError as JsonValidationError  # type:ignore[import-untyped]
+    from jsonschema.validators import Draft7Validator  # type:ignore[import-untyped]
     from referencing import Registry
     from referencing.jsonschema import DRAFT7
 
     if TYPE_CHECKING:  # pragma: no cover
-        from jsonschema.protocols import Validator as JsonSchemaValidator  # type: ignore[import]
+        from jsonschema.protocols import Validator as JsonSchemaValidator  # type:ignore[import-untyped]
 except ImportError as err:
     _missing_deps_error = MissingOptionalDependencyException(
         'This functionality requires optional dependencies.\n'
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index 2fae6692e..295674448 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -29,7 +29,7 @@
 
 _missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
 try:
-    from lxml.etree import XMLParser, XMLSchema, fromstring as xml_fromstring  # type: ignore[import]
+    from lxml.etree import XMLParser, XMLSchema, fromstring as xml_fromstring  # type:ignore[import-untyped]
 except ImportError as err:
     _missing_deps_error = MissingOptionalDependencyException(
         'This functionality requires optional dependencies.\n'
diff --git a/examples/complex.py b/examples/complex.py
index 1b9b068f5..94799ec52 100644
--- a/examples/complex.py
+++ b/examples/complex.py
@@ -43,7 +43,7 @@
 # region build the BOM
 
 bom = Bom()
-bom.metadata.component = rootComponent = Component(
+bom.metadata.component = root_component = Component(
     name='myApp',
     type=ComponentType.APPLICATION,
     licenses=[lc_factory.make_from_string('MIT')],
@@ -64,7 +64,7 @@
     purl=PackageURL('generic', 'acme', 'some-component', '1.33.7-beta.1')
 )
 bom.components.add(component1)
-bom.register_dependency(rootComponent, [component1])
+bom.register_dependency(root_component, [component1])
 
 component2 = Component(
     type=ComponentType.LIBRARY,
diff --git a/pyproject.toml b/pyproject.toml
index 223f10356..0f3762aa9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -74,19 +74,20 @@ xml-validation = ["lxml"]
 
 [tool.poetry.dev-dependencies]
 ddt = "1.6.0"
-coverage = "7.3.1"
+coverage = "7.3.2"
 flake8 = { version="6.1.0", python=">=3.8.1" }
 flake8-annotations = { version="3.0.1", python=">=3.8.1" }
 flake8-bugbear = { version="23.9.16", python=">=3.8.1" }
 flake8-isort = "6.1.0 "
+flake8-quotes = "3.3.2"
+flake8-use-fstring = "1.4"
+pep8-naming = "0.13.3"
 isort = "5.12.0"
 autopep8 = "2.0.4"
-mypy = "1.5.1"
+mypy = "1.6.1"
 tox = "4.11.3"
 xmldiff = "2.6.3"
 
-
-
 [tool.semantic_release]
 # see https://python-semantic-release.readthedocs.io/en/latest/configuration.html
 commit_author = "semantic-release <semantic-release>"
diff --git a/tests/__init__.py b/tests/__init__.py
index f70814842..f0eaf33c5 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -45,20 +45,21 @@
 class SnapshotMixin:
 
     @staticmethod
-    def getSnapshotFile(snapshot_name: str) -> str:
+    def getSnapshotFile(snapshot_name: str) -> str:  # noqa: N802
         return join(SNAPSHOTS_DIRECTORY, f'{snapshot_name}.bin')
 
     @classmethod
-    def writeSnapshot(cls, snapshot_name: str, data: str) -> None:
+    def writeSnapshot(cls, snapshot_name: str, data: str) -> None:  # noqa: N802
         with open(cls.getSnapshotFile(snapshot_name), 'w') as s:
             s.write(data)
 
     @classmethod
-    def readSnapshot(cls, snapshot_name: str) -> str:
+    def readSnapshot(cls, snapshot_name: str) -> str:  # noqa: N802
         with open(cls.getSnapshotFile(snapshot_name), 'r') as s:
             return s.read()
 
-    def assertEqualSnapshot(self: Union[TestCase, 'SnapshotMixin'], actual: str, snapshot_name: str) -> None:
+    def assertEqualSnapshot(self: Union[TestCase, 'SnapshotMixin'],  # noqa: N802
+                            actual: str, snapshot_name: str) -> None:
         if RECREATE_SNAPSHOTS:
             self.writeSnapshot(snapshot_name, actual)
         _omd = self.maxDiff
@@ -71,36 +72,38 @@ def assertEqualSnapshot(self: Union[TestCase, 'SnapshotMixin'], actual: str, sna
 
 
 class DeepCompareMixin:
-    def assertDeepEqual(self: Union[TestCase, 'DeepCompareMixin'], first: Any, second: Any,
+    def assertDeepEqual(self: Union[TestCase, 'DeepCompareMixin'],  # noqa: N802
+                        first: Any, second: Any,
                         msg: Optional[str] = None) -> None:
         """costly compare, but very verbose"""
         _omd = self.maxDiff
         self.maxDiff = None
         try:
             self.maxDiff = None
-            dd1 = self.__deepDict(first)
-            dd2 = self.__deepDict(second)
+            dd1 = self.__deep_dict(first)
+            dd2 = self.__deep_dict(second)
             self.assertDictEqual(dd1, dd2, msg)
         finally:
             self.maxDiff = _omd
 
-    def __deepDict(self, o: Any) -> Any:
+    def __deep_dict(self, o: Any) -> Any:
         if isinstance(o, tuple):
-            return tuple(self.__deepDict(i) for i in o)
+            return tuple(self.__deep_dict(i) for i in o)
         if isinstance(o, list):
-            return list(self.__deepDict(i) for i in o)
+            return list(self.__deep_dict(i) for i in o)
         if isinstance(o, dict):
-            return {k: self.__deepDict(v) for k, v in o.items()}
+            return {k: self.__deep_dict(v) for k, v in o.items()}
         if isinstance(o, (set, SortedSet)):
             # this method returns dict. `dict` is not hashable, so use `tuple` instead.
-            return tuple(self.__deepDict(i) for i in sorted(o, key=hash)) + ('%conv:%set',)
+            return tuple(self.__deep_dict(i) for i in sorted(o, key=hash)) + ('%conv:%set',)
         if hasattr(o, '__dict__'):
-            d = {a: self.__deepDict(v) for a, v in o.__dict__.items() if '__' not in a}
+            d = {a: self.__deep_dict(v) for a, v in o.__dict__.items() if '__' not in a}
             d['%conv'] = str(type(o))
             return d
         return o
 
-    def assertBomDeepEqual(self: Union[TestCase, 'DeepCompareMixin'], expected: 'Bom', actual: 'Bom',
+    def assertBomDeepEqual(self: Union[TestCase, 'DeepCompareMixin'],  # noqa: N802
+                           expected: 'Bom', actual: 'Bom',
                            msg: Optional[str] = None, *,
                            fuzzy_deps: bool = True) -> None:
         # deps might have been upgraded on serialization, so they might differ
@@ -112,12 +115,13 @@ def assertBomDeepEqual(self: Union[TestCase, 'DeepCompareMixin'], expected: 'Bom
         try:
             self.assertDeepEqual(expected, actual, msg)
             if fuzzy_deps:
-                self._assertDependenciesFuzzyEqual(edeps, adeps)
+                self.assertDependenciesFuzzyEqual(edeps, adeps)
         finally:
             expected.dependencies = edeps
             actual.dependencies = adeps
 
-    def _assertDependenciesFuzzyEqual(self: TestCase, a: Iterable['Dependency'], b: Iterable['Dependency']) -> None:
+    def assertDependenciesFuzzyEqual(self: TestCase,  # noqa: N802
+                                     a: Iterable['Dependency'], b: Iterable['Dependency']) -> None:
         delta = set(a) ^ set(b)
         for d in delta:
             # only actual relevant dependencies shall be taken into account.
diff --git a/tests/_data/models.py b/tests/_data/models.py
index 6a1e178c1..bc66b5122 100644
--- a/tests/_data/models.py
+++ b/tests/_data/models.py
@@ -107,7 +107,7 @@
 BOM_TIMESTAMP = datetime.fromisoformat('2023-01-07 13:44:32.312678+00:00')
 
 
-def _makeBom(**kwargs: Any) -> Bom:
+def _make_bom(**kwargs: Any) -> Bom:
     bom = Bom(**kwargs)
     bom.serial_number = BOM_SERIAL_NUMBER
     bom.metadata.timestamp = BOM_TIMESTAMP
@@ -115,29 +115,29 @@ def _makeBom(**kwargs: Any) -> Bom:
 
 
 def get_bom_with_component_setuptools_basic() -> Bom:
-    return _makeBom(components=[get_component_setuptools_simple()])
+    return _make_bom(components=[get_component_setuptools_simple()])
 
 
 def get_bom_with_component_setuptools_with_cpe() -> Bom:
     component = get_component_setuptools_simple()
     component.cpe = 'cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*'
-    return _makeBom(components=[component])
+    return _make_bom(components=[component])
 
 
 def get_bom_with_component_setuptools_no_component_version() -> Bom:
-    return _makeBom(components=[get_component_setuptools_simple_no_version()])
+    return _make_bom(components=[get_component_setuptools_simple_no_version()])
 
 
 def get_bom_with_component_setuptools_with_release_notes() -> Bom:
     component = get_component_setuptools_simple()
     component.release_notes = get_release_notes()
-    return _makeBom(components=[component])
+    return _make_bom(components=[component])
 
 
 def get_bom_with_dependencies_valid() -> Bom:
     c1 = get_component_setuptools_simple()
     c2 = get_component_toml_with_hashes_with_references()
-    return _makeBom(
+    return _make_bom(
         components=[c1, c2], dependencies=[
             Dependency(ref=c1.bom_ref, dependencies=[
                 Dependency(ref=c2.bom_ref)
@@ -154,7 +154,7 @@ def get_bom_with_dependencies_hanging() -> Bom:
     """
     c1 = get_component_setuptools_simple('setuptools')
     c2 = get_component_toml_with_hashes_with_references('toml')
-    bom = _makeBom(
+    bom = _make_bom(
         version=23,
         metadata=BomMetaData(
             component=Component(name='rootComponent', type=ComponentType.APPLICATION, bom_ref='root-component'),
@@ -175,12 +175,12 @@ def get_bom_with_dependencies_unlinked_invalid() -> Bom:
     it is expected to throw on output.
     """
     c1 = get_component_setuptools_simple()
-    return _makeBom(components=[c1], dependencies=[Dependency(ref=BomRef('link-to-ref-not-in-document'))])
+    return _make_bom(components=[c1], dependencies=[Dependency(ref=BomRef('link-to-ref-not-in-document'))])
 
 
 def get_bom_with_metadata_component_and_dependencies() -> Bom:
     cs = get_component_toml_with_hashes_with_references()
-    bom = _makeBom(components=[cs])
+    bom = _make_bom(components=[cs])
     bom.metadata.component = get_component_setuptools_simple()
     bom.dependencies.add(
         Dependency(ref=bom.metadata.component.bom_ref, dependencies=[
@@ -191,11 +191,11 @@ def get_bom_with_metadata_component_and_dependencies() -> Bom:
 
 
 def get_bom_with_component_setuptools_complete() -> Bom:
-    return _makeBom(components=[get_component_setuptools_complete()])
+    return _make_bom(components=[get_component_setuptools_complete()])
 
 
 def get_bom_with_component_setuptools_with_vulnerability() -> Bom:
-    bom = _makeBom()
+    bom = _make_bom()
     component = get_component_setuptools_simple()
     if not component.purl:
         raise ValueError('purl is required here')
@@ -258,11 +258,11 @@ def get_bom_with_component_setuptools_with_vulnerability() -> Bom:
 
 
 def get_bom_with_component_toml_1() -> Bom:
-    return _makeBom(components=[get_component_toml_with_hashes_with_references()])
+    return _make_bom(components=[get_component_toml_with_hashes_with_references()])
 
 
 def get_bom_just_complete_metadata() -> Bom:
-    bom = _makeBom()
+    bom = _make_bom()
     bom.metadata.authors = [get_org_contact_1(), get_org_contact_2()]
     bom.metadata.component = get_component_setuptools_complete()
     bom.metadata.manufacture = get_org_entity_1()
@@ -280,14 +280,14 @@ def get_bom_just_complete_metadata() -> Bom:
 
 
 def get_bom_with_external_references() -> Bom:
-    bom = _makeBom(external_references=[
+    bom = _make_bom(external_references=[
         get_external_reference_1(), get_external_reference_2()
     ])
     return bom
 
 
 def get_bom_with_services_simple() -> Bom:
-    bom = _makeBom(services=[
+    bom = _make_bom(services=[
         Service(name='my-first-service', bom_ref='my-specific-bom-ref-for-my-first-service'),
         Service(name='my-second-service', bom_ref='my-specific-bom-ref-for-my-second-service')
     ])
@@ -299,7 +299,7 @@ def get_bom_with_services_simple() -> Bom:
 
 
 def get_bom_with_services_complex() -> Bom:
-    bom = _makeBom(services=[
+    bom = _make_bom(services=[
         Service(
             name='my-first-service', bom_ref='my-specific-bom-ref-for-my-first-service',
             provider=get_org_entity_1(), group='a-group', version='1.2.3',
@@ -327,7 +327,7 @@ def get_bom_with_services_complex() -> Bom:
 
 
 def get_bom_with_nested_services() -> Bom:
-    bom = _makeBom(services=[
+    bom = _make_bom(services=[
         Service(
             name='my-first-service', bom_ref='my-specific-bom-ref-for-my-first-service',
             provider=get_org_entity_1(), group='a-group', version='1.2.3',
@@ -381,10 +381,10 @@ def get_bom_for_issue_275_components() -> Bom:
     see https://github.com/CycloneDX/cyclonedx-python-lib/issues/275
     """
 
-    app = Component(bom_ref=MOCK_UUID[0], name="app", version="1.0.0")
-    comp_a = Component(bom_ref=MOCK_UUID[1], name="comp_a", version="1.0.0")
-    comp_b = Component(bom_ref=MOCK_UUID[2], name="comp_b", version="1.0.0")
-    comp_c = Component(bom_ref=MOCK_UUID[3], name="comp_c", version="1.0.0")
+    app = Component(bom_ref=MOCK_UUID[0], name='app', version='1.0.0')
+    comp_a = Component(bom_ref=MOCK_UUID[1], name='comp_a', version='1.0.0')
+    comp_b = Component(bom_ref=MOCK_UUID[2], name='comp_b', version='1.0.0')
+    comp_c = Component(bom_ref=MOCK_UUID[3], name='comp_c', version='1.0.0')
 
     comp_b.components.add(comp_c)
     # comp_b.dependencies.add(comp_c.bom_ref)
@@ -393,7 +393,7 @@ def get_bom_for_issue_275_components() -> Bom:
     # app.dependencies.add(comp_a.bom_ref)
     # app.dependencies.add(comp_b.bom_ref)
 
-    bom = _makeBom(components=libs)
+    bom = _make_bom(components=libs)
     bom.metadata.component = app
     bom.register_dependency(target=app, depends_on=[comp_a, comp_b])
     bom.register_dependency(target=comp_b, depends_on=[comp_c])
@@ -421,7 +421,7 @@ def get_bom_for_issue_328_components() -> Bom:
     """regression test for issue #328
     see https://github.com/CycloneDX/cyclonedx-python-lib/issues/328
     """
-    bom = _makeBom()
+    bom = _make_bom()
 
     comp_root = Component(type=ComponentType.APPLICATION,
                           name='my-project', version='1', bom_ref='my-project')
@@ -583,7 +583,7 @@ def get_pedigree_1() -> Pedigree:
             get_component_toml_with_hashes_with_references(bom_ref='e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66'),
             get_component_setuptools_simple(bom_ref='ded1d73e-1fca-4302-b520-f1bc53979958')
         ],
-        commits=[Commit(uid='a-random-uid', message="A commit message")],
+        commits=[Commit(uid='a-random-uid', message='A commit message')],
         patches=[Patch(type=PatchClassification.BACKPORT)],
         notes='Some notes here please'
     )
@@ -602,12 +602,12 @@ def get_release_notes() -> ReleaseNotes:
     ).decode(encoding='UTF-8')
 
     return ReleaseNotes(
-        type='major', title="Release Notes Title",
+        type='major', title='Release Notes Title',
         featured_image=XsUri('https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png'),
         social_image=XsUri('https://cyclonedx.org/cyclonedx-icon.png'),
-        description="This release is a test release", timestamp=MOCK_TIMESTAMP,
+        description='This release is a test release', timestamp=MOCK_TIMESTAMP,
         aliases=[
-            "First Test Release"
+            'First Test Release'
         ],
         tags=['test', 'alpha'],
         resolves=[get_issue_1()],
@@ -662,7 +662,7 @@ def get_vulnerability_source_owasp() -> VulnerabilitySource:
 
 
 def get_bom_with_licenses() -> Bom:
-    return _makeBom(
+    return _make_bom(
         metadata=BomMetaData(
             licenses=[DisjunctiveLicense(id='CC-BY-1.0')],
             component=Component(name='app', type=ComponentType.APPLICATION, bom_ref='my-app',
@@ -741,7 +741,7 @@ def get_bom_with_multiple_licenses() -> Bom:
         DisjunctiveLicense(id='MIT'),
         DisjunctiveLicense(name='foo license'),
     )
-    return _makeBom(
+    return _make_bom(
         metadata=BomMetaData(
             licenses=multi_licenses,
             component=Component(name='app', type=ComponentType.APPLICATION, bom_ref='my-app',
diff --git a/tests/test_component.py b/tests/test_component.py
index 92c54c8c7..e20be7aee 100644
--- a/tests/test_component.py
+++ b/tests/test_component.py
@@ -66,7 +66,7 @@ def test_from_xml_file_with_path_for_bom(self) -> None:
         test_file = join(OWN_DATA_DIRECTORY, 'xml', '1.4', 'bom_setuptools.xml')
         c = Component.for_file(absolute_file_path=test_file, path_for_bom='fixtures/bom_setuptools.xml')
         sha1_hash: str = sha1sum(filename=test_file)
-        expected_version = '0.0.0-{}'.format(sha1_hash[0:12])
+        expected_version = f'0.0.0-{sha1_hash[0:12]}'
         self.assertEqual(c.name, 'fixtures/bom_setuptools.xml')
         self.assertEqual(c.version, expected_version)
         purl = PackageURL(
diff --git a/tests/test_model.py b/tests/test_model.py
index 97ffc4a9e..75096f2a3 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -503,10 +503,10 @@ def test_sort(self) -> None:
         # expected sort order: (uri)
         expected_order = [2, 1, 3, 0]
         uris = [
-            XsUri(uri="d"),
-            XsUri(uri="b"),
-            XsUri(uri="a"),
-            XsUri(uri="c"),
+            XsUri(uri='d'),
+            XsUri(uri='b'),
+            XsUri(uri='a'),
+            XsUri(uri='c'),
         ]
         sorted_uris = sorted(uris)
         expected_uris = reorder(uris, expected_order)
diff --git a/tests/test_model_component.py b/tests/test_model_component.py
index ccee271e0..0333b46f4 100644
--- a/tests/test_model_component.py
+++ b/tests/test_model_component.py
@@ -63,16 +63,16 @@ def test_no_parameters(self) -> None:
 
     def test_same(self) -> None:
         ia_comitter = IdentifiableAction(timestamp=datetime.datetime.utcnow(), name='The Committer')
-        c1 = Commit(uid='a-random-uid', author=ia_comitter, committer=ia_comitter, message="A commit message")
-        c2 = Commit(uid='a-random-uid', author=ia_comitter, committer=ia_comitter, message="A commit message")
+        c1 = Commit(uid='a-random-uid', author=ia_comitter, committer=ia_comitter, message='A commit message')
+        c2 = Commit(uid='a-random-uid', author=ia_comitter, committer=ia_comitter, message='A commit message')
         self.assertEqual(hash(c1), hash(c2))
         self.assertTrue(c1 == c2)
 
     def test_not_same(self) -> None:
         ia_author = IdentifiableAction(timestamp=datetime.datetime.utcnow(), name='The Author')
         ia_comitter = IdentifiableAction(timestamp=datetime.datetime.utcnow(), name='The Committer')
-        c1 = Commit(uid='a-random-uid', author=ia_comitter, committer=ia_comitter, message="A commit message")
-        c2 = Commit(uid='a-random-uid', author=ia_author, committer=ia_comitter, message="A commit message")
+        c1 = Commit(uid='a-random-uid', author=ia_comitter, committer=ia_comitter, message='A commit message')
+        c2 = Commit(uid='a-random-uid', author=ia_author, committer=ia_comitter, message='A commit message')
         self.assertNotEqual(hash(c1), hash(c2))
         self.assertFalse(c1 == c2)
 
@@ -259,15 +259,15 @@ def test_sort(self) -> None:
             Component(name='component-a', type=ComponentType.LIBRARY, group='group-2'),
             Component(name='component-a', type=ComponentType.FILE),
             Component(name='component-b', type=ComponentType.FILE),
-            Component(name='component-a', type=ComponentType.FILE, version="1.0.0"),
+            Component(name='component-a', type=ComponentType.FILE, version='1.0.0'),
         ]
         sorted_components = sorted(components)
         expected_components = reorder(components, expected_order)
         self.assertListEqual(sorted_components, expected_components)
 
     def test_nested_components_1(self) -> None:
-        comp_b = Component(name="comp_b")
-        comp_c = Component(name="comp_c")
+        comp_b = Component(name='comp_b')
+        comp_c = Component(name='comp_c')
         comp_b.components.add(comp_c)
 
         self.assertEqual(1, len(comp_b.components))
@@ -275,9 +275,9 @@ def test_nested_components_1(self) -> None:
         self.assertEqual(1, len(comp_b.get_all_nested_components(include_self=False)))
 
     def test_nested_components_2(self) -> None:
-        comp_a = Component(name="comp_a")
-        comp_b = Component(name="comp_b")
-        comp_c = Component(name="comp_c")
+        comp_a = Component(name='comp_a')
+        comp_b = Component(name='comp_b')
+        comp_c = Component(name='comp_c')
         comp_b.components.add(comp_c)
         comp_b.components.add(comp_a)
 
diff --git a/tests/test_model_dependency.py b/tests/test_model_dependency.py
index 4439d6aa0..1b0d2f646 100644
--- a/tests/test_model_dependency.py
+++ b/tests/test_model_dependency.py
@@ -28,14 +28,14 @@ def test_sort(self) -> None:
         # expected sort order: (value)
         expected_order = [3, 2, 0, 1]
         deps = [
-            Dependency(ref=BomRef(value="be2c6502-7e9a-47db-9a66-e34f729810a3"), dependencies=[
-                Dependency(ref=BomRef(value="0b049d09-64c0-4490-a0f5-c84d9aacf857")),
-                Dependency(ref=BomRef(value="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda"))
+            Dependency(ref=BomRef(value='be2c6502-7e9a-47db-9a66-e34f729810a3'), dependencies=[
+                Dependency(ref=BomRef(value='0b049d09-64c0-4490-a0f5-c84d9aacf857')),
+                Dependency(ref=BomRef(value='17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda'))
             ]),
-            Dependency(ref=BomRef(value="cd3e9c95-9d41-49e7-9924-8cf0465ae789")),
-            Dependency(ref=BomRef(value="17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda")),
-            Dependency(ref=BomRef(value="0b049d09-64c0-4490-a0f5-c84d9aacf857"), dependencies=[
-                Dependency(ref=BomRef(value="cd3e9c95-9d41-49e7-9924-8cf0465ae789"))
+            Dependency(ref=BomRef(value='cd3e9c95-9d41-49e7-9924-8cf0465ae789')),
+            Dependency(ref=BomRef(value='17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda')),
+            Dependency(ref=BomRef(value='0b049d09-64c0-4490-a0f5-c84d9aacf857'), dependencies=[
+                Dependency(ref=BomRef(value='cd3e9c95-9d41-49e7-9924-8cf0465ae789'))
             ])
         ]
         sorted_deps = sorted(deps)
diff --git a/tests/test_model_issue.py b/tests/test_model_issue.py
index b7a127ae6..548169956 100644
--- a/tests/test_model_issue.py
+++ b/tests/test_model_issue.py
@@ -67,15 +67,15 @@ def test_no_params(self) -> None:
             IssueTypeSource()
 
     def test_same(self) -> None:
-        its_1 = IssueTypeSource(name="The Source", url=XsUri('https://cyclonedx.org'))
-        its_2 = IssueTypeSource(name="The Source", url=XsUri('https://cyclonedx.org'))
+        its_1 = IssueTypeSource(name='The Source', url=XsUri('https://cyclonedx.org'))
+        its_2 = IssueTypeSource(name='The Source', url=XsUri('https://cyclonedx.org'))
         self.assertNotEqual(id(its_1), id(its_2))
         self.assertEqual(hash(its_1), hash(its_2))
         self.assertTrue(its_1 == its_2)
 
     def test_not_same(self) -> None:
-        its_1 = IssueTypeSource(name="The Source", url=XsUri('https://cyclonedx.org'))
-        its_2 = IssueTypeSource(name="Not the Source", url=XsUri('https://cyclonedx.org'))
+        its_1 = IssueTypeSource(name='The Source', url=XsUri('https://cyclonedx.org'))
+        its_2 = IssueTypeSource(name='Not the Source', url=XsUri('https://cyclonedx.org'))
         self.assertNotEqual(id(its_1), id(its_2))
         self.assertNotEqual(hash(its_1), hash(its_2))
         self.assertFalse(its_1 == its_2)
diff --git a/tests/test_model_release_note.py b/tests/test_model_release_note.py
index c65f1ad28..fbbb4e942 100644
--- a/tests/test_model_release_note.py
+++ b/tests/test_model_release_note.py
@@ -41,18 +41,18 @@ def test_simple(self) -> None:
     def test_complete(self) -> None:
         timestamp: datetime.datetime = datetime.datetime.utcnow()
         rn = ReleaseNotes(
-            type='major', title="Release Notes Title",
+            type='major', title='Release Notes Title',
             featured_image=XsUri('https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png'),
             social_image=XsUri('https://cyclonedx.org/cyclonedx-icon.png'),
-            description="This release is a test release", timestamp=timestamp,
+            description='This release is a test release', timestamp=timestamp,
             aliases=[
-                "First Test Release"
+                'First Test Release'
             ],
             tags=['test', 'alpha'],
             resolves=[],
             notes=[]
         )
-        rn.aliases.add("Release Alpha")
+        rn.aliases.add('Release Alpha')
         rn.tags.add('testing')
 
         self.assertEqual(rn.type, 'major')
@@ -63,7 +63,7 @@ def test_complete(self) -> None:
         )
         self.assertEqual(str(rn.social_image), 'https://cyclonedx.org/cyclonedx-icon.png')
         self.assertEqual(rn.description, 'This release is a test release')
-        self.assertSetEqual(rn.aliases, {"Release Alpha", "First Test Release"})
+        self.assertSetEqual(rn.aliases, {'Release Alpha', 'First Test Release'})
         self.assertSetEqual(rn.tags, {'test', 'testing', 'alpha'})
         self.assertSetEqual(rn.resolves, set())
         self.assertFalse(rn.notes)
diff --git a/tests/test_output.py b/tests/test_output.py
index aade691b5..bfacdda3c 100644
--- a/tests/test_output.py
+++ b/tests/test_output.py
@@ -45,7 +45,7 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
         *(('foo', sv, (ValueError, "Unexpected output_format: 'foo'")) for sv in SchemaVersion),
     )
     @unpack
-    def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
+    def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raises_regex: Tuple) -> None:
         bom = Mock(spec=Bom)
-        with self.assertRaisesRegex(*raisesRegex):
+        with self.assertRaisesRegex(*raises_regex):
             make_outputter(bom, of, sv)
diff --git a/tests/test_output_json.py b/tests/test_output_json.py
index 0a291fa27..02f68c1bf 100644
--- a/tests/test_output_json.py
+++ b/tests/test_output_json.py
@@ -39,9 +39,9 @@ class TestOutputJson(TestCase, SnapshotMixin):
 
     @data(*UNSUPPORTED_SV)
     def test_unsupported_schema_raises(self, sv: SchemaVersion) -> None:
-        outputterClass = BY_SCHEMA_VERSION[sv]
-        self.assertTrue(issubclass(outputterClass, Json))
-        outputter = outputterClass(Mock(spec=Bom))
+        outputter_class = BY_SCHEMA_VERSION[sv]
+        self.assertTrue(issubclass(outputter_class, Json))
+        outputter = outputter_class(Mock(spec=Bom))
         with self.assertRaises(FormatNotSupportedException):
             outputter.output_as_string()
 
@@ -86,8 +86,8 @@ class TestFunctionalBySchemaVersion(TestCase):
 
     @idata(SchemaVersion)
     def test_get_outputter_expected(self, sv: SchemaVersion) -> None:
-        outputterClass = BY_SCHEMA_VERSION[sv]
-        self.assertTrue(issubclass(outputterClass, Json))
-        outputter = outputterClass(Mock(spec=Bom))
+        outputter_class = BY_SCHEMA_VERSION[sv]
+        self.assertTrue(issubclass(outputter_class, Json))
+        outputter = outputter_class(Mock(spec=Bom))
         self.assertIs(outputter.schema_version, sv)
         self.assertIs(outputter.output_format, OutputFormat.JSON)
diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py
index c78a87551..6e580acc3 100644
--- a/tests/test_output_xml.py
+++ b/tests/test_output_xml.py
@@ -74,8 +74,8 @@ class TestFunctionalBySchemaVersion(TestCase):
 
     @idata(SchemaVersion)
     def test_get_outputter_expected(self, sv: SchemaVersion) -> None:
-        outputterClass = BY_SCHEMA_VERSION[sv]
-        self.assertTrue(issubclass(outputterClass, Xml))
-        outputter = outputterClass(Mock(spec=Bom))
+        outputter_class = BY_SCHEMA_VERSION[sv]
+        self.assertTrue(issubclass(outputter_class, Xml))
+        outputter = outputter_class(Mock(spec=Bom))
         self.assertIs(outputter.schema_version, sv)
         self.assertIs(outputter.output_format, OutputFormat.XML)
diff --git a/tests/test_validation.py b/tests/test_validation.py
index 567dff316..8755191a2 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -49,6 +49,6 @@ def test_as_expected(self, of: OutputFormat, sv: SchemaVersion) -> None:
         *((f, v, (ValueError, 'Unsupported schema_version')) for f, v in UNDEFINED_FORMAT_VERSION)
     )
     @unpack
-    def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raisesRegex: Tuple) -> None:
-        with self.assertRaisesRegex(*raisesRegex):
+    def test_fails_on_wrong_args(self, of: OutputFormat, sv: SchemaVersion, raises_regex: Tuple) -> None:
+        with self.assertRaisesRegex(*raises_regex):
             make_schemabased_validator(of, sv)
diff --git a/tools/schema-downloader.py b/tools/schema-downloader.py
index 6027117ff..ca70f85e0 100644
--- a/tools/schema-downloader.py
+++ b/tools/schema-downloader.py
@@ -19,7 +19,7 @@
 SOURCE_ROOT = 'https://raw.githubusercontent.com/CycloneDX/specification/master/schema/'
 TARGET_ROOT = join(dirname(__file__), '..', 'cyclonedx', 'schema', '_res')
 
-bom_xsd = {
+BOM_XSD = {
     'versions': ['1.4', '1.3', '1.2', '1.1', '1.0'],
     'sourcePattern': f'{SOURCE_ROOT}bom-%s.xsd',
     'targetPattern': join(TARGET_ROOT, 'bom-%s.SNAPSHOT.xsd'),
@@ -31,22 +31,22 @@
 
 # "version" is not required but optional with a default value!
 #   this is wrong in schema<1.5
-_bomSchemaEnumMatch = re.compile(
+_BOM_SCHEMA_ENUM_RE = re.compile(
     r'("\$id": "(http://cyclonedx\.org/schema/bom.+?\.schema\.json)".*"enum": \[\s+")'
     r'http://cyclonedx\.org/schema/bom.+?\.schema\.json"',
     re.DOTALL)
-_bomSchemaEnumReplace = r'\1\2"'
+_BOM_SCHEMA_ENUM_REPL = r'\1\2"'
 
 
 # "version" is not required but optional with a default value!
 # this is wrong in schema<1.5
-_bomRequired = """
+_BOM_REQUIRED_S = """
   "required": [
     "bomFormat",
     "specVersion",
     "version"
   ],"""
-_bomRequiredReplace = """
+_BOM_REQUIRED_R = """
   "required": [
     "bomFormat",
     "specVersion"
@@ -55,20 +55,20 @@
 
 # there was a case where the default value did not match the own pattern ...
 # this is wrong in schema<1.5
-_defaultWithPatternMatch = re.compile(r'\s+"default": "",(?![^}]*?"pattern": "\^\(\.\*\)\$")', re.MULTILINE)
-_defaultWithPatternReplace = r''
+_DEFAULTS_WITH_PATTERN_RE = re.compile(r'\s+"default": "",(?![^}]*?"pattern": "\^\(\.\*\)\$")', re.MULTILINE)
+_DEFAULTS_WITH_PATERN_REPL = r''
 
-bom_json_lax = {
+BOM_JSON_LAX = {
     'versions': ['1.4', '1.3', '1.2'],
     'sourcePattern': f'{SOURCE_ROOT}bom-%s.schema.json',
     'targetPattern': join(TARGET_ROOT, 'bom-%s.SNAPSHOT.schema.json'),
     'replace': [
         ('spdx.schema.json', 'spdx.SNAPSHOT.schema.json'),
         ('jsf-0.82.schema.json', 'jsf-0.82.SNAPSHOT.schema.json'),
-        (_bomRequired, _bomRequiredReplace),
+        (_BOM_REQUIRED_S, _BOM_REQUIRED_R),
     ],
     'replaceRE': [
-        (_bomSchemaEnumMatch, _bomSchemaEnumReplace),
+        (_BOM_SCHEMA_ENUM_RE, _BOM_SCHEMA_ENUM_REPL),
         # there was a case where the default value did not match the own pattern ...
         # this is wrong in schema<1.5
         # with current SchemaValidator this is no longer required, as defaults are not applied
@@ -76,21 +76,21 @@
     ]
 }
 
-bom_json_strict = {
+BOM_JSON_STRICT = {
     'versions': ['1.3', '1.2'],
     'sourcePattern': f'{SOURCE_ROOT}bom-%s-strict.schema.json',
     'targetPattern': join(TARGET_ROOT, 'bom-%s-strict.SNAPSHOT.schema.json'),
-    'replace': bom_json_lax['replace'],
-    'replaceRE': bom_json_lax['replaceRE']
+    'replace': BOM_JSON_LAX['replace'],
+    'replaceRE': BOM_JSON_LAX['replaceRE']
 }
 
-other_downloadables = [
+OTHER_DOWNLOADABLES = [
     (f'{SOURCE_ROOT}spdx.schema.json', join(TARGET_ROOT, 'spdx.SNAPSHOT.schema.json')),
     (f'{SOURCE_ROOT}spdx.xsd', join(TARGET_ROOT, 'spdx.SNAPSHOT.xsd')),
     (f'{SOURCE_ROOT}jsf-0.82.schema.json', join(TARGET_ROOT, 'jsf-0.82.SNAPSHOT.schema.json')),
 ]
 
-for dspec in (bom_xsd, bom_json_lax, bom_json_strict):
+for dspec in (BOM_XSD, BOM_JSON_LAX, BOM_JSON_STRICT):
     for version in dspec['versions']:
         source = dspec['sourcePattern'].replace('%s', version)
         target = dspec['targetPattern'].replace('%s', version)
@@ -104,5 +104,5 @@
                     text = search.sub(replace, text)
                 tarf.write(text)
 
-for source, target in other_downloadables:
+for source, target in OTHER_DOWNLOADABLES:
     urlretrieve(source, target)
diff --git a/tox.ini b/tox.ini
index 6b16c1c89..56aa09d36 100644
--- a/tox.ini
+++ b/tox.ini
@@ -37,20 +37,3 @@ commands =
 [testenv:flake8]
 commands =
     poetry run flake8 cyclonedx/ tests/ typings/ examples/ tools/
-
-[flake8]
-## keep in sync with isort config - in `isort.cfg` file
-exclude =
-    build,dist,__pycache__,.eggs,*.egg-info*,
-    *_cache,*.cache,
-    .git,.tox,.venv,venv,.venv*,venv*,
-    _OLD,_TEST,
-    docs
-max-line-length = 120
-ignore =
-    E305
-    # ignore `self`, `cls` markers of flake8-annotations>=2.0
-    ANN101,ANN102
-    # ignore ANN401 for dynamically typed *args and **kwargs
-    ANN401
-    B028

From a2af2eddf2fbfc2e8fbf407527c07877961dcedd Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Fri, 20 Oct 2023 12:31:19 +0200
Subject: [PATCH 38/42] style: qa

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .flake8                      | 2 +-
 cyclonedx/validation/json.py | 4 ++--
 cyclonedx/validation/xml.py  | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.flake8 b/.flake8
index b35235263..ff61f2bdd 100644
--- a/.flake8
+++ b/.flake8
@@ -11,7 +11,7 @@ exclude =
 
 max-line-length = 120
 
-max-complexity = 20
+max-complexity = 10
 
 ignore =
     # ignore `self`, `cls` markers of flake8-annotations>=2.0
diff --git a/cyclonedx/validation/json.py b/cyclonedx/validation/json.py
index f1ab46c10..8a7dab8ab 100644
--- a/cyclonedx/validation/json.py
+++ b/cyclonedx/validation/json.py
@@ -54,11 +54,11 @@ def __init__(self, schema_version: 'SchemaVersion') -> None:
         # this is the def that is used for generating the documentation
         super().__init__(schema_version)
 
-    if _missing_deps_error:
+    if _missing_deps_error:  # noqa:C901
         __MDERROR = _missing_deps_error
 
         def validate_str(self, data: str) -> Optional[ValidationError]:
-            raise self.__MDERROR[0]  # from functionality_not_implemented_error[1]
+            raise self.__MDERROR[0] from self.__MDERROR[1]
 
     else:
         def validate_str(self, data: str) -> Optional[ValidationError]:
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index 295674448..cfa5ae813 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -51,7 +51,7 @@ def __init__(self, schema_version: 'SchemaVersion') -> None:
         __MDERROR = _missing_deps_error
 
         def validate_str(self, data: str) -> Optional[ValidationError]:
-            raise self.__MDERROR[0]  # from functionality_not_implemented_error[1]
+            raise self.__MDERROR[0] from self.__MDERROR[1]
     else:
         def validate_str(self, data: str) -> Optional[ValidationError]:
             return self._validata_data(

From e298726a0a62aee5e1988cd3a2dd230dfbda95f8 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Fri, 20 Oct 2023 23:28:33 +0200
Subject: [PATCH 39/42] feat: v5.0.0-rc.2

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>

From ccbb01bf6efa93d4925287fe2ecbff6e5ee7e969 Mon Sep 17 00:00:00 2001
From: semantic-release <semantic-release>
Date: Fri, 20 Oct 2023 21:39:41 +0000
Subject: [PATCH 40/42] chore(release): 5.0.0-rc.2

Automatically generated by python-semantic-release

Signed-off-by: semantic-release <semantic-release>
---
 CHANGELOG.md          | 318 +++++++++++++++++++++++++++++++++++++++++-
 cyclonedx/__init__.py |   2 +-
 docs/conf.py          |   2 +-
 pyproject.toml        |   2 +-
 4 files changed, 319 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 106f0fcdb..24f3dfd78 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,25 +2,339 @@
 
 
 
+## v5.0.0-rc.2 (2023-10-20)
+
+### Ci
+
+* ci: revisit coverage reporting
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`bc8e30b`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/bc8e30b32163db3ffd31a7c96460a907637b1794))
+
+* ci: revisit coverage reporting
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`2967f28`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/2967f284cf7e5ab4da69406d599d890b07e62ce1))
+
+### Documentation
+
+* docs: update title
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`9373afc`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/9373afc1b94542680c324bacbc59e7b3a015f721))
+
+### Feature
+
+* feat: v5.0.0-rc.2
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`e298726`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/e298726a0a62aee5e1988cd3a2dd230dfbda95f8))
+
+### Style
+
+* style: qa
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a2af2ed`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a2af2eddf2fbfc2e8fbf407527c07877961dcedd))
+
+* style: streamline code quality (#472)
+
+- raised some dev tools
+- added more quality checkers and rules
+- documented and applied additional code standards
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`bb0f7a5`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/bb0f7a5d3610ffcd035ea0b89742225dea5abce9))
+
+### Unknown
+
+* reduce imports
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`d09ac36`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/d09ac3685dda97a054be7e0655e95c5b6356057d))
+
+* Merge remote-tracking branch &#39;origin/main&#39; into 5.0.0-dev ([`c4f7281`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/c4f7281b09100208f6b5bc6831344052962e95c4))
+
+
 ## v4.2.3 (2023-10-16)
 
 ### Chore
 
+* chore: revert changelog
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a911106`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a911106d09a7b5538e5ae77edf4fc4c2122f1f8b))
+
+### Fix
+
+* fix: SPDX-expression-validation internal crashes are cought and handled (#471)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5fa66a0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5fa66a043818eb5747dbd630496c6d31f818c0ab))
+
+### Refactor
+
+* refactor(DX): rename `get_instance()` (#469)
+
+- deprecate function `output.get_instance()`
+- add function `outout.make_outputter()`
+- rename function `validation.get_instance()` -&gt; `validation.make_schemabased_validator()`
+- rename function `validation.schema.get_instance()` -&gt; `validation.make_schemabased_validator()`
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`2a2b2dd`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/2a2b2dd509100eea5ec3153e1ec10ff5dda6f269))
+
+* refactor: schema based validator (#468)
+
+- restructured validators, to enable possible non-schema-based validation. 
+- optimized `validation.schema.get_instance()`
+- optimized `output.get_instance()`
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`65e79cf`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/65e79cfeb4fed3e31f85a4ec6d06215988a3a6d1))
+
+### Unknown
+
+* tidy
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`6316f09`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/6316f094552e8bbd38777bc66a17c5546f2b7d14))
+
+* Merge branch &#39;main&#39; into 5.0.0-dev ([`55f6f4d`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/55f6f4d0ad23189ce2bfce7ed7380e92470ac8b7))
+
+
+## v5.0.0-rc.1 (2023-10-11)
+
+### Breaking
+
+* chore!: bump major version to v5
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`bae8a84`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/bae8a84e7aa329780f91f49212c15f4d8c13ddcb))
+
+### Chore
+
+* chore: revisit license headers
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1e963bd`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1e963bd3d7e6c7d9437e41a34ecd622e0d32f3d8))
+
+* chore: clean deps
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`ac6ad0e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/ac6ad0ed5b5933f03d1132c3bbce0ada1915fc40))
+
+* chore: remove encoding hint (#459)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`37219c3`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/37219c321ac7ce5b507a0c0a74776f8204b400bf))
+
 * chore: Update CONTRIBUTING.md
 
 Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`0ebaa21`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0ebaa216d43a1389362dbdb33f9b49f43a21ab66))
 
+* chore: config sem-release
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`839fe11`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/839fe114bafac6117879175eb54a8759b7ef8963))
+
+* chore: sem-release config
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`18b4eca`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/18b4eca2c0fe2a2b4f1ca79976719c1afa0816bc))
+
+* chore: absolute tet imports
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`39e0eb9`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/39e0eb9af29a13e1cad6a073e5eb20955e492484))
+
+* chore(build): test before release
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5cb695e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5cb695ebf9989f9bdefaa6823f5814d5c2fe9998))
+
+* chore: init 5.0.0-dev
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`0a3ae26`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0a3ae26f8fe50e1dc03fb72fb7fdba51654c7f8b))
+
 ### Ci
 
 * ci: publish coverage report to codacy (#439)
 
 Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`0012a82`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0012a82382f9f33831a80aa0e26c0cbb7fd8984b))
 
+### Documentation
+
+* docs: fix hilighter
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`9d49280`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/9d49280b680a4f8a7c4b8795f35928584e29baee))
+
+* docs: fix typo
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`6adc98f`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/6adc98f66da94b7bac987bc5b25da7099498fe3a))
+
+### Feature
+
+* feat: support python 3.12 (#460)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`eaba7a0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/eaba7a048de190bce0797fb9ce40c4e2de49c5d9))
+
+* feat: options for beautiful output (#458)
+
+add indention to outputters. this may come at a cost!
+
+
+Breaking Changes
+------------------
+* abstract Method `output.BaseOutput.output_as_string()` got new optional kwarg `indent`
+* abstract Method `output.BaseOutput.output_as_string()` accepts arbitrary kwargs
+
+Changed
+----------
+* XML output uses a default namespace, which makes results smaller.
+
+
+Added
+------------------
+* All outputters&#39; method `output_as_string()` got new optional kwarg `indent`
+* All outputters&#39; method `output_as_string()` accepts arbitrary kwargs
+* All outputters&#39; method `output_to_file()` got new optional kwarg `indent`
+* All outputters&#39; method `output_to_file()` accepts arbitrary kwargs
+
+-----
+
+- [x] implementation
+- [x] tests (snapshot binary compare; structural equal compare) 
+
+-----
+
+enables https://github.com/CycloneDX/cyclonedx-python/issues/424
+fixes #437
+fixes #438
+supersedes #449
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`3bcd9e9`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/3bcd9e99a58b74c9dc1fc474b468e67fc92fb7c4))
+
+* feat: easy access validators (#448)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1c9ea9e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1c9ea9e22e53933347a8f366c5fc06febe811757))
+
+* feat: add CycloneDX document validators to public API (#433)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a4f5ec5`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a4f5ec5d63d576c04bcef5c0b6641f6c47164cfb))
+
 ### Fix
 
-* fix: SPDX-expression-validation internal crashes are cought and handled (#471)
+* fix: multiple licenses issue #365 (#466)
 
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5fa66a0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5fa66a043818eb5747dbd630496c6d31f818c0ab))
+breaking changes
+------------------
+* Reworked license related models and collections
+* API
+  * Removed class `factory.license.LicenseChoiceFactory`  
+    The old functionality was integrated into `factory.license.LicenseFactory`.
+  * Method `factory.license.LicenseFactory.make_from_string()`&#39;s parameter `name_or_spdx` was renamed to `value`
+  * Method `factory.license.LicenseFactory.make_from_string()`&#39;s return value can also be a `LicenseExpression`
+    The behavior imitates the old `factory.license.LicenseChoiceFactory.make_from_string()`
+  * Renamed class `module.License` to `module.license.DisjunctliveLicense`
+  * Removed class `module.LicenseChoice`
+    Use dedicated classes `module.license.DisjunctliveLicense` and `module.license.LicenseExpression` instead
+  * All occurrences of `models.LicenseChoice` were replaced by `models.licenses.License`
+  * All occurrences of `SortedSet[LicenseChoice]` were specialized to `models.license.LicenseRepository`
+
+
+fixes
+------------------
+* serialization of multy-licenses #365
+
+added
+------------------
+* API
+  * Method `factory.license.LicenseFactory.make_with_expression()`
+  * Class `model.license.DisjunctiveLicense`
+  * Class `model.license.LicenseExpression`
+  * Class `model.license.LicenseRepository`
+  * Class `serialization.LicenseRepositoryHelper`
+
+tests
+------------------
+* added regression test for bug #365
+
+misc
+------------------
+* raised dependency `py-serializable@^9.15`
+
+
+
+----
+
+fixes #365
+
+~~BLOCKED by a feature request to serializer: &lt;https://github.com/madpah/serializable/pull/32&gt;~~
+
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`6770786`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/67707864ac0f1b27bac166a8fd537ea38523fe6f))
+
+* fix: typing for `kwargs` (#462)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`2240b4d`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/2240b4dda824c13bc563bce1574dffe563016ac2))
+
+* fix: tuple stuff (#461)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`84c6504`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/84c6504fc92d1207135f7719b6b6477fae7950cb))
+
+* fix: `bom.validate()` detects invalid license constellations (#452)
+
+
+
+If a LicenseExpression is set, then there must be no other license.
+
+fixes #453
+
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`16843b2`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/16843b29086d8f871a7239c33beb930543cfde45))
+
+### Performance
+
+* perf: make validation more secure
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5d7b86c`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5d7b86c0ba84fe17becc53b2ccf4385113f90905))
+
+### Unknown
+
+* tests for backwards compatibility of #365 (#467)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`4c2ef14`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/4c2ef14017467980509bdb69f937b5098d8c0965))
+
+* tests: snapshots and complete deep comparison, instead of pseudo-compare (#464)
+
+part of https://github.com/CycloneDX/cyclonedx-python-lib/issues/437
+also fixed a bug: unused first level dependencies were not detected. now they are.
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`7543789`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/75437896c04e352b51d83e6e52cf94874347f4a6))
+
+* Feat: typing, typehints, &amp; overload (#463)
+
+also: bump `py-serializable@^0.14.0`
+
+---------
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a68ae24`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a68ae2464539d07ed0fc037aa1e315e5ccda054a))
+
+* Merge branch &#39;main&#39; into 5.0.0-dev ([`c8c2183`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/c8c218366298ccc340e769fa180204e79a9a0f3e))
+
+* tests: use internal json strict validation
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`7186b52`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/7186b52a540e478196799ef7a3580f48f77544e9))
+
+* proper enums (#447)
+
+fixes #442
+part of #446
+
+BREAKING CHANGE
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`06b5eb0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/06b5eb03d479e9908b9b62bcee48d23a873dd4ba))
+
+* typo
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`3de2493`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/3de24936533a51c0cbf61de4b19785ee7407526c))
+
+* Drop py37 (#441)
+
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1571d21`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1571d21057b11f11cb81e74a5a702f7f30582b09))
 
 
 ## v4.2.2 (2023-09-14)
diff --git a/cyclonedx/__init__.py b/cyclonedx/__init__.py
index feb796167..b737880f8 100644
--- a/cyclonedx/__init__.py
+++ b/cyclonedx/__init__.py
@@ -21,4 +21,4 @@
 # !! version is managed by semantic_release
 # do not use typing here, or else `semantic_release` might have issues finding the variable
 # flake8: noqa
-__version__ = "5.0.0-rc.1"
+__version__ = "5.0.0-rc.2"
diff --git a/docs/conf.py b/docs/conf.py
index 9bc5732eb..273aa588a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -20,7 +20,7 @@
 
 # The full version, including alpha/beta/rc tags
 # !! version is managed by semantic_release
-release = '5.0.0-rc.1'
+release = '5.0.0-rc.2'
 
 # -- General configuration ---------------------------------------------------
 
diff --git a/pyproject.toml b/pyproject.toml
index 0f3762aa9..81d633513 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
 [tool.poetry]
 name = "cyclonedx-python-lib"
 # !! version is managed by semantic_release
-version = "5.0.0-rc.1"
+version = "5.0.0-rc.2"
 description = "A library for producing CycloneDX SBOM (Software Bill of Materials) files."
 authors = [
   "Paul Horton <phorton@sonatype.com>",

From 744c0953a3b96bc54123ce6f3a7a39cbe4f2691d Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Fri, 20 Oct 2023 23:44:14 +0200
Subject: [PATCH 41/42] chore: revert Chanelog

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 CHANGELOG.md | 318 +--------------------------------------------------
 1 file changed, 2 insertions(+), 316 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24f3dfd78..106f0fcdb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,339 +2,25 @@
 
 
 
-## v5.0.0-rc.2 (2023-10-20)
-
-### Ci
-
-* ci: revisit coverage reporting
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`bc8e30b`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/bc8e30b32163db3ffd31a7c96460a907637b1794))
-
-* ci: revisit coverage reporting
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`2967f28`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/2967f284cf7e5ab4da69406d599d890b07e62ce1))
-
-### Documentation
-
-* docs: update title
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`9373afc`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/9373afc1b94542680c324bacbc59e7b3a015f721))
-
-### Feature
-
-* feat: v5.0.0-rc.2
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`e298726`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/e298726a0a62aee5e1988cd3a2dd230dfbda95f8))
-
-### Style
-
-* style: qa
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a2af2ed`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a2af2eddf2fbfc2e8fbf407527c07877961dcedd))
-
-* style: streamline code quality (#472)
-
-- raised some dev tools
-- added more quality checkers and rules
-- documented and applied additional code standards
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`bb0f7a5`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/bb0f7a5d3610ffcd035ea0b89742225dea5abce9))
-
-### Unknown
-
-* reduce imports
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`d09ac36`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/d09ac3685dda97a054be7e0655e95c5b6356057d))
-
-* Merge remote-tracking branch &#39;origin/main&#39; into 5.0.0-dev ([`c4f7281`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/c4f7281b09100208f6b5bc6831344052962e95c4))
-
-
 ## v4.2.3 (2023-10-16)
 
 ### Chore
 
-* chore: revert changelog
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a911106`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a911106d09a7b5538e5ae77edf4fc4c2122f1f8b))
-
-### Fix
-
-* fix: SPDX-expression-validation internal crashes are cought and handled (#471)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5fa66a0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5fa66a043818eb5747dbd630496c6d31f818c0ab))
-
-### Refactor
-
-* refactor(DX): rename `get_instance()` (#469)
-
-- deprecate function `output.get_instance()`
-- add function `outout.make_outputter()`
-- rename function `validation.get_instance()` -&gt; `validation.make_schemabased_validator()`
-- rename function `validation.schema.get_instance()` -&gt; `validation.make_schemabased_validator()`
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`2a2b2dd`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/2a2b2dd509100eea5ec3153e1ec10ff5dda6f269))
-
-* refactor: schema based validator (#468)
-
-- restructured validators, to enable possible non-schema-based validation. 
-- optimized `validation.schema.get_instance()`
-- optimized `output.get_instance()`
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`65e79cf`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/65e79cfeb4fed3e31f85a4ec6d06215988a3a6d1))
-
-### Unknown
-
-* tidy
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`6316f09`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/6316f094552e8bbd38777bc66a17c5546f2b7d14))
-
-* Merge branch &#39;main&#39; into 5.0.0-dev ([`55f6f4d`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/55f6f4d0ad23189ce2bfce7ed7380e92470ac8b7))
-
-
-## v5.0.0-rc.1 (2023-10-11)
-
-### Breaking
-
-* chore!: bump major version to v5
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`bae8a84`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/bae8a84e7aa329780f91f49212c15f4d8c13ddcb))
-
-### Chore
-
-* chore: revisit license headers
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1e963bd`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1e963bd3d7e6c7d9437e41a34ecd622e0d32f3d8))
-
-* chore: clean deps
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`ac6ad0e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/ac6ad0ed5b5933f03d1132c3bbce0ada1915fc40))
-
-* chore: remove encoding hint (#459)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`37219c3`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/37219c321ac7ce5b507a0c0a74776f8204b400bf))
-
 * chore: Update CONTRIBUTING.md
 
 Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`0ebaa21`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0ebaa216d43a1389362dbdb33f9b49f43a21ab66))
 
-* chore: config sem-release
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`839fe11`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/839fe114bafac6117879175eb54a8759b7ef8963))
-
-* chore: sem-release config
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`18b4eca`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/18b4eca2c0fe2a2b4f1ca79976719c1afa0816bc))
-
-* chore: absolute tet imports
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`39e0eb9`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/39e0eb9af29a13e1cad6a073e5eb20955e492484))
-
-* chore(build): test before release
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5cb695e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5cb695ebf9989f9bdefaa6823f5814d5c2fe9998))
-
-* chore: init 5.0.0-dev
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`0a3ae26`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0a3ae26f8fe50e1dc03fb72fb7fdba51654c7f8b))
-
 ### Ci
 
 * ci: publish coverage report to codacy (#439)
 
 Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`0012a82`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/0012a82382f9f33831a80aa0e26c0cbb7fd8984b))
 
-### Documentation
-
-* docs: fix hilighter
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`9d49280`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/9d49280b680a4f8a7c4b8795f35928584e29baee))
-
-* docs: fix typo
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@owasp.org&gt; ([`6adc98f`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/6adc98f66da94b7bac987bc5b25da7099498fe3a))
-
-### Feature
-
-* feat: support python 3.12 (#460)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`eaba7a0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/eaba7a048de190bce0797fb9ce40c4e2de49c5d9))
-
-* feat: options for beautiful output (#458)
-
-add indention to outputters. this may come at a cost!
-
-
-Breaking Changes
-------------------
-* abstract Method `output.BaseOutput.output_as_string()` got new optional kwarg `indent`
-* abstract Method `output.BaseOutput.output_as_string()` accepts arbitrary kwargs
-
-Changed
-----------
-* XML output uses a default namespace, which makes results smaller.
-
-
-Added
-------------------
-* All outputters&#39; method `output_as_string()` got new optional kwarg `indent`
-* All outputters&#39; method `output_as_string()` accepts arbitrary kwargs
-* All outputters&#39; method `output_to_file()` got new optional kwarg `indent`
-* All outputters&#39; method `output_to_file()` accepts arbitrary kwargs
-
------
-
-- [x] implementation
-- [x] tests (snapshot binary compare; structural equal compare) 
-
------
-
-enables https://github.com/CycloneDX/cyclonedx-python/issues/424
-fixes #437
-fixes #438
-supersedes #449
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`3bcd9e9`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/3bcd9e99a58b74c9dc1fc474b468e67fc92fb7c4))
-
-* feat: easy access validators (#448)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1c9ea9e`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1c9ea9e22e53933347a8f366c5fc06febe811757))
-
-* feat: add CycloneDX document validators to public API (#433)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a4f5ec5`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a4f5ec5d63d576c04bcef5c0b6641f6c47164cfb))
-
 ### Fix
 
-* fix: multiple licenses issue #365 (#466)
-
-breaking changes
-------------------
-* Reworked license related models and collections
-* API
-  * Removed class `factory.license.LicenseChoiceFactory`  
-    The old functionality was integrated into `factory.license.LicenseFactory`.
-  * Method `factory.license.LicenseFactory.make_from_string()`&#39;s parameter `name_or_spdx` was renamed to `value`
-  * Method `factory.license.LicenseFactory.make_from_string()`&#39;s return value can also be a `LicenseExpression`
-    The behavior imitates the old `factory.license.LicenseChoiceFactory.make_from_string()`
-  * Renamed class `module.License` to `module.license.DisjunctliveLicense`
-  * Removed class `module.LicenseChoice`
-    Use dedicated classes `module.license.DisjunctliveLicense` and `module.license.LicenseExpression` instead
-  * All occurrences of `models.LicenseChoice` were replaced by `models.licenses.License`
-  * All occurrences of `SortedSet[LicenseChoice]` were specialized to `models.license.LicenseRepository`
-
-
-fixes
-------------------
-* serialization of multy-licenses #365
-
-added
-------------------
-* API
-  * Method `factory.license.LicenseFactory.make_with_expression()`
-  * Class `model.license.DisjunctiveLicense`
-  * Class `model.license.LicenseExpression`
-  * Class `model.license.LicenseRepository`
-  * Class `serialization.LicenseRepositoryHelper`
-
-tests
-------------------
-* added regression test for bug #365
-
-misc
-------------------
-* raised dependency `py-serializable@^9.15`
-
-
-
-----
-
-fixes #365
-
-~~BLOCKED by a feature request to serializer: &lt;https://github.com/madpah/serializable/pull/32&gt;~~
-
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`6770786`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/67707864ac0f1b27bac166a8fd537ea38523fe6f))
-
-* fix: typing for `kwargs` (#462)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`2240b4d`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/2240b4dda824c13bc563bce1574dffe563016ac2))
-
-* fix: tuple stuff (#461)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`84c6504`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/84c6504fc92d1207135f7719b6b6477fae7950cb))
-
-* fix: `bom.validate()` detects invalid license constellations (#452)
-
-
-
-If a LicenseExpression is set, then there must be no other license.
-
-fixes #453
-
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`16843b2`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/16843b29086d8f871a7239c33beb930543cfde45))
-
-### Performance
-
-* perf: make validation more secure
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5d7b86c`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5d7b86c0ba84fe17becc53b2ccf4385113f90905))
-
-### Unknown
-
-* tests for backwards compatibility of #365 (#467)
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`4c2ef14`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/4c2ef14017467980509bdb69f937b5098d8c0965))
-
-* tests: snapshots and complete deep comparison, instead of pseudo-compare (#464)
-
-part of https://github.com/CycloneDX/cyclonedx-python-lib/issues/437
-also fixed a bug: unused first level dependencies were not detected. now they are.
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`7543789`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/75437896c04e352b51d83e6e52cf94874347f4a6))
-
-* Feat: typing, typehints, &amp; overload (#463)
-
-also: bump `py-serializable@^0.14.0`
-
----------
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`a68ae24`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/a68ae2464539d07ed0fc037aa1e315e5ccda054a))
-
-* Merge branch &#39;main&#39; into 5.0.0-dev ([`c8c2183`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/c8c218366298ccc340e769fa180204e79a9a0f3e))
-
-* tests: use internal json strict validation
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`7186b52`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/7186b52a540e478196799ef7a3580f48f77544e9))
-
-* proper enums (#447)
-
-fixes #442
-part of #446
-
-BREAKING CHANGE
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`06b5eb0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/06b5eb03d479e9908b9b62bcee48d23a873dd4ba))
-
-* typo
-
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`3de2493`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/3de24936533a51c0cbf61de4b19785ee7407526c))
-
-* Drop py37 (#441)
+* fix: SPDX-expression-validation internal crashes are cought and handled (#471)
 
-Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`1571d21`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/1571d21057b11f11cb81e74a5a702f7f30582b09))
+Signed-off-by: Jan Kowalleck &lt;jan.kowalleck@gmail.com&gt; ([`5fa66a0`](https://github.com/CycloneDX/cyclonedx-python-lib/commit/5fa66a043818eb5747dbd630496c6d31f818c0ab))
 
 
 ## v4.2.2 (2023-09-14)

From 14d1185e95861d177d38e6a7fb33877bd9a5b6c4 Mon Sep 17 00:00:00 2001
From: Jan Kowalleck <jan.kowalleck@gmail.com>
Date: Sat, 21 Oct 2023 02:21:36 +0200
Subject: [PATCH 42/42] tests: find common security issues (#473)

---------

Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
---
 .editorconfig                       |  2 +-
 .github/workflows/python.yml        | 24 ++++++++++++++++++++++++
 bandit.yml                          |  9 +++++++++
 cyclonedx/model/__init__.py         |  2 +-
 cyclonedx/output/xml.py             |  7 ++++---
 cyclonedx/serialization/__init__.py |  2 +-
 cyclonedx/validation/xml.py         | 10 ++++++++--
 pyproject.toml                      |  1 +
 tools/schema-downloader.py          |  4 ++--
 tox.ini                             |  7 +++++++
 10 files changed, 58 insertions(+), 10 deletions(-)
 create mode 100644 bandit.yml

diff --git a/.editorconfig b/.editorconfig
index 17d087db6..0b244df1e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -31,7 +31,7 @@ trim_trailing_whitespace = false
 indent_style = space
 indent_size = 4
 
-[*.ini]
+[{*.ini,.bandit,.flake8}]
 charset = latin1
 indent_style = space
 indent_size = 4
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index b2a3ca237..be8b5813b 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -48,6 +48,30 @@ jobs:
       - name: Run tox
         run: poetry run tox run -e flake8 -s false
 
+  security-issues:
+    name: find Security Issues
+    runs-on: ubuntu-latest
+    timeout-minutes: 10
+    steps:
+      - name: Checkout
+        # see https://github.com/actions/checkout
+        uses: actions/checkout@v4
+      - name: Setup Python Environment
+        # see https://github.com/actions/setup-python
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ env.PYTHON_VERSION_DEFAULT }}
+          architecture: 'x64'
+      - name: Install poetry
+        # see https://github.com/marketplace/actions/setup-poetry
+        uses: Gr1N/setup-poetry@v8
+        with:
+          poetry-version: ${{ env.POETRY_VERSION }}
+      - name: Install dependencies
+        run: poetry install --no-root
+      - name: Run tox
+        run: poetry run tox run -e bandit -s false
+
   static-code-analysis:
     name: StaticCodingAnalysis (py${{ matrix.python-version}} ${{ matrix.toxenv-factors }})
     runs-on: ${{ matrix.os }}
diff --git a/bandit.yml b/bandit.yml
new file mode 100644
index 000000000..03d6ead6f
--- /dev/null
+++ b/bandit.yml
@@ -0,0 +1,9 @@
+# https://bandit.readthedocs.io
+# filename must be like this, so codacy can pick it up: https://github.com/codacy/codacy-bandit/blob/master/src/main/scala/codacy/bandit/Bandit.scala#L35C49-L35C59
+
+exclude_dirs:
+  - docs
+  - .venv
+
+skips:
+  - B101
diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
index 5b5b0d8b8..5441049c1 100644
--- a/cyclonedx/model/__init__.py
+++ b/cyclonedx/model/__init__.py
@@ -55,7 +55,7 @@ def sha1sum(filename: str) -> str:
     Returns:
         SHA-1 hash
     """
-    h = sha1()
+    h = sha1()  # nosec B303, B324
     with open(filename, 'rb') as f:
         for byte_block in iter(lambda: f.read(4096), b''):
             h.update(byte_block)
diff --git a/cyclonedx/output/xml.py b/cyclonedx/output/xml.py
index b57e2db89..1f5981130 100644
--- a/cyclonedx/output/xml.py
+++ b/cyclonedx/output/xml.py
@@ -17,8 +17,8 @@
 
 
 from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Type, Union
-from xml.dom.minidom import parseString as dom_parseString
-from xml.etree.ElementTree import Element as XmlElement, tostring as xml_dumps
+from xml.dom.minidom import parseString as dom_parseString  # nosec B408
+from xml.etree.ElementTree import Element as XmlElement, tostring as xml_dumps  # nosec B405
 
 from ..schema import OutputFormat, SchemaVersion
 from ..schema.schema import (
@@ -80,7 +80,8 @@ def output_as_string(self, *,
                          indent: Optional[Union[int, str]] = None,
                          **kwargs: Any) -> str:
         self.generate()
-        return self._bom_xml if indent is None else dom_parseString(self._bom_xml).toprettyxml(
+        return self._bom_xml if indent is None else dom_parseString(  # nosecc B318
+            self._bom_xml).toprettyxml(
             indent=self.__make_indent(indent)
             # do not set `encoding` - this would convert result to binary, not string
         )
diff --git a/cyclonedx/serialization/__init__.py b/cyclonedx/serialization/__init__.py
index 7c5475866..720ee94d5 100644
--- a/cyclonedx/serialization/__init__.py
+++ b/cyclonedx/serialization/__init__.py
@@ -21,7 +21,7 @@
 from json import loads as json_loads
 from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type
 from uuid import UUID
-from xml.etree.ElementTree import Element
+from xml.etree.ElementTree import Element  # nosec B405
 
 # See https://github.com/package-url/packageurl-python/issues/65
 from packageurl import PackageURL
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index cfa5ae813..f868f4ee9 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -29,7 +29,11 @@
 
 _missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
 try:
-    from lxml.etree import XMLParser, XMLSchema, fromstring as xml_fromstring  # type:ignore[import-untyped]
+    from lxml.etree import (  # type:ignore[import-untyped] # nosec B410
+        XMLParser,
+        XMLSchema,
+        fromstring as xml_fromstring,
+    )
 except ImportError as err:
     _missing_deps_error = MissingOptionalDependencyException(
         'This functionality requires optional dependencies.\n'
@@ -55,7 +59,9 @@ def validate_str(self, data: str) -> Optional[ValidationError]:
     else:
         def validate_str(self, data: str) -> Optional[ValidationError]:
             return self._validata_data(
-                xml_fromstring(bytes(data, encoding='utf8'), parser=self.__xml_parser))
+                xml_fromstring(  # nosec B320
+                    bytes(data, encoding='utf8'),
+                    parser=self.__xml_parser))
 
         def _validata_data(self, data: Any) -> Optional[ValidationError]:
             validator = self._validator  # may throw on error that MUST NOT be caught
diff --git a/pyproject.toml b/pyproject.toml
index 81d633513..ad12f7b88 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -87,6 +87,7 @@ autopep8 = "2.0.4"
 mypy = "1.6.1"
 tox = "4.11.3"
 xmldiff = "2.6.3"
+bandit = "1.7.5"
 
 [tool.semantic_release]
 # see https://python-semantic-release.readthedocs.io/en/latest/configuration.html
diff --git a/tools/schema-downloader.py b/tools/schema-downloader.py
index ca70f85e0..af0b11305 100644
--- a/tools/schema-downloader.py
+++ b/tools/schema-downloader.py
@@ -94,7 +94,7 @@
     for version in dspec['versions']:
         source = dspec['sourcePattern'].replace('%s', version)
         target = dspec['targetPattern'].replace('%s', version)
-        tempfile, _ = urlretrieve(source)
+        tempfile, _ = urlretrieve(source)  # nosec B310
         with open(tempfile, 'r') as tmpf:
             with open(target, 'w') as tarf:
                 text = tmpf.read()
@@ -105,4 +105,4 @@
                 tarf.write(text)
 
 for source, target in OTHER_DOWNLOADABLES:
-    urlretrieve(source, target)
+    urlretrieve(source, target)  # nosec B310
diff --git a/tox.ini b/tox.ini
index 56aa09d36..8187a2c18 100644
--- a/tox.ini
+++ b/tox.ini
@@ -9,6 +9,7 @@ envlist =
     flake8
     mypy-{current,lowest}
     py{312,311,310,39,38}-{allExtras,noExtras}
+    bandit
 skip_missing_interpreters = True
 usedevelop = False
 download = False
@@ -37,3 +38,9 @@ commands =
 [testenv:flake8]
 commands =
     poetry run flake8 cyclonedx/ tests/ typings/ examples/ tools/
+
+[testenv:bandit]
+commands =
+    poetry run bandit -c bandit.yml -v -r cyclonedx tests examples tools
+
+
