Skip to content

Commit 4c4dec1

Browse files
[issue-406] fix xml specific problems, update parse/write_anything
Signed-off-by: Armin Tänzer <armin.taenzer@tngtech.com>
1 parent 24d8f3b commit 4c4dec1

6 files changed

Lines changed: 45 additions & 13 deletions

File tree

src/parser/jsonlikedict/package_parser.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,15 @@ def parse_package(self, package_dict: Dict) -> Package:
6060
external_refs: List[ExternalPackageRef] = parse_field_or_log_error(logger, package_dict.get("externalRefs"),
6161
self.parse_external_refs)
6262

63-
files_analyzed: Optional[bool] = parse_field_or_log_error(logger, package_dict.get("filesAnalyzed"),
63+
files_analyzed: Optional[Union[bool, str]] = parse_field_or_log_error(logger, package_dict.get("filesAnalyzed"),
6464
lambda x: x, True)
65+
66+
if isinstance(files_analyzed, str): # XML does not support boolean typed values
67+
if files_analyzed.lower() == "true":
68+
files_analyzed = True
69+
elif files_analyzed.lower() == "false":
70+
files_analyzed = False
71+
6572
homepage: Optional[str] = package_dict.get("homepage")
6673
license_comments: Optional[str] = package_dict.get("licenseComments")
6774
license_concluded = parse_field_or_log_error(

src/parser/jsonlikedict/snippet_parser.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,13 @@ def parse_snippet(self, snippet_dict: Dict) -> Snippet:
4141
spdx_id: Optional[str] = snippet_dict.get("SPDXID")
4242
file_spdx_id: Optional[str] = snippet_dict.get("snippetFromFile")
4343
name: Optional[str] = snippet_dict.get("name")
44+
4445
ranges: Dict = parse_field_or_log_error(logger, snippet_dict.get("ranges", []), self.parse_ranges, default={})
45-
byte_range: Tuple[int, int] = ranges.get(RangeType.BYTE)
46-
line_range: Optional[Tuple[int, int]] = ranges.get(RangeType.LINE)
46+
byte_range: Optional[Tuple[Union[int, str], Union[int, str]]] = ranges.get(RangeType.BYTE)
47+
line_range: Optional[Tuple[Union[int, str], Union[int, str]]] = ranges.get(RangeType.LINE)
48+
byte_range = self.convert_range_from_str(byte_range)
49+
line_range = self.convert_range_from_str(line_range)
50+
4751
attribution_texts: List[str] = snippet_dict.get("attributionTexts", [])
4852
comment: Optional[str] = snippet_dict.get("comment")
4953
copyright_text: Optional[str] = snippet_dict.get("copyrightText")
@@ -114,3 +118,15 @@ def validate_pointer_and_get_type(pointer: Dict) -> RangeType:
114118
if "offset" not in pointer and "lineNumber" not in pointer:
115119
raise ValueError('Couldn\'t determine type of pointer: neither "offset" nor "lineNumber" provided as key.')
116120
return RangeType.BYTE if "offset" in pointer else RangeType.LINE
121+
122+
@staticmethod
123+
def convert_range_from_str(_range: Tuple[Union[int, str], Union[int, str]]) -> Tuple[Union[int, str], Union[int, str]]:
124+
# XML does not support integers, so we have to convert from string (if possible)
125+
if not _range:
126+
return _range
127+
128+
if isinstance(_range[0], str) and _range[0].isdigit():
129+
_range = int(_range[0]), _range[1]
130+
if isinstance(_range[1], str) and _range[1].isdigit():
131+
_range = _range[0], int(_range[1])
132+
return _range

src/parser/parse_anything.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111
from src.formats import file_name_to_format, FileFormat
12-
from src.parser.json.json_parser import JsonParser
12+
from src.parser.json import json_parser
13+
from src.parser.xml import xml_parser
14+
from src.parser.yaml import yaml_parser
1315

1416

1517
def parse_file(file_name: str):
@@ -19,8 +21,8 @@ def parse_file(file_name: str):
1921
elif input_format == FileFormat.TAG_VALUE:
2022
raise NotImplementedError("Currently, the tag-value parser is not implemented")
2123
elif input_format == FileFormat.JSON:
22-
return JsonParser().parse(file_name)
24+
return json_parser.parse_from_file(file_name)
2325
elif input_format == FileFormat.XML:
24-
raise NotImplementedError("Currently, the xml parser is not implemented")
26+
return xml_parser.parse_from_file(file_name)
2527
elif input_format == FileFormat.YAML:
26-
raise NotImplementedError("Currently, the yaml parser is not implemented")
28+
return yaml_parser.parse_from_file(file_name)

src/parser/xml/xml_parser.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import xmltodict
1414

1515
from src.model.document import Document
16+
from src.parser.error import SPDXParsingError
1617
from src.parser.jsonlikedict.json_like_dict_parser import JsonLikeDictParser
1718

1819

@@ -40,14 +41,18 @@
4041
"ranges",
4142
"licenseInfoInSnippets",
4243
"packageVerificationCodeExcludedFiles",
44+
"attributionTexts"
4345
]
4446

4547

4648
def parse_from_file(file_name: str) -> Document:
4749
with open(file_name) as file:
4850
parsed_xml: Dict = xmltodict.parse(file.read(), encoding="utf-8")
4951

50-
input_doc_as_dict: Dict = _fix_list_like_fields(parsed_xml)
52+
input_doc_as_dict: Dict = _fix_list_like_fields(parsed_xml).get("Document")
53+
54+
if not input_doc_as_dict:
55+
raise SPDXParsingError(['Did not find the XML top level tag "Document".'])
5156

5257
return JsonLikeDictParser().parse(input_doc_as_dict)
5358

src/writer/write_anything.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,18 @@
1212
from src.model.document import Document
1313
from src.writer.json import json_writer
1414
from src.writer.tagvalue import tagvalue_writer
15+
from src.writer.xml import xml_writer
16+
from src.writer.yaml import yaml_writer
1517

1618

1719
def write_file(document: Document, file_name: str, validate: bool = True):
1820
output_format = file_name_to_format(file_name)
1921
if output_format == FileFormat.JSON:
20-
json_writer.write_document(document, file_name, validate)
22+
json_writer.write_document(document, file_name, validate=False)
2123
elif output_format == FileFormat.YAML:
22-
raise NotImplementedError("Currently, the yaml writer is not implemented")
24+
yaml_writer.write_document_to_file(document, file_name, validate=False)
2325
elif output_format == FileFormat.XML:
24-
raise NotImplementedError("Currently, the xml writer is not implemented")
26+
xml_writer.write_document_to_file(document, file_name, validate=False)
2527
elif output_format == FileFormat.TAG_VALUE:
2628
tagvalue_writer.write_document_to_file(document, file_name)
2729
elif output_format == FileFormat.RDF_XML:

src/writer/xml/xml_writer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from src.validation.validation_message import ValidationMessage
1919

2020

21-
def write_document(document: Document, file_name: str, validate: bool = True, converter: DocumentConverter = None):
21+
def write_document_to_file(document: Document, file_name: str, validate: bool = True, converter: DocumentConverter = None):
2222
"""
2323
Serializes the provided document to XML and writes it to a file with the provided name. Unless validate is set
2424
to False, validates the document before serialization. Unless a DocumentConverter instance is provided,
@@ -31,6 +31,6 @@ def write_document(document: Document, file_name: str, validate: bool = True, co
3131
raise ValueError(f"Document is not valid. The following errors were detected: {validation_messages}")
3232
if converter is None:
3333
converter = DocumentConverter()
34-
document_dict = converter.convert(document)
34+
document_dict = {"Document": converter.convert(document)}
3535
with open(file_name, "w") as out:
3636
xmltodict.unparse(document_dict, out, encoding="utf-8", pretty=True)

0 commit comments

Comments
 (0)