/** * @covers PKPLocale */ public function testGet3LetterIsoFromLocale() { self::assertEquals('eng', Locale::get3LetterIsoFromLocale('en_US')); self::assertEquals('por', Locale::get3LetterIsoFromLocale('pt_BR')); self::assertEquals('por', Locale::get3LetterIsoFromLocale('pt_PT')); self::assertNull(Locale::get3LetterIsoFromLocale('xx_XX')); }
/** * @see MetadataDataObjectAdapter::extractMetadataFromDataObject() * @param $submission Submission * @param $authorMarcrelatorRole string the marcrelator role to be used * for submission authors. * @return MetadataDescription */ function &extractMetadataFromDataObject(&$submission, $authorMarcrelatorRole = 'aut') { assert(is_a($submission, 'Submission')); $mods34Description =& $this->instantiateMetadataDescription(); // Retrieve the primary locale. $catalogingLocale = Locale::getPrimaryLocale(); $catalogingLanguage = Locale::get3LetterIsoFromLocale($catalogingLocale); // Establish the association between the meta-data description // and the submission. $mods34Description->setAssocId($submission->getId()); // Title $localizedTitles =& $submission->getTitle(null); // Localized $this->addLocalizedStatements($mods34Description, 'titleInfo/title', $localizedTitles); // Authors // FIXME: Move this to a dedicated adapter in the Author class. $authors =& $submission->getAuthors(); foreach ($authors as $author) { /* @var $author Author */ // Create a new name description. $authorDescription = new MetadataDescription('lib.pkp.plugins.metadata.mods34.schema.Mods34NameSchema', ASSOC_TYPE_AUTHOR); // Type $authorType = 'personal'; $authorDescription->addStatement('[@type]', $authorType); // Family Name $authorDescription->addStatement('namePart[@type="family"]', $author->getLastName()); // Given Names $firstName = (string) $author->getFirstName(); $middleName = (string) $author->getMiddleName(); $givenNames = trim($firstName . ' ' . $middleName); if (!empty($givenNames)) { $authorDescription->addStatement('namePart[@type="given"]', $givenNames); } // Affiliation // NB: Our MODS mapping currently doesn't support translation for names. // This can be added when required by data consumers. We therefore only use // translations in the cataloging language. $affiliation = $author->getAffiliation($catalogingLocale); if ($affiliation) { $authorDescription->addStatement('affiliation', $affiliation); } // Terms of address (unmapped field) $termsOfAddress = $author->getData('nlm34:namePart[@type="termsOfAddress"]'); if ($termsOfAddress) { $authorDescription->addStatement('namePart[@type="termsOfAddress"]', $termsOfAddress); } // Date (unmapped field) $date = $author->getData('nlm34:namePart[@type="date"]'); if ($date) { $authorDescription->addStatement('namePart[@type="date"]', $date); } // Role $authorDescription->addStatement('role/roleTerm[@type="code" @authority="marcrelator"]', $authorMarcrelatorRole); // Add the author to the MODS schema. $mods34Description->addStatement('name', $authorDescription); unset($authorDescription); } // Sponsor // NB: Our MODS mapping currently doesn't support translation for names. // This can be added when required by data consumers. We therefore only use // translations in the cataloging language. $supportingAgency = $submission->getSponsor($catalogingLocale); if ($supportingAgency) { $supportingAgencyDescription = new MetadataDescription('lib.pkp.plugins.metadata.mods34.schema.Mods34NameSchema', ASSOC_TYPE_AUTHOR); $sponsorNameType = 'corporate'; $supportingAgencyDescription->addStatement('[@type]', $sponsorNameType); $supportingAgencyDescription->addStatement('namePart', $supportingAgency); $sponsorRole = 'spn'; $supportingAgencyDescription->addStatement('role/roleTerm[@type="code" @authority="marcrelator"]', $sponsorRole); $mods34Description->addStatement('name', $supportingAgencyDescription); } // Type of resource $typeOfResource = 'text'; $mods34Description->addStatement('typeOfResource', $typeOfResource); // Creation & copyright date $submissionDate = $submission->getDateSubmitted(); if (strlen($submissionDate) >= 4) { $mods34Description->addStatement('originInfo/dateCreated[@encoding="w3cdtf"]', $submissionDate); $mods34Description->addStatement('originInfo/copyrightDate[@encoding="w3cdtf"]', substr($submissionDate, 0, 4)); } // Submission language $submissionLanguage = Locale::get3LetterFrom2LetterIsoLanguage($submission->getLanguage()); if (!$submissionLanguage) { // Assume the cataloging language by default. $submissionLanguage = $catalogingLanguage; } $mods34Description->addStatement('language/languageTerm[@type="code" @authority="iso639-2b"]', $submissionLanguage); // Pages (extent) $mods34Description->addStatement('physicalDescription/extent', $submission->getPages()); // Abstract $localizedAbstracts =& $submission->getAbstract(null); // Localized $this->addLocalizedStatements($mods34Description, 'abstract', $localizedAbstracts); // Discipline $localizedDisciplines = $submission->getDiscipline(null); // Localized $this->addLocalizedStatements($mods34Description, 'subject/topic', $localizedDisciplines); // Subject class $localizedSubjectClasses = $submission->getSubjectClass(null); // Localized $this->addLocalizedStatements($mods34Description, 'subject/topic', $localizedSubjectClasses); // Subject $localizedSubjects = $submission->getSubject(null); // Localized $this->addLocalizedStatements($mods34Description, 'subject/topic', $localizedSubjects); // Geographical coverage $localizedCoverageGeo = $submission->getCoverageGeo(null); // Localized $this->addLocalizedStatements($mods34Description, 'subject/geographic', $localizedCoverageGeo); // Chronological coverage $localizedCoverageChron = $submission->getCoverageChron(null); // Localized $this->addLocalizedStatements($mods34Description, 'subject/temporal', $localizedCoverageChron); // Record creation date $recordCreationDate = date('Y-m-d'); $mods34Description->addStatement('recordInfo/recordCreationDate[@encoding="w3cdtf"]', $recordCreationDate); // Record identifier $mods34Description->addStatement('recordInfo/recordIdentifier[@source="pkp"]', $submission->getId()); // Cataloging language $mods34Description->addStatement('recordInfo/languageOfCataloging/languageTerm[@authority="iso639-2b"]', $catalogingLanguage); // Handle unmapped fields. $this->extractUnmappedDataObjectMetadataFields($submission, $mods34Description); return $mods34Description; }
/** * Create a hierarchical array that represents the MODS DOM * from the meta-data description. * * @param $doc XMLNode|DOMDocument the MODS document node. * @param $root XMLNode|DOMDocument the root node of the * MODS document. * @param $modsDescription MetadataDescription * @return array a hierarchical array of XMLNode|DOMDocument objects * representing the MODS document. */ function &_buildDocumentHierarchy(&$doc, &$root, &$modsDescription) { // Get the MODS schema. $modsSchema =& $modsDescription->getMetadataSchema(); if (is_a($modsSchema, 'ModsSchema')) { // Identify the cataloging language. assert($modsDescription->hasStatement('recordInfo/languageOfCataloging/languageTerm[@authority="iso639-2b"]')); $catalogingLanguage = $modsDescription->getStatement('recordInfo/languageOfCataloging/languageTerm[@authority="iso639-2b"]'); } else { // This must be a MODS name schema. assert(is_a($modsSchema, 'ModsNameSchema')); $catalogingLanguage = 'undefined'; } // Initialize the document hierarchy with the root node. $documentHierarchy = array('@branch' => &$root); // Find the translations required for top-level elements. // We need this array later because we'll have to repeat non-translated // values for every translated top-level element. $properties = $modsDescription->getProperties(); $translations = array(); foreach ($properties as $propertyName => $property) { /* @var $property MetadataProperty */ if ($modsDescription->hasStatement($propertyName)) { $nodes = explode('/', $propertyName); $topLevelNode = array_shift($nodes); if (!isset($translations[$topLevelNode])) { $translations[$topLevelNode] = array(); } if ($property->getTranslated()) { foreach ($modsDescription->getStatementTranslations($propertyName) as $locale => $value) { $isoLanguage = Locale::get3LetterIsoFromLocale($locale); if (!in_array($isoLanguage, $translations[$topLevelNode])) { $translations[$topLevelNode][] = $isoLanguage; } } } else { if (!in_array($catalogingLanguage, $translations[$topLevelNode])) { $translations[$topLevelNode][] = $catalogingLanguage; } } } } // Build the document hierarchy. foreach ($properties as $propertyName => $property) { /* @var $property MetadataProperty */ if ($modsDescription->hasStatement($propertyName)) { // Get relevant property attributes. $translated = $property->getTranslated(); $cardinality = $property->getCardinality(); // Get the XML element hierarchy. $nodes = explode('/', $propertyName); $hierarchyDepth = count($nodes) - 1; // Normalize property values to an array of translated strings. if ($translated) { // Only the main MODS schema can contain translated values. assert(is_a($modsSchema, 'ModsSchema')); // Retrieve the translated values of the statement. $localizedValues =& $modsDescription->getStatementTranslations($propertyName); // Translate the PKP locale into ISO639-2b 3-letter codes. $translatedValues = array(); foreach ($localizedValues as $locale => $translatedValue) { $isoLanguage = Locale::get3LetterIsoFromLocale($locale); assert(!is_null($isoLanguage)); $translatedValues[$isoLanguage] = $translatedValue; } } else { // Untranslated statements will be repeated for all languages // present in the top-level element. $untranslatedValue =& $modsDescription->getStatement($propertyName); $translatedValues = array(); assert(isset($translations[$nodes[0]])); foreach ($translations[$nodes[0]] as $isoLanguage) { $translatedValues[$isoLanguage] = $untranslatedValue; } } // Normalize all values to arrays so that we can // handle them uniformly. $translatedValueArrays = array(); foreach ($translatedValues as $isoLanguage => $translatedValue) { if ($cardinality == METADATA_PROPERTY_CARDINALITY_ONE) { assert(is_scalar($translatedValue)); $translatedValueArrays[$isoLanguage] = array(&$translatedValue); } else { assert(is_array($translatedValue)); $translatedValueArrays[$isoLanguage] =& $translatedValue; } unset($translatedValue); } // Add the translated values one by one to the element hierarchy. foreach ($translatedValueArrays as $isoLanguage => $translatedValueArray) { foreach ($translatedValueArray as $translatedValue) { // Add a language attribute to the top-level element if // it differs from the cataloging language. $translatedNodes = $nodes; if ($isoLanguage != $catalogingLanguage) { assert(strpos($translatedNodes[0], '[') === false); $translatedNodes[0] .= '[@lang="' . $isoLanguage . '"]'; } // Create the node hierarchy for the statement. $currentNodeList =& $documentHierarchy; foreach ($translatedNodes as $nodeDepth => $nodeName) { // Are we at a leaf node? if ($nodeDepth == $hierarchyDepth) { // Is this a top-level attribute? if (substr($nodeName, 0, 1) == '[') { assert($nodeDepth == 0); assert($translated == false); assert($cardinality == METADATA_PROPERTY_CARDINALITY_ONE); assert(!is_object($translatedValue)); $attributeName = trim($nodeName, '[@"]'); XMLCustomWriter::setAttribute($root, $attributeName, (string) $translatedValue); continue; } // This is a sub-element. if (isset($currentNodeList[$nodeName])) { // Only properties with cardinality "many" can // have more than one leaf node. assert($cardinality == METADATA_PROPERTY_CARDINALITY_MANY); // Check that the leaf list is actually there. assert(isset($currentNodeList[$nodeName]['@leaves'])); // We should never find any branch in a leaves node. assert(!isset($currentNodeList[$nodeName]['@branch'])); } else { // Create the leaf list in the hierarchy. $currentNodeList[$nodeName]['@leaves'] = array(); } if (is_a($translatedValue, 'MetadataDescription')) { // Recursively process composite properties. $leafNode =& $this->_processCompositeProperty($doc, $propertyName, $translatedValue); } else { // Cast scalar values to string types for XML binding. $translatedValue = (string) $translatedValue; // Create the leaf element. $leafNode =& $this->_createNode($doc, $nodeName, $translatedValue); } // Add the leaf element to the leaves list. $currentNodeList[$nodeName]['@leaves'][] =& $leafNode; unset($leafNode); } else { // This is a branch node. // Has the branch already been created? If not: create it. if (isset($currentNodeList[$nodeName])) { // Check that the branch node is actually there. assert(isset($currentNodeList[$nodeName]['@branch'])); // We should never find any leaves in a branch node. assert(!isset($currentNodeList[$nodeName]['@leaves'])); } else { // Create the branch node. $branchNode =& $this->_createNode($doc, $nodeName); // Add the branch node list and add the new node as it's root element. $currentNodeList[$nodeName] = array('@branch' => &$branchNode); unset($branchNode); } } // Set the node list pointer to the sub-element $currentNodeList =& $currentNodeList[$nodeName]; } } } } } return $documentHierarchy; }