def export_csv(dir, overwrite_existing, template): dir = Path(dir) export = DocumentExport(UserTemplate.load(template) if template else DWC) for p in dir.glob('*' + InselectDocument.EXTENSION): try: debug_print('Loading [{0}]'.format(p)) doc = InselectDocument.load(p) validation = export.validation_problems(doc) csv_path = export.csv_path(doc) if validation.any_problems: print( 'Not exporting metadata for [{0}] because there are ' 'validation problems'.format(p) ) for msg in format_validation_problems(validation): print(msg) elif not overwrite_existing and csv_path.is_file(): print('CSV file [{0}] exists - skipping'.format(csv_path)) else: print('Writing CSV for [{0}]'.format(p)) export.export_csv(doc) except KeyboardInterrupt: raise except Exception: print('Error saving CSV from [{0}]'.format(p)) traceback.print_exc()
def save_crops(dir, overwrite_existing, template): dir = Path(dir) export = DocumentExport(UserTemplate.load(template) if template else DWC) for p in dir.glob('*' + InselectDocument.EXTENSION): try: debug_print('Loading [{0}]'.format(p)) doc = InselectDocument.load(p) validation = export.validation_problems(doc) if validation.any_problems: print( u'Not saving crops for [{0}] because there are validation ' u'problems'.format(p) ) for msg in format_validation_problems(validation): print(msg) elif not overwrite_existing and doc.crops_dir.is_dir(): print(u'Crops dir [{0}] exists - skipping'.format(doc.crops_dir)) else: print(u'Will save crops for [{0}] to [{1}]'.format(p, doc.crops_dir)) debug_print(u'Loading full-resolution scanned image') doc.scanned.array debug_print(u'Saving crops') export.save_crops(doc) except Exception: print(u'Error saving crops from [{0}]'.format(p)) traceback.print_exc()
def test_export_csv_invalid_document(self, mock_question, mock_setdetailed, mock_settext): """The user wants to export to CSV for a document with a single validation failure """ w = self.window w.open_document(path=TESTDATA / 'shapes.inselect') template = UserTemplate({ 'Name': 'T1', 'Fields': [{'Name': 'F1'}], 'Cropped file suffix': '.jpg', 'Thumbnail width pixels': 5000, 'Object label': '{catalogNumber}', }) # Set the catalogNumber for each box to the same value, creating a # single validation problem for index in (w.model.index(row, 0) for row in range(5)): w.model.setData(index, {'catalogNumber': '1234'}, MetadataRole) w.export_csv(user_template=template) # Close the document with patch.object(QMessageBox, 'question', return_value=QMessageBox.No): self.assertTrue(self.window.close_document()) # Should have been called self.assertEqual(1, mock_settext.call_count) self.assertIn('The document contains 1 validation problems', mock_settext.call_args[0][0]) # Detailed text should not have been given self.assertEqual(0, mock_setdetailed.call_count)
def save_crops(dir, overwrite_existing, template): dir = Path(dir) export = DocumentExport(UserTemplate.load(template) if template else DWC) for p in dir.glob('*' + InselectDocument.EXTENSION): try: debug_print('Loading [{0}]'.format(p)) doc = InselectDocument.load(p) validation = export.validation_problems(doc) if validation.any_problems: print( 'Not saving crops for [{0}] because there are validation ' 'problems'.format(p) ) for msg in format_validation_problems(validation): print(msg) elif not overwrite_existing and doc.crops_dir.is_dir(): print('Crops dir [{0}] exists - skipping'.format(doc.crops_dir)) else: print('Will save crops for [{0}] to [{1}]'.format(p, doc.crops_dir)) debug_print('Loading full-resolution scanned image') doc.scanned.array debug_print('Saving crops') export.save_crops(doc) except KeyboardInterrupt: raise except Exception: print('Error saving crops from [{0}]'.format(p)) traceback.print_exc()
class TestCropFnameCollision(unittest.TestCase): TEMPLATE = UserTemplate({ 'Name': 'Test', 'Cropped file suffix': '.png', 'Thumbnail width pixels': 4096, 'Object label': '{scientificName}', 'Fields': [{ 'Name': 'scientificName' }] }) def test_fname_collison(self): "Duplicated crop fnames have numerical suffixes to avoid collisions" class FakeDocument(object): pass document = FakeDocument() document.items = [{ "fields": { "scientificName": "A" }, }, { "fields": { "scientificName": "A" }, }, { "fields": { "scientificName": "A" }, }, { "fields": { "scientificName": "D" }, }, { "fields": { "scientificName": "B" }, }, { "fields": { "scientificName": "D" }, }, { "fields": { "scientificName": "A" }, }] fnames = list(DocumentExport(self.TEMPLATE).crop_fnames(document)) self.assertEqual([ 'A.png', 'A-1.png', 'A-2.png', 'D.png', 'B.png', 'D-1.png', 'A-3.png' ], fnames)
def test_from_file(self): "Load from a YAML file" doc = UserTemplate.load(TESTDATA / 'test.inselect_template') self.assertEqual(doc.name, "Test user template") self.assertEqual(doc.cropped_file_suffix, '.jpg') self.assertEqual(doc.thumbnail_width_pixels, 4096) self.assertEqual(4, len(doc.fields)) self.assertEqual('Department', doc.fields[0].name) self.assertEqual('Palaeontology', doc.fields[0].fixed_value) self.assertEqual('catalogNumber', doc.fields[1].name) self.assertEqual('Catalog number', doc.fields[1].label) self.assertEqual('http://rs.tdwg.org/dwc/terms/catalogNumber', doc.fields[1].uri) self.assertTrue(doc.fields[1].mandatory) self.assertEqual('Catalog number', doc.fields[1].label) self.assertEqual('Location', doc.fields[2].name) self.assertTrue(doc.fields[2].mandatory) self.assertEqual('Taxonomy', doc.fields[3].name) self.assertTrue(doc.fields[3].mandatory)
def test_save_crops_invalid_document(self, mock_question, mock_setdetailed, mock_settext): """The user wants to export crops for a document with many validation failures """ w = self.window # This document has 15 validation problems with this template w.open_document(path=TESTDATA / 'shapes.inselect') template = UserTemplate.load(TESTDATA / 'test.inselect_template') w.save_crops(user_template=template) # Close the document self.assertTrue(w.close_document()) # Should have been called self.assertEqual(1, mock_settext.call_count) self.assertIn('The document contains 15 validation problems', mock_settext.call_args[0][0]) # Detailed text should not have been given self.assertEqual(1, mock_setdetailed.call_count)
class TestUserTemplate(unittest.TestCase): TEMPLATE = UserTemplate({ 'Name': 'T1', 'Fields': [{ 'Name': 'F1' }], 'Cropped file suffix': '.tiff', 'Thumbnail width pixels': 5000, 'Object label': '{ItemNumber:03}-{First}-{Second}-{Second-value}-{Last}', 'Fields': [ { 'Name': 'First', 'Mandatory': True, 'Choices': ['A', 'B'] }, { 'Name': 'Second', 'Choices with data': OrderedDict([ ('ABC', 0), ('DEF', 1), ]), }, { 'Name': 'Third', 'Parser': 'int' }, { 'Name': 'Last', 'Regex parser': '^[0-9]{9}$' }, ], }) def test_str_repr(self): t = self.TEMPLATE self.assertEqual('UserTemplate [T1] with 4 fields', str(t)) self.assertEqual('<UserTemplate [T1] with 4 fields>', repr(t)) def test_properties(self): t = self.TEMPLATE self.assertEqual('T1', t.name) self.assertEqual('.tiff', t.cropped_file_suffix) self.assertEqual(5000, t.thumbnail_width_pixels) self.assertEqual(4, len(t.fields)) self.assertEqual('First', t.fields[0].name) self.assertTrue(t.fields[0].mandatory) self.assertEqual(['A', 'B'], t.fields[0].choices) self.assertIsNone(t.fields[0].choices_with_data) self.assertIsNone(t.fields[0].parse_fn) self.assertEqual('Second', t.fields[1].name) self.assertFalse(t.fields[1].mandatory) self.assertIsNone(t.fields[1].choices) self.assertEqual(OrderedDict([('ABC', 0), ('DEF', 1)]), t.fields[1].choices_with_data) self.assertIsNone(t.fields[1].parse_fn) self.assertEqual('Third', t.fields[2].name) self.assertTrue(t.fields[2].parse_fn) self.assertEqual('Last', t.fields[3].name) self.assertTrue(t.fields[3].parse_fn) def test_field_names(self): t = self.TEMPLATE self.assertEqual( RESERVED_FIELD_NAMES + ('First', 'Second', 'Second-value', 'Third', 'Last'), tuple(t.field_names())) def test_format_label(self): t = self.TEMPLATE metadata = {'Second': 'DEF', 'Last': '22'} self.assertEqual('010--DEF-1-22', t.format_label(10, metadata)) def test_validate_field_mandatory(self): t = self.TEMPLATE self.assertTrue(t.validate_field('Second', 'ABC')) self.assertTrue(t.validate_field('Not a field', '123')) self.assertFalse(t.validate_field('First', '')) self.assertTrue(t.validate_field('First', 'A')) def test_validate_field_parser(self): t = self.TEMPLATE self.assertTrue(t.validate_field('Third', '')) self.assertFalse(t.validate_field('Third', 'x')) self.assertTrue(t.validate_field('Third', '123')) def test_validate_field_parser_regex(self): t = self.TEMPLATE self.assertTrue(t.validate_field('Last', '')) self.assertFalse(t.validate_field('Last', '12345678')) self.assertTrue(t.validate_field('Last', '123456789')) def test_validate_metadata_fail_parse(self): t = self.TEMPLATE self.assertTrue(t.validate_metadata({'First': 'A', 'Third': ''})) self.assertFalse(t.validate_metadata({'First': 'A', 'Third': 'xyz'})) self.assertTrue(t.validate_metadata({'First': 'A', 'Third': '0'})) self.assertTrue(t.validate_metadata({'First': 'A', 'Third': '1'})) def test_validate_metadata_missing_mandatory(self): t = self.TEMPLATE self.assertFalse(t.validate_metadata({'First': ''})) self.assertTrue(t.validate_metadata({'First': 'A'})) def test_validate_not_in_choices(self): t = self.TEMPLATE self.assertFalse(t.validate_metadata({'First': 'xyz'})) self.assertFalse(t.validate_metadata({'Second': 'xyz'})) def test_from_file(self): "Load from a YAML file" doc = UserTemplate.load(TESTDATA / 'test.inselect_template') self.assertEqual(doc.name, "Test user template") self.assertEqual(doc.cropped_file_suffix, '.jpg') self.assertEqual(doc.thumbnail_width_pixels, 4096) self.assertEqual(4, len(doc.fields)) self.assertEqual('Department', doc.fields[0].name) self.assertEqual('Palaeontology', doc.fields[0].fixed_value) self.assertEqual('catalogNumber', doc.fields[1].name) self.assertEqual('Catalog number', doc.fields[1].label) self.assertEqual('http://rs.tdwg.org/dwc/terms/catalogNumber', doc.fields[1].uri) self.assertTrue(doc.fields[1].mandatory) self.assertEqual('Catalog number', doc.fields[1].label) self.assertEqual('Location', doc.fields[2].name) self.assertTrue(doc.fields[2].mandatory) self.assertEqual('Taxonomy', doc.fields[3].name) self.assertTrue(doc.fields[3].mandatory)
def _load(self, path): "Loads the UserTemplate in path" debug_print('UserTemplateChoice._load [{0}]'.format(path)) return UserTemplate.load(path)
class TestDocumentExportWithTemplate(unittest.TestCase): TEMPLATE = UserTemplate({ 'Name': 'Test', 'Cropped file suffix': '.png', 'Thumbnail width pixels': 4096, 'Object label': '{ItemNumber:02}_{scientificName-value}', 'Fields': [ { 'Name': 'catalogNumber', }, { 'Name': 'Department', 'Fixed value': 'Entomology', }, { 'Name': 'scientificName', 'Choices with data': [ ('A', 1), ('B', 2), ('Elsinoë', 3), ('D', 4), ('インセクト', 10), ], }, ] }) def test_save_crops(self): "Cropped object images are written correctly" with temp_directory_with_files(TESTDATA / 'shapes.inselect', TESTDATA / 'shapes.png') as tempdir: doc = InselectDocument.load(tempdir / 'shapes.inselect') crops_dir = DocumentExport(self.TEMPLATE).save_crops(doc) self.assertTrue(crops_dir.is_dir()) self.assertEqual(crops_dir, doc.crops_dir) cropped_fnames = sorted(crops_dir.glob('*.png')) self.assertEqual( ['01_1.png', '02_2.png', '03_10.png', '04_3.png', '05_4.png'], [f.name for f in cropped_fnames]) # Check the contents of each file boxes = doc.scanned.from_normalised(i['rect'] for i in doc.items) for box, path in zip(boxes, sorted(crops_dir.glob('*.png'))): x0, y0, x1, y1 = box.coordinates self.assertTrue( np.all(doc.scanned.array[y0:y1, x0:x1] == cv2.imread(str(path)))) def test_cancel_save_crops(self): "User cancels save crops" with temp_directory_with_files(TESTDATA / 'shapes.inselect', TESTDATA / 'shapes.png') as tempdir: doc = InselectDocument.load(tempdir / 'shapes.inselect') # Create crops dir with some data doc.crops_dir.mkdir() with doc.crops_dir.joinpath('a_file').open('w') as outfile: outfile.write('Some data\n') class CancelExport(Exception): pass def progress(msg): "A progress function that cancels the export" raise CancelExport() self.assertRaises(CancelExport, DocumentExport(self.TEMPLATE).save_crops, doc, progress=progress) # Nothing should have changed within tempdir self.assertEqual( ['shapes.inselect', 'shapes.png', doc.crops_dir.name], sorted(p.name for p in tempdir.iterdir())) self.assertEqual(['a_file'], [p.name for p in doc.crops_dir.iterdir()]) def test_csv_export(self): "CSV data are exported as expected" with temp_directory_with_files(TESTDATA / 'shapes.inselect', TESTDATA / 'shapes.png') as tempdir: doc = InselectDocument.load(tempdir / 'shapes.inselect') csv_path = DocumentExport(self.TEMPLATE).export_csv(doc) self.assertEqual(csv_path, tempdir / 'shapes.csv') # Check CSV contents with csv_path.open('rb') as f: reader = unicodecsv.reader(f, encoding='utf8') headers = [ 'Cropped_image_name', 'ItemNumber', 'NormalisedLeft', 'NormalisedTop', 'NormalisedRight', 'NormalisedBottom', 'ThumbnailLeft', 'ThumbnailTop', 'ThumbnailRight', 'ThumbnailBottom', 'OriginalLeft', 'OriginalTop', 'OriginalRight', 'OriginalBottom', 'catalogNumber', 'Department', 'scientificName', 'scientificName-value' ] self.assertEqual(headers, next(reader)) # Check only the metadata columns and 'original' coordinates # columns, ignoring thumbnail (which doesn't exist) # and normalised (which are floating point) coordinates metadata_cols = itemgetter(0, 1, 10, 11, 12, 13, 14, 15, 16, 17) self.assertEqual(('01_1.png', '1', '0', '0', '189', '189', '1', 'Entomology', 'A', '1'), metadata_cols(next(reader))) self.assertEqual(('02_2.png', '2', '271', '0', '459', '189', '2', 'Entomology', 'B', '2'), metadata_cols(next(reader))) self.assertEqual(('03_10.png', '3', '194', '196', '257', '232', '3', 'Entomology', 'インセクト', '10'), metadata_cols(next(reader))) self.assertEqual(('04_3.png', '4', '0', '248', '189', '437', '4', 'Entomology', 'Elsinoë', '3'), metadata_cols(next(reader))) self.assertEqual(('05_4.png', '5', '271', '248', '459', '437', '5', 'Entomology', 'D', '4'), metadata_cols(next(reader))) self.assertIsNone(next(reader, None))
DWC = UserTemplate.from_specification({ 'Name': 'Simple Darwin Core terms', 'Fields': [ { "Group": "Identifier", "Name": "occurrenceID", "Label": "Occurrence ID", "URI": "http://rs.tdwg.org/dwc/terms/occurrenceID", }, { "Group": "Identifier", "Name": "organismID", "Label": "Organism ID", "URI": "http://rs.tdwg.org/dwc/terms/organismID", }, { "Group": "Identifier", "Name": "materialSampleID", "Label": "Material sample ID", "URI": "http://rs.tdwg.org/dwc/terms/materialSampleID", }, { "Group": "Identifier", "Name": "eventID", "Label": "Event ID", "URI": "http://rs.tdwg.org/dwc/terms/eventID", }, { "Group": "Identifier", "Name": "locationID", "Label": "Location ID", "URI": "http://rs.tdwg.org/dwc/terms/locationID", }, { "Group": "Identifier", "Name": "geologicalContextID", "Label": "Geological context ID", "URI": "http://rs.tdwg.org/dwc/terms/geologicalContextID", }, { "Group": "Identifier", "Name": "identificationID", "Label": "Identification ID", "URI": "http://rs.tdwg.org/dwc/terms/identificationID", }, { "Group": "Identifier", "Name": "taxonID", "Label": "Taxon ID", "URI": "http://rs.tdwg.org/dwc/terms/taxonID", }, { "Group": "Record level", "Name": "type", "Label": "Type", "URI": "http://purl.org/dc/terms/type", }, { "Group": "Record level", "Name": "modified", "Label": "Modified", "URI": "http://purl.org/dc/terms/modified" }, { "Group": "Record level", "Name": "language", "Label": "Language", "URI": "http://purl.org/dc/terms/language" }, { "Group": "Record level", "Name": "license", "Label": "License", "URI": "http://purl.org/dc/terms/license" }, { "Group": "Record level", "Name": "rightsHolder", "Label": "Rights holder", "URI": "http://purl.org/dc/terms/rightsHolder" }, { "Group": "Record level", "Name": "accessRights", "Label": "Access rights", "URI": "http://purl.org/dc/terms/accessRights" }, { "Group": "Record level", "Name": "bibliographicCitation", "Label": "Bibliographic citation", "URI": "http://purl.org/dc/terms/bibliographicCitation" }, { "Group": "Record level", "Name": "references", "Label": "References", "URI": "http://purl.org/dc/terms/references" }, { "Group": "Record level", "Name": "institutionID", "Label": "Institution ID", "URI": "http://rs.tdwg.org/dwc/terms/institutionID", }, { "Group": "Record level", "Name": "collectionID", "Label": "Collection ID", "URI": "http://rs.tdwg.org/dwc/terms/collectionID", }, { "Group": "Record level", "Name": "datasetID", "Label": "Dataset ID", "URI": "http://rs.tdwg.org/dwc/terms/datasetID", }, { "Group": "Record level", "Name": "institutionCode", "Label": "Institution code", "URI": "http://rs.tdwg.org/dwc/terms/institutionCode", }, { "Group": "Record level", "Name": "collectionCode", "Label": "Collection code", "URI": "http://rs.tdwg.org/dwc/terms/collectionCode", }, { "Group": "Record level", "Name": "datasetName", "Label": "Dataset name", "URI": "http://rs.tdwg.org/dwc/terms/datasetName", }, { "Group": "Record level", "Name": "ownerInstitutionCode", "Label": "Owner institution code", "URI": "http://rs.tdwg.org/dwc/terms/ownerInstitutionCode", }, { "Group": "Record level", "Name": "basisOfRecord", "Label": "Basis of record", "URI": "http://rs.tdwg.org/dwc/terms/basisOfRecord", }, { "Group": "Record level", "Name": "informationWithheld", "Label": "Information withheld", "URI": "http://rs.tdwg.org/dwc/terms/informationWithheld", }, { "Group": "Record level", "Name": "dataGeneralizations", "Label": "Data generalizations", "URI": "http://rs.tdwg.org/dwc/terms/dataGeneralizations", }, { "Group": "Record level", "Name": "dynamicProperties", "Label": "Dynamic properties", "URI": "http://rs.tdwg.org/dwc/terms/dynamicProperties", }, { "Group": "Occurrence", "Name": "catalogNumber", "Label": "Catalog number", "URI": "http://rs.tdwg.org/dwc/terms/catalogNumber", }, { "Group": "Occurrence", "Name": "recordNumber", "Label": "Record number", "URI": "http://rs.tdwg.org/dwc/terms/recordNumber", }, { "Group": "Occurrence", "Name": "recordedBy", "Label": "Recorded by", "URI": "http://rs.tdwg.org/dwc/terms/recordedBy", }, { "Group": "Occurrence", "Name": "individualCount", "Label": "Individual count", "URI": "http://rs.tdwg.org/dwc/terms/individualCount", "Parser": "int_gt0", }, { "Group": "Occurrence", "Name": "sex", "Label": "Sex", "URI": "http://rs.tdwg.org/dwc/terms/sex", }, { "Group": "Occurrence", "Name": "lifeStage", "Label": "Life stage", "URI": "http://rs.tdwg.org/dwc/terms/lifeStage", }, { "Group": "Occurrence", "Name": "reproductiveCondition", "Label": "Reproductive condition", "URI": "http://rs.tdwg.org/dwc/terms/reproductiveCondition", }, { "Group": "Occurrence", "Name": "behavior", "Label": "Behavior", "URI": "http://rs.tdwg.org/dwc/terms/behavior", }, { "Group": "Occurrence", "Name": "establishmentMeans", "Label": "Establishment means", "URI": "http://rs.tdwg.org/dwc/terms/establishmentMeans", }, { "Group": "Occurrence", "Name": "occurrenceStatus", "Label": "Occurrence status", "URI": "http://rs.tdwg.org/dwc/terms/occurrenceStatus", }, { "Group": "Occurrence", "Name": "preparations", "Label": "Preparations", "URI": "http://rs.tdwg.org/dwc/terms/preparations", }, { "Group": "Occurrence", "Name": "disposition", "Label": "Disposition", "URI": "http://rs.tdwg.org/dwc/terms/disposition", }, { "Group": "Occurrence", "Name": "associatedMedia", "Label": "Associated media", "URI": "http://rs.tdwg.org/dwc/terms/associatedMedia", }, { "Group": "Occurrence", "Name": "associatedReferences", "Label": "Associated references", "URI": "http://rs.tdwg.org/dwc/terms/associatedReferences", }, { "Group": "Occurrence", "Name": "associatedSequences", "Label": "Associated sequences", "URI": "http://rs.tdwg.org/dwc/terms/associatedSequences", }, { "Group": "Occurrence", "Name": "associatedTaxa", "Label": "Associated taxa", "URI": "http://rs.tdwg.org/dwc/terms/associatedTaxa", }, { "Group": "Occurrence", "Name": "otherCatalogNumbers", "Label": "Other catalog numbers", "URI": "http://rs.tdwg.org/dwc/terms/otherCatalogNumbers", }, { "Group": "Occurrence", "Name": "occurrenceRemarks", "Label": "Occurrence remarks", "URI": "http://rs.tdwg.org/dwc/terms/occurrenceRemarks", }, { "Group": "Organism", "Name": "organismName", "Label": "Organism name", "URI": "http://rs.tdwg.org/dwc/terms/organismName", }, { "Group": "Organism", "Name": "organismScope", "Label": "Organism scope", "URI": "http://rs.tdwg.org/dwc/terms/organismScope", }, { "Group": "Organism", "Name": "associatedOccurrences", "Label": "Associated occurrences", "URI": "http://rs.tdwg.org/dwc/terms/associatedOccurrences", }, { "Group": "Organism", "Name": "associatedOrganisms", "Label": "Associated organisms", "URI": "http://rs.tdwg.org/dwc/terms/associatedOrganisms", }, { "Group": "Organism", "Name": "previousIdentifications", "Label": "Previous identifications", "URI": "http://rs.tdwg.org/dwc/terms/previousIdentifications", }, { "Group": "Organism", "Name": "organismRemarks", "Label": "Organism remarks", "URI": "http://rs.tdwg.org/dwc/terms/organismRemarks", }, { "Group": "Event", "Name": "eventDate", "Label": "Event date", "URI": "http://rs.tdwg.org/dwc/terms/eventDate", "Parser": "date", }, { "Group": "Event", "Name": "eventTime", "Label": "Event time", "URI": "http://rs.tdwg.org/dwc/terms/eventTime", # TODO Parser }, { "Group": "Event", "Name": "startDayOfYear", "Label": "Start day of year", "URI": "http://rs.tdwg.org/dwc/terms/startDayOfYear", }, { "Group": "Event", "Name": "endDayOfYear", "Label": "End day of year", "URI": "http://rs.tdwg.org/dwc/terms/endDayOfYear", }, { "Group": "Event", "Name": "year", "Label": "Year", "URI": "http://rs.tdwg.org/dwc/terms/year", "Parser": "four_digit_int", }, { "Group": "Event", "Name": "month", "Label": "Month", "URI": "http://rs.tdwg.org/dwc/terms/month", "Parser": "one_or_two_digit_int", }, { "Group": "Event", "Name": "day", "Label": "Day", "URI": "http://rs.tdwg.org/dwc/terms/day", "Parser": "one_or_two_digit_int", }, { "Group": "Event", "Name": "verbatimEventDate", "Label": "Verbatim event date", "URI": "http://rs.tdwg.org/dwc/terms/verbatimEventDate", }, { "Group": "Event", "Name": "habitat", "Label": "Habitat", "URI": "http://rs.tdwg.org/dwc/terms/habitat", }, { "Group": "Event", "Name": "fieldNumber", "Label": "Field number", "URI": "http://rs.tdwg.org/dwc/terms/fieldNumber", }, { "Group": "Event", "Name": "samplingProtocol", "Label": "Sampling protocol", "URI": "http://rs.tdwg.org/dwc/terms/samplingProtocol", }, { "Group": "Event", "Name": "samplingEffort", "Label": "Sampling effort", "URI": "http://rs.tdwg.org/dwc/terms/samplingEffort", }, { "Group": "Event", "Name": "fieldNotes", "Label": "Field notes", "URI": "http://rs.tdwg.org/dwc/terms/fieldNotes", }, { "Group": "Event", "Name": "eventRemarks", "Label": "Event remarks", "URI": "http://rs.tdwg.org/dwc/terms/eventRemarks", }, { "Group": "Location", "Name": "higherGeographyID", "Label": "Higher geography ID", "URI": "http://rs.tdwg.org/dwc/terms/higherGeographyID", }, { "Group": "Location", "Name": "higherGeography", "Label": "Higher geography", "URI": "http://rs.tdwg.org/dwc/terms/higherGeography", }, { "Group": "Location", "Name": "continent", "Label": "Continent", "URI": "http://rs.tdwg.org/dwc/terms/continent", }, { "Group": "Location", "Name": "waterbody", "Label": "Waterbody", "URI": "http://rs.tdwg.org/dwc/terms/waterbody", }, { "Group": "Location", "Name": "islandGroup", "Label": "Island group", "URI": "http://rs.tdwg.org/dwc/terms/islandGroup", }, { "Group": "Location", "Name": "island", "Label": "Island", "URI": "http://rs.tdwg.org/dwc/terms/island", }, { "Group": "Location", "Name": "country", "Label": "Country", "URI": "http://rs.tdwg.org/dwc/terms/country", }, { "Group": "Location", "Name": "countryCode", "Label": "Country code", "URI": "http://rs.tdwg.org/dwc/terms/countryCode", }, { "Group": "Location", "Name": "stateProvince", "Label": "State province", "URI": "http://rs.tdwg.org/dwc/terms/stateProvince", }, { "Group": "Location", "Name": "county", "Label": "County", "URI": "http://rs.tdwg.org/dwc/terms/county", }, { "Group": "Location", "Name": "municipality", "Label": "Municipality", "URI": "http://rs.tdwg.org/dwc/terms/municipality", }, { "Group": "Location", "Name": "locality", "Label": "Locality", "URI": "http://rs.tdwg.org/dwc/terms/locality", }, { "Group": "Location", "Name": "verbatimLocality", "Label": "Verbatim locality", "URI": "http://rs.tdwg.org/dwc/terms/verbatimLocality", }, { "Group": "Location", "Name": "minimumElevationInMeters", "Label": "Minimum elevation in meters", "URI": "http://rs.tdwg.org/dwc/terms/minimumElevationInMeters", "Parser": "float_ge0", }, { "Group": "Location", "Name": "maximumElevationInMeters", "Label": "Maximum elevation in meters", "URI": "http://rs.tdwg.org/dwc/terms/maximumElevationInMeters", "Parser": "float_ge0", }, { "Group": "Location", "Name": "verbatimElevation", "Label": "Verbatim elevation", "URI": "http://rs.tdwg.org/dwc/terms/verbatimElevation", }, { "Group": "Location", "Name": "minimumDepthInMeters", "Label": "Minimum depth in meters", "URI": "http://rs.tdwg.org/dwc/terms/minimumDepthInMeters", "Parser": "float_ge0", }, { "Group": "Location", "Name": "maximumDepthInMeters", "Label": "Maximum depth in meters", "URI": "http://rs.tdwg.org/dwc/terms/maximumDepthInMeters", "Parser": "float_ge0", }, { "Group": "Location", "Name": "verbatimDepth", "Label": "Verbatim depth", "URI": "http://rs.tdwg.org/dwc/terms/verbatimDepth", }, { "Group": "Location", "Name": "minimumDistanceAboveSurfaceInMeters", "Label": "Minimum distance above surface in meters", "URI": "http://rs.tdwg.org/dwc/terms/minimumDistanceAboveSurfaceInMeters", "Parser": "float_ge0", }, { "Group": "Location", "Name": "maximumDistanceAboveSurfaceInMeters", "Label": "Maximum distance above surface in meters", "URI": "http://rs.tdwg.org/dwc/terms/maximumDistanceAboveSurfaceInMeters", "Parser": "float_ge0", }, { "Group": "Location", "Name": "locationRemarks", "Label": "Location remarks", "URI": "http://rs.tdwg.org/dwc/terms/locationRemarks", }, { "Group": "Location", "Name": "decimalLatitude", "Label": "Decimal latitude", "URI": "http://rs.tdwg.org/dwc/terms/decimalLatitude", "Parser": "latitude", }, { "Group": "Location", "Name": "decimalLongitude", "Label": "Decimal longitude", "URI": "http://rs.tdwg.org/dwc/terms/decimalLongitude", "Parser": "longitude", }, { "Group": "Location", "Name": "geodeticDatum", "Label": "Geodetic datum", "URI": "http://rs.tdwg.org/dwc/terms/geodeticDatum", }, { "Group": "Location", "Name": "coordinateUncertaintyInMeters", "Label": "Coordinate uncertainty in meters", "URI": "http://rs.tdwg.org/dwc/terms/coordinateUncertaintyInMeters", "Parser": "float_gt0", }, { "Group": "Location", "Name": "coordinatePrecision", "Label": "Coordinate precision", "URI": "http://rs.tdwg.org/dwc/terms/coordinatePrecision", "Parser": "float_gt0", }, { "Group": "Location", "Name": "pointRadiusSpatialFit", "Label": "Point radius spatial fit", "URI": "http://rs.tdwg.org/dwc/terms/pointRadiusSpatialFit", }, { "Group": "Location", "Name": "verbatimCoordinates", "Label": "Verbatim coordinates", "URI": "http://rs.tdwg.org/dwc/terms/verbatimCoordinates", }, { "Group": "Location", "Name": "verbatimLatitude", "Label": "Verbatim latitude", "URI": "http://rs.tdwg.org/dwc/terms/verbatimLatitude", }, { "Group": "Location", "Name": "verbatimLongitude", "Label": "Verbatim longitude", "URI": "http://rs.tdwg.org/dwc/terms/verbatimLongitude", }, { "Group": "Location", "Name": "verbatimCoordinateSystem", "Label": "Verbatim coordinate system", "URI": "http://rs.tdwg.org/dwc/terms/verbatimCoordinateSystem", }, { "Group": "Location", "Name": "verbatimSRS", "Label": "Verbatim srs", "URI": "http://rs.tdwg.org/dwc/terms/verbatimSRS", }, { "Group": "Location", "Name": "footprintWKT", "Label": "Footprint wkt", "URI": "http://rs.tdwg.org/dwc/terms/footprintWKT", }, { "Group": "Location", "Name": "footprintSRS", "Label": "Footprint srs", "URI": "http://rs.tdwg.org/dwc/terms/footprintSRS", }, { "Group": "Location", "Name": "footprintSpatialFit", "Label": "Footprint spatial fit", "URI": "http://rs.tdwg.org/dwc/terms/footprintSpatialFit", }, { "Group": "Location", "Name": "georeferencedBy", "Label": "Georeferenced by", "URI": "http://rs.tdwg.org/dwc/terms/georeferencedBy", }, { "Group": "Location", "Name": "georeferencedDate", "Label": "Georeferenced date", "URI": "http://rs.tdwg.org/dwc/terms/georeferencedDate", "Parser": "date", }, { "Group": "Location", "Name": "georeferenceProtocol", "Label": "Georeference protocol", "URI": "http://rs.tdwg.org/dwc/terms/georeferenceProtocol", }, { "Group": "Location", "Name": "georeferenceSources", "Label": "Georeference sources", "URI": "http://rs.tdwg.org/dwc/terms/georeferenceSources", }, { "Group": "Location", "Name": "georeferenceVerificationStatus", "Label": "Georeference verification status", "URI": "http://rs.tdwg.org/dwc/terms/georeferenceVerificationStatus", }, { "Group": "Location", "Name": "georeferenceRemarks", "Label": "Georeference remarks", "URI": "http://rs.tdwg.org/dwc/terms/georeferenceRemarks", }, { "Group": "Geological context", "Name": "earliestEonOrLowestEonothem", "Label": "Earliest eon or lowest eonothem", "URI": "http://rs.tdwg.org/dwc/terms/earliestEonOrLowestEonothem", }, { "Group": "Geological context", "Name": "latestEonOrHighestEonothem", "Label": "Latest eon or highest eonothem", "URI": "http://rs.tdwg.org/dwc/terms/latestEonOrHighestEonothem", }, { "Group": "Geological context", "Name": "earliestEraOrLowestErathem", "Label": "Earliest era or lowest erathem", "URI": "http://rs.tdwg.org/dwc/terms/earliestEraOrLowestErathem", }, { "Group": "Geological context", "Name": "latestEraOrHighestErathem", "Label": "Latest era or highest erathem", "URI": "http://rs.tdwg.org/dwc/terms/latestEraOrHighestErathem", }, { "Group": "Geological context", "Name": "earliestPeriodOrLowestSystem", "Label": "Earliest period or lowest system", "URI": "http://rs.tdwg.org/dwc/terms/earliestPeriodOrLowestSystem", }, { "Group": "Geological context", "Name": "latestPeriodOrHighestSystem", "Label": "Latest period or highest system", "URI": "http://rs.tdwg.org/dwc/terms/latestPeriodOrHighestSystem", }, { "Group": "Geological context", "Name": "earliestEpochOrLowestSeries", "Label": "Earliest epoch or lowest series", "URI": "http://rs.tdwg.org/dwc/terms/earliestEpochOrLowestSeries", }, { "Group": "Geological context", "Name": "latestEpochOrHighestSeries", "Label": "Latest epoch or highest series", "URI": "http://rs.tdwg.org/dwc/terms/latestEpochOrHighestSeries", }, { "Group": "Geological context", "Name": "earliestAgeOrLowestStage", "Label": "Earliest age or lowest stage", "URI": "http://rs.tdwg.org/dwc/terms/earliestAgeOrLowestStage", }, { "Group": "Geological context", "Name": "latestAgeOrHighestStage", "Label": "Latest age or highest stage", "URI": "http://rs.tdwg.org/dwc/terms/latestAgeOrHighestStage", }, { "Group": "Geological context", "Name": "lowestBiostratigraphicZone", "Label": "Lowest biostratigraphic zone", "URI": "http://rs.tdwg.org/dwc/terms/lowestBiostratigraphicZone", }, { "Group": "Geological context", "Name": "highestBiostratigraphicZone", "Label": "Highest biostratigraphic zone", "URI": "http://rs.tdwg.org/dwc/terms/highestBiostratigraphicZone", }, { "Group": "Geological context", "Name": "lithostratigraphicTerms", "Label": "Lithostratigraphic terms", "URI": "http://rs.tdwg.org/dwc/terms/lithostratigraphicTerms", }, { "Group": "Geological context", "Name": "group", "Label": "Group", "URI": "http://rs.tdwg.org/dwc/terms/group", }, { "Group": "Geological context", "Name": "formation", "Label": "Formation", "URI": "http://rs.tdwg.org/dwc/terms/formation", }, { "Group": "Geological context", "Name": "member", "Label": "Member", "URI": "http://rs.tdwg.org/dwc/terms/member", }, { "Group": "Geological context", "Name": "bed", "Label": "Bed", "URI": "http://rs.tdwg.org/dwc/terms/bed", }, { "Group": "Identification", "Name": "identificationQualifier", "Label": "Identification qualifier", "URI": "http://rs.tdwg.org/dwc/terms/identificationQualifier", }, { "Group": "Identification", "Name": "typeStatus", "Label": "Type status", "URI": "http://rs.tdwg.org/dwc/terms/typeStatus", }, { "Group": "Identification", "Name": "identifiedBy", "Label": "Identified by", "URI": "http://rs.tdwg.org/dwc/terms/identifiedBy", }, { "Group": "Identification", "Name": "dateIdentified", "Label": "Date identified", "URI": "http://rs.tdwg.org/dwc/terms/dateIdentified", "Parser": "date", }, { "Group": "Identification", "Name": "identificationReferences", "Label": "Identification references", "URI": "http://rs.tdwg.org/dwc/terms/identificationReferences", }, { "Group": "Identification", "Name": "identificationVerificationStatus", "Label": "Identification verification status", "URI": "http://rs.tdwg.org/dwc/terms/identificationVerificationStatus", }, { "Group": "Identification", "Name": "identificationRemarks", "Label": "Identification remarks", "URI": "http://rs.tdwg.org/dwc/terms/identificationRemarks", }, { "Group": "Taxon", "Name": "scientificNameID", "Label": "Scientific name ID", "URI": "http://rs.tdwg.org/dwc/terms/scientificNameID", }, { "Group": "Taxon", "Name": "acceptedNameUsageID", "Label": "Accepted name usage ID", "URI": "http://rs.tdwg.org/dwc/terms/acceptedNameUsageID", }, { "Group": "Taxon", "Name": "parentNameUsageID", "Label": "Parent name usage ID", "URI": "http://rs.tdwg.org/dwc/terms/parentNameUsageID", }, { "Group": "Taxon", "Name": "originalNameUsageID", "Label": "Original name usage ID", "URI": "http://rs.tdwg.org/dwc/terms/originalNameUsageID", }, { "Group": "Taxon", "Name": "nameAccordingToID", "Label": "Name according to ID", "URI": "http://rs.tdwg.org/dwc/terms/nameAccordingToID", }, { "Group": "Taxon", "Name": "namePublishedInID", "Label": "Name published in ID", "URI": "http://rs.tdwg.org/dwc/terms/namePublishedInID", }, { "Group": "Taxon", "Name": "taxonConceptID", "Label": "Taxon concept ID", "URI": "http://rs.tdwg.org/dwc/terms/taxonConceptID", }, { "Group": "Taxon", "Name": "scientificName", "Label": "Scientific name", "URI": "http://rs.tdwg.org/dwc/terms/scientificName", }, { "Group": "Taxon", "Name": "acceptedNameUsage", "Label": "Accepted name usage", "URI": "http://rs.tdwg.org/dwc/terms/acceptedNameUsage", }, { "Group": "Taxon", "Name": "parentNameUsage", "Label": "Parent name usage", "URI": "http://rs.tdwg.org/dwc/terms/parentNameUsage", }, { "Group": "Taxon", "Name": "originalNameUsage", "Label": "Original name usage", "URI": "http://rs.tdwg.org/dwc/terms/originalNameUsage", }, { "Group": "Taxon", "Name": "nameAccordingTo", "Label": "Name according to", "URI": "http://rs.tdwg.org/dwc/terms/nameAccordingTo", }, { "Group": "Taxon", "Name": "namePublishedIn", "Label": "Name published in", "URI": "http://rs.tdwg.org/dwc/terms/namePublishedIn", }, { "Group": "Taxon", "Name": "namePublishedInYear", "Label": "Name published in year", "URI": "http://rs.tdwg.org/dwc/terms/namePublishedInYear", "Parser": "four_digit_int", }, { "Group": "Taxon", "Name": "higherClassification", "Label": "Higher classification", "URI": "http://rs.tdwg.org/dwc/terms/higherClassification", }, { "Group": "Taxon", "Name": "kingdom", "Label": "Kingdom", "URI": "http://rs.tdwg.org/dwc/terms/kingdom", }, { "Group": "Taxon", "Name": "phylum", "Label": "Phylum", "URI": "http://rs.tdwg.org/dwc/terms/phylum", }, { "Group": "Taxon", "Name": "class", "Label": "Class", "URI": "http://rs.tdwg.org/dwc/terms/class", }, { "Group": "Taxon", "Name": "order", "Label": "Order", "URI": "http://rs.tdwg.org/dwc/terms/order", }, { "Group": "Taxon", "Name": "family", "Label": "Family", "URI": "http://rs.tdwg.org/dwc/terms/family", }, { "Group": "Taxon", "Name": "genus", "Label": "Genus", "URI": "http://rs.tdwg.org/dwc/terms/genus", }, { "Group": "Taxon", "Name": "subgenus", "Label": "Subgenus", "URI": "http://rs.tdwg.org/dwc/terms/subgenus", }, { "Group": "Taxon", "Name": "specificEpithet", "Label": "Specific epithet", "URI": "http://rs.tdwg.org/dwc/terms/specificEpithet", }, { "Group": "Taxon", "Name": "infraspecificEpithet", "Label": "Infraspecific epithet", "URI": "http://rs.tdwg.org/dwc/terms/infraspecificEpithet", }, { "Group": "Taxon", "Name": "taxonRank", "Label": "Taxon rank", "URI": "http://rs.tdwg.org/dwc/terms/taxonRank", }, { "Group": "Taxon", "Name": "verbatimTaxonRank", "Label": "Verbatim taxon rank", "URI": "http://rs.tdwg.org/dwc/terms/verbatimTaxonRank", }, { "Group": "Taxon", "Name": "scientificNameAuthorship", "Label": "Scientific name authorship", "URI": "http://rs.tdwg.org/dwc/terms/scientificNameAuthorship", }, { "Group": "Taxon", "Name": "vernacularName", "Label": "Vernacular name", "URI": "http://rs.tdwg.org/dwc/terms/vernacularName", }, { "Group": "Taxon", "Name": "nomenclaturalCode", "Label": "Nomenclatural code", "URI": "http://rs.tdwg.org/dwc/terms/nomenclaturalCode", }, { "Group": "Taxon", "Name": "taxonomicStatus", "Label": "Taxonomic status", "URI": "http://rs.tdwg.org/dwc/terms/taxonomicStatus", }, { "Group": "Taxon", "Name": "nomenclaturalStatus", "Label": "Nomenclatural status", "URI": "http://rs.tdwg.org/dwc/terms/nomenclaturalStatus", }, { "Group": "Taxon", "Name": "taxonRemarks", "Label": "Taxon remarks", "URI": "http://rs.tdwg.org/dwc/terms/taxonRemarks", }, ] })