123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- # %%
- import csv
- import json
- import openpyxl as op
- import re
- # BASIC CONFIGURATION
- DATA_FOLDER = './data/'
- OUTPUT_FOLDER = './output/'
- ONTO_FILENAME = 'manoscritti_dariah' # No extension!
- ent_filename = ONTO_FILENAME + '_entities.csv'
- rel_filename = ONTO_FILENAME + '_relations.csv'
- # PART I: parse xlsx to (multiple) csv
- # Excel configuration
- XLSX_FILENAME = 'Struttura_NEW.xlsx'
- ENTITIES_SHEETNAME = 'Entità'
- RELATIONS_SHEETNAME = 'Relazioni'
- # %%
- # Import the defining xlsx through openpyxl
- input_data = op.load_workbook(DATA_FOLDER + XLSX_FILENAME)
- # Read relevant sheets
- entities_sheet = input_data[ENTITIES_SHEETNAME]
- relations_sheet = input_data[RELATIONS_SHEETNAME]
- # Parse sheet data into a dict (assuming the xlsx has headers)
- entities_keys = [cell for cell in next(entities_sheet.values) if cell]
- raw_entities = [{key: row[ind] for ind, key in enumerate(entities_keys)} for row in entities_sheet.values][1:]
- #
- relations_keys = [cell for cell in next(relations_sheet.values) if cell]
- raw_relations = [{key: row[ind] for ind, key in enumerate(relations_keys)} for row in relations_sheet.values][1:]
- # %%
- # NOTE:
- # a. Non ci sono, al momento, constraint di unicità per le relazioni imposti tramite il "foglio master"
- # b. Non ci sono neanche constraint di esistenza, TRANNE l'id univoca, intesa NON come quella del sistema ma quella della comunità di riferimento, e tipica del settore di dominio considerato
- # c. Per identificare le informazioni 'atomiche' non si usa un campo dedicato, ma una logica. AL MOMENTO la logica è che si considera atomica una entità che non è mai 'prima' in una relazione. L'ORDINE DELLE RELAZIONI E' IMPORTANTE a differenza di quanto assumevo inizialmente.
- # d. Si effettua un controllo di unicità sulle entità, basato sul nome normalizzato (parole con iniziale maiuscola e il resto minuscolo, spazi ridotti a spazio singolo, strip()). Nessuna entità può avere nome vuoto.
- # e. Si effettua un controllo di unicità sulle relazioni, che però riguarda tutta la terna SOGGETTO-RELAZIONE-OGGETTO (normalizzata in modo simile ai nomi di entità, ma nella RELAZIONE gli spazi sono underscores e si usa lower() invece che title()). Nessuno dei membri della terna può essere vuoto; il nome della relazione inversa è opzionale.
- # f. Si effettuano controlli di consistenza sulle relazioni:
- # .f1. Nessuna relazione con entità non definite
- # .f2. Nessuna entità "orfana", ovvero non presente in alcuna relazione
- #
- # TODO: completare secondo le specifiche sopra
- # TODO: effettuare il merge con i "miei" CSV, che hanno informazioni in più!
- # TODO: ottimizzare un po' la scrittura del codice
- # Process entities:
- # 1. Filter out unnamed entities, normalize entity names, collect aliases, discover duplicates
- clean_entities = {}
- for ent in raw_entities:
- entity_names = ent['Concetto']
- if not isinstance(entity_names, str):
- continue
- aliases = [re.sub(r'\s+', ' ', al.strip().title()) for al in entity_names.split('\n') if al.strip()]
- if not aliases:
- continue
- entity_name = aliases[0]
- entity_same_as = aliases[1:]
- if clean_entities.get(entity_name):
- # DUPLICATE!
- clean_entities[entity_name].append({'Alias': aliases, 'Raw': ent})
- else:
- clean_entities[entity_name] = [{'Alias': aliases, 'Raw': ent}]
- all_entities = clean_entities.keys()
- duplicated_entities = [ent_name for ent_name, ent_val in clean_entities.items() if len(ent_val)>1]
- # %%
- # Process relations:
- # 1. Filter ill-formed relations and normalize entity names
- clean_relations = []
- for rel in raw_relations:
- subj = rel['Soggetto']
- obj = rel['Oggetto']
- if not isinstance(subj, str) or not isinstance(obj, str):
- continue
- subj = re.sub(r'\s+', ' ', subj.strip().title())
- obj = re.sub(r'\s+', ' ', obj.strip().title())
- if subj==obj:
- continue
- rel_name = rel['Relazione']
- if isinstance(rel_name, str):
- rel_name = re.sub(r'\s+', '_', rel_name.strip().lower()).replace('__', '_')
- clean_rel = {'Soggetto': subj, 'Relazione': rel_name, 'Oggetto': obj}
- clean_relations.append(clean_rel)
- all_rels = set((rel['Soggetto'], rel['Relazione'], rel['Oggetto']) for rel in clean_relations)
- all_subjects = set(rel['Soggetto'] for rel in clean_relations)
- all_cited_entities = set(sum([[rel['Soggetto'], rel['Oggetto']] for rel in clean_relations], []))
- undefined_entities = all_cited_entities - all_entities
- unused_entities = all_entities - all_cited_entities
- atomic_entities = all_cited_entities - all_subjects
- problematic_entities = undefined_entities - atomic_entities
- # %%
- ####
- # MANUS ONLINE (MOL) API: https://api.iccu.sbn.it/devportal/apis
- ####
- # %%
- for ent in sorted(list(problematic_entities)):
- print(ent)
- # %%
- for ent in sorted(list(atomic_entities)):
- print(ent)
- # %%
- for ent in sorted(list(unused_entities)):
- print(ent)
- # %%
- for ent in sorted(list(undefined_entities)):
- print(ent)
- # %%
|