I'll assume that you want to actually check these are valid xml or json documents (or neither).
I see no issue with your method structure, apart from catching Exception
which is probably too general. You either want to be catching something more specific like ValueError or custom error for your types.
I'm not a fan of the other suggestions, just checking the first character in the file, nor using regex to strip whitespace then look for a certain variety of brackets. There are good modules in the standard library available that will parse JSON or XML, and do the work for you, for example json and ElementTree.
Here's a python 2 / 3 compatible version of how you could fit those modules into your existing class.
I've done it fairly simply. Some people prefer not to do IO or slow things in the object __init__
but if your class is really an abstract representation of a json/xml document then it is the perfect situation to use @property
for getter-only attributes and set them in the parse_report_file
method.
To take this further of course it needs some unit tests, but I've done a quick test by adding some things to the entry point. It's expecting 3 files, here's the contents if you want to try.
real.xml
<?xml version='1.0' encoding='utf-8' ?>
<root>
<some-node thing='stuff'>some text</some-node>
</root>
real.json
{
"key" : "value"
}
blank.txt
This file is really empty but it could just be anything that is not valid xml or json.
Code
from __future__ import print_function
import xml.etree.cElementTree as ET
import json
class ReportDocument(object):
"""
ReportDocument is an abstraction of a JSON, XML or neither file type.
"""
def __init__(self, report_input_file=None, *args, **kwargs):
self._is_json_report_file=False
self._is_xml_report_file=False
self._parsed_report_file=None
if report_input_file is not None:
self.parse_report_file(report_input_file)
@property
def is_json_report_file(self):
return self._is_json_report_file
@property
def is_xml_report_file(self):
return self._is_xml_report_file
def _parse_json_file(self,report_input_file):
"""
Given a text file, returns a JSON object or None
"""
with open(report_input_file,'rb') as in_file:
return json.load(in_file)
def _parse_xml_file(self,report_input_file):
"""
Given a text file, returns an XML element or None
"""
with open(report_input_file,'rb') as in_file:
return ET.parse(in_file)
def parse_report_file(self, report_input_file):
"""
Checks if input report file is of type json or xml
returns a json object or an xml element or None
"""
try:
self._parsed_report_file = self._parse_xml_file(report_input_file)
self._is_xml_report_file = True
except ET.ParseError:
try:
self._parsed_report_file = self._parse_json_file(report_input_file)
self._is_json_report_file = True
except ValueError: # or in Python3 the specific error json.decoder.JSONDecodeError
pass
if __name__ == '__main__':
files_to_test = ['real.xml', 'real.json', 'blank.txt']
for file_type in files_to_test:
test_class = ReportDocument(file_type)
print("{file_type}: \n\t is_json:{is_json_report_file} \n\t is_xml:{is_xml_report_file}".format(
file_type=file_type,
is_json_report_file=test_class.is_json_report_file,
is_xml_report_file = test_class.is_xml_report_file)
)
if(s.startswith('<')
wheres
is the first in your file. An XML document entity (in common parlance, an XML document) must start with<
. \$\endgroup\$try-catch
for cases where thereport_input_file
is on neither of these two formats. \$\endgroup\$