From 6501def691701642e9007eeac025f8ad6c3aaba3 Mon Sep 17 00:00:00 2001 From: Finn Bacall Date: Tue, 6 Feb 2024 16:04:27 +0000 Subject: [PATCH] Extract multiple organizers (comma-separated) Also include any ID/URL in parentheses ElixirTeSS/TeSS#914 --- lib/tess/rdf/event_extractor.rb | 2 +- lib/tess/rdf/extraction.rb | 19 +++++ test/extraction_test.rb | 16 ++++- test/field_test.rb | 32 +++++++++ test/fixtures/ifb-multi-organizers.json | 95 +++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/ifb-multi-organizers.json diff --git a/lib/tess/rdf/event_extractor.rb b/lib/tess/rdf/event_extractor.rb index bf76185..6423829 100644 --- a/lib/tess/rdf/event_extractor.rb +++ b/lib/tess/rdf/event_extractor.rb @@ -18,7 +18,7 @@ def extract_params params[:online] = extract_online params.merge!(extract_location) - params[:organizer] = extract_names_or_values(RDF::Vocab::SCHEMA.organizer).first + params[:organizer] = extract_names_or_ids(RDF::Vocab::SCHEMA.organizer).join(', ') params[:capacity] = extract_value(RDF::Vocab::SCHEMA.maximumAttendeeCapacity) diff --git a/lib/tess/rdf/extraction.rb b/lib/tess/rdf/extraction.rb index 61e9eb5..9586ac6 100644 --- a/lib/tess/rdf/extraction.rb +++ b/lib/tess/rdf/extraction.rb @@ -255,6 +255,25 @@ def extract_mentions(subject: resource) [:mention, RDF::Vocab::SCHEMA.url, :url, { optional: true }]).map { |a| { title: a[:name], url: a[:url] } }.compact end + def extract_names_or_ids(predicate, subject: resource) + query([subject, predicate, :thing], + [:thing, RDF::Vocab::SCHEMA.name, :name, { optional: true }], + [:thing, RDF::Vocab::SCHEMA.url, :url, { optional: true }]).map do |r| + if r[:name].nil? + r[:thing] + else + v = r[:name] + if r[:thing] + v += " (#{r[:thing]})" + elsif r[:url] + v += " (#{r[:url]})" + end + v + end + end.compact.uniq.sort + end + + def parse_value(value) # Using 'value.class.name' instead of just 'value' here or things like RDF::Literal::DateTime fall into the RDF::Literal block # Not using 'value.class' because 'case' uses '===' for comparison and RDF::URI === RDF::URI is false! diff --git a/test/extraction_test.rb b/test/extraction_test.rb index 27a9c16..69aa49d 100644 --- a/test/extraction_test.rb +++ b/test/extraction_test.rb @@ -167,7 +167,7 @@ class ExtractionTest < Test::Unit::TestCase assert_equal '2022-08-22', params[:start] assert_equal '2022-08-25', params[:end] assert_equal ['training', 'biostatistics', 'raphael gottardo group'].sort, params[:keywords].sort - assert_equal 'Patricia Palagi', params[:organizer] + assert_equal 'Patricia Palagi (https://orcid.org/0000-0001-9062-6303), SIB Swiss Institute of Bioinformatics (https://ror.org/002n09z45)', params[:organizer] assert params[:node_names].include?('Switzerland') end @@ -311,4 +311,18 @@ class ExtractionTest < Test::Unit::TestCase assert_equal ['Bioinformatics', 'Genomics', 'Long-read', 'Metabarcoding', 'Metagenomics'], params[:scientific_topic_names] assert_equal ['Edinburgh Genomics'], params[:host_institutions] end + + test 'extract multiple organizers as comma-separated string' do + file = fixture_file('ifb-multi-organizers.json') + base_uri = 'https://catalogue.france-bioinformatique.fr/api/event/591/?format=json-ld' + + extractor = Tess::Rdf::CourseInstanceExtractor.new(file.read, :jsonld, base_uri: base_uri) + resources = extractor.extract + + assert_equal 1, resources.count + params = resources.first + + assert_equal "https://catalogue.france-bioinformatique.fr/api/organisation/CIRAD/?format=json-ld, https://catalogue.france-bioinformatique.fr/api/organisation/INRAE/?format=json-ld, https://catalogue.france-bioinformatique.fr/api/organisation/IRD/?format=json-ld, https://catalogue.france-bioinformatique.fr/api/team/South%20Green/?format=json-ld", + params[:organizer] + end end diff --git a/test/field_test.rb b/test/field_test.rb index dd841f8..0c81115 100644 --- a/test/field_test.rb +++ b/test/field_test.rb @@ -224,6 +224,38 @@ class FieldTest < Test::Unit::TestCase { title: 'European Genome-phenome Archive', url: 'https://www.ebi.ac.uk/ega/home' }], learning_resource_extractor(json).send(:extract_mentions) end + test 'extract multiple organizers' do + json = %( +[{ + "@context": "http://schema.org", + "@type": "CourseInstance", + "http://purl.org/dc/terms/conformsTo": { + "@id": "https://bioschemas.org/profiles/TrainingMaterial/1.0-RELEASE", + "@type": "CreativeWork" + }, + "organizer": [ + { + "@type": "Person", + "@id": "https://orcid.org/0000-0001-9062-6303", + "name": "Patricia Palagi" + }, + { + "@type": "Person", + "name": "Someone" + }, + { + "@type": "Organization", + "name": "SIB Swiss Institute of Bioinformatics", + "url": "https://www.sib.swiss/" + }, + { + "@id" : "https://cool.guys" + } + ] +}]) + assert_equal 'Patricia Palagi (https://orcid.org/0000-0001-9062-6303), SIB Swiss Institute of Bioinformatics (https://www.sib.swiss/), Someone, https://cool.guys', + course_instance_extractor(json).send(:extract_names_or_ids, RDF::Vocab::SCHEMA.organizer).join(', ') + end private def course_extractor(fixture, format: :jsonld, base_uri: 'https://example.com/my.json') diff --git a/test/fixtures/ifb-multi-organizers.json b/test/fixtures/ifb-multi-organizers.json new file mode 100644 index 0000000..a42dbdf --- /dev/null +++ b/test/fixtures/ifb-multi-organizers.json @@ -0,0 +1,95 @@ +[ + { + "@id": "https://catalogue.france-bioinformatique.fr/api/event/591/?format=json-ld", + "@type": [ + "https://schema.org/CourseInstance" + ], + "https://schema.org/description": [ + { + "@type": "https://schema.org/Text", + "@value": "Ce module vise à fournir une expérience d’analyse de données de génomique.\r\nLes technologies Next Generation Sequencing (NGS) ont conduit à une production massive de\r\ndonnées « Omiques » pour les plantes cultivées majeures, ce qui demande de nouvelles\r\napproches d’analyses haut débit. La connaissance de ces approches et des outils qui en\r\ndécoulent pour analyser la séquence et la structure des génomes, les annoter et caractériser\r\nleur diversité et leurs profils d’expression permet d’aborder des questions de recherche\r\nbiologique avancée sur la diversité et l’adaptation des plantes. Les espèces prises en\r\nconsidération sont des espèces phares des instituts de recherche agronomique de Montpellier\r\net font partie des cultures les plus importantes pour l’agriculture mondiale. Des plateformes\r\nd’outils bioinformatiques récents reposant sur des centres de calcul et de stockage haute\r\ncapacité, sont en place pour analyser des jeux de données originales permettant de mieux\r\ncomprendre comment les génomes de plantes évoluent et s’expriment. L’ensemble de ces\r\nconnaissances Findable, Accessible, Interoperable, Reusable car intégré dans des systèmes\r\nd’information peut soutenir l'identification de gènes responsables de caractères adaptatifs ou\r\nde production. La mobilisation de jeunes chercheurs sur ces sujets est primordiale tant la\r\ndemande est importante.\r\nLe module est structuré sous la forme de cours et de travaux tutorés avec la rencontre de\r\ngénéticiens et de bioinformaticiens permettant d’appréhender les formes variées des progrès\r\nen bioanalyse génomique. Il permet d’acquérir les lignes directrices pour l’accès, l'utilisation\r\net l'analyse de différents types de données omique (e.g. (épi)génomique, transcriptomique,\r\nprotéique, métabolique) en vue d’accélérer les recherches en génomique fonctionnelle et\r\nbiotechnologie des plantes.\r\nL’évaluation sera faite sur la base de la participation et de la qualité du projet proposé par\r\nl’étudiant en fin de module, individuellement ou en binôme, suivant les consignes détaillées en\r\ndébut de module" + } + ], + "https://schema.org/endDate": [ + { + "@type": "https://schema.org/Date", + "@value": "2024-03-08" + } + ], + "https://schema.org/location": [ + { + "@id": "_:N6703f4fcf2b04f2d8b90e5b0341f8f09" + } + ], + "https://schema.org/maximumAttendeeCapacity": [ + { + "@type": "https://schema.org/Integer", + "@value": "50" + } + ], + "https://schema.org/name": [ + { + "@type": "https://schema.org/Text", + "@value": "BIGomics, Génomique Comparative Biopolis" + } + ], + "https://schema.org/offers": [ + { + "@type": "https://schema.org/Demand", + "@value": "Free to academics" + } + ], + "https://schema.org/organizer": [ + { + "@id": "https://catalogue.france-bioinformatique.fr/api/organisation/CIRAD/?format=json-ld" + }, + { + "@id": "https://catalogue.france-bioinformatique.fr/api/organisation/INRAE/?format=json-ld" + }, + { + "@id": "https://catalogue.france-bioinformatique.fr/api/organisation/IRD/?format=json-ld" + }, + { + "@id": "https://catalogue.france-bioinformatique.fr/api/team/South%20Green/?format=json-ld" + } + ], + "https://schema.org/startDate": [ + { + "@type": "https://schema.org/Date", + "@value": "2024-03-04" + } + ], + "https://schema.org/url": [ + { + "@type": "https://schema.org/URL", + "@value": "https://cibio.up.pt/en/events/bigomics-high-throughput-genetic-diversity-analyses-of-tropical-crops/" + } + ] + }, + { + "@id": "_:N6703f4fcf2b04f2d8b90e5b0341f8f09", + "@type": [ + "https://schema.org/PostalAddress" + ], + "https://schema.org/addressCountry": [ + { + "@value": "France" + } + ], + "https://schema.org/addressLocality": [ + { + "@value": "Montpellier" + } + ], + "https://schema.org/postalCode": [ + { + "@value": "" + } + ], + "https://schema.org/streetAddress": [ + { + "@value": "Salle 159 Batiment 3 CIRAD Lavalette, Avenue Agropolis" + } + ] + } +] \ No newline at end of file