Francesco 1 year ago
commit
e7570db04e

+ 62 - 0
app.py

@@ -0,0 +1,62 @@
+from flask import Flask, request, redirect, render_template
+from parsers.CSV_to_RDF_generico import parse, parsefromfile
+from parsers.get_form_fields import getFormFields
+
+
+app = Flask(__name__)
+
+@app.route('/', methods=['POST','GET'])
+def main():
+
+    configurationFolder = 'parsers/configuration_files/'
+    configurationFileName = 'configuration.json'   
+    confFilePath = configurationFolder + configurationFileName
+
+    try:
+        formFields = getFormFields(confFilePath)
+    except:
+        return redirect('/error/')
+
+
+    if request.method == 'POST':
+
+        outputFolder = 'samples/RDF/'
+
+        fileFromRequest = request.files['FILE']
+        filename = fileFromRequest.filename
+
+        if filename != '':
+            outFileName = fileFromRequest.filename.replace('.csv', '') + '.ttl'
+            outFilePath = outputFolder+outFileName
+            inFile = fileFromRequest.read()
+            # try to create list of dictionaries keyed by header row
+            parsefromfile(confFilePath, formFields, inFile, outFilePath)
+
+        else:
+            # Da completare
+            data =  {}
+            for field in formFields:
+                data[field] = request.form[field]
+
+            check = [val for val in data.values() if val!='']
+
+            if len(check)>0:
+                parse(confFilePath, formFields,[data], outputFolder + 'form_output.ttl')
+            else:
+                return redirect('/error/')
+
+        return redirect('/')
+
+    return render_template('index.html', data=formFields)
+
+
+@app.route('/error/', methods=['POST','GET'])
+def error():
+    if request.method == 'POST':
+        return redirect('/')
+    else:
+        return render_template('error.html')
+
+
+if __name__ == '__main__':
+    app.run()

+ 160 - 0
parsers/CSV_to_RDF_generico.py

@@ -0,0 +1,160 @@
+## IMPORTS
+
+# Utilities to read/write csv files
+import csv, json
+from operator import truediv
+
+
+# Custom class to store URIs + related infos for the ontologies/repositories
+
+class RDFcoords:
+    def __init__(self, uri, prefix, code = None):
+        self.uri = uri
+        self.prefix = prefix
+        self.code = code
+
+
+# Repositories
+museoCoords = RDFcoords('<https://palazzopretorio.prato.it/it/le-opere/alcuni-capolavori/>', 'mpp:')
+autCoords = RDFcoords('<https://palazzopretorio.prato.it/it/opere/autori/>', 'aut:')
+foafCoords = RDFcoords('<http://xmlns.com/foaf/0.1/>', 'foaf:')
+
+cidocCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/>', 'crm:')
+aatCoords = RDFcoords('<http://vocab.getty.edu/aat/>', 'aat:')
+nsCoords = RDFcoords('<http://www.w3.org/1999/02/22-rdf-syntax-ns#>', 'rdf:')
+schemaCoords = RDFcoords('<http://www.schema.org/>', 'schema:')
+rdfsCoords = RDFcoords('<http://www.w3.org/2000/01/rdf-schema#>', 'rdfs:')
+
+
+# Basic utilities to format triples / shortened triples in TTL format
+#
+# Format full triple
+def triple(subject, predicate, object1):
+    line = subject + ' ' + predicate + ' ' + object1
+    return line
+
+# Format entry in predicate list (no subject)
+def doublet(predicate, object1):
+    line = '    ' + predicate + ' ' + object1
+    return line
+
+# Format entry in object list (object only)
+def singlet(object1):
+    line = '        ' + object1
+    return line
+
+# Line endings
+continueLine1 = ' ;\n' # Before a predicate list, that is if the FOLLOWING triple has the same subject
+continueLine2 = ' ,\n' # Before an object list, that is if the FOLLOWING triple has the same subject and predicate
+closeLine = ' .\n' # To end a triple / a triples block
+
+
+def writeTTLHeader(output):
+    output.write('@prefix ' + museoCoords.prefix + ' ' + museoCoords.uri + closeLine)
+    output.write('@prefix ' + foafCoords.prefix + ' ' + foafCoords.uri + closeLine)
+    output.write('@prefix ' + autCoords.prefix + ' ' + autCoords.uri + closeLine)
+    output.write('@prefix ' + cidocCoords.prefix + ' ' + cidocCoords.uri + closeLine)
+    output.write('@prefix ' + aatCoords.prefix + ' ' + aatCoords.uri + closeLine)
+    output.write('@prefix ' + schemaCoords.prefix + ' ' + schemaCoords.uri + closeLine)
+    output.write('@prefix ' + nsCoords.prefix + ' ' + nsCoords.uri + closeLine)
+    output.write('@prefix ' + rdfsCoords.prefix + ' ' + rdfsCoords.uri + closeLine)
+    output.write('\n')
+
+max_entries = None
+
+def parsefromfile(mapfilename, formFields, infile, outfilename):
+    inputFile = infile.decode()
+    csv_dicts = [{k: v for k, v in row.items()} for row in csv.DictReader(inputFile.splitlines(), skipinitialspace=True)]
+    parse(mapfilename, formFields, csv_dicts, outfilename)
+
+
+def parse(mapfilename, formFields, csv_dicts, outfilename):
+
+    with open (mapfilename) as mapfile:
+        triple_blocks = json.load(mapfile)
+    
+    allRefs = getRefs(triple_blocks)
+    doReplace = True
+    while doReplace:
+        doReplace = False
+        for ref in allRefs['subjects_with_refs']:
+            oldVal = ref['value']
+            newVal = replaceRefs(allRefs, oldVal)
+            if(oldVal != newVal):
+                ref['value'] = newVal
+                doReplace = True
+        for ref in allRefs['objects_with_refs']:
+            oldVal = ref['value']
+            newVal = replaceRefs(allRefs, oldVal)
+            if(oldVal != newVal):
+                ref['value'] = newVal
+                doReplace = True
+
+
+    with open(outfilename, 'w') as outputfile:
+
+        writeTTLHeader(outputfile)
+
+        for csvrow in csv_dicts:
+            for entry in triple_blocks:
+
+                subject = entry['subject']['value'] if type(entry['subject']) is dict else entry['subject']
+                subject = replaceRefs(allRefs, subject)
+                subject = replace_csv_values(formFields, csvrow, subject)
+                for content in entry['content']:
+                    attribute = content['predicate']
+                    object1 = content['object']['value'] if type(content['object']) is dict else content['object']
+                    object1 = replaceRefs(allRefs, object1)
+                    object1 = replace_csv_values(formFields, csvrow, object1)
+
+                    toWrite = triple(subject, attribute, object1)
+
+                    outputfile.write(toWrite)
+                    outputfile.write(closeLine)
+                
+            outputfile.write('\n')
+                
+
+
+def getRefs(triple_blocks: dict):
+    subjects_with_refs = []
+    for block in triple_blocks:
+        try:
+            subject_ref = block['subject']['ref']
+        except:
+            subject_ref = None
+        if subject_ref is not None:
+            subjects_with_refs.append(block['subject'])
+    
+    objects_with_refs = []
+    for block in triple_blocks:
+        for content in block['content']:
+            try:
+                object_ref = content['object']['ref']
+            except:
+                object_ref = None
+            if object_ref is not None:
+                objects_with_refs.append(content['object'])
+    
+    return {'subjects_with_refs': subjects_with_refs, 'objects_with_refs': objects_with_refs}
+
+
+def replace_csv_values(formFields: list, csvrow: dict, val: str):
+    
+    outStr = val
+    for field in formFields:
+        outStr = outStr.replace('#csv:'+field+'#', csvrow[field])
+
+    return outStr
+
+
+def replaceRefs(allRefs, val):
+
+    outStr = val
+    for ref in allRefs['subjects_with_refs']:
+        outStr = outStr.replace('#ref:'+ref['ref']+'#', ref['value'])
+    for ref in allRefs['objects_with_refs']:
+        outStr = outStr.replace('#obj_ref:'+ref['ref']+'#', ref['value'])
+    
+    return outStr
+

+ 0 - 0
parsers/__init__.py


BIN
parsers/__pycache__/CSV_to_RDF_Autori.cpython-38.pyc


BIN
parsers/__pycache__/CSV_to_RDF_generico.cpython-38.pyc


BIN
parsers/__pycache__/__init__.cpython-38.pyc


BIN
parsers/__pycache__/get_form_fields.cpython-38.pyc


+ 202 - 0
parsers/configuration_files/configuration.json

@@ -0,0 +1,202 @@
+[
+    {
+        "subject": {
+          "value": "aut:#csv:URL#",
+          "ref": "MAIN"
+        },
+        "comment": "OPZIONALE - ci si può scrivere icché si vòle.",
+        "content": [
+            {
+              "predicate": "rdf:type",
+              "object": "crm:E21_Person"
+            },
+            {
+              "predicate": "rdf:type",
+              "object": "foaf:person"
+            },
+            {
+              "predicate": "foaf:name",
+              "object": "\"#csv:AUTN#\""
+            },
+            {
+              "predicate": "foaf:givenName",
+              "object": "\"#csv:AUTO#\""
+            },
+            {
+              "predicate": "foaf:gender",
+              "object": "\"#csv:AUTZ#\""
+            },
+            {
+              "predicate": "rdfs:label",
+              "object": "\"#csv:AUTN#, #csv:AUTA#\""
+            },
+            {
+              "predicate": "crm:P3_has_note",
+              "object": {
+                "value": "#ref:MAIN#_E62",
+                "ref": "E62"
+              }
+            },
+            {
+              "predicate": "crm:P98i_was_born",
+              "object": {
+                "value": "#ref:MAIN#_E67",
+                "ref": "E67"
+              }
+            },
+            {
+              "predicate": "crm:P100i_died_in",
+              "object": {
+                "value": "#ref:MAIN#_E69",
+                "ref": "E69"
+              }
+            },
+            {
+              "predicate": "crm:P1_is_identified_by",
+              "object": {
+                "value": "aut:#csv:AUTH#",
+                "ref": "E42"
+              }
+            },
+            {
+              "predicate": "schema:hasOccupation",
+              "object": {
+                "value": "mpp:#csv:AUTQ#",
+                "ref": "OCCUPATION"
+              }
+            }
+        ]
+    },
+    {
+      "subject": "#obj_ref:E62#",
+      "content": [
+          {
+            "predicate": "rdf:type",
+            "object": "crm:E62_String"
+          },
+          {
+            "predicate": "rdfs:label",
+            "object": "\"Fonte: Museo di Palazzo Pretorio - Collezione Martini\""
+          }
+      ]
+    },
+    {
+      "subject": "#obj_ref:E42#",
+      "content": [
+          {
+            "predicate": "rdf:type",
+            "object": "crm:E42_Identifier"
+          },
+          {
+            "predicate": "rdfs:label",
+            "object": "\"#csv:AUTH#\""
+          }
+      ]
+    },
+    {
+      "subject": "#obj_ref:E67#",
+      "content": [
+          {
+            "predicate": "rdf:type",
+            "object": "crm:E67_Birth"
+          },
+          {
+            "predicate": "rdfs:label",
+            "object": "\"Nascita di #csv:AUTN#\""
+          },
+          {
+            "predicate": "crm:P7_took_place_at",
+            "object": {
+              "value": "mpp:#csv:AUTL#",
+              "ref": "LOC-BIRTH"
+            }
+          },
+          {
+            "predicate": "crm:P4_has_time-span",
+            "object": {
+              "value": "mpp:#csv:AUTD#",
+              "ref": "TIME-BIRTH"
+            }
+          }
+      ]
+    },
+    {
+      "subject": "#obj_ref:E69#",
+      "content": [
+          {
+            "predicate": "rdf:type",
+            "object": "crm:E69_Death"
+          },
+          {
+            "predicate": "rdfs:label",
+            "object": "\"Morte di #csv:AUTN#\""
+          },
+          {
+            "predicate": "crm:P7_took_place_at",
+            "object": {
+              "value": "mpp:#csv:AUTX#",
+              "ref": "LOC-DEATH"
+            }
+          },
+          {
+            "predicate": "crm:P4_has_time-span",
+            "object": {
+              "value": "mpp:#csv:AUTT#",
+              "ref": "TIME-DEATH"
+            }
+          }
+      ]
+    },
+    {
+      "subject": "#obj_ref:TIME-BIRTH#",
+      "content": [
+          {
+            "predicate": "rdf:type",
+            "object": "crm:E52_Time-Span"
+          },
+          {
+            "predicate": "rdfs:label",
+            "object": "\"#csv:AUTD#\""
+          }
+      ]
+    },
+    {
+      "subject": "#obj_ref:LOC-BIRTH#",
+      "content": [
+          {
+            "predicate": "rdf:type",
+            "object": "crm:E53_Place"
+          },
+          {
+            "predicate": "rdfs:label",
+            "object": "\"#csv:AUTL#\""
+          }
+      ]
+    },
+    {
+      "subject": "#obj_ref:TIME-DEATH#",
+      "content": [
+          {
+            "predicate": "rdf:type",
+            "object": "crm:E52_Time-Span"
+          },
+          {
+            "predicate": "rdfs:label",
+            "object": "\"#csv:AUTT#\""
+          }
+      ]
+    },
+    {
+      "subject": "#obj_ref:LOC-DEATH#",
+      "content": [
+          {
+            "predicate": "rdf:type",
+            "object": "crm:E53_Place"
+          },
+          {
+            "predicate": "rdfs:label",
+            "object": "\"#csv:AUTX#\""
+          }
+      ]
+    }
+]

+ 45 - 0
parsers/get_form_fields.py

@@ -0,0 +1,45 @@
+## IMPORTS
+
+# Utilities to read/write csv files
+import json
+import re
+
+def getFormFields(mapfilename):
+
+    with open (mapfilename) as mapfile:
+        triple_blocks = json.load(mapfile)
+
+        all_csvs = []
+        for block in triple_blocks:
+            all_csvs = all_csvs + extractFields(block)
+
+        all_csvs_filtered = []
+        for csv in all_csvs:
+            if csv in all_csvs_filtered:
+                continue
+            all_csvs_filtered.append(csv)
+
+        return all_csvs_filtered
+
+
+def extractFields(entry: dict):
+    try:
+        subject_val = entry['subject']['value'] if type(entry['subject']) is dict else entry['subject']
+        all_csvs = list( csvsFromVals(subject_val) )
+
+        objs = map(lambda el: el['object'], entry['content'])
+        for obj in objs:
+            val = obj['value'] if type(obj) is dict else obj
+            obj_csvs = csvsFromVals(val)
+            all_csvs = all_csvs + list(obj_csvs)
+
+        return all_csvs        
+            
+    except:
+        raise Exception('Malformed Configuration File')
+
+def csvsFromVals(value: str):
+    val_parts = re.split('#', value)
+    val_csvs = list( filter(lambda str1: str1.startswith('csv:'), val_parts) )
+    val_csvs = map(lambda str1: str1.replace('csv:', ''), val_csvs)
+    return val_csvs

+ 1 - 0
parsers/prebuilt_parsers/readme.txt

@@ -0,0 +1 @@
+Put existing parsers here!

+ 21 - 0
readme.md

@@ -0,0 +1,21 @@
+To get flask running (use Python 3!):
+
+1. [Optional but recommendend] Create and activate virtual environment by:
+
+	- Going to the FORMS subdirectory
+	- Executing: **python** (or python3 or py depending on your system) **-m venv [virtual_environment_name]**
+	- Executing: **source [virtual_environment_name]/bin/activate**
+
+2. Install Flask by executing:
+
+	- **pip install flask**
+
+3. [Optional] Activate Debug Mode by setting the environment variable:
+
+	- FLASK_ENV=development (for instance by executing **export FLASK_ENV=development** in bash)
+
+4. Start the app by executing:
+
+	- **flask run**
+
+(vscode can do 3. and 4. automatically, and possibly the venv setup too)

+ 1 - 0
samples/CSV/.~lock.AR20AUT_Ospedale_2.csv#

@@ -0,0 +1 @@
+,kora,koras,22.09.2022 09:06,file:///home/kora/.config/libreoffice/4;

+ 3 - 0
samples/CSV/AR20AUT_Datini.csv

@@ -0,0 +1,3 @@
+TSK,ESC,AUTN,URL,AUTA,AUTC,AUTO,AUTV,AUTZ,AUTL,AUTD,AUTX,AUTT,AUTU,AUTQ,AUTH,CMPD,CMPN,RSR,FUR
+AUT,C100005,Lippi Filippo,filippo-lippi-1406-1469,1406/ 1469,Lippi,Filippo,Fra Filippo,M,Firenze,1406,Spoleto,1469,scuola fiorentina,pittore,17,2017,Gelli, Marta,Iacopino, Rita,Iacopino, Rita
+AUT,C100005,Buti Lodovico,ludovico-buti,1550-1560 ca./ 1611,Buti,Lodovico,Buti Ludovico,M,Firenze,1550-1560 ca.,Firenze,1661,scuola fiorentina,pittore,81,2020,Gelli, Marta,Iacopino, Rita,Iacopino, Rita

+ 21 - 0
samples/CSV/AR20AUT_Martini.csv

@@ -0,0 +1,21 @@
+TSK,ESC,AUTN,AUTA,AUTC,AUTO,AUTZ,AUTG,AUTU,AUTQ,AUTH,CMPD,CMPN,RSR,FUR,AUTL,AUTD,AUTX,AUTT,ECP,AUTV,flags,AUTP,AUTF,URL
+AUT,C100005,Graziani Pietro,notizie prima metà sec. XVIII,Graziani,Pietro,M,attivo Napoli prima metà sec. XVIII,scuola napoletana,pittore,62,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",,,,,,,,,,andrea-casali
+AUT,C100005,Baldini Taddeo,1623/ 1694,Baldini,Taddeo,M,,scuola fiorentina,pittore,47,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Firenze,1623,Firenze,1694,,,,,,taddeo-baldini
+AUT,C100005,Chiari Giuseppe Bartolomeo,1654/ 1727,Chiari,Giuseppe Bartolomeo,M,,scuola romana,pittore,63,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Roma,1654,Roma,1727,C100005,,,,,pietro-graziani-napoli-inizi-del-xviii-secolo
+AUT,C100005,Domenico di Michelino,1417/ 1491,,Domenico,M,,,pittore,15,2017,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Firenze,1417,Firenze,1491,,Domenico di Francesco,,,,domenico-di-michelino
+AUT,C100005,Strozzi Zanobi,1412/ 1468,Strozzi,Zanobi,M,,,pittore,16,2017,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Firenze,1412,Firenze,1468,,,,,,zanobi-strozzi
+AUT,C100005,Manieri Carlo,1633/ 1702,Manieri,Carlo,M,,scuola romana,pittore,57,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Taranto,1633,Roma,1702,,,,,,giuseppe-bartolomeo-chiari-attribuito
+AUT,C100005,Von Tamm Franz Werner,1658/ 1724,Von Tamm,Franz Werner,M,,scuola austriaca,pittore,55,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Amburgo,1658,Vienna,1724,,Monsù D'Aprè,,,,Carlo-Mainieri
+AUT,C100005,Van Kessel Jan,1626/ 1679,Van Kessel,Jan,M,,scuola fiamminga,pittore,54,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Anversa,1626,Anversa,1679,,,,,,franz-werner-von-tamm-detto-monsu-daprait-o-dapre-
+AUT,C100005,Casali Andrea,1705/ 1784,Casali,Andrea,M,,scuola romana,pittore,65,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Roma,1705,Roma,1784,C100005,,,,,Maria-Luisa-Raggi
+AUT,C100005,Navarra Pietro,notizie fine sec. XVII-inizio sec. XVIII,Navarra,Pietro,M,attivo Roma 1685-1714,scuola romana,pittore,56,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",,,,,,,,,,jan-van-kessel-il-vecchio-anversa-1626-1679
+AUT,C100005,Rocca Michele,1671/ 1751,Rocca,Michele,M,,scuola bolognese/ scuola romana,pittore,64,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Parma,1671,Venezia,1751,C100005,,,,,nicola-malinconico
+AUT,C100005,Costanzi Placido,1702/ 1759,Costanzi,Placido,M,,scuola romana,pittore,61,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Roma,1702,Roma,1759,,,I,,,giacomo-e-giulio-francia-giacomo-e-giulio-raibolin
+AUT,C100005,Malinconico Nicola,1663/ 1721,Malinconico,Nicola,M,,scuola napoletana,pittore,49,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Napoli,1663,Napoli,1721,,,,,,placido-costanzi
+AUT,C100005,Stern Ludovico,1709/ 1777,Stern,Ludovico,M,,scuola romana,pittore,58,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Roma,1709,Roma,1777,,,,,,michele-rocca-parma-167075-venezia-1751-ca
+AUT,C100005,"Francia, Giulio",1487/ 1545,Raibolini,Giulio,M,Bologna,scuola bolognese,,30,2019,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",,1487,,1545,,,,Giulio Francia,,pietro-navarra
+AUT,C100005,Van Lint Giovanni Giacomo,1723-1790,Van Lint,Giovanni Giacomo,M,,,pittore,53,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Roma,1723,Roma,1790,,,,,,giacomo-van-lint
+AUT,C100005,Vermoelen Jacob Xavier,1714/ 1784,Vermoelen,Jacob Xavier,M,,,pittore,60,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Anversa,1714,Roma,1784,,Vermoelen Jacques Xavier/ Vermoelen Jacobus Xaverus/ Vermolen Jacob Xaver/ Vermeulen Jacob Xavier,,,J. X. Vermoelen,j-xavier-van-orlen
+AUT,C100005,Lopez Gasparo,1650/ 1740,Lopez,Gasparo,M,,scuola napoletana,pittore,59,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Napoli,1650,Firenze,1740,,,,,,gaspare-lopez
+AUT,C100005,Raggi Maria Luigia,1742/ 1813,Raggi,Maria Luigia,F,,,pittore,77,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Genova,1743,Genova,1813,,Raggi Maria Luisa,,,,ludovico-stern-roma-1709-1777
+AUT,C100005,Van Wittel Gaspar,1653/ 1736,Van Wittel,Gasparo,M,,,pittore,76,2020,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",Amersfoort,1653,Roma,1736,,Gaspare degli Occhiali,,Gaspare Vanvitelli,G: V: W:,Gaspar-van-wittel

+ 2 - 0
samples/CSV/AR20AUT_Ospedale_2.csv

@@ -0,0 +1,2 @@
+TSK,ESC,AUTN,AUTA,AUTO,AUTP,AUTZ,AUTL,AUTD,AUTX,AUTT,AUTQ,AUTH,CMPD,CMPN,RSR,FUR,AUTV,AUTU,ECP,AUTC,URL
+AUT,C100005,Benedetto di Leonardo detto Benedetto da Maiano,1442/ 1497,Benedetto,Benedetto da Maiano,M,Firenze,1442,Firenze,1497,scultore,28,2018,"Gelli, Marta","Iacopino, Rita","Iacopino, Rita",,,,,da-benedetto-da-maiano

+ 24 - 0
samples/CSV/BiblioDatini_IDAspo.csv

@@ -0,0 +1,24 @@
+id,num_aspo,sigla,num_ovi,titolo,descrizione,mittente,destinatario,luogo_emissione,luogo_arrivo,data_partenza,data_arrivo,segnatura,tipologia,lingua,area_linguistica,edizione,edizione_abbr,raccolta,anno_inizio,anno_fine,note;;;;;;;;;;
+"ASPO00055304,1,G97,1,Lettera di Michele di Iacopo Lottieri a Francesco di Marco Datini,Michele di Iacopo Lottieri-Fr.Datini 15.01.1395 Gaeta-Firenze 1000063 (B649/40),Michele di Iacopo Lottieri,Francesco di Marco Datini,Gaeta,Firenze,15.01.1395,15.02.1395,""ASPrato, Archivio Datini, n. 649/40, 1000063"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 88-189, n. 190."",Cecchi Aste 1997,Carteggio di Gaeta,1395,1395, ";;;;;;;;;;
+"ASPO00055319,1,H17,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 21.04.1397 Gaeta-Firenze 1000064 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,21.04.1397,[ma Pisa] 07.05.1397,""ASPrato, Archivio Datini, n. 649/43, 1000064"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 203-204, n. 210."",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ";;;;;;;;;;
+"ASPO00055320,1,H23,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 19.06.1397 Gaeta-Firenze [ma Pisa] 1000065 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze [ma Pisa],19.06.1397,10.07.1397,""ASPrato, Archivio Datini, n. 649/43, 1000065"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, p. 211, n. 216."",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ";;;;;;;;;;
+"ASPO00055321,1,H24,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 08.09.1397 Gaeta-Firenze 1000066 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,08.09.1397,[ma Pisa] 24.09.1397,""ASPrato, Archivio Datini, n. 649/43, 1000066"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 211-212, n. 217."",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ";;;;;;;;;;
+"ASPO00055322,1,H30,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 13.11.1397 Gaeta-Firenze 1000067 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,13.11.1397,[ma Pisa] 03.12.1397,""ASPrato, Archivio Datini, n. 649/43, 1000067"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 215-216, n. 223."",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ";;;;;;;;;;
+"ASPO00055306,1,G98,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Firenze (Stoldo di Lorenzo di Berizo Ormanni),Michele di Iacopo Lottieri-Comp.Datini di Firenze (Stoldo di Lorenzo) 31.03.1395 Gaeta-Firenze 1000068 (B649/41),Michele di Iacopo Lottieri,Compagnia Datini di Firenze (Stoldo di Lorenzo di Berizo Ormanni),Gaeta,Firenze,31.03.1395,15.04.1395,""ASPrato, Archivio Datini, n. 649/41, 1000068"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 189, n. 191."",Cecchi Aste 1997,Carteggio di Gaeta,1395,1395, ";;;;;;;;;;
+"ASPO00055307,1,G99,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Firenze,Michele di Iacopo Lottieri-Comp.Datini di Firenze 07.04.1395 Gaeta-Firenze 1000069 (B649/41),Michele di Iacopo Lottieri,Compagnia Datini di Firenze,Gaeta,Firenze,07.04.1395,12.04.1395,""ASPrato, Archivio Datini, n. 649/41, 1000069"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 189-190, n. 192."",Cecchi Aste 1997,Carteggio di Gaeta,1395,1395, ";;;;;;;;;;
+"ASPO00055308,1,H00,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Firenze,Michele di Iacopo Lottieri-Comp.Datini di Firenze 19.04.1395 Gaeta-Firenze 1000070 (B649/41),Michele di Iacopo Lottieri,Compagnia Datini di Firenze,Gaeta,Firenze,19.04.1395,03.05.1395,""ASPrato, Archivio Datini, n. 649/41, 1000070"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, p. 190, n. 193."",Cecchi Aste 1997,Carteggio di Gaeta,1395,1395, ";;;;;;;;;;
+"ASPO00055309,1,H09,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Firenze (Stoldo di Lorenzo di Berizo Ormanni),Michele di Iacopo Lottieri-Comp.Datini di Firenze (Stoldo di Lorenzo) 25.12.1396 Gaeta-Firenze 1000071 (B649/41),Michele di Iacopo Lottieri,Compagnia Datini di Firenze (Stoldo di Lorenzo di Berizo Ormanni),Gaeta,Firenze,25.12.1396,05.01.1397,""ASPrato, Archivio Datini, n. 649/41, 1000071"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, p. 196, n. 202."",Cecchi Aste 1997,Carteggio di Gaeta,1396,1396, ";;;;;;;;;;
+"ASPO00055310,1,H10,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Firenze (Stoldo di Lorenzo di Berizo Ormanni),Michele di Iacopo Lottieri-Comp.Datini di Firenze (Stoldo di Lorenzo) 23.01.1397 Gaeta-Firenze 1000072 (B649/41),Michele di Iacopo Lottieri,Compagnia Datini di Firenze (Stoldo di Lorenzo di Berizo Ormanni),Gaeta,Firenze,23.01.1397,06.02.1397,""ASPrato, Archivio Datini, n. 649/41, 1000072"",lettera,italiano,toscano,""Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 196-197, n. 203."",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ";;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;
+;;;;;;;;;;s

+ 11 - 0
samples/CSV/OSPEDALE-onomastica-persone-singole.csv

@@ -0,0 +1,11 @@
+recordId,ID collegato,entityType,nameEntry@normal,nameEntry@prime,genere,nome proprio,nome di famiglia,patronimico/matronimico,avo 1,avo 2,recordID relazione,nome relazione,provenienza,Variante,Alias,Qualifica,occupation_1,place occupation  1 PROVINCIA,place occupation 1 COMUNE,place occupation 1 MICROTOPONIMO,place occupation 1 ENTE,occupation_2,place occupation 2 PROVINCIA,place occupation 2 COMUNE,place occupation 2 MICROTOPONIMO,place occupation 2 ENTE,occupation_3,place occupation 3 PROVINCIA,place occupation 3 COMUNE,place occupation 3 MICROTOPONIMO,place occupation 3 ENTE,biogHist p,nameEntry@ulterior,nameEntry@ord,place PROVINCIA,place COMUNE,place MICROTOPONIMO
+IT-ASPO-AU00002-0001329,,person,[...] Bice,,F,Bice,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+IT-ASPO-AU00002-0001325,,person,[...] Giovanni,,M,Giovanni,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+IT-ASPO-AU00002-0001140,,person,[...] Giovanni di Andrea,,M,Giovanni,,di Andrea,,,,,,,,,vice camarlingo,PRATO,PRATO,,COMUNE,,,,,,,,,,,Vice camarlingo del Comune di Prato.,,Vechi (?),,,
+IT-ASPO-AU00002-0001230,,person,Accolti Angelo di Graziasanta da Arezzo,,M,Angelo ,Accolti ,di Graziasanta ,,,,,da Arezzo,,,,,,,,,,,,,,,,,,,,,,,,
+IT-ASPO-AU00002-0001275,,person,Agostino di Andrea di Fioco,,M,Agostino ,,di Andrea ,di Fioco,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+IT-ASPO-AU00002-0000001,,person,Aiazzi Antonio,,M,Antonio,Aiazzi ,,,,,,,,,,,,,,,,,,,,,,,,,,,Aiazzi,,,
+IT-ASPO-AU00002-0000002,,person,Alamanno di ser Betto,,M,Alamanno ,,di ser Betto,,,,,,,,,notaio,PRATO,PRATO,,,,,,,,,,,,,Notaio pubblico di Prato.,,,,,
+IT-ASPO-AU00002-0000003,,person,Albani Giovanni Francesco (papa Clemente XI),,M,Giovanni Francesco ,Albani,,,,,,,,Clemente XI,papa,,,,,,,,,,,,,,,,1700-1721,,Albani,,,
+IT-ASPO-AU00002-0000004,,person,Alberto di Teri,,M,Alberto ,,di Teri,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+IT-ASPO-AU00002-0000005,,person,Albizzi Rinaldo,,M,Rinaldo,Albizzi ,,,,,,,,,,,,,,,,,,,,,,,,,,,Albizzi,,,

+ 73 - 0
samples/RDF/AR20AUT_Datini.ttl

@@ -0,0 +1,73 @@
+@prefix mpp: <https://palazzopretorio.prato.it/it/le-opere/alcuni-capolavori/> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix aut: <https://palazzopretorio.prato.it/it/opere/autori/> .
+@prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> .
+@prefix aat: <http://vocab.getty.edu/aat/> .
+@prefix schema: <http://www.schema.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+aut:filippo-lippi-1406-1469 rdf:type crm:E21_Person .
+aut:filippo-lippi-1406-1469 rdf:type foaf:person .
+aut:filippo-lippi-1406-1469 foaf:name "Lippi Filippo" .
+aut:filippo-lippi-1406-1469 foaf:givenName "Filippo" .
+aut:filippo-lippi-1406-1469 foaf:gender "M" .
+aut:filippo-lippi-1406-1469 rdfs:label "Lippi Filippo, 1406/ 1469" .
+aut:filippo-lippi-1406-1469 crm:P3_has_note aut:filippo-lippi-1406-1469_E62 .
+aut:filippo-lippi-1406-1469 crm:P98i_was_born aut:filippo-lippi-1406-1469_E67 .
+aut:filippo-lippi-1406-1469 crm:P100i_died_in aut:filippo-lippi-1406-1469_E69 .
+aut:filippo-lippi-1406-1469 crm:P1_is_identified_by aut:17 .
+aut:filippo-lippi-1406-1469 schema:hasOccupation mpp:pittore .
+aut:filippo-lippi-1406-1469_E62 rdf:type crm:E62_String .
+aut:filippo-lippi-1406-1469_E62 rdfs:label "Fonte: Museo di Palazzo Pretorio - Collezione Martini" .
+aut:17 rdf:type crm:E42_Identifier .
+aut:17 rdfs:label "17" .
+aut:filippo-lippi-1406-1469_E67 rdf:type crm:E67_Birth .
+aut:filippo-lippi-1406-1469_E67 rdfs:label "Nascita di Lippi Filippo" .
+aut:filippo-lippi-1406-1469_E67 crm:P7_took_place_at mpp:Firenze .
+aut:filippo-lippi-1406-1469_E67 crm:P4_has_time-span mpp:1406 .
+aut:filippo-lippi-1406-1469_E69 rdf:type crm:E69_Death .
+aut:filippo-lippi-1406-1469_E69 rdfs:label "Morte di Lippi Filippo" .
+aut:filippo-lippi-1406-1469_E69 crm:P7_took_place_at mpp:Spoleto .
+aut:filippo-lippi-1406-1469_E69 crm:P4_has_time-span mpp:1469 .
+mpp:1406 rdf:type crm:E52_Time-Span .
+mpp:1406 rdfs:label "1406" .
+mpp:Firenze rdf:type crm:E53_Place .
+mpp:Firenze rdfs:label "Firenze" .
+mpp:1469 rdf:type crm:E52_Time-Span .
+mpp:1469 rdfs:label "1469" .
+mpp:Spoleto rdf:type crm:E53_Place .
+mpp:Spoleto rdfs:label "Spoleto" .
+
+aut:ludovico-buti rdf:type crm:E21_Person .
+aut:ludovico-buti rdf:type foaf:person .
+aut:ludovico-buti foaf:name "Buti Lodovico" .
+aut:ludovico-buti foaf:givenName "Lodovico" .
+aut:ludovico-buti foaf:gender "M" .
+aut:ludovico-buti rdfs:label "Buti Lodovico, 1550-1560 ca./ 1611" .
+aut:ludovico-buti crm:P3_has_note aut:ludovico-buti_E62 .
+aut:ludovico-buti crm:P98i_was_born aut:ludovico-buti_E67 .
+aut:ludovico-buti crm:P100i_died_in aut:ludovico-buti_E69 .
+aut:ludovico-buti crm:P1_is_identified_by aut:81 .
+aut:ludovico-buti schema:hasOccupation mpp:pittore .
+aut:ludovico-buti_E62 rdf:type crm:E62_String .
+aut:ludovico-buti_E62 rdfs:label "Fonte: Museo di Palazzo Pretorio - Collezione Martini" .
+aut:81 rdf:type crm:E42_Identifier .
+aut:81 rdfs:label "81" .
+aut:ludovico-buti_E67 rdf:type crm:E67_Birth .
+aut:ludovico-buti_E67 rdfs:label "Nascita di Buti Lodovico" .
+aut:ludovico-buti_E67 crm:P7_took_place_at mpp:Firenze .
+aut:ludovico-buti_E67 crm:P4_has_time-span mpp:1550-1560 ca. .
+aut:ludovico-buti_E69 rdf:type crm:E69_Death .
+aut:ludovico-buti_E69 rdfs:label "Morte di Buti Lodovico" .
+aut:ludovico-buti_E69 crm:P7_took_place_at mpp:Firenze .
+aut:ludovico-buti_E69 crm:P4_has_time-span mpp:1661 .
+mpp:1550-1560 ca. rdf:type crm:E52_Time-Span .
+mpp:1550-1560 ca. rdfs:label "1550-1560 ca." .
+mpp:Firenze rdf:type crm:E53_Place .
+mpp:Firenze rdfs:label "Firenze" .
+mpp:1661 rdf:type crm:E52_Time-Span .
+mpp:1661 rdfs:label "1661" .
+mpp:Firenze rdf:type crm:E53_Place .
+mpp:Firenze rdfs:label "Firenze" .
+

+ 31 - 0
samples/RDF/BiblioDatini_edition.ttl

@@ -0,0 +1,31 @@
+@prefix dt: <http://datini.archiviodistato.prato.it/la-ricerca/scheda/> .
+@prefix pa: <http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/IT-ASPO-AU00003-> .
+@prefix tp: <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> .
+@prefix te: <http://www.cidoc-crm.org/cidoc-crm/P2_has_type> .
+@prefix mo: <http://www.cidoc-crm.org/cidoc-crm/E22_Man-Made_Object> .
+@prefix ca: <http://www.cidoc-crm.org/cidoc-crm/P128_carries> .
+@prefix io: <http://www.cidoc-crm.org/cidoc-crm/E73_Information_Object> .
+@prefix ib: <http://www.cidoc-crm.org/cidoc-crm/P1_is_identified_by> .
+@prefix ti: <http://www.cidoc-crm.org/cidoc-crm/E35_Title> .
+@prefix lb: <http://www.w3.org/2000/01/rdf-schema#label> .
+@prefix id: <http://www.cidoc-crm.org/cidoc-crm/E42_Identifier> .
+@prefix wb: <http://www.cidoc-crm.org/cidoc-crm/P92i_was_brought_into_existence_by> .
+@prefix ty: <http://www.cidoc-crm.org/cidoc-crm/E55_Type> .
+@prefix cb: <http://www.cidoc-crm.org/cidoc-crm/P14_carried_out_by> .
+@prefix ps: <http://www.cidoc-crm.org/cidoc-crm/E21_Person> .
+@prefix af: <http://www.cidoc-crm.org/cidoc-crm/P139_has_alternative_form> .
+@prefix no: <http://www.cidoc-crm.org/cidoc-crm/P3_has_note> .
+@prefix tn: <http://www.cidoc-crm.org/cidoc-crm/P3.1_has_type> .
+@prefix sr: <http://www.cidoc-crm.org/cidoc-crm/E62_String> .
+@prefix lj: <http://www.cidoc-crm.org/cidoc-crm/E33_Linguistic_Object> .
+@prefix ln: <http://www.cidoc-crm.org/cidoc-crm/E56_Language> .
+@prefix hl: <http://www.cidoc-crm.org/cidoc-crm/P72_has_language> .
+@prefix ds: <http://www.cidoc-crm.org/cidoc-crm/P70_documents> .
+@prefix ap: <http://www.cidoc-crm.org/cidoc-crm/E41_appellation> .
+@prefix pj: <http://www.cidoc-crm.org/cidoc-crm/E89_Propositional_Object> .
+@prefix hc: <http://www.cidoc-crm.org/cidoc-crm/P148_has_component> .
+
+<http://datini.archiviodistato.prato.it/la-ricerca/scheda/ASPO00055319,1,H17,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 21.04.1397 Gaeta-Firenze 1000064 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,21.04.1397,[ma Pisa] 07.05.1397,"ASPrato, Archivio Datini, n. 649/43, 1000064",lettera,italiano,toscano,"Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 203-204, n. 210.",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ;;;;;;;;;;/E73_OVI_ED> ds: <http://datini.archiviodistato.prato.it/la-ricerca/scheda/ASPO00055319,1,H17,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 21.04.1397 Gaeta-Firenze 1000064 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,21.04.1397,[ma Pisa] 07.05.1397,"ASPrato, Archivio Datini, n. 649/43, 1000064",lettera,italiano,toscano,"Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 203-204, n. 210.",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ;;;;;;;;;;/E73_OVI> .
+<http://datini.archiviodistato.prato.it/la-ricerca/scheda/ASPO00055319,1,H17,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 21.04.1397 Gaeta-Firenze 1000064 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,21.04.1397,[ma Pisa] 07.05.1397,"ASPrato, Archivio Datini, n. 649/43, 1000064",lettera,italiano,toscano,"Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 203-204, n. 210.",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ;;;;;;;;;;/E73_OVI_ED> lb: "Edizione" .
+<http://datini.archiviodistato.prato.it/la-ricerca/scheda/ASPO00055319,1,H17,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 21.04.1397 Gaeta-Firenze 1000064 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,21.04.1397,[ma Pisa] 07.05.1397,"ASPrato, Archivio Datini, n. 649/43, 1000064",lettera,italiano,toscano,"Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 203-204, n. 210.",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ;;;;;;;;;;/E73_OVI_ED> ib: <http://datini.archiviodistato.prato.it/la-ricerca/scheda/ASPO00055319,1,H17,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 21.04.1397 Gaeta-Firenze 1000064 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,21.04.1397,[ma Pisa] 07.05.1397,"ASPrato, Archivio Datini, n. 649/43, 1000064",lettera,italiano,toscano,"Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 203-204, n. 210.",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ;;;;;;;;;;/E73_OVI_ED_E41> .
+<http://datini.archiviodistato.prato.it/la-ricerca/scheda/ASPO00055319,1,H17,1,Lettera di Michele di Iacopo Lottieri alla compagnia Datini di Pisa (Manno d'Albizo degli Agli),Michele di Iacopo Lottieri-Comp.Datini di Pisa (Manno d'Albizo degli Agli) 21.04.1397 Gaeta-Firenze 1000064 (B649/43),Michele di Iacopo Lottieri,Compagnia Datini di Pisa (Manno d'Albizo degli Agli),Gaeta,Firenze,21.04.1397,[ma Pisa] 07.05.1397,"ASPrato, Archivio Datini, n. 649/43, 1000064",lettera,italiano,toscano,"Elena Cecchi Aste, Il carteggio di Gaeta nell'archivio del mercante pratese Francesco di Marco Datini, 1387-1405, Gaeta, 1997, pp. 203-204, n. 210.",Cecchi Aste 1997,Carteggio di Gaeta,1397,1397, ;;;;;;;;;;/E73_OVI_ED_E41> tp: ap: .

+ 147 - 0
samples/RDF/OSPEDALE-onomastica-persone-singole.ttl

@@ -0,0 +1,147 @@
+@prefix aspo: <http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> .
+@prefix person: <http://www.w3.org/ns/person#> .
+@prefix schema: <http://schema.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+
+aspo:IT-ASPO-AU00002-0001329 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0001329 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0001329 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0001329 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0001329_E42 .
+aspo:IT-ASPO-AU00002-0001329_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0001329_E42 rdfs:label "IT-ASPO-AU00002-0001329" .
+aspo:IT-ASPO-AU00002-0001329 foaf:name "[...] Bice" .
+aspo:IT-ASPO-AU00002-0001329 rdfs:label "[...] Bice" .
+aspo:IT-ASPO-AU00002-0001329 foaf:givenName "Bice" .
+aspo:IT-ASPO-AU00002-0001329 foaf:gender "F" .
+
+aspo:IT-ASPO-AU00002-0001325 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0001325 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0001325 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0001325 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0001325_E42 .
+aspo:IT-ASPO-AU00002-0001325_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0001325_E42 rdfs:label "IT-ASPO-AU00002-0001325" .
+aspo:IT-ASPO-AU00002-0001325 foaf:name "[...] Giovanni" .
+aspo:IT-ASPO-AU00002-0001325 rdfs:label "[...] Giovanni" .
+aspo:IT-ASPO-AU00002-0001325 foaf:givenName "Giovanni" .
+aspo:IT-ASPO-AU00002-0001325 foaf:gender "M" .
+
+aspo:IT-ASPO-AU00002-0001140 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0001140 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0001140 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0001140 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0001140_E42 .
+aspo:IT-ASPO-AU00002-0001140_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0001140_E42 rdfs:label "IT-ASPO-AU00002-0001140" .
+aspo:IT-ASPO-AU00002-0001140 foaf:name "[...] Giovanni di Andrea" .
+aspo:IT-ASPO-AU00002-0001140 rdfs:label "[...] Giovanni di Andrea" .
+aspo:IT-ASPO-AU00002-0001140 foaf:givenName "Giovanni" .
+aspo:IT-ASPO-AU00002-0001140 foaf:gender "M" .
+aspo:IT-ASPO-AU00002-0001140 person:patronymicName "di Andrea" .
+aspo:IT-ASPO-AU00002-0001140 crm:P3_has_note "Vice camarlingo del Comune di Prato." .
+
+aspo:IT-ASPO-AU00002-0001230 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0001230 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0001230 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0001230 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0001230_E42 .
+aspo:IT-ASPO-AU00002-0001230_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0001230_E42 rdfs:label "IT-ASPO-AU00002-0001230" .
+aspo:IT-ASPO-AU00002-0001230 foaf:name "Accolti Angelo di Graziasanta da Arezzo" .
+aspo:IT-ASPO-AU00002-0001230 rdfs:label "Accolti Angelo di Graziasanta da Arezzo" .
+aspo:IT-ASPO-AU00002-0001230 foaf:givenName "Angelo " .
+aspo:IT-ASPO-AU00002-0001230 foaf:familyName "Accolti " .
+aspo:IT-ASPO-AU00002-0001230 foaf:gender "M" .
+aspo:IT-ASPO-AU00002-0001230 person:patronymicName "di Graziasanta " .
+aspo:IT-ASPO-AU00002-0001230 crm:P74_has_current_or_former_residence <http://www.archiviodistato.prato.it/Arezzo> .
+<http://www.archiviodistato.prato.it/Arezzo> rdf:type crm:E53_Place .
+<http://www.archiviodistato.prato.it/Arezzo> rdfs:label "da Arezzo" .
+<http://www.archiviodistato.prato.it/Arezzo> crm:P2_has_type "Provenienza" .
+
+aspo:IT-ASPO-AU00002-0001275 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0001275 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0001275 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0001275 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0001275_E42 .
+aspo:IT-ASPO-AU00002-0001275_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0001275_E42 rdfs:label "IT-ASPO-AU00002-0001275" .
+aspo:IT-ASPO-AU00002-0001275 foaf:name "Agostino di Andrea di Fioco" .
+aspo:IT-ASPO-AU00002-0001275 rdfs:label "Agostino di Andrea di Fioco" .
+aspo:IT-ASPO-AU00002-0001275 foaf:givenName "Agostino " .
+aspo:IT-ASPO-AU00002-0001275 foaf:gender "M" .
+aspo:IT-ASPO-AU00002-0001275 person:patronymicName "di Andrea " .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_Fioco_AVO1_IT-ASPO-AU00002-0001275> rdf:type crm:E13_Attribute_Assignment .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_Fioco_AVO1_IT-ASPO-AU00002-0001275> crm:P141_assigned aspo:IT-ASPO-AU00002-0001275 .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_Fioco_AVO1_IT-ASPO-AU00002-0001275> rdfs:label "Relazione: di Fioco avo di secondo grado di IT-ASPO-AU00002-0001275" .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_fioco> crm:P141_assigned <http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_Fioco_AVO1_IT-ASPO-AU00002-0001275> .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_fioco> rdfs:label "di Fioco" .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_fioco> rdf:type crm:E21_Person .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_fioco> rdf:type person:Person .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_fioco> rdf:type foaf:person .
+<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/di_Fioco_AVO1_IT-ASPO-AU00002-0001275> crm:P42_assigned <http://www.archiviodistato.prato.it/avo_secondo_grado> .
+<http://www.archiviodistato.prato.it/avo_secondo_grado> rdfs:label "Avo di secondo grado" .
+
+aspo:IT-ASPO-AU00002-0000001 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0000001 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0000001 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0000001 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0000001_E42 .
+aspo:IT-ASPO-AU00002-0000001_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0000001_E42 rdfs:label "IT-ASPO-AU00002-0000001" .
+aspo:IT-ASPO-AU00002-0000001 foaf:name "Aiazzi Antonio" .
+aspo:IT-ASPO-AU00002-0000001 rdfs:label "Aiazzi Antonio" .
+aspo:IT-ASPO-AU00002-0000001 foaf:givenName "Antonio" .
+aspo:IT-ASPO-AU00002-0000001 foaf:familyName "Aiazzi " .
+aspo:IT-ASPO-AU00002-0000001 foaf:gender "M" .
+
+aspo:IT-ASPO-AU00002-0000002 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0000002 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0000002 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0000002 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0000002_E42 .
+aspo:IT-ASPO-AU00002-0000002_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0000002_E42 rdfs:label "IT-ASPO-AU00002-0000002" .
+aspo:IT-ASPO-AU00002-0000002 foaf:name "Alamanno di ser Betto" .
+aspo:IT-ASPO-AU00002-0000002 rdfs:label "Alamanno di ser Betto" .
+aspo:IT-ASPO-AU00002-0000002 foaf:givenName "Alamanno " .
+aspo:IT-ASPO-AU00002-0000002 foaf:gender "M" .
+aspo:IT-ASPO-AU00002-0000002 person:patronymicName "di ser Betto" .
+aspo:IT-ASPO-AU00002-0000002 crm:P3_has_note "Notaio pubblico di Prato." .
+
+aspo:IT-ASPO-AU00002-0000003 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0000003 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0000003 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0000003 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0000003_E42 .
+aspo:IT-ASPO-AU00002-0000003_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0000003_E42 rdfs:label "IT-ASPO-AU00002-0000003" .
+aspo:IT-ASPO-AU00002-0000003 foaf:name "Albani Giovanni Francesco (papa Clemente XI)" .
+aspo:IT-ASPO-AU00002-0000003 rdfs:label "Albani Giovanni Francesco (papa Clemente XI)" .
+aspo:IT-ASPO-AU00002-0000003 foaf:givenName "Giovanni Francesco " .
+aspo:IT-ASPO-AU00002-0000003 foaf:familyName "Albani" .
+aspo:IT-ASPO-AU00002-0000003 schema:alternateName "Clemente XI" .
+aspo:IT-ASPO-AU00002-0000003 foaf:gender "M" .
+aspo:IT-ASPO-AU00002-0000003 schema:honorificPrefix "papa" .
+aspo:IT-ASPO-AU00002-0000003 crm:P3_has_note "1700-1721" .
+
+aspo:IT-ASPO-AU00002-0000004 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0000004 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0000004 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0000004 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0000004_E42 .
+aspo:IT-ASPO-AU00002-0000004_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0000004_E42 rdfs:label "IT-ASPO-AU00002-0000004" .
+aspo:IT-ASPO-AU00002-0000004 foaf:name "Alberto di Teri" .
+aspo:IT-ASPO-AU00002-0000004 rdfs:label "Alberto di Teri" .
+aspo:IT-ASPO-AU00002-0000004 foaf:givenName "Alberto " .
+aspo:IT-ASPO-AU00002-0000004 foaf:gender "M" .
+aspo:IT-ASPO-AU00002-0000004 person:patronymicName "di Teri" .
+
+aspo:IT-ASPO-AU00002-0000005 rdf:type crm:E21_Person .
+aspo:IT-ASPO-AU00002-0000005 rdf:type person:Person .
+aspo:IT-ASPO-AU00002-0000005 rdf:type foaf:person .
+aspo:IT-ASPO-AU00002-0000005 crm:P1_is_identified_by aspo:IT-ASPO-AU00002-0000005_E42 .
+aspo:IT-ASPO-AU00002-0000005_E42 rdf:type crm:E42_Identifier .
+aspo:IT-ASPO-AU00002-0000005_E42 rdfs:label "IT-ASPO-AU00002-0000005" .
+aspo:IT-ASPO-AU00002-0000005 foaf:name "Albizzi Rinaldo" .
+aspo:IT-ASPO-AU00002-0000005 rdfs:label "Albizzi Rinaldo" .
+aspo:IT-ASPO-AU00002-0000005 foaf:givenName "Rinaldo" .
+aspo:IT-ASPO-AU00002-0000005 foaf:familyName "Albizzi " .
+aspo:IT-ASPO-AU00002-0000005 foaf:gender "M" .
+

+ 41 - 0
samples/RDF/form_output.ttl

@@ -0,0 +1,41 @@
+@prefix mpp: <https://palazzopretorio.prato.it/it/le-opere/alcuni-capolavori/> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix aut: <https://palazzopretorio.prato.it/it/opere/autori/> .
+@prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> .
+@prefix aat: <http://vocab.getty.edu/aat/> .
+@prefix schema: <http://www.schema.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+aut:Ciao rdf:type crm:E21_Person .
+aut:Ciao rdf:type foaf:person .
+aut:Ciao foaf:name "Pippo Jiollo" .
+aut:Ciao foaf:givenName "Pippo Baldini" .
+aut:Ciao foaf:gender "" .
+aut:Ciao rdfs:label "Pippo Jiollo, " .
+aut:Ciao crm:P3_has_note aut:Ciao_E62 .
+aut:Ciao crm:P98i_was_born aut:Ciao_E67 .
+aut:Ciao crm:P100i_died_in aut:Ciao_E69 .
+aut:Ciao crm:P1_is_identified_by aut: .
+aut:Ciao schema:hasOccupation mpp: .
+aut:Ciao_E62 rdf:type crm:E62_String .
+aut:Ciao_E62 rdfs:label "Fonte: Museo di Palazzo Pretorio - Collezione Martini" .
+aut: rdf:type crm:E42_Identifier .
+aut: rdfs:label "" .
+aut:Ciao_E67 rdf:type crm:E67_Birth .
+aut:Ciao_E67 rdfs:label "Nascita di Pippo Jiollo" .
+aut:Ciao_E67 crm:P7_took_place_at mpp: .
+aut:Ciao_E67 crm:P4_has_time-span mpp: .
+aut:Ciao_E69 rdf:type crm:E69_Death .
+aut:Ciao_E69 rdfs:label "Morte di Pippo Jiollo" .
+aut:Ciao_E69 crm:P7_took_place_at mpp: .
+aut:Ciao_E69 crm:P4_has_time-span mpp: .
+mpp: rdf:type crm:E52_Time-Span .
+mpp: rdfs:label "" .
+mpp: rdf:type crm:E53_Place .
+mpp: rdfs:label "" .
+mpp: rdf:type crm:E52_Time-Span .
+mpp: rdfs:label "" .
+mpp: rdf:type crm:E53_Place .
+mpp: rdfs:label "" .
+

+ 303 - 0
samples/parsers/CSV_to_RDF_Autori.py

@@ -0,0 +1,303 @@
+## IMPORTS
+
+# Utilities to read/write csv files
+import csv
+
+
+
+# Directories
+import_dir = '/Users/federicaspinelli/TEAMOVI/Parser/DATA/MPP/CSV/corretti/'
+export_dir = '/Users/federicaspinelli/TEAMOVI/Parser/DATA/MPP/RDF/'
+
+# Custom class to store URIs + related infos for the ontologies/repositories
+
+class RDFcoords:
+    def __init__(self, uri, prefix, code = None):
+        self.uri = uri
+        self.prefix = prefix
+        self.code = code
+
+
+# Repositories
+museoCoords = RDFcoords('<https://palazzopretorio.prato.it/it/le-opere/alcuni-capolavori/>', 'mpp:')
+autCoords = RDFcoords('<https://palazzopretorio.prato.it/it/opere/autori/>', 'aut:')
+foafCoords = RDFcoords('<http://xmlns.com/foaf/0.1/>', 'foaf:')
+
+cidocCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/>', 'crm:')
+aatCoords = RDFcoords('<http://vocab.getty.edu/aat/>', 'aat:')
+nsCoords = RDFcoords('<http://www.w3.org/1999/02/22-rdf-syntax-ns#>', 'rdf:')
+schemaCoords = RDFcoords('<http://www.schema.org/>', 'schema:')
+rdfsCoords = RDFcoords('<http://www.w3.org/2000/01/rdf-schema#>', 'rdfs:')
+
+
+# Basic utilities to format triples / shortened triples in TTL format
+#
+# Format full triple
+def triple(subject, predicate, object1):
+    line = subject + ' ' + predicate + ' ' + object1
+    return line
+
+# Format entry in predicate list (no subject)
+def doublet(predicate, object1):
+    line = '    ' + predicate + ' ' + object1
+    return line
+
+# Format entry in object list (object only)
+def singlet(object1):
+    line = '        ' + object1
+    return line
+
+# Line endings
+continueLine1 = ' ;\n' # Before a predicate list, that is if the FOLLOWING triple has the same subject
+continueLine2 = ' ,\n' # Before an object list, that is if the FOLLOWING triple has the same subject and predicate
+closeLine = ' .\n' # To end a triple / a triples block
+
+
+def writeTTLHeader(output):
+    output.write('@prefix ' + museoCoords.prefix + ' ' + museoCoords.uri + closeLine)
+    output.write('@prefix ' + foafCoords.prefix + ' ' + foafCoords.uri + closeLine)
+    output.write('@prefix ' + autCoords.prefix + ' ' + autCoords.uri + closeLine)
+    output.write('@prefix ' + cidocCoords.prefix + ' ' + cidocCoords.uri + closeLine)
+    output.write('@prefix ' + aatCoords.prefix + ' ' + aatCoords.uri + closeLine)
+    output.write('@prefix ' + schemaCoords.prefix + ' ' + schemaCoords.uri + closeLine)
+    output.write('@prefix ' + nsCoords.prefix + ' ' + nsCoords.uri + closeLine)
+    output.write('@prefix ' + rdfsCoords.prefix + ' ' + rdfsCoords.uri + closeLine)
+    output.write('\n')
+
+
+filePrefix = 'AR20AUT_'
+fileType = 'Datini'
+max_entries = None
+
+def parsefromfile(infile, outfile):
+    pyppa = infile.decode()
+    csv_dicts = [{k: v for k, v in row.items()} for row in csv.DictReader(pyppa.splitlines(), skipinitialspace=True)]
+    parse(csv_dicts, outfile)
+
+def parse(dict_list, outfile):
+    with open(outfile, 'w') as output:
+        writeTTLHeader(output)
+        first = True # In case something needs processing only once for the whole CSV input
+        for ii, row in enumerate(dict_list):
+            # The index ii is mainly used to limit the number of entries to process, for testing purposes
+
+            url = row['URL']
+
+            #placeHolders
+            e21placeHolder = autCoords.prefix + url
+            e62placeHolder = autCoords.prefix + url + '_E62'
+            e42placeHolder = autCoords.prefix + row['AUTH']
+            e67placeHolder = autCoords.prefix + url + '_E67'
+            e69placeHolder = autCoords.prefix + url + '_E69'
+
+            line = triple(e21placeHolder, nsCoords.prefix + 'type',
+                        cidocCoords.prefix + 'E21_Person') + closeLine
+            output.write(line)
+            
+            line = triple(e21placeHolder,
+                            nsCoords.prefix + 'type',
+                            foafCoords.prefix + 'person') + closeLine
+            output.write(line)
+            
+            if row['AUTN'] != '':
+                line = triple(e21placeHolder,
+                                foafCoords.prefix + 'name',
+                                '\"' + row['AUTN'] + '\"') + closeLine
+                output.write(line)
+
+            if row['AUTC'] != '':
+                line = triple(e21placeHolder,
+                                foafCoords.prefix + 'familyName',
+                                '\"' + row['AUTC'] + '\"') + closeLine
+                output.write(line)
+
+            if row['AUTO'] != '':
+                line = triple(e21placeHolder,
+                                foafCoords.prefix + 'givenName',
+                                '\"' + row['AUTO'] + '\"') + closeLine
+                output.write(line)
+
+            if row['AUTZ'] != '':
+                line = triple(e21placeHolder,
+                                foafCoords.prefix + 'gender',
+                                '\"' + row['AUTZ'] + '\"') + closeLine
+                output.write(line)
+
+            line = triple(e21placeHolder, rdfsCoords.prefix + 'label',
+                        '\"' + row['AUTN'] + ', ' + row['AUTA'] + '\"') + closeLine
+            output.write(line)
+
+            line = triple(e21placeHolder, cidocCoords.prefix + 'P3_has_note',
+                        e62placeHolder) + closeLine
+            output.write(line)
+
+            line = triple(e62placeHolder, nsCoords.prefix + 'type',
+                        cidocCoords.prefix + 'E62_String') + closeLine
+            output.write(line)
+            line = triple(e62placeHolder, rdfsCoords.prefix + 'label',
+                        '\"Fonte: Museo di Palazzo Pretorio - Collezione Martini\"') + closeLine
+            output.write(line)
+
+            #E21 - P1 - E42
+            line = triple(e21placeHolder, cidocCoords.prefix + 'P1_is_identified_by',
+                        e42placeHolder) + closeLine
+            output.write(line)
+            line = triple(e42placeHolder, nsCoords.prefix + 'type',
+                        cidocCoords.prefix + 'E42_Identifier') + closeLine
+            output.write(line)
+            line = triple(e42placeHolder, rdfsCoords.prefix + 'label',
+                        '\"' + row['AUTH'] + '\"') + closeLine
+            output.write(line)
+
+            # E21 - P107i - E74
+            if row['AUTU'] != '':
+                group = []
+                if '/' in row['AUTU']:
+                    group = row['AUTU'].split('/')
+                else:
+                    group.append(row['AUTU'])
+
+                for gr in group:
+                    gg = gr.replace(' ', '')
+                    e74placeHolder = museoCoords.prefix + gg
+                    line = triple(e21placeHolder,
+                                cidocCoords.prefix + 'P107i_is_current_or_former_member_of',
+                                e74placeHolder) + closeLine
+                    output.write(line)
+                    line = triple(e74placeHolder,
+                                nsCoords.prefix + 'type',
+                                cidocCoords.prefix + 'E74_Group') + closeLine
+                    output.write(line)
+                    line = triple(e74placeHolder,
+                                rdfsCoords.prefix + 'label',
+                                '\"' + row['AUTU'] + '\"') + closeLine
+                    output.write(line)
+
+            #E21 - P98i - E67
+            line = triple(e21placeHolder,
+                        cidocCoords.prefix + 'P98i_was_born',
+                        e67placeHolder) + closeLine
+            output.write(line)
+            line = triple(e67placeHolder,
+                        nsCoords.prefix + 'type',
+                        cidocCoords.prefix + 'E67_Birth') + closeLine
+            output.write(line)
+            line = triple(e67placeHolder,
+                        rdfsCoords.prefix + 'label',
+                        '\"Nascita di ' + row['AUTN'] + '\"') + closeLine
+            output.write(line)
+
+            line = triple(e21placeHolder,
+                        cidocCoords.prefix + 'P100i_died_in',
+                        e69placeHolder) + closeLine
+            output.write(line)
+            line = triple(e69placeHolder,
+                        nsCoords.prefix + 'type',
+                        cidocCoords.prefix + 'E69_Death') + closeLine
+            output.write(line)
+            line = triple(e69placeHolder,
+                        rdfsCoords.prefix + 'label',
+                        '\"Morte di ' + row['AUTN'] + '\"') + closeLine
+            output.write(line)
+
+            #E67 - P7 - E53
+            if row['AUTL'] != '':
+                line = triple(e67placeHolder,
+                            cidocCoords.prefix + 'P7_took_place_at',
+                            museoCoords.prefix + row['AUTL']) + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + row['AUTL'],
+                            nsCoords.prefix + 'type',
+                            cidocCoords.prefix + 'E53_Place') + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + row['AUTL'],
+                            rdfsCoords.prefix + 'label',
+                            '\"' + row['AUTL'] + '\"') + closeLine
+                output.write(line)
+
+            # E67 - P4 - E52
+
+            if row['AUTD'] != '':
+                tt = row['AUTD'].replace(' ', '')
+                tim = tt.replace('/', '')
+                time = tim.replace('.', '')
+                line = triple(e67placeHolder,
+                            cidocCoords.prefix + 'P4_has_time-span',
+                            museoCoords.prefix + time) + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + time,
+                            nsCoords.prefix + 'type',
+                            cidocCoords.prefix + 'E52_Time-Span') + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + time,
+                            rdfsCoords.prefix + 'label',
+                            '\"' + row['AUTD'] + '\"') + closeLine
+                output.write(line)
+
+            # E69 - P7 - E53
+            if row['AUTX'] != '':
+                line = triple(e69placeHolder,
+                            cidocCoords.prefix + 'P7_took_place_at',
+                            museoCoords.prefix + row['AUTX']) + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + row['AUTX'],
+                            nsCoords.prefix + 'type',
+                            cidocCoords.prefix + 'E53_Place') + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + row['AUTX'],
+                            rdfsCoords.prefix + 'label',
+                            '\"' + row['AUTX'] + '\"') + closeLine
+                output.write(line)
+
+            # E69 - P4 - E52
+            if row['AUTT'] != '':
+                tt = row['AUTT'].replace(' ', '')
+                tim = tt.replace('/', '')
+                time = tim.replace('.', '')
+                line = triple(e69placeHolder,
+                            cidocCoords.prefix + 'P4_has_time-span',
+                            museoCoords.prefix + time) + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + time,
+                            nsCoords.prefix + 'type',
+                            cidocCoords.prefix + 'E52_Time-Span') + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + time,
+                            rdfsCoords.prefix + 'label',
+                            '\"' + row['AUTT'] + '\"') + closeLine
+                output.write(line)
+            
+            # E21 - occupation 
+            if row['AUTQ'] != '':
+                line = triple(e21placeHolder,
+                            schemaCoords.prefix + 'hasOccupation',
+                            museoCoords.prefix + row['AUTQ']) + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + row['AUTQ'],
+                            nsCoords.prefix + 'type',
+                            schemaCoords.prefix + 'Occupation') + closeLine
+                output.write(line)
+                line = triple(museoCoords.prefix + row['AUTQ'],
+                            rdfsCoords.prefix + 'label',
+                            '\"' + row['AUTQ'] + '\"') + closeLine
+                output.write(line)
+
+            # E21 - P139 - E41
+            if row['AUTV'] != '':
+                autv = []
+                if '/' in row['AUTV']:
+                    autv = row['AUTV'].split('/')
+                else:
+                    autv.append(row['AUTV'])
+                autvplaceHolder = museoCoords.prefix + row['AUTV'].replace(' ', '-').replace('\'', '')
+                line = triple(e21placeHolder,
+                            cidocCoords.prefix + 'P139_has_alternative-form',
+                            '\"' + row['AUTV'] + '\"') + closeLine
+                output.write(line)
+
+            output.write('\n')
+            #
+            #
+            # To limit number of entries processed (if desired for testing purposes)
+            if (max_entries is not None and ii > max_entries):
+                break

+ 96 - 0
samples/parsers/CSV_to_RDF_generico_composta.py

@@ -0,0 +1,96 @@
+## IMPORTS
+
+# Utilities to read/write csv files
+import csv, json
+
+# Custom class to store URIs + related infos for the ontologies/repositories
+
+class RDFcoords:
+    def __init__(self, uri, prefix, code = None):
+        self.uri = uri
+        self.prefix = prefix
+        self.code = code
+
+
+# Repositories
+museoCoords = RDFcoords('<https://palazzopretorio.prato.it/it/le-opere/alcuni-capolavori/>', 'mpp:')
+autCoords = RDFcoords('<https://palazzopretorio.prato.it/it/opere/autori/>', 'aut:')
+foafCoords = RDFcoords('<http://xmlns.com/foaf/0.1/>', 'foaf:')
+
+cidocCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/>', 'crm:')
+aatCoords = RDFcoords('<http://vocab.getty.edu/aat/>', 'aat:')
+nsCoords = RDFcoords('<http://www.w3.org/1999/02/22-rdf-syntax-ns#>', 'rdf:')
+schemaCoords = RDFcoords('<http://www.schema.org/>', 'schema:')
+rdfsCoords = RDFcoords('<http://www.w3.org/2000/01/rdf-schema#>', 'rdfs:')
+
+
+# Basic utilities to format triples / shortened triples in TTL format
+#
+# Format full triple
+def triple(subject, predicate, object1):
+    line = subject + ' ' + predicate + ' ' + object1
+    return line
+
+# Format entry in predicate list (no subject)
+def doublet(predicate, object1):
+    line = '    ' + predicate + ' ' + object1
+    return line
+
+# Format entry in object list (object only)
+def singlet(object1):
+    line = '        ' + object1
+    return line
+
+# Line endings
+continueLine1 = ' ;\n' # Before a predicate list, that is if the FOLLOWING triple has the same subject
+continueLine2 = ' ,\n' # Before an object list, that is if the FOLLOWING triple has the same subject and predicate
+closeLine = ' .\n' # To end a triple / a triples block
+
+
+def writeTTLHeader(output):
+    output.write('@prefix ' + museoCoords.prefix + ' ' + museoCoords.uri + closeLine)
+    output.write('@prefix ' + foafCoords.prefix + ' ' + foafCoords.uri + closeLine)
+    output.write('@prefix ' + autCoords.prefix + ' ' + autCoords.uri + closeLine)
+    output.write('@prefix ' + cidocCoords.prefix + ' ' + cidocCoords.uri + closeLine)
+    output.write('@prefix ' + aatCoords.prefix + ' ' + aatCoords.uri + closeLine)
+    output.write('@prefix ' + schemaCoords.prefix + ' ' + schemaCoords.uri + closeLine)
+    output.write('@prefix ' + nsCoords.prefix + ' ' + nsCoords.uri + closeLine)
+    output.write('@prefix ' + rdfsCoords.prefix + ' ' + rdfsCoords.uri + closeLine)
+    output.write('\n')
+
+max_entries = None
+
+def parsefromfile(mapfilename, infile, outfilename):
+    inputFile = infile.decode()
+    csv_dicts = [{k: v for k, v in row.items()} for row in csv.DictReader(inputFile.splitlines(), skipinitialspace=True)]
+    with open (mapfilename) as mapfile:
+        json_dicts = json.load(mapfile)
+        parse(json_dicts, csv_dicts, outfilename)
+
+
+def parse(json_dicts, csv_dicts, outfilename):
+    with open(outfilename, 'w') as outputfile:
+        writeTTLHeader(outputfile)
+        first = True # In case something needs processing only once for the whole CSV input
+        for ii, csvrow in enumerate(csv_dicts):
+            # The index ii is mainly used to limit the number of entries to process, for testing purposes
+            for jj, node in enumerate(json_dicts):
+                csvvalue = csvrow[node["colonna"]]
+                line = triple(node["uri"].replace('$VALORE_CSV$', csvvalue), nsCoords.prefix + 'type', node["tipo"]) + closeLine
+                outputfile.write(line)
+                if node["sottoelementodi"] != '':
+                    parent = next (filter(lambda el: el["identificatore"]==node["sottoelementodi"], json_dicts), None)
+                    if parent is not None:
+                        subject = parent["uri"].replace('$VALORE_CSV$', parent["colonna"])
+                        property = node["relazione"]
+                        object = node["uri"].replace('$VALORE_CSV$', csvvalue)
+                        line = triple(subject, property,
+                        object) + closeLine
+                        outputfile.write(line)
+         
+                outputfile.write('\n')
+            #
+            #
+            # To limit number of entries processed (if desired for testing purposes)
+            if (max_entries is not None and ii > max_entries): 
+                break

+ 418 - 0
samples/parsers/CSV_to_RDF_onomastica_ospedale_person.py

@@ -0,0 +1,418 @@
+#Parser to convert the Datini onomastics CSV file into TTL format
+
+# Utilities to read/write csv files
+import csv
+# Utilities to handle character encodings
+import unicodedata
+# Ordered Dicts
+from collections import OrderedDict
+
+import json
+import re
+
+
+# OPZIONAL IMPORTS
+
+# For timestamping/simple speed tests
+from datetime import datetime
+# Random number generator
+from random import *
+# System & command line utilities
+import sys
+# Json for the dictionary
+import json
+
+import_dir = 'CSV/'
+export_dir = 'RDF/'
+
+# Custom class to store URIs + related infos for the ontologies/repositories
+
+class RDFcoords:
+    def __init__(self, uri, prefix, code = None):
+        self.uri = uri
+        self.prefix = prefix
+        self.code = code
+
+# Repositories
+aspoCoords = RDFcoords('<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/>', 'aspo:')
+foafCoords = RDFcoords('<http://xmlns.com/foaf/0.1/>', 'foaf:')
+cidocCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/>', 'crm:')
+schemaCoords = RDFcoords('<http://schema.org/>', 'schema:')
+personCoords = RDFcoords('<http://www.w3.org/ns/person#>', 'person:')
+nsCoords = RDFcoords('<http://www.w3.org/1999/02/22-rdf-syntax-ns#>', 'rdf:')
+rdfsCoords = RDFcoords('<http://www.w3.org/2000/01/rdf-schema#>', 'rdfs:')
+owlCoords = RDFcoords('<http://www.w3.org/2002/07/owl#>', 'owl:')
+
+# Basic functions for triples / shortened triples in TTL format
+
+def triple(subject, predicate, object1):
+    line = subject + ' ' + predicate + ' ' + object1
+    return line
+
+def doublet(predicate, object1):
+    line = '    ' + predicate + ' ' + object1
+    return line
+
+def singlet(object1):
+    line = '        ' + object1
+    return line
+
+# Line endings in TTL format
+continueLine1 = ' ;\n'
+continueLine2 = ' ,\n'
+closeLine = ' .\n'
+
+def writeTTLHeader(output):
+    output.write('@prefix ' + aspoCoords.prefix + ' ' + aspoCoords.uri + closeLine)
+    output.write('@prefix ' + foafCoords.prefix + ' ' + foafCoords.uri + closeLine)
+    output.write('@prefix ' + cidocCoords.prefix + ' ' + cidocCoords.uri + closeLine)
+    output.write('@prefix ' + personCoords.prefix + ' ' + personCoords.uri + closeLine)
+    output.write('@prefix ' + schemaCoords.prefix + ' ' + schemaCoords.uri + closeLine)
+    output.write('@prefix ' + nsCoords.prefix + ' ' + nsCoords.uri + closeLine)
+    output.write('@prefix ' + rdfsCoords.prefix + ' ' + rdfsCoords.uri + closeLine)
+    output.write('@prefix ' + owlCoords.prefix + ' ' + owlCoords.uri + closeLine)
+    output.write('\n')
+
+
+filePrefix = 'OSPEDALE-onomastica'
+fileType = '-persone-singole'
+max_entries = 10000000000000
+
+with open(import_dir + filePrefix + fileType + '.csv', newline="") as csv_file, open(
+        export_dir + filePrefix + fileType + '.ttl', 'w') as output:
+    reader = csv.DictReader(csv_file)
+    writeTTLHeader(output)
+    first = True
+    ii = 0
+    for row in reader:
+        # The index ii is used to process a limited number of entries for testing purposes
+        ii = ii + 1
+        if row['entityType'] == 'person':
+
+            id_aspo = row['recordId']
+            #placeHolders
+            aspoPlaceHolder = aspoCoords.prefix + id_aspo
+            line = triple(aspoPlaceHolder, 
+                          nsCoords.prefix + 'type', 
+                          cidocCoords.prefix + 'E21_Person') + closeLine
+            output.write(line)
+
+            line = triple(aspoPlaceHolder, 
+                          nsCoords.prefix + 'type', 
+                          personCoords.prefix + 'Person') + closeLine
+            output.write(line)
+
+            line = triple(aspoPlaceHolder,
+                          nsCoords.prefix + 'type',
+                          foafCoords.prefix + 'person') + closeLine
+            output.write(line)
+
+            line = triple(aspoPlaceHolder,
+                          cidocCoords.prefix + 'P1_is_identified_by',
+                          aspoPlaceHolder + "_E42") + closeLine
+            output.write(line)
+
+            line = triple(aspoPlaceHolder + "_E42",
+                          nsCoords.prefix + 'type',
+                          cidocCoords.prefix + 'E42_Identifier') + closeLine
+            output.write(line)
+            line = triple(aspoPlaceHolder + "_E42",
+                          rdfsCoords.prefix + 'label',
+                          '\"' + id_aspo + '\"') + closeLine
+            output.write(line)
+
+            line = triple(aspoPlaceHolder,
+                          foafCoords.prefix + 'name',
+                          '\"' + row['nameEntry@normal'] + '\"') + closeLine
+            output.write(line)
+
+            line = triple(aspoPlaceHolder,
+                          rdfsCoords.prefix + 'label',
+                          '\"' + row['nameEntry@normal'] + '\"') + closeLine
+            output.write(line)
+
+            if row['nome proprio'] != '':
+                #Remove all white-space characters:
+                txt = row['nome proprio']
+                x = re.sub(" \n", "", txt)
+                y = re.sub("\s\s", "", x)
+                name = re.sub("\n", "", y)
+                line = triple(aspoPlaceHolder,
+                              foafCoords.prefix + 'givenName',
+                              '\"' + name + '\"') + closeLine
+                output.write(line)
+
+            if row['nome di famiglia'] != '':
+                #Remove all white-space characters:
+                txt = row['nome di famiglia']
+                x = re.sub("\n", " ", txt)
+                y = re.sub("\s\s", "", x)
+                line = triple(aspoPlaceHolder,
+                              foafCoords.prefix + 'familyName',
+                              '\"' + y + '\"') + closeLine
+                output.write(line)
+            
+            if row['Alias'] != '' and row['Alias'] != ' ':
+                #Remove all white-space characters:
+                txt = row['Alias']
+                x = re.sub("\n", " ", txt)
+                y = re.sub("\s\s", "", x)
+                line = triple(aspoPlaceHolder,
+                              schemaCoords.prefix + 'alternateName',
+                              '\"' + y + '\"') + closeLine
+                output.write(line)
+
+            if row['genere'] != '':
+                #Remove all white-space characters:
+                txt = row['genere']
+                x = re.sub("\n", " ", txt)
+                y = re.sub("\s\s", "", x)
+                line = triple(aspoPlaceHolder,
+                              foafCoords.prefix + 'gender',
+                              '\"' + y + '\"') + closeLine
+                output.write(line)
+
+            if row['patronimico/matronimico'] != '':
+                #Remove all white-space characters:
+                txt = row['patronimico/matronimico']
+                x = re.sub("\n", " ", txt)
+                y = re.sub("\s\s", "", x)
+                line = triple(aspoPlaceHolder,
+                              personCoords.prefix + 'patronymicName',
+                              '\"' + y + '\"') + closeLine
+                output.write(line)
+
+            if (row['avo 1'] != ''):
+                id = row['avo 1']
+                E13placeHolder = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['avo 1'].replace(' ', '_') + '_AVO1_' + row['recordId'] + ">"
+                line = triple(E13placeHolder, 
+                nsCoords.prefix + 'type', 
+                cidocCoords.prefix + 'E13_Attribute_Assignment') + closeLine
+                output.write(line)
+                line = triple(E13placeHolder, cidocCoords.prefix + 'P141_assigned', aspoPlaceHolder) + closeLine
+                output.write(line)
+                line = triple(E13placeHolder,
+                                    rdfsCoords.prefix + 'label',
+                                    '\"Relazione: ' + row['avo 1'] + ' avo di secondo grado di ' + row['recordId'] + '\"') + closeLine
+                output.write(line)
+                if re.match(r'IT-ASPO', id):
+                    relazioneid = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['avo 1']+ ">"
+                    line = triple(relazioneid, cidocCoords.prefix + 'P141_assigned', E13placeHolder) + closeLine
+                    output.write(line)
+                else:
+                    relazionenoid = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['avo 1'].replace(' ', '_').lower()+ ">"
+                    line = triple(relazionenoid, cidocCoords.prefix + 'P141_assigned', E13placeHolder ) + closeLine
+                    output.write(line)
+                    line = triple(relazionenoid,
+                                    rdfsCoords.prefix + 'label',
+                                    '\"' + row['avo 1'] + '\"') + closeLine
+                    output.write(line)
+                    line = triple(relazionenoid, 
+                          nsCoords.prefix + 'type', 
+                          cidocCoords.prefix + 'E21_Person') + closeLine
+                    output.write(line)
+
+                    line = triple(relazionenoid, 
+                                nsCoords.prefix + 'type', 
+                                personCoords.prefix + 'Person') + closeLine
+                    output.write(line)
+
+                    line = triple(relazionenoid,
+                                nsCoords.prefix + 'type',
+                                foafCoords.prefix + 'person') + closeLine
+                    output.write(line)
+                E55placeHolder = '<http://www.archiviodistato.prato.it/avo_secondo_grado>'
+                line = triple(E13placeHolder, cidocCoords.prefix + 'P42_assigned', E55placeHolder) + closeLine
+                output.write(line)
+                line = triple(E55placeHolder,
+                                            rdfsCoords.prefix + 'label',
+                                            '\"Avo di secondo grado\"') + closeLine
+                output.write(line)      
+
+            if (row['avo 2'] != ''):
+                id = row['avo 2']
+                E13placeHolder = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['avo 2'].replace(' ', '_') + '_AVO2_' + row['recordId'] + ">"
+                line = triple(E13placeHolder, 
+                nsCoords.prefix + 'type', 
+                cidocCoords.prefix + 'E13_Attribute_Assignment') + closeLine
+                output.write(line)
+                line = triple(E13placeHolder, cidocCoords.prefix + 'P141_assigned', aspoPlaceHolder) + closeLine
+                output.write(line)
+                line = triple(E13placeHolder,
+                                    rdfsCoords.prefix + 'label',
+                                    '\"Relazione: ' + row['avo 2'] + ' avo di terzo grado di ' + row['recordId'] + '\"') + closeLine
+                output.write(line)
+                if re.match(r'IT-ASPO', id):
+                    relazioneid = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['avo 2']+ ">"
+                    line = triple(relazioneid, cidocCoords.prefix + 'P141_assigned', E13placeHolder) + closeLine
+                    output.write(line)
+                else:
+                    relazionenoid = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['avo 2'].replace(' ', '_').lower()+ ">"
+                    line = triple(relazionenoid, cidocCoords.prefix + 'P141_assigned', E13placeHolder ) + closeLine
+                    output.write(line)
+                    line = triple(relazionenoid,
+                                    rdfsCoords.prefix + 'label',
+                                    '\"' + row['avo 2'] + '\"') + closeLine
+                    output.write(line)
+                    line = triple(relazionenoid, 
+                          nsCoords.prefix + 'type', 
+                          cidocCoords.prefix + 'E21_Person') + closeLine
+                    output.write(line)
+
+                    line = triple(relazionenoid, 
+                                nsCoords.prefix + 'type', 
+                                personCoords.prefix + 'Person') + closeLine
+                    output.write(line)
+
+                    line = triple(relazionenoid,
+                                nsCoords.prefix + 'type',
+                                foafCoords.prefix + 'person') + closeLine
+                    output.write(line)
+                E55placeHolder = '<http://www.archiviodistato.prato.it/avo_terzo_grado>'
+                line = triple(E13placeHolder, cidocCoords.prefix + 'P42_assigned', E55placeHolder) + closeLine
+                output.write(line)
+                line = triple(E55placeHolder,
+                                            rdfsCoords.prefix + 'label',
+                                            '\"Avo di terzo grado\"') + closeLine
+                output.write(line)      
+
+            if row['Qualifica'] != '':
+                qualifiche = []
+                pipe = "|"
+                if pipe in row['Qualifica']:
+                    qualifiche = row['Qualifica'].split('|') 
+                    for qualifica in qualifiche:
+                        #Remove all white-space characters:
+                        txt = qualifica
+                        x = re.sub("\n", " ", txt)
+                        y = re.sub("\s\s", " ", x)
+                        line = triple(aspoPlaceHolder, schemaCoords.prefix + 'honorificPrefix', '\"' + str(y) + '\"') + closeLine
+                        output.write(line)
+                else:
+                #Remove all white-space characters:
+                    txt = row['Qualifica']
+                    x = re.sub("\n", " ", txt)
+                    y = re.sub("\s\s", " ", x)
+                    line = triple(aspoPlaceHolder, schemaCoords.prefix + 'honorificPrefix', '\"' + y + '\"') + closeLine
+                    output.write(line)
+
+            if row['biogHist p'] != '':
+                #Remove all white-space characters:
+                txt = row['biogHist p']
+                x = re.sub("\n", " ", txt)
+                y = re.sub("\s\s", " ", x)
+                note = re.sub("\"", "", x)
+                line = triple(aspoPlaceHolder,
+                              cidocCoords.prefix + 'P3_has_note',
+                              '\"' + note + '\"') + closeLine
+                output.write(line)
+            
+            if row['Variante'] != '': 
+                varianti = []
+                pipe = "|"
+                if pipe in row['Variante']:
+                    varianti = row['Variante'].split('|')
+                    for variante in varianti: 
+                        line = triple(aspoPlaceHolder,
+                        owlCoords.prefix + 'sameAs',
+                        aspoCoords.prefix + str(variante)) + closeLine
+                        output.write(line)
+                else:
+                    line = triple(aspoPlaceHolder,
+                    owlCoords.prefix + 'sameAs',
+                    aspoCoords.prefix + row['Variante']) + closeLine
+                    output.write(line)
+
+            if row['provenienza'] != '': 
+                e53placeHolder = "<http://www.archiviodistato.prato.it/" + row['provenienza'].replace('da', '').replace(' ', '') + ">"
+                line = triple(aspoPlaceHolder, 
+                                cidocCoords.prefix + 'P74_has_current_or_former_residence',
+                                e53placeHolder) + closeLine
+                output.write(line)
+                line = triple(e53placeHolder,
+                          nsCoords.prefix + 'type',
+                          cidocCoords.prefix + 'E53_Place') + closeLine
+                output.write(line)
+                line = triple(e53placeHolder,
+                            rdfsCoords.prefix + 'label',
+                            '\"' + row['provenienza'] + '\"') + closeLine
+                output.write(line)
+                line = triple(e53placeHolder,
+                          cidocCoords.prefix + 'P2_has_type',
+                          '\"Provenienza\"') + closeLine
+                output.write(line)
+
+            if (row['recordID relazione'] != ''):
+                id = row['recordID relazione']
+                E13placeHolder = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['recordID relazione'].replace(' ', '_') + '_R_' + row['recordId'] + ">"
+                line = triple(E13placeHolder, 
+                nsCoords.prefix + 'type', 
+                cidocCoords.prefix + 'E13_Attribute_Assignment') + closeLine
+                output.write(line)
+                line = triple(E13placeHolder, cidocCoords.prefix + 'P141_assigned', aspoPlaceHolder) + closeLine
+                output.write(line)
+                line = triple(E13placeHolder,
+                                    rdfsCoords.prefix + 'label',
+                                    '\"Relazione: ' + row['recordID relazione'] + row['nome relazione'] + ' di ' + row['recordId'] + '\"') + closeLine
+                output.write(line)
+                if re.match(r'IT-ASPO', id):
+                    relazioneid = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['recordID relazione']+ ">"
+                    line = triple(relazioneid, cidocCoords.prefix + 'P141_assigned', E13placeHolder) + closeLine
+                    output.write(line)
+                else:
+                    relazionenoid = '<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/' + row['recordID relazione'].replace(' ', '_').lower()+ ">"
+                    line = triple(relazionenoid, cidocCoords.prefix + 'P141_assigned', E13placeHolder) + closeLine
+                    output.write(line)
+                    line = triple(relazionenoid,
+                                    rdfsCoords.prefix + 'label',
+                                    '\"' + row['recordID relazione'] + '\"') + closeLine
+                    output.write(line)
+                    line = triple(relazionenoid, 
+                          nsCoords.prefix + 'type', 
+                          cidocCoords.prefix + 'E21_Person') + closeLine
+                    output.write(line)
+
+                    line = triple(relazionenoid, 
+                                nsCoords.prefix + 'type', 
+                                personCoords.prefix + 'Person') + closeLine
+                    output.write(line)
+
+                    line = triple(relazionenoid,
+                                nsCoords.prefix + 'type',
+                                foafCoords.prefix + 'person') + closeLine
+                    output.write(line)
+                if (row['nome relazione'] != ''):
+                        relazioni = []
+                        pipe = "|" 
+                        if pipe in row['nome relazione']:
+                            relazioni = row['nome relazione'].split('|') 
+                            for relazione in relazioni:
+                                #Remove all white-space characters:
+                                txt = relazione
+                                x = re.sub("\n", " ", txt)
+                                y = re.sub("\s\s", "", x)
+                                rel = re.sub(r'[^A-Za-z]','', y)
+                                cleanlabel = rel.rstrip().lstrip()
+                                E55placeHolder = '<http://www.archiviodistato.prato.it/relation_' + cleanlabel.replace(" ","") + '>'
+                                line = triple(E13placeHolder, cidocCoords.prefix + 'P42_assigned', E55placeHolder) + closeLine
+                                output.write(line)
+                                line = triple(E55placeHolder,
+                                            rdfsCoords.prefix + 'label',
+                                            '\"' + cleanlabel + '\"') + closeLine
+                                output.write(line)
+                        else:
+                            E55placeHolder = '<http://www.archiviodistato.prato.it/relation_' + cleanlabel.replace(' ', '') + '>'
+                            line = triple(E13placeHolder, cidocCoords.prefix + 'P42_assigned', E55placeHolder) + closeLine
+                            output.write(line)
+                            cleanlabel = row['nome relazione'].rstrip().lstrip()
+                            line = triple(E55placeHolder,
+                                        rdfsCoords.prefix + 'label',
+                                        '\"' + cleanlabel + '\"') + closeLine
+                            output.write(line)
+                            
+        output.write('\n')
+        #
+        #
+        # Limit number of entries processed (if desired)
+        if (ii > max_entries):
+            break

+ 258 - 0
samples/parsers/CSV_to_RDF_ovi_edition.ipynb

@@ -0,0 +1,258 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Utilities to read/write csv files\n",
+    "import csv\n",
+    "import unicodedata\n",
+    "# Ordered Dicts\n",
+    "from collections import OrderedDict\n",
+    "import json\n",
+    "\n",
+    "\n",
+    "# OPZIONAL IMPORTS\n",
+    "\n",
+    "# For timestamping/simple speed tests\n",
+    "from datetime import datetime\n",
+    "# Random number generator\n",
+    "from random import *\n",
+    "# System & command line utilities\n",
+    "import sys\n",
+    "# Json for the dictionary\n",
+    "import json"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import_dir = '../CSV/'\n",
+    "export_dir = '../RDF/'"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Custom class to store URIs + related infos for the ontologies/repositories\n",
+    "\n",
+    "class RDFcoords:\n",
+    "    def __init__(self, uri, prefix, code = None):\n",
+    "        self.uri = uri\n",
+    "        self.prefix = prefix\n",
+    "        self.code = code\n",
+    "\n",
+    "\n",
+    "# Repositories\n",
+    "datiniCoords = RDFcoords('<http://datini.archiviodistato.prato.it/la-ricerca/scheda/>', 'dt:')\n",
+    "personAuthCoords = RDFcoords('<http://www.archiviodistato.prato.it/accedi-e-consulta/aspoMV001/scheda/IT-ASPO-AU00003->', 'pa:')\n",
+    "# W3/CIDOC Predicates\n",
+    "hasTypeCoords = RDFcoords('<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>', 'tp:')\n",
+    "hasTypePCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P2_has_type>', 'te:')\n",
+    "carriesCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P128_carries>', 'ca:')\n",
+    "identifiedByCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P1_is_identified_by>', 'ib:')\n",
+    "labelCoords = RDFcoords('<http://www.w3.org/2000/01/rdf-schema#label>', 'lb:')\n",
+    "wasBroughtCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P92i_was_brought_into_existence_by>', 'wb:')\n",
+    "carriedByCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P14_carried_out_by>', 'cb:')\n",
+    "hasAlternativeFormCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P139_has_alternative_form>', 'af:')\n",
+    "hasNoteCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P3_has_note>', 'no:')\n",
+    "hasTypeNCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P3.1_has_type>', 'tn:')\n",
+    "hasLanguageCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P72_has_language>', 'hl:')\n",
+    "documentsCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P70_documents>', 'ds:')\n",
+    "hasComponentCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/P148_has_component>', 'hc:')\n",
+    "\n",
+    "# CIDOC Objects\n",
+    "manMadeObjectCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E22_Man-Made_Object>', 'mo:', 'E22')\n",
+    "informationObjectCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E73_Information_Object>', 'io:', 'E73')\n",
+    "titleCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E35_Title>', 'ti:' ,'E35')\n",
+    "placeAppellationCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E44_Place_appellation>', 'pa:', 'E44')\n",
+    "identifierCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E42_Identifier>', 'id:', 'E42')\n",
+    "typeCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E55_Type>', 'ty:', 'E55')\n",
+    "creationCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E65_Creation>', 'cr:', 'E65')\n",
+    "personCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E21_Person>', 'ps:', 'E21')\n",
+    "stringCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E62_String>', 'sr:', 'E62')\n",
+    "linguisticObjCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E33_Linguistic_Object>', 'lj:', 'E33')\n",
+    "languageCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E56_Language>', 'ln:', 'E56')\n",
+    "appellationCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E41_appellation>', 'ap:', 'E41')\n",
+    "propositionalObjCoords = RDFcoords('<http://www.cidoc-crm.org/cidoc-crm/E89_Propositional_Object>', 'pj:', 'E89')\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Basic functions for triples / shortened triples in TTL format\n",
+    "\n",
+    "def triple(subject, predicate, object1):\n",
+    "    line = subject + ' ' + predicate + ' ' + object1\n",
+    "    return line\n",
+    "\n",
+    "def doublet(predicate, object1):\n",
+    "    line = '    ' + predicate + ' ' + object1\n",
+    "    return line\n",
+    "\n",
+    "def singlet(object1):\n",
+    "    line = '        ' + object1\n",
+    "    return line\n",
+    "\n",
+    "# Line endings in TTL format\n",
+    "continueLine1 = ' ;\\n'\n",
+    "continueLine2 = ' ,\\n'\n",
+    "closeLine = ' .\\n'"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def writeTTLHeader(output):\n",
+    "    output.write('@prefix ' + datiniCoords.prefix + ' ' + datiniCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + personAuthCoords.prefix + ' ' + personAuthCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + hasTypeCoords.prefix + ' ' + hasTypeCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + hasTypePCoords.prefix + ' ' + hasTypePCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + manMadeObjectCoords.prefix + ' ' + manMadeObjectCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + carriesCoords.prefix + ' ' + carriesCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + informationObjectCoords.prefix + ' ' + informationObjectCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + identifiedByCoords.prefix + ' ' + identifiedByCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + titleCoords.prefix + ' ' + titleCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + labelCoords.prefix + ' ' + labelCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + identifierCoords.prefix + ' ' + identifierCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + wasBroughtCoords.prefix + ' ' + wasBroughtCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + typeCoords.prefix + ' ' + typeCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + carriedByCoords.prefix + ' ' + carriedByCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + personCoords.prefix + ' ' + personCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + hasAlternativeFormCoords.prefix + ' ' + hasAlternativeFormCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + hasNoteCoords.prefix + ' ' + hasNoteCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + hasTypeNCoords.prefix + ' ' + hasTypeNCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + stringCoords.prefix + ' ' + stringCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + linguisticObjCoords.prefix + ' ' + linguisticObjCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + languageCoords.prefix + ' ' + languageCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + hasLanguageCoords.prefix + ' ' + hasLanguageCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + documentsCoords.prefix + ' ' + documentsCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + appellationCoords.prefix + ' ' + appellationCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + propositionalObjCoords.prefix + ' ' + propositionalObjCoords.uri + closeLine)\n",
+    "    output.write('@prefix ' + hasComponentCoords.prefix + ' ' + hasComponentCoords.uri + closeLine)\n",
+    "    output.write('\\n')\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "filePrefix = 'Biblio'\n",
+    "fileType = 'Datini'\n",
+    "max_entries = 10000\n",
+    "\n",
+    "with open(import_dir + filePrefix + fileType + '_IDAspo.csv', newline=\"\") as csv_file, open(export_dir + filePrefix + fileType + '_edition.ttl', 'w') as output:\n",
+    "    reader = csv.DictReader(csv_file)\n",
+    "    writeTTLHeader(output)\n",
+    "    first = True\n",
+    "    ii = 0\n",
+    "    for row in reader:\n",
+    "        # The index ii is used to process a limited number of entries for testing purposes\n",
+    "        ii = ii+0\n",
+    "        # Skip the first line as it carries info we don't want to triplify\n",
+    "        if(first):\n",
+    "            first = False\n",
+    "            continue\n",
+    "        \n",
+    "        if(row['num_ovi'] != '2'):\n",
+    "            e73placeHolder = \"<http://datini.archiviodistato.prato.it/la-ricerca/scheda/\" + row['id'] + \"/\" + informationObjectCoords.code + \"_OVI\"\n",
+    "        else: \n",
+    "            e73placeHolder = \"<http://datini.archiviodistato.prato.it/la-ricerca/scheda/\" + row['id'] + \"/\" + informationObjectCoords.code + \"_OVI_2\"\n",
+    "\n",
+    "        #edizione\n",
+    "        e73placeHolderE = e73placeHolder + \"_ED>\"            \n",
+    "        line = triple(e73placeHolderE, documentsCoords.prefix, e73placeHolder + \">\") + closeLine\n",
+    "        output.write(line)\n",
+    "        line = triple(e73placeHolderE, labelCoords.prefix, '\\\"Edizione\\\"') + closeLine\n",
+    "        output.write(line)\n",
+    "        e41placeHolder = e73placeHolder + \"_ED\" + \"_\" + appellationCoords.code + \">\"\n",
+    "        line = triple(e73placeHolderE , identifiedByCoords.prefix, e41placeHolder) + closeLine\n",
+    "        output.write(line)\n",
+    "        line = triple(e41placeHolder, hasTypeCoords.prefix, appellationCoords.prefix) + closeLine\n",
+    "        output.write(line)            \n",
+    "        line = triple(e41placeHolder, labelCoords.prefix, '\\\"'  + row['edizione'].replace('\\\\','\\\\\\\\').replace('\"','\\\\\"') + '\\\"') + closeLine\n",
+    "        output.write(line)\n",
+    "\n",
+    "        #edizione abbreviata\n",
+    "        e41placeHolder2 = e73placeHolder + \"_ED_AB>\"\n",
+    "        line = triple(e41placeHolder, hasAlternativeFormCoords.prefix, e41placeHolder2) + closeLine\n",
+    "        output.write(line)\n",
+    "        line = triple(e41placeHolder2, labelCoords.prefix, '\\\"' + row['edizione_abbr'].replace('\\\\','\\\\\\\\').replace('\"','\\\\\"') + '\\\"') + closeLine\n",
+    "        output.write(line)\n",
+    "        e41e55placeHolder2 = e73placeHolder + \"_ED_AB_E55>\"\n",
+    "        line = triple(e41placeHolder2, hasTypePCoords.prefix, e41e55placeHolder2) + closeLine\n",
+    "        output.write(line)\n",
+    "        line = triple(e41e55placeHolder2, labelCoords.prefix, '\\\"Edizione abbreviata\\\"') + closeLine\n",
+    "        output.write(line)\n",
+    "\n",
+    "        #raccolta\n",
+    "        e89placeHolder = e73placeHolder + \"_\" + propositionalObjCoords.code + \">\"\n",
+    "        line = triple(e89placeHolder, hasComponentCoords.prefix, e73placeHolder+ \">\") + closeLine\n",
+    "        output.write(line)\n",
+    "        line = triple(e89placeHolder, hasTypeCoords.prefix, propositionalObjCoords.prefix) + closeLine\n",
+    "        output.write(line)  \n",
+    "        line = triple(e89placeHolder, labelCoords.prefix, '\\\"' + row['raccolta'].replace('\\\\','\\\\\\\\').replace('\"','\\\\\"') + '\\\"') + closeLine\n",
+    "        output.write(line)\n",
+    "        e89e55placeHolder = e73placeHolder + \"_\" + propositionalObjCoords.code + \"_E55>\"\n",
+    "        line = triple(e89placeHolder, hasTypePCoords.prefix, e89e55placeHolder) + closeLine\n",
+    "        output.write(line)\n",
+    "        line = triple(e89e55placeHolder, labelCoords.prefix, '\\\"Raccolta\\\"') + closeLine\n",
+    "        output.write(line)\n",
+    "\n",
+    "        output.write('\\n')\n",
+    "\n",
+    "\n",
+    "        # Limit number of entries processed (if desired)\n",
+    "        if(ii>max_entries):\n",
+    "            break\n",
+    "        "
+   ]
+  }
+ ],
+ "metadata": {
+  "interpreter": {
+   "hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49"
+  },
+  "kernelspec": {
+   "display_name": "Python 3.9.0 64-bit",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.10.4"
+  },
+  "metadata": {
+   "interpreter": {
+    "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
+   }
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}

+ 9 - 0
templates/error.html

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<body>
+<form method="POST">
+Un mi sembra tu m'abbia dato dati...<br/>
+<input type="submit" value="Artonna">
+</form>
+</body>
+</html>

+ 30 - 0
templates/index.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<body>
+<h1>PARSER: da CSV a RDF</h1>
+  <form method="POST" enctype = "multipart/form-data">
+    <div>
+      Carica un file CSV:
+      <fieldset>
+        <input type="file" id="FILE" name="FILE"><br/><br/>
+      </fieldset>
+      <input type="submit" value="ALO'">
+    </div>
+    <div>
+      ... oppure inserisci manualmente i dati di un record:
+      <fieldset>
+        <legend>Record:</legend>
+        {% for entry in data: %}
+          <label for="nome">{{entry}}</label><br>
+          <input type="text" id="{{entry}}" name="{{entry}}" placeholder="data"><br><br>
+        {% endfor %}
+      </fieldset>
+    </div>
+  </form>
+
+<p>Quande pigi "alò", questa robina di qualità trasforma l'in-put direttamente in RDF (TTL) passando dal parser!</p>
+<p>(Se viene uplodato un CSV poco bòno, questo sofisticato codice stianta)</p>
+
+
+</body>
+</html>

+ 10 - 0
templates/provina.html

@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<h1>File upload button example</h1>
+<p>Click on the "Choose File" button to upload a file:</p>
+<form>
+<input type="file" id="FILE" name="filename">
+</form>
+</body>
+</html>