from abc import ABC, abstractmethod
from typing import List
import xml.etree.ElementTree as ET
import json
# Contact data container class
class Contact:
def __init__(self, full_name, email, phone_number, is_friend):
self.full_name = full_name
self.email = email
self.phone_number = phone_number
self.is_friend = is_friend
def __str__(self):
return f"{self.full_name} ({self.email}) - {self.phone_number} {'(Friend)' if self.is_friend else ''}"
# Our base class for reading file data
class FileReader(ABC) :
def __init__(self, file_name):
self.file_name = file_name
abstractmethod
def read(self) -> str:
pass
# Abstract base class for all Contact Data Adapters
class ContactsAdapter(ABC):
def __init__(self, data_source: FileReader):
self.data_source = data_source
abstractmethod
def get_contacts(self) -> List[Contact]:
pass
# Specific implementation of the adapter to read XML Source data
class XMLContactsAdapter(ContactsAdapter):
def get_contacts(self):
# Parse XML data into an ElementTree object
root = ET.fromstring(self.data_source.read()) # Read XML data from a file
# Extract contact information from the XML and create Contact objects
contacts = []
for elem in root.iter():
if elem.tag == 'contact':
full_name = elem.find('full_name').text
email = elem.find('email').text
phone_number = elem.find('phone_number').text
is_friend = elem.find('is_friend').text.lower() == 'true'
contact = Contact(full_name, email, phone_number, is_friend)
contacts.append(contact)
return contacts
# Specific implementation of the adapter to read JSON Source data
class JSONContactsAdapter(ContactsAdapter):
def get_contacts(self):
# Parse JSON data into a dictionary
data_dict = json.loads(self.data_source.read()) # Read JSON data from a file
# Extract contact information from the dictionary and create Contact objects
contacts = []
for contact_data in data_dict['contacts']:
full_name = contact_data['full_name']
email = contact_data['email']
phone_number = contact_data['phone_number']
is_friend = contact_data['is_friend']
contact = Contact(full_name, email, phone_number, is_friend)
contacts.append(contact)
return contacts
# Specific implementation of the file reader to be used with XML Files
class XMLReader(FileReader):
def read(self):
# Read the contents of the XML file and return as a string
with open(self.file_name, 'r') as f:
return f.read()
# Specific implementation of the file reader to be used with JSON files
class JSONReader(FileReader):
def read(self):
# Read the contents of the JSON file and return as a string
with open(self.file_name, 'r') as f:
return f.read()
# Simple display routine to display Contact data to the console
def print_contact_data(contacts_source : ContactsAdapter):
# Print the Contact objects
for contact in contacts_source.get_contacts():
print(contact)
# Example usage
xml_reader = XMLReader('contacts.xml')
# Create an XML adapter and convert the data to a list of Contact objects
xml_adapter = XMLContactsAdapter(xml_reader)
# Print the Contact objects
print_contact_data(xml_adapter)
json_reader = JSONReader('contacts.json')
# Create a JSON adapter and convert the data to a list of Contact objects
json_adapter = JSONContactsAdapter(json_reader)
# Print the Contact objects
print_contact_data(json_adapter)