From d94d6a0cf8911a65cc6d95ba64cc792b421d008f Mon Sep 17 00:00:00 2001 From: Daniel Berthereau <Daniel.github@Berthereau.net> Date: Mon, 13 Aug 2018 00:00:00 +0200 Subject: [PATCH] Added the simple but non-standard format "oai_dcterms". --- README.md | 7 + config/module.config.php | 1 + src/OaiPmh/Metadata/Mets.php | 32 ++-- src/OaiPmh/Metadata/OaiDc.php | 40 +++-- src/OaiPmh/Metadata/OaiDcterms.php | 161 ++++++++++++++++++ .../OaiPmh/Metadata/OaiDctermsFactory.php | 30 ++++ 6 files changed, 247 insertions(+), 24 deletions(-) create mode 100644 src/OaiPmh/Metadata/OaiDcterms.php create mode 100644 src/Service/OaiPmh/Metadata/OaiDctermsFactory.php diff --git a/README.md b/README.md index d3021ab..1ad0a0a 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,13 @@ The Dublin Core is required by the OAI-PMH specification for all repositories. Omeka S metadata fields are mapped one-to-one with fields for this output format. +### [Dublin Core Terms] (prefix `oai_dcterms`) + +The OAI-PMH standard does not manage the complete set of Dublin Core, but it is +largely used. So this format is similar to `oai_dc`, but with all 55 terms. + +**NOTE**: The namespace and the schema don’t exist. + ### [CDWA Lite] (prefix `cdwalite`) The mapping between Omeka’s metadata and CDWA Lite metadata is more complicated, diff --git a/config/module.config.php b/config/module.config.php index 3de75aa..a713c0c 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -85,6 +85,7 @@ return [ 'mets' => Service\OaiPmh\Metadata\MetsFactory::class, 'mods' => Service\OaiPmh\Metadata\ModsFactory::class, 'oai_dc' => Service\OaiPmh\Metadata\OaiDcFactory::class, + 'oai_dcterms' => Service\OaiPmh\Metadata\OaiDctermsFactory::class, ], ], 'oai_set_formats' => [ diff --git a/src/OaiPmh/Metadata/Mets.php b/src/OaiPmh/Metadata/Mets.php index 8989bff..a11e238 100755 --- a/src/OaiPmh/Metadata/Mets.php +++ b/src/OaiPmh/Metadata/Mets.php @@ -59,18 +59,30 @@ class Mets extends AbstractMetadata $dcXml = $this->appendNewElement($dcWrap, 'xmlData'); $dcXml->setAttribute('xmlns:dc', self::DC_NAMESPACE_URI); - $dcElementNames = [ - 'title', 'creator', 'subject', 'description', 'publisher', - 'contributor', 'date', 'type', 'format', 'identifier', 'source', - 'language', 'relation', 'coverage', 'rights', + $localNames = [ + 'title', + 'creator', + 'subject', + 'description', + 'publisher', + 'contributor', + 'date', + 'type', + 'format', + 'identifier', + 'source', + 'language', + 'relation', + 'coverage', + 'rights', ]; - foreach ($dcElementNames as $elementName) { - $term = 'dcterms:' . $elementName; + foreach ($localNames as $localName) { + $term = 'dcterms:' . $localName; $values = $item->value($term, ['all' => true, 'default' => []]); $values = $this->filterValues($item, $term, $values); foreach ($values as $value) { - $this->appendNewElement($dcXml, "dc:$elementName", (string) $value); + $this->appendNewElement($dcXml, 'dc:' . $localName, (string) $value); } } @@ -112,12 +124,12 @@ class Mets extends AbstractMetadata $fileIds[] = $fileId; - foreach ($dcElementNames as $elementName) { - $term = 'dcterms:' . $elementName; + foreach ($localNames as $localName) { + $term = 'dcterms:' . $localName; $values = $media->value($term, ['all' => true, 'default' => []]); $values = $this->filterValues($media, $term, $values); foreach ($values as $value) { - $this->appendNewElement($fileDcXml, 'dc:' . $elementName, (string) $value); + $this->appendNewElement($fileDcXml, 'dc:' . $localName, (string) $value); } } } diff --git a/src/OaiPmh/Metadata/OaiDc.php b/src/OaiPmh/Metadata/OaiDc.php index 6ef1385..d6258ed 100644 --- a/src/OaiPmh/Metadata/OaiDc.php +++ b/src/OaiPmh/Metadata/OaiDc.php @@ -38,48 +38,60 @@ class OaiDc extends AbstractMetadata { $document = $metadataElement->ownerDocument; - $oai_dc = $document->createElementNS(self::METADATA_NAMESPACE, 'oai_dc:dc'); - $metadataElement->appendChild($oai_dc); + $oai = $document->createElementNS(self::METADATA_NAMESPACE, 'oai_dc:dc'); + $metadataElement->appendChild($oai); /* Must manually specify XML schema uri per spec, but DOM won't include * a redundant xmlns:xsi attribute, so we just set the attribute */ - $oai_dc->setAttribute('xmlns:dc', self::DC_NAMESPACE_URI); - $oai_dc->setAttribute('xmlns:xsi', parent::XML_SCHEMA_NAMESPACE_URI); - $oai_dc->setAttribute('xsi:schemaLocation', self::METADATA_NAMESPACE . ' ' . + $oai->setAttribute('xmlns:dc', self::DC_NAMESPACE_URI); + $oai->setAttribute('xmlns:xsi', parent::XML_SCHEMA_NAMESPACE_URI); + $oai->setAttribute('xsi:schemaLocation', self::METADATA_NAMESPACE . ' ' . self::METADATA_SCHEMA); /* Each of the 15 unqualified Dublin Core elements, in the order * specified by the oai_dc XML schema */ - $dcElementNames = [ - 'title', 'creator', 'subject', 'description', 'publisher', - 'contributor', 'date', 'type', 'format', 'identifier', 'source', - 'language', 'relation', 'coverage', 'rights', + $localNames = [ + 'title', + 'creator', + 'subject', + 'description', + 'publisher', + 'contributor', + 'date', + 'type', + 'format', + 'identifier', + 'source', + 'language', + 'relation', + 'coverage', + 'rights', ]; /* Must create elements using createElement to make DOM allow a * top-level xmlns declaration instead of wasteful and non- * compliant per-node declarations. */ - foreach ($dcElementNames as $elementName) { - $term = 'dcterms:' . $elementName; + foreach ($localNames as $localName) { + $term = 'dcterms:' . $localName; $values = $item->value($term, ['all' => true, 'default' => []]); $values = $this->filterValues($item, $term, $values); foreach ($values as $value) { - $this->appendNewElement($oai_dc, "dc:$elementName", (string) $value); + $this->appendNewElement($oai, 'dc:' . $localName, (string) $value); } } $appendIdentifier = $this->singleIdentifier($item); if ($appendIdentifier) { - $this->appendNewElement($oai_dc, 'dc:identifier', $appendIdentifier); + $this->appendNewElement($oai, 'dc:identifier', $appendIdentifier); } // Also append an identifier for each file if ($this->settings->get('oaipmhrepository_expose_media', false)) { foreach ($item->media() as $media) { - $this->appendNewElement($oai_dc, 'dc:identifier', $media->originalUrl()); + $this->appendNewElement($oai, 'dc:identifier', $media->originalUrl()); } } } diff --git a/src/OaiPmh/Metadata/OaiDcterms.php b/src/OaiPmh/Metadata/OaiDcterms.php new file mode 100644 index 0000000..f7faeb3 --- /dev/null +++ b/src/OaiPmh/Metadata/OaiDcterms.php @@ -0,0 +1,161 @@ +<?php +/** + * @author John Flatness, Yu-Hsun Lin + * @copyright Copyright 2009 John Flatness, Yu-Hsun Lin + * @copyright BibLibre, 2016 + * @copyright Daniel Berthereau, 2014-2018 + * @license http://www.gnu.org/licenses/gpl-3.0.txt + */ +namespace OaiPmhRepository\OaiPmh\Metadata; + +use DOMElement; +use Omeka\Api\Representation\ItemRepresentation; + +/** + * Class implementing metadata output for the oai_dcterms metadata format. + * oai_dcterms is output of the 55 Dublin Core terms. + * + * This format is not standardized, but used by some repositories. + * Note: the namespace and the schema don’t exist. It is designed as an extended + * version of oai_dc. + * + * @link http://www.bl.uk/schemas/ + * @link http://dublincore.org/documents/dc-xml-guidelines/ + * @link http://dublincore.org/schemas/xmls/qdc/dcterms.xsd + */ +class OaiDcterms extends AbstractMetadata +{ + /** OAI-PMH metadata prefix */ + const METADATA_PREFIX = 'oai_dcterms'; + + /** XML namespace for output format */ + const METADATA_NAMESPACE = 'http://www.openarchives.org/OAI/2.0/oai_dcterms/'; + + /** XML schema for output format */ + const METADATA_SCHEMA = 'http://www.openarchives.org/OAI/2.0/oai_dcterms.xsd'; + + /** XML namespace for Dublin Core */ + const DCTERMS_NAMESPACE_URI = 'http://purl.org/dc/terms/'; + + /** + * Appends Dublin Core terms metadata. + * + * {@inheritDoc} + */ + public function appendMetadata(DOMElement $metadataElement, ItemRepresentation $item) + { + $document = $metadataElement->ownerDocument; + + $oai = $document->createElementNS(self::METADATA_NAMESPACE, 'oai_dcterms:dcterms'); + $metadataElement->appendChild($oai); + + /* Must manually specify XML schema uri per spec, but DOM won't include + * a redundant xmlns:xsi attribute, so we just set the attribute + */ + $oai->setAttribute('xmlns:dcterms', self::DCTERMS_NAMESPACE_URI); + $oai->setAttribute('xmlns:xsi', parent::XML_SCHEMA_NAMESPACE_URI); + $oai->setAttribute('xsi:schemaLocation', self::METADATA_NAMESPACE . ' ' . + self::METADATA_SCHEMA); + + // Each of the 55 Dublin Core terms, in the Omeka order. + $localNames = [ + // Dublin Core Elements. + 'title', + 'creator', + 'subject', + 'description', + 'publisher', + 'contributor', + 'date', + 'type', + 'format', + 'identifier', + 'source', + 'language', + 'relation', + 'coverage', + 'rights', + // Dublin Core terms. + 'audience', + 'alternative', + 'tableOfContents', + 'abstract', + 'created', + 'valid', + 'available', + 'issued', + 'modified', + 'extent', + 'medium', + 'isVersionOf', + 'hasVersion', + 'isReplacedBy', + 'replaces', + 'isRequiredBy', + 'requires', + 'isPartOf', + 'hasPart', + 'isReferencedBy', + 'references', + 'isFormatOf', + 'hasFormat', + 'conformsTo', + 'spatial', + 'temporal', + 'mediator', + 'dateAccepted', + 'dateCopyrighted', + 'dateSubmitted', + 'educationLevel', + 'accessRights', + 'bibliographicCitation', + 'license', + 'rightsHolder', + 'provenance', + 'instructionalMethod', + 'accrualMethod', + 'accrualPeriodicity', + 'accrualPolicy', + ]; + + /* Must create elements using createElement to make DOM allow a + * top-level xmlns declaration instead of wasteful and non- + * compliant per-node declarations. + */ + foreach ($localNames as $localName) { + $term = 'dcterms:' . $localName; + $values = $item->value($term, ['all' => true, 'default' => []]); + $values = $this->filterValues($item, $term, $values); + foreach ($values as $value) { + $this->appendNewElement($oai, $term, (string) $value); + } + } + + $appendIdentifier = $this->singleIdentifier($item); + if ($appendIdentifier) { + $this->appendNewElement($oai, 'dcterms:identifier', $appendIdentifier); + } + + // Also append an identifier for each file + if ($this->settings->get('oaipmhrepository_expose_media', false)) { + foreach ($item->media() as $media) { + $this->appendNewElement($oai, 'dcterms:identifier', $media->originalUrl()); + } + } + } + + public function getMetadataPrefix() + { + return self::METADATA_PREFIX; + } + + public function getMetadataSchema() + { + return self::METADATA_SCHEMA; + } + + public function getMetadataNamespace() + { + return self::METADATA_NAMESPACE; + } +} diff --git a/src/Service/OaiPmh/Metadata/OaiDctermsFactory.php b/src/Service/OaiPmh/Metadata/OaiDctermsFactory.php new file mode 100644 index 0000000..7ec8865 --- /dev/null +++ b/src/Service/OaiPmh/Metadata/OaiDctermsFactory.php @@ -0,0 +1,30 @@ +<?php + +namespace OaiPmhRepository\Service\OaiPmh\Metadata; + +use Interop\Container\ContainerInterface; +use OaiPmhRepository\OaiPmh\Metadata\OaiDcterms; +use Zend\ServiceManager\Factory\FactoryInterface; + +class OaiDctermsFactory implements FactoryInterface +{ + /** + * Prepare the OaiDcterms format. + * + * @return OaiDcterms + */ + public function __invoke(ContainerInterface $services, $requestedName, array $options = null) + { + $settings = $services->get('Omeka\Settings'); + $oaiSetManager = $services->get('OaiPmhRepository\OaiPmh\OaiSetManager'); + $oaiSet = $oaiSetManager->get($settings->get('oaipmhrepository_oai_set_format', 'base')); + $metadataFormat = new OaiDcterms(); + $metadataFormat->setEventManager($services->get('EventManager')); + $metadataFormat->setSettings($settings); + $metadataFormat->setOaiSet($oaiSet); + $isGlobalRepository = !$services->get('ControllerPluginManager') + ->get('params')->fromRoute('__SITE__', false); + $metadataFormat->setIsGlobalRepository($isGlobalRepository); + return $metadataFormat; + } +} -- GitLab