/** * @covers MetadataDescriptionDummyAdapter */ public function testMetadataDescriptionDummyAdapter() { $schema = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema'; // Instantiate a test description. $originalDescription = new MetadataDescription($schema, ASSOC_TYPE_CITATION); $originalDescription->addStatement('source', $originalTitle = 'original source'); $originalDescription->addStatement('article-title', $originalTitle = 'original title'); // Test constructor. $adapter = new MetadataDescriptionDummyAdapter($originalDescription); self::assertEquals(ASSOC_TYPE_CITATION, $adapter->getAssocType()); self::assertEquals($schema, $adapter->getMetadataSchemaName()); self::assertInstanceOf('Nlm30CitationSchema', $adapter->getMetadataSchema()); // Test metadata injection. $sourceDescription = new MetadataDescription($schema, ASSOC_TYPE_CITATION); $sourceDescription->addStatement('article-title', $injectedTitle = 'injected title'); $resultDescription =& $adapter->injectMetadataIntoDataObject($sourceDescription, $originalDescription); $expectedResult = array('source' => array('en_US' => 'original source'), 'article-title' => array('en_US' => 'injected title')); self::assertEquals($expectedResult, $resultDescription->getStatements()); // Test meta-data extraction. $extractedDescription = $adapter->extractMetadataFromDataObject($originalDescription); self::assertEquals($originalDescription, $extractedDescription); // Test meta-data field names (only test one field of each // category (translated or not) so that the test doesn't // break when we expand the NLM schema). $fieldNames = $adapter->getMetadataFieldNames(false); self::assertTrue(in_array('date', $fieldNames)); // NB: no namespace pre-fix in this case! $fieldNames = $adapter->getMetadataFieldNames(true); self::assertTrue(in_array('article-title', $fieldNames)); }
/** * Creates a test description in Openurl10 format * @return MetadataDescription */ protected function getTestOpenurl10Description() { $citationData = array('aulast' => 'von Surname1', 'aufirst' => 'Given1 P', 'auinit1' => 'G', 'auinitm' => 'P', 'auinit' => 'GP', 'ausuffix' => 'suff', 'au' => array(0 => 'Surname1 suff, P. (Given1) von', 1 => 'Surname2, (Given2)'), 'genre' => 'article', 'jtitle' => 'Some Journal Title', 'atitle' => 'Some Article Title', 'date' => '2005-07-03', 'issn' => '0694760949645', 'spage' => 17, 'epage' => 33, 'volume' => '7', 'issue' => '5', 'eissn' => '3049674960475', 'artnum' => '45', 'coden' => 'coden', 'sici' => 'sici'); $openurl10Description = new MetadataDescription('lib.pkp.plugins.metadata.openurl10.schema.Openurl10JournalSchema', ASSOC_TYPE_CITATION); self::assertTrue($openurl10Description->setStatements($citationData)); return $openurl10Description; }
private function serializeCitationDescription(MetadataDescription &$citationDescription) { // Prepare transformation tables for the output serialization: // - the following lines will be deleted from our output file static $linesToDelete = array(' [0-9]+ => ', ' array \\(', ' \'_data\' => ', ' \\),'); // Transform person descriptions to arrays $citationDescriptionArray = $citationDescription->getStatements(); $personDescriptionProperties = array('person-group[@person-group-type="author"]', 'person-group[@person-group-type="editor"]'); foreach ($personDescriptionProperties as $personDescriptionProperty) { if (isset($citationDescriptionArray[$personDescriptionProperty])) { foreach ($citationDescriptionArray[$personDescriptionProperty] as &$person) { $person = $person->getStatements(); } } } // Transform the result into an array that we can serialize // in a human-readable form and also re-import as PHP-parsable code. $citationDescriptionOutput = var_export($citationDescriptionArray, true); $citationDescriptionOutputArray = explode("\n", $citationDescriptionOutput); foreach ($citationDescriptionOutputArray as $key => &$citationDescriptionOutputLine) { // Remove redundant lines foreach ($linesToDelete as $lineToDelete) { if (preg_match('/^' . $lineToDelete . '$/', $citationDescriptionOutputLine)) { unset($citationDescriptionOutputArray[$key]); } } // Correctly indent the output line $citationDescriptionOutputLine = "\t\t\t" . preg_replace('/^\\t\\t\\t/', "\t\t", str_replace(' ', "\t", $citationDescriptionOutputLine)); } // Create the final serialized format return implode("\n", $citationDescriptionOutputArray); }
/** * @covers Nlm30CitationSchemaCitationAdapter */ public function testNlm30CitationSchemaCitationAdapter() { // Test constructor. $adapter = new Nlm30CitationSchemaCitationAdapter(PersistableFilter::tempGroup('metadata::lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema(CITATION)', 'class::lib.pkp.classes.citation.Citation')); self::assertEquals(ASSOC_TYPE_CITATION, $adapter->getAssocType()); self::assertType('Nlm30CitationSchema', $adapter->getMetadataSchema()); self::assertEquals('Citation', $adapter->getDataObjectClass()); // Instantiate a test description. $authorDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema', ASSOC_TYPE_AUTHOR); $authorDescription->addStatement('surname', $surname = 'some surname'); $citationDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema', ASSOC_TYPE_CITATION); $citationDescription->addStatement('article-title', $articleTitle = 'article title'); $citationDescription->addStatement('person-group[@person-group-type="author"]', $authorDescription); // Instantiate test citation. $citation = new Citation(); // Test metadata injection. $resultCitation =& $adapter->injectMetadataIntoDataObject($citationDescription, $citation); $expectedResult = array('rawCitation' => '', 'nlm30:person-group[@person-group-type="author"]' => array(array('surname' => 'some surname')), 'nlm30:article-title' => array('en_US' => 'article title')); self::assertEquals($expectedResult, $resultCitation->getAllData()); // Instantiate and inject a second test description. $authorDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema', ASSOC_TYPE_AUTHOR); $authorDescription->addStatement('surname', $anotherSurname = 'another surname'); $secondDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema', ASSOC_TYPE_CITATION); $secondDescription->addStatement('person-group[@person-group-type="author"]', $authorDescription); $secondDescription->addStatement('source', $source = 'some source'); $resultCitation =& $adapter->injectMetadataIntoDataObject($secondDescription, $citation); $expectedResult = array('rawCitation' => '', 'nlm30:person-group[@person-group-type="author"]' => array(array('surname' => 'another surname')), 'nlm30:article-title' => array('en_US' => 'article title'), 'nlm30:source' => array('en_US' => 'some source')); self::assertEquals($expectedResult, $resultCitation->getAllData()); // Test meta-data extraction. $adapter = new Nlm30CitationSchemaCitationAdapter(PersistableFilter::tempGroup('class::lib.pkp.classes.citation.Citation', 'metadata::lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema(CITATION)')); $extractedDescription =& $adapter->extractMetadataFromDataObject($resultCitation); $secondDescription->addStatement('article-title', $articleTitle = 'article title'); self::assertEquals($secondDescription, $extractedDescription); }
/** * @covers PKPSubmissionNlm30XmlFilter */ public function testExecute() { // Instantiate test meta-data for a citation. import('lib.pkp.classes.metadata.MetadataDescription'); $nameSchemaName = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema'; $nameDescription = new MetadataDescription($nameSchemaName, ASSOC_TYPE_AUTHOR); $nameDescription->addStatement('given-names', $value = 'Peter'); $nameDescription->addStatement('given-names', $value = 'B'); $nameDescription->addStatement('surname', $value = 'Bork'); $nameDescription->addStatement('prefix', $value = 'Mr.'); $citationSchemaName = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema'; $citationDescription = new MetadataDescription($citationSchemaName, ASSOC_TYPE_CITATION); $citationDescription->addStatement('person-group[@person-group-type="author"]', $nameDescription); $citationDescription->addStatement('article-title', $value = 'PHPUnit in a nutshell', 'en_US'); $citationDescription->addStatement('date', $value = '2009-08-17'); $citationDescription->addStatement('size', $value = 320); $citationDescription->addStatement('uri', $value = 'http://phpunit.org/nutshell'); $citationDescription->addStatement('[@publication-type]', $value = 'book'); $citation =& $this->getCitation($citationDescription); // Persist a few copies of the citation for testing. $citationDao =& $this->getCitationDao(); for ($seq = 1; $seq <= 10; $seq++) { $citation->setSeq($seq); $citation->setCitationState(CITATION_APPROVED); $citationId = $citationDao->insertObject($citation); self::assertTrue(is_numeric($citationId)); self::assertTrue($citationId > 0); } // Execute the filter and check the outcome. $mockSubmission =& $this->getTestSubmission(); // FIXME: Add NLM 3.0 tag set schema validation as soon as we implement the full tag set, see #5648. $filter = new PKPSubmissionNlm30XmlFilter(PersistableFilter::tempGroup('class::lib.pkp.classes.submission.Submission', 'xml::*')); $nlm30Xml = $filter->execute($mockSubmission); self::assertXmlStringEqualsXmlFile('./lib/pkp/tests/plugins/metadata/nlm30/filter/sample-nlm30-citation.xml', $nlm30Xml); }
/** * @covers Nlm30NameSchemaPersonStringFilter * @covers Nlm30PersonStringFilter * @depends testExecuteWithSinglePersonDescription */ public function testExecuteWithMultiplePersonDescriptions($personDescription1) { $personDescription2 = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema', ASSOC_TYPE_AUTHOR); $personDescription2->addStatement('given-names', $givenNames1 = 'Bernardo'); $personDescription2->addStatement('given-names', $givenNames2 = 'Antonio'); $personDescription2->addStatement('surname', $surname = 'Elis'); $personDescriptions = array($personDescription1, $personDescription2, PERSON_STRING_FILTER_ETAL); $nlm30NameSchemaPersonStringFilter = new Nlm30NameSchemaPersonStringFilter(PERSON_STRING_FILTER_MULTIPLE); self::assertEquals('Assis Jr, (Machado) de; Elis, A. (Bernardo); et al', $nlm30NameSchemaPersonStringFilter->execute($personDescriptions)); // Test template and delimiter $nlm30NameSchemaPersonStringFilter->setDelimiter(':'); $nlm30NameSchemaPersonStringFilter->setTemplate('%firstname%%initials%%prefix% %surname%%suffix%'); self::assertEquals('Machado de Assis Jr:Bernardo A. Elis:et al', $nlm30NameSchemaPersonStringFilter->execute($personDescriptions)); }
public function testCitationCrud() { $nameSchema = new NlmNameSchema(); $nameDescription = new MetadataDescription($nameSchema, ASSOC_TYPE_AUTHOR); $nameDescription->addStatement('given-names', $value = 'Peter'); $nameDescription->addStatement('given-names', $value = 'B'); $nameDescription->addStatement('surname', $value = 'Bork'); $nameDescription->addStatement('prefix', $value = 'Mr.'); $citationSchema = new NlmCitationSchema(); $citationDescription = new MetadataDescription($citationSchema, ASSOC_TYPE_CITATION); $citationDescription->addStatement('person-group[@person-group-type="author"]', $nameDescription); $citationDescription->addStatement('article-title', $value = 'PHPUnit in a nutshell', 'en_US'); $citationDescription->addStatement('article-title', $value = 'PHPUnit in Kürze', 'de_DE'); $citationDescription->addStatement('date', $value = '2009-08-17'); $citationDescription->addStatement('size', $value = 320); $citationDescription->addStatement('uri', $value = 'http://phpunit.org/nutshell'); $citation = new Citation('raw citation'); $citation->setAssocType(ASSOC_TYPE_ARTICLE); $citation->setAssocId(5); $citation->setEditedCitation('edited citation'); $citation->setParseScore(50); $citation->injectMetadata($citationDescription); $citationId = $this->citationDAO->insertCitation($citation); self::assertTrue(is_numeric($citationId)); self::assertTrue($citationId > 0); }
/** * @covers NlmNameSchemaPersonStringFilter::supports * @covers NlmNameSchemaPersonStringFilter::execute * @covers NlmNameSchemaPersonStringFilter::isValid * @covers NlmNameSchemaPersonStringFilter::_flattenPersonsDescriptions * @depends testExecuteWithSinglePersonDescription */ public function testExecuteWithMultiplePersonDescriptions($personDescription1) { $nlmNameSchema = new NlmNameSchema(); $personDescription2 = new MetadataDescription($nlmNameSchema, ASSOC_TYPE_AUTHOR); $personDescription2->addStatement('given-names', $givenNames1 = 'Bernardo'); $personDescription2->addStatement('given-names', $givenNames2 = 'Antonio'); $personDescription2->addStatement('surname', $surname = 'Elis'); $personDescriptions = array($personDescription1, $personDescription2); $this->_nlmNameSchemaPersonStringFilter->setFilterMode(PERSON_STRING_FILTER_MULTIPLE); self::assertEquals('Assis Jr, (Machado) de; Elis, A. (Bernardo)', $this->_nlmNameSchemaPersonStringFilter->execute($personDescriptions)); // Test template and delimiter $this->_nlmNameSchemaPersonStringFilter->setDelimiter(':'); $this->_nlmNameSchemaPersonStringFilter->setTemplate('%firstname%%initials%%prefix% %surname%%suffix%'); self::assertEquals('Machado de Assis Jr:Bernardo A. Elis', $this->_nlmNameSchemaPersonStringFilter->execute($personDescriptions)); }
public function testCitationCrud() { $nameSchema = new NlmNameSchema(); $nameDescription = new MetadataDescription($nameSchema, ASSOC_TYPE_AUTHOR); $nameDescription->addStatement('given-names', $value = 'Peter'); $nameDescription->addStatement('given-names', $value = 'B'); $nameDescription->addStatement('surname', $value = 'Bork'); $nameDescription->addStatement('prefix', $value = 'Mr.'); $citationSchema = new NlmCitationSchema(); $citationDescription = new MetadataDescription($citationSchema, ASSOC_TYPE_CITATION); $citationDescription->addStatement('person-group[@person-group-type="author"]', $nameDescription); $citationDescription->addStatement('article-title', $value = 'PHPUnit in a nutshell', 'en_US'); $citationDescription->addStatement('article-title', $value = 'PHPUnit in Kürze', 'de_DE'); $citationDescription->addStatement('date', $value = '2009-08-17'); $citationDescription->addStatement('size', $value = 320); $citationDescription->addStatement('uri', $value = 'http://phpunit.org/nutshell'); $citation = new Citation('raw citation'); $citation->setAssocType(ASSOC_TYPE_ARTICLE); $citation->setAssocId(999999); $citation->setEditedCitation('edited citation'); $citation->setParseScore(50); $citation->injectMetadata($citationDescription); // Create citation $citationId = $this->citationDAO->insertCitation($citation); self::assertTrue(is_numeric($citationId)); self::assertTrue($citationId > 0); // Retrieve citation $citationById = $this->citationDAO->getCitation($citationId); $citationById->getMetadataFieldNames(); // Initializes internal state for comparison. self::assertEquals($citation, $citationById); $citationsByAssocIdDaoFactory = $this->citationDAO->getCitationsByAssocId(ASSOC_TYPE_ARTICLE, 999999); $citationsByAssocId = $citationsByAssocIdDaoFactory->toArray(); self::assertEquals(1, count($citationsByAssocId)); $citationsByAssocId[0]->getMetadataFieldNames(); // Initializes internal state for comparison. self::assertEquals($citation, $citationsByAssocId[0]); // Update citation $citationDescription->removeStatement('date'); $citationDescription->addStatement('article-title', $value = 'PHPUnit rápido', 'pt_BR'); $updatedCitation = new Citation('another raw citation'); $updatedCitation->setId($citationId); $updatedCitation->setAssocType(ASSOC_TYPE_ARTICLE); $updatedCitation->setAssocId(999998); $updatedCitation->setEditedCitation('another edited citation'); $updatedCitation->setParseScore(50); $updatedCitation->injectMetadata($citationDescription); $this->citationDAO->updateCitation($updatedCitation); $citationAfterUpdate = $this->citationDAO->getCitation($citationId); $citationAfterUpdate->getMetadataFieldNames(); // Initializes internal state for comparison. self::assertEquals($updatedCitation, $citationAfterUpdate); // Delete citation $this->citationDAO->deleteCitationsByAssocId(ASSOC_TYPE_ARTICLE, 999998); self::assertNull($this->citationDAO->getCitation($citationId)); }
/** * This implementation of the CrosswalkFilter * simply removes statements from the incoming meta-data * description that are not in the target description's schema. * @see Filter::process() * @param $input MetadataDescription * @return MetadataDescription */ function &process(&$input) { // Create the target description $output = new MetadataDescription($this->_toSchema); // Compare the property names of the incoming description with // the property names allowed in the target schema. $sourceProperties = $input->getSetPropertyNames(); $targetProperties = $output->getPropertyNames(); $propertiesToBeRemoved = array_diff($sourceProperties, $targetProperties); // Remove statements for properties that are not in the target schema. $statements =& $input->getStatements(); foreach ($propertiesToBeRemoved as $propertyToBeRemoved) { assert(isset($statements[$propertyToBeRemoved])); unset($statements[$propertyToBeRemoved]); } // Set the remaining statements in the target description $success = $output->setStatements($statements); assert($success); return $output; }
/** * Map OpenURL properties to NLM properties. * NB: OpenURL has no i18n so we use the default * locale when mapping. * @see Filter::process() * @param $input MetadataDescription * @return MetadataDescription */ function &process(&$input) { $nullVar = null; // Instantiate the target description. $outputSchema = new NlmCitationSchema(); $output = new MetadataDescription($outputSchema, $input->getAssocType()); // Parse au statements into name descriptions import('metadata.nlm.PersonStringNlmNameSchemaFilter'); $personStringFilter = new PersonStringNlmNameSchemaFilter(ASSOC_TYPE_AUTHOR); $authors =& $input->getStatement('au'); if (is_array($authors) && count($authors)) { // TODO: We might improve results here by constructing the // first author from aufirst, aulast fields. foreach ($authors as $author) { $authorDescription =& $personStringFilter->execute($author); $success = $output->addStatement('person-group[@person-group-type="author"]', $authorDescription); assert($success); unset($authorDescription); } } // Publication type if ($input->hasStatement('genre')) { $genre = $input->getStatement('genre'); $genreMap = $this->_getOpenUrlGenreTranslationMapping(); $publicationType = isset($genreMap[$genre]) ? $genreMap[$genre] : $genre; $success = $output->addStatement('[@publication-type]', $publicationType); assert($success); } // Get NLM => OpenURL property mapping. $propertyMap =& $this->nlmOpenUrlMapping($publicationType, $input->getMetadataSchema()); // Transfer mapped properties with default locale foreach ($propertyMap as $nlmProperty => $openUrlProperty) { if ($input->hasStatement($openUrlProperty)) { $success = $output->addStatement($nlmProperty, $input->getStatement($openUrlProperty)); assert($success); } } return $output; }
/** * Custom implementation of Form::validate() that validates * meta-data form data and injects it into the internal citation * object. * * NB: The configuration of the internal citation object * would normally be done in readInputData(). Validation and * injection can easily be done in one step. It therefore avoids * code duplication and improves performance to do both here. */ function validate() { // Make sure that this method is not called twice which // would corrupt internal state. assert(empty($this->_metadataDescriptions)); parent::validate(); // Validate form data and inject it into // the associated citation object. $citation =& $this->getCitation(); $citation->setRawCitation($this->getData('rawCitation')); if ($this->getData('citationApproved') == 'citationApproved') { // Editor's shortcut to the approved state, e.g. for manually edited citations. $citation->setCitationState(CITATION_APPROVED); } elseif (in_array($this->getData('citationState'), Citation::_getSupportedCitationStates())) { // Reset citation state if necessary if ($this->getData('citationState') == CITATION_APPROVED) { $this->setData('citationState', CITATION_LOOKED_UP); } $citation->setCitationState($this->getData('citationState')); } // Extract data from citation form fields and inject it into the citation import('lib.pkp.classes.metadata.MetadataDescription'); $metadataSchemas = $citation->getSupportedMetadataSchemas(); foreach ($metadataSchemas as $metadataSchema) { /* @var $metadataSchema MetadataSchema */ // Instantiate a meta-data description for the given schema $metadataDescription = new MetadataDescription($metadataSchema->getClassName(), ASSOC_TYPE_CITATION); // Set the meta-data statements foreach ($metadataSchema->getProperties() as $propertyName => $property) { $fieldName = $metadataSchema->getNamespacedPropertyId($propertyName); $fieldValue = trim($this->getData($fieldName)); if (empty($fieldValue)) { // Delete empty statements so that previously set // statements (if any) will be deleted. $metadataDescription->removeStatement($propertyName); if ($property->getMandatory()) { // A mandatory field is missing - add a validation error. $this->addError($fieldName, __($property->getValidationMessage())); $this->addErrorField($fieldName); } } else { // Try to convert the field value to (a) strongly // typed object(s) if applicable. Start with the most // specific allowed type so that we always get the // most strongly typed result possible. $allowedTypes = $property->getAllowedTypes(); switch (true) { case isset($allowedTypes[METADATA_PROPERTY_TYPE_VOCABULARY]) && is_numeric($fieldValue): case isset($allowedTypes[METADATA_PROPERTY_TYPE_INTEGER]) && is_numeric($fieldValue): $typedFieldValues = array((int) $fieldValue); break; case isset($allowedTypes[METADATA_PROPERTY_TYPE_DATE]): import('lib.pkp.classes.metadata.DateStringNormalizerFilter'); $dateStringFilter = new DateStringNormalizerFilter(); assert($dateStringFilter->supportsAsInput($fieldValue)); $typedFieldValues = array($dateStringFilter->execute($fieldValue)); break; case isset($allowedTypes[METADATA_PROPERTY_TYPE_COMPOSITE]): // We currently only support name composites $allowedAssocIds = $allowedTypes[METADATA_PROPERTY_TYPE_COMPOSITE]; if (in_array(ASSOC_TYPE_AUTHOR, $allowedAssocIds)) { $assocType = ASSOC_TYPE_AUTHOR; } elseif (in_array(ASSOC_TYPE_EDITOR, $allowedAssocIds)) { $assocType = ASSOC_TYPE_EDITOR; } else { assert(false); } // Try to transform the field to a name composite. import('lib.pkp.plugins.metadata.nlm30.filter.PersonStringNlm30NameSchemaFilter'); $personStringFilter = new PersonStringNlm30NameSchemaFilter($assocType, PERSON_STRING_FILTER_MULTIPLE); assert($personStringFilter->supportsAsInput($fieldValue)); $typedFieldValues =& $personStringFilter->execute($fieldValue); break; default: $typedFieldValues = array($fieldValue); } // Inject data into the meta-data description and thereby // implicitly validate the field value. foreach ($typedFieldValues as $typedFieldValue) { if (!$metadataDescription->addStatement($propertyName, $typedFieldValue)) { // Add form field error $this->addError($fieldName, __($property->getValidationMessage())); $this->addErrorField($fieldName); } unset($typedFieldValue); } unset($typedFieldValues); } } // Inject the meta-data into the citation. $citation->injectMetadata($metadataDescription); // Save the meta-data description for later usage. $this->_metadataDescriptions[] =& $metadataDescription; unset($metadataDescription); } return $this->isValid(); }
/** * @covers Nlm30Nlm23CrosswalkFilter */ public function testExecute() { $this->markTestSkipped('Weird class interaction with ControlledVocabEntryDAO leads to failure'); // Instantiate test meta-data for a citation. This must use the complete // available schema (although in practice this doesn't make sense) so that // we can make sure all tags are correctly converted. import('lib.pkp.classes.metadata.MetadataDescription'); $nameSchemaName = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema'; $nameDescription = new MetadataDescription($nameSchemaName, ASSOC_TYPE_AUTHOR); $nameDescription->addStatement('given-names', $value = 'Peter'); $nameDescription->addStatement('given-names', $value = 'B'); $nameDescription->addStatement('surname', $value = 'Bork'); $nameDescription->addStatement('prefix', $value = 'Mr.'); $nameDescription->addStatement('suffix', $value = 'Jr'); $citationSchemaName = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema'; $citationDescription = new MetadataDescription($citationSchemaName, ASSOC_TYPE_CITATION); $citationDescription->addStatement('person-group[@person-group-type="author"]', $nameDescription); $citationDescription->addStatement('person-group[@person-group-type="editor"]', $nameDescription); $citationDescription->addStatement('article-title', $value = 'PHPUnit in a nutshell', 'en_US'); $citationDescription->addStatement('source', $value = 'PHPUnit in a nutshell', 'en_US'); $citationDescription->addStatement('date', $value = '2009-08-17'); $citationDescription->addStatement('date-in-citation[@content-type="access-date"]', $value = '2009-08'); $citationDescription->addStatement('issue', $value = 5); $citationDescription->addStatement('volume', $value = 6); $citationDescription->addStatement('season', $value = 'Summer'); $citationDescription->addStatement('chapter-title', $value = 'Introduction'); $citationDescription->addStatement('edition', $value = '2nd edition'); $citationDescription->addStatement('series', $value = 7); $citationDescription->addStatement('supplement', $value = 'Summer Special'); $citationDescription->addStatement('conf-date', $value = '2009-08-17'); $citationDescription->addStatement('conf-loc', $value = 'Helsinki'); $citationDescription->addStatement('conf-name', $value = 'PHPUnit Hackfest'); $citationDescription->addStatement('conf-sponsor', $value = 'Basti himself'); $citationDescription->addStatement('institution', $value = 'PKP'); $citationDescription->addStatement('fpage', $value = 9); $citationDescription->addStatement('lpage', $value = 312); $citationDescription->addStatement('size', $value = 320); $citationDescription->addStatement('publisher-loc', $value = 'Vancouver'); $citationDescription->addStatement('publisher-name', $value = 'SFU'); $citationDescription->addStatement('isbn', $value = '123456789'); $citationDescription->addStatement('issn[@pub-type="ppub"]', $value = '987654321'); $citationDescription->addStatement('issn[@pub-type="epub"]', $value = '111111111'); $citationDescription->addStatement('pub-id[@pub-id-type="doi"]', $value = '10420/39406'); $citationDescription->addStatement('pub-id[@pub-id-type="publisher-id"]', $value = 'xyz'); $citationDescription->addStatement('pub-id[@pub-id-type="coden"]', $value = 'abc'); $citationDescription->addStatement('pub-id[@pub-id-type="sici"]', $value = 'def'); $citationDescription->addStatement('pub-id[@pub-id-type="pmid"]', $value = '999999'); $citationDescription->addStatement('uri', $value = 'http://phpunit.org/nutshell'); $citationDescription->addStatement('comment', $value = 'just nonsense'); $citationDescription->addStatement('annotation', $value = 'more nonsense'); $citationDescription->addStatement('[@publication-type]', $value = 'conf-proc'); $citation =& $this->getCitation($citationDescription); // Persist one copy of the citation for testing. $citationDao =& $this->getCitationDao(); $citation->setSeq(1); $citation->setCitationState(CITATION_APPROVED); $citationId = $citationDao->insertObject($citation); self::assertTrue(is_numeric($citationId)); self::assertTrue($citationId > 0); // Construct the expected output. $expectedOutput = ''; // Prepare NLM 3.0 input. $mockSubmission =& $this->getTestSubmission(); import('lib.pkp.plugins.metadata.nlm30.filter.PKPSubmissionNlm30XmlFilter'); $nlm30Filter = new PKPSubmissionNlm30XmlFilter(PersistableFilter::tempGroup('class::lib.pkp.classes.submission.Submission', 'xml::*')); $nlm30Xml = $nlm30Filter->execute($mockSubmission); // Test the downgrade filter. import('lib.pkp.classes.xslt.XSLTransformationFilter'); // FIXME: Add NLM 2.3 and 3.0 tag set schema validation as soon as we implement the full tag set, see #5648. $downgradeFilter = new XSLTransformationFilter(PersistableFilter::tempGroup('xml::*', 'xml::*'), 'NLM 3.0 to 2.3 ref-list downgrade'); $downgradeFilter->setXSLFilename('lib/pkp/plugins/metadata/nlm30/filter/nlm30-to-23-ref-list.xsl'); $nlm30Xml = $downgradeFilter->execute($nlm30Xml); self::assertXmlStringEqualsXmlFile('./lib/pkp/tests/plugins/metadata/nlm30/filter/sample-nlm23-citation.xml', $nlm30Xml); }
/** * @copydoc MetadataDataObjectAdapter::extractMetadataFromDataObject() * @param $dataObject Citation * @return MetadataDescription */ function extractMetadataFromDataObject(&$dataObject) { $metadataDescription = $this->instantiateMetadataDescription(); // Establish the association between the meta-data description // and the citation object. $metadataDescription->setAssocId($dataObject->getId()); // Identify the length of the name space prefix $namespacePrefixLength = strlen($this->getMetadataNamespace()) + 1; // Get all meta-data field names $fieldNames = array_merge($this->getDataObjectMetadataFieldNames(false), $this->getDataObjectMetadataFieldNames(true)); // Retrieve the statements from the data object $statements = array(); foreach ($fieldNames as $fieldName) { if ($dataObject->hasData($fieldName)) { // Remove the name space prefix $propertyName = substr($fieldName, $namespacePrefixLength); if (in_array($propertyName, array('person-group[@person-group-type="author"]', 'person-group[@person-group-type="editor"]'))) { // Retrieve the names array (must not be by-ref // to protect the original citation object!) $names = $dataObject->getData($fieldName); // Convert key/value arrays to MetadataDescription objects. foreach ($names as $key => $name) { if (is_array($name)) { // Construct a meta-data description from // this name array. switch ($propertyName) { case 'person-group[@person-group-type="author"]': $assocType = ASSOC_TYPE_AUTHOR; break; case 'person-group[@person-group-type="editor"]': $assocType = ASSOC_TYPE_EDITOR; break; } $nameDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema', $assocType); $nameDescription->setStatements($name); $names[$key] =& $nameDescription; unset($nameDescription); } else { // The only non-structured data allowed here // is the et-al string. import('lib.pkp.plugins.metadata.nlm30.filter.Nlm30PersonStringFilter'); assert($name == PERSON_STRING_FILTER_ETAL); } } $statements[$propertyName] =& $names; unset($names); } else { $statements[$propertyName] =& $dataObject->getData($fieldName); } } } // Set the statements in the meta-data description $success = $metadataDescription->setStatements($statements); assert($success); return $metadataDescription; }
public function testExecuteWithConferenceProceeding() { $this->markTestSkipped('Weird class interaction with ControlledVocabEntryDAO leads to failure'); $nameSchemaName = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema'; $citationSchemaName = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema'; // An author $personDescription = new MetadataDescription($nameSchemaName, ASSOC_TYPE_AUTHOR); $personDescription->addStatement('surname', $surname = 'Liu'); $personDescription->addStatement('given-names', $givenName = 'Sen'); // A conference paper found on the web $citationDescription = new MetadataDescription($citationSchemaName, ASSOC_TYPE_CITATION); $citationDescription->addStatement('[@publication-type]', $pubType = NLM30_PUBLICATION_TYPE_CONFPROC); $citationDescription->addStatement('person-group[@person-group-type="author"]', $personDescription); $citationDescription->addStatement('article-title', $articleTitle = 'Defending against business crises with the help of intelligent agent based early warning solutions'); $citationDescription->addStatement('conf-name', $confName = 'The Seventh International Conference on Enterprise Information Systems'); $citationDescription->addStatement('conf-loc', $confLoc = 'Miami, FL'); $citationDescription->addStatement('date', $date = '2005-05'); $citationDescription->addStatement('date-in-citation[@content-type="access-date"]', $accessDate = '2006-08-12'); $citationDescription->addStatement('uri', $uri = 'http://www.iceis.org/iceis2005/abstracts_2005.htm'); $citationOutputFilter = $this->getFilterInstance(); $result = $citationOutputFilter->execute($citationDescription); $expectedResult = $this->getConfProcResult(); self::assertEquals($expectedResult[0] . $this->getConfProcResultGoogleScholar() . $expectedResult[1], $result); }
/** * Fills the given citation object with * meta-data retrieved from PubMed. * @param $pmid string * @return MetadataDescription */ function &_lookup($pmid) { $nullVar = null; // Use eFetch to get XML metadata for the given PMID $lookupParams = array('db' => 'pubmed', 'mode' => 'xml', 'tool' => 'pkp-wal', 'id' => $pmid); if (!is_null($this->getEmail())) { $lookupParams['email'] = $this->getEmail(); } // Call the eFetch URL and get an XML result if (is_null($resultDOM = $this->callWebService(PUBMED_WEBSERVICE_EFETCH, $lookupParams))) { return $nullVar; } $articleTitleNodes =& $resultDOM->getElementsByTagName("ArticleTitle"); $articleTitleFirstNode =& $articleTitleNodes->item(0); $medlineTaNodes =& $resultDOM->getElementsByTagName("MedlineTA"); $medlineTaFirstNode =& $medlineTaNodes->item(0); $metadata = array('pub-id[@pub-id-type="pmid"]' => $pmid, 'article-title' => $articleTitleFirstNode->textContent, 'source' => $medlineTaFirstNode->textContent); $volumeNodes =& $resultDOM->getElementsByTagName("Volume"); $issueNodes =& $resultDOM->getElementsByTagName("Issue"); if ($volumeNodes->length > 0) { $volumeFirstNode =& $volumeNodes->item(0); } $metadata['volume'] = $volumeFirstNode->textContent; if ($issueNodes->length > 0) { $issueFirstNode =& $issueNodes->item(0); } $metadata['issue'] = $issueFirstNode->textContent; // Get list of author full names foreach ($resultDOM->getElementsByTagName("Author") as $authorNode) { if (!isset($metadata['person-group[@person-group-type="author"]'])) { $metadata['person-group[@person-group-type="author"]'] = array(); } // Instantiate an NLM name description $authorDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema', ASSOC_TYPE_AUTHOR); // Surname $lastNameNodes =& $authorNode->getElementsByTagName("LastName"); $lastNameFirstNode =& $lastNameNodes->item(0); $authorDescription->addStatement('surname', $lastNameFirstNode->textContent); // Given names $givenNamesString = ''; $firstNameNodes =& $authorNode->getElementsByTagName("FirstName"); if ($firstNameNodes->length > 0) { $firstNameFirstNode =& $firstNameNodes->item(0); $givenNamesString = $firstNameFirstNode->textContent; } else { $foreNameNodes =& $authorNode->getElementsByTagName("ForeName"); if ($foreNameNodes->length > 0) { $foreNameFirstNode =& $foreNameNodes->item(0); $givenNamesString = $foreNameFirstNode->textContent; } } if (!empty($givenNamesString)) { foreach (explode(' ', $givenNamesString) as $givenName) { $authorDescription->addStatement('given-names', String::trimPunctuation($givenName)); } } // Suffix $suffixNodes =& $authorNode->getElementsByTagName("Suffix"); if ($suffixNodes->length > 0) { $suffixFirstNode =& $suffixNodes->item(0); $authorDescription->addStatement('suffix', $suffixFirstNode->textContent); } // Include collective names // FIXME: This corresponds to an NLM-citation <collab> tag and should be part of the Metadata implementation /*if ($resultDOM->getElementsByTagName("CollectiveName")->length > 0 && $authorNode->getElementsByTagName("CollectiveName")->item(0)->textContent != '') { }*/ $metadata['person-group[@person-group-type="author"]'][] =& $authorDescription; unset($authorDescription); } // Extract pagination $medlinePgnNodes =& $resultDOM->getElementsByTagName("MedlinePgn"); $medlinePgnFirstNode =& $medlinePgnNodes->item(0); if (String::regexp_match_get("/^[:p\\.\\s]*(?P<fpage>[Ee]?\\d+)(-(?P<lpage>\\d+))?/", $medlinePgnFirstNode->textContent, $pages)) { $fPage = (int) $pages['fpage']; $metadata['fpage'] = $fPage; if (!empty($pages['lpage'])) { $lPage = (int) $pages['lpage']; // Deal with shortcuts like '382-7' if ($lPage < $fPage) { $lPage = (int) (String::substr($pages['fpage'], 0, -String::strlen($pages['lpage'])) . $pages['lpage']); } $metadata['lpage'] = $lPage; } } // Get publication date (can be in several places in PubMed). $dateNode = null; $articleDateNodes =& $resultDOM->getElementsByTagName("ArticleDate"); if ($articleDateNodes->length > 0) { $dateNode =& $articleDateNodes->item(0); } else { $pubDateNodes =& $resultDOM->getElementsByTagName("PubDate"); if ($pubDateNodes->length > 0) { $dateNode =& $pubDateNodes->item(0); } } // Retrieve the data parts and assemble date. if (!is_null($dateNode)) { $publicationDate = ''; $requiresNormalization = false; foreach (array('Year' => 4, 'Month' => 2, 'Day' => 2) as $dateElement => $padding) { $dateElementNodes =& $dateNode->getElementsByTagName($dateElement); if ($dateElementNodes->length > 0) { if (!empty($publicationDate)) { $publicationDate .= '-'; } $dateElementFirstNode =& $dateElementNodes->item(0); $datePart = str_pad($dateElementFirstNode->textContent, $padding, '0', STR_PAD_LEFT); if (!is_numeric($datePart)) { $requiresNormalization = true; } $publicationDate .= $datePart; } else { break; } } // Normalize the date to NLM standard if necessary. if ($requiresNormalization) { $dateFilter = new DateStringNormalizerFilter(); $publicationDate = $dateFilter->execute($publicationDate); } if (!empty($publicationDate)) { $metadata['date'] = $publicationDate; } } // Get publication type $publicationTypeNodes =& $resultDOM->getElementsByTagName("PublicationType"); if ($publicationTypeNodes->length > 0) { foreach ($publicationTypeNodes as $publicationType) { // The vast majority of items on PubMed are articles so catch these... if (String::strpos(String::strtolower($publicationType->textContent), 'article') !== false) { $metadata['[@publication-type]'] = NLM30_PUBLICATION_TYPE_JOURNAL; break; } } } // Get DOI if it exists $articleIdNodes =& $resultDOM->getElementsByTagName("ArticleId"); foreach ($articleIdNodes as $idNode) { if ($idNode->getAttribute('IdType') == 'doi') { $metadata['pub-id[@pub-id-type="doi"]'] = $idNode->textContent; } } // Use eLink utility to find fulltext links $lookupParams = array('dbfrom' => 'pubmed', 'cmd' => 'llinks', 'tool' => 'pkp-wal', 'id' => $pmid); if (!is_null($resultDOM = $this->callWebService(PUBMED_WEBSERVICE_ELINK, $lookupParams))) { // Get a list of possible links foreach ($resultDOM->getElementsByTagName("ObjUrl") as $linkOut) { $attributes = ''; foreach ($linkOut->getElementsByTagName("Attribute") as $attribute) { $attributes .= String::strtolower($attribute->textContent) . ' / '; } // Only add links to open access resources if (String::strpos($attributes, "subscription") === false && String::strpos($attributes, "membership") === false && String::strpos($attributes, "fee") === false && $attributes != "") { $urlNodes =& $linkOut->getElementsByTagName("Url"); $urlFirstNode =& $urlNodes->item(0); $links[] = $urlFirstNode->textContent; } } // Take the first link if we have any left (presumably pubmed returns them in preferential order) if (isset($links[0])) { $metadata['uri'] = $links[0]; } } return $this->getNlm30CitationDescriptionFromMetadataArray($metadata); }
/** * @see MetadataDataObjectAdapter::extractMetadataFromDataObject() * @param $submission Submission * @return MetadataDescription */ function extractMetadataFromDataObject(&$submission) { assert(is_a($submission, 'Submission')); $mods34Description = $this->instantiateMetadataDescription(); // Retrieve the primary locale. $catalogingLocale = AppLocale::getPrimaryLocale(); $catalogingLanguage = AppLocale::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"]', 'aut'); // 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 $language = $submission->getLanguage(); if ($language) { $submissionLanguage = AppLocale::get3LetterFrom2LetterIsoLanguage($submission->getLanguage()); } else { $submissionLanguage = null; } 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 $localizedSubjects = $submission->getSubject(null); // Localized $this->addLocalizedStatements($mods34Description, 'subject/topic', $localizedSubjects); // FIXME: Coverage not included // 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; }
/** * Fills the given citation object with * meta-data retrieved from PubMed. * @param $pmid string * @param $citationDescription MetadataDescription * @return MetadataDescription */ function &_lookup($pmid, &$citationDescription) { $nullVar = null; // Use eFetch to get XML metadata for the given PMID $lookupParams = array('db' => 'pubmed', 'mode' => 'xml', 'tool' => 'pkp-wal', 'id' => $pmid); if (!is_null($this->getEmail())) { $lookupParams['email'] = $this->getEmail(); } // Call the eFetch URL and get an XML result if (is_null($resultDOM = $this->callWebService(PUBMED_WEBSERVICE_EFETCH, $lookupParams))) { return $nullVar; } $metadata = array('pub-id[@pub-id-type="pmid"]' => $pmid, 'article-title' => $resultDOM->getElementsByTagName("ArticleTitle")->item(0)->textContent, 'source' => $resultDOM->getElementsByTagName("MedlineTA")->item(0)->textContent); if ($resultDOM->getElementsByTagName("Volume")->length > 0) { $metadata['volume'] = $resultDOM->getElementsByTagName("Volume")->item(0)->textContent; } if ($resultDOM->getElementsByTagName("Issue")->length > 0) { $metadata['issue'] = $resultDOM->getElementsByTagName("Issue")->item(0)->textContent; } // get list of author full names $nlmNameSchema = new NlmNameSchema(); foreach ($resultDOM->getElementsByTagName("Author") as $authorNode) { if (!isset($metadata['person-group[@person-group-type="author"]'])) { $metadata['person-group[@person-group-type="author"]'] = array(); } // Instantiate an NLM name description $authorDescription = new MetadataDescription($nlmNameSchema, ASSOC_TYPE_AUTHOR); // Surname $authorDescription->addStatement('surname', $authorNode->getElementsByTagName("LastName")->item(0)->textContent); // Given names $givenNamesString = ''; if ($authorNode->getElementsByTagName("FirstName")->length > 0) { $givenNamesString = $authorNode->getElementsByTagName("FirstName")->item(0)->textContent; } elseif ($authorNode->getElementsByTagName("ForeName")->length > 0) { $givenNamesString = $authorNode->getElementsByTagName("ForeName")->item(0)->textContent; } if (!empty($givenNamesString)) { foreach (explode(' ', $givenNamesString) as $givenName) { $authorDescription->addStatement('given-names', String::trimPunctuation($givenName)); } } // Suffix if ($authorNode->getElementsByTagName("Suffix")->length > 0) { $authorDescription->addStatement('suffix', $authorNode->getElementsByTagName("Suffix")->item(0)->textContent); } // Include collective names /*if ($resultDOM->getElementsByTagName("CollectiveName")->length > 0 && $authorNode->getElementsByTagName("CollectiveName")->item(0)->textContent != '') { // FIXME: This corresponds to an NLM-citation <collab> tag and should be part of the Metadata implementation }*/ $metadata['person-group[@person-group-type="author"]'][] =& $authorDescription; unset($authorDescription); } // Extract pagination if (String::regexp_match_get("/^[:p\\.\\s]*(?P<fpage>[Ee]?\\d+)(-(?P<lpage>\\d+))?/", $resultDOM->getElementsByTagName("MedlinePgn")->item(0)->textContent, $pages)) { $fPage = (int) $pages['fpage']; $metadata['fpage'] = $fPage; if (!empty($pages['lpage'])) { $lPage = (int) $pages['lpage']; // Deal with shortcuts like '382-7' if ($lPage < $fPage) { $lPage = (int) (String::substr($pages['fpage'], 0, -String::strlen($pages['lpage'])) . $pages['lpage']); } $metadata['lpage'] = $lPage; } } // Get publication date // TODO: The publication date could be in multiple places if ($resultDOM->getElementsByTagName("ArticleDate")->length > 0) { $publicationDate = $resultDOM->getElementsByTagName("ArticleDate")->item(0)->getElementsByTagName("Year")->item(0)->textContent . '-' . $resultDOM->getElementsByTagName("ArticleDate")->item(0)->getElementsByTagName("Month")->item(0)->textContent . '-' . $resultDOM->getElementsByTagName("ArticleDate")->item(0)->getElementsByTagName("Day")->item(0)->textContent; $metadata['date'] = $publicationDate; } // Get publication type if ($resultDOM->getElementsByTagName("PublicationType")->length > 0) { foreach ($resultDOM->getElementsByTagName("PublicationType") as $publicationType) { // The vast majority of items on PubMed are articles so catch these... if (String::strpos(String::strtolower($publicationType->textContent), 'article') !== false) { $metadata['[@publication-type]'] = NLM_PUBLICATION_TYPE_JOURNAL; break; } } } // Get DOI if it exists foreach ($resultDOM->getElementsByTagName("ArticleId") as $idNode) { if ($idNode->getAttribute('IdType') == 'doi') { $metadata['pub-id[@pub-id-type="doi"]'] = $idNode->textContent; } } // Use eLink utility to find fulltext links $lookupParams = array('dbfrom' => 'pubmed', 'cmd' => 'llinks', 'tool' => 'pkp-wal', 'id' => $pmid); if (!is_null($resultDOM = $this->callWebService(PUBMED_WEBSERVICE_ELINK, $lookupParams))) { // Get a list of possible links foreach ($resultDOM->getElementsByTagName("ObjUrl") as $linkOut) { $attributes = ''; foreach ($linkOut->getElementsByTagName("Attribute") as $attribute) { $attributes .= String::strtolower($attribute->textContent) . ' / '; } // Only add links to open access resources if (String::strpos($attributes, "subscription") === false && String::strpos($attributes, "membership") === false && String::strpos($attributes, "fee") === false && $attributes != "") { $links[] = $linkOut->getElementsByTagName("Url")->item(0)->textContent; } } // Take the first link if we have any left (presumably pubmed returns them in preferential order) if (isset($links[0])) { $metadata['uri'] = $links[0]; } } return $this->addMetadataArrayToNlmCitationDescription($metadata, $citationDescription); }
/** * @covers CitationDAO */ public function testCitationCrud() { $citationDao = DAORegistry::getDAO('CitationDAO'); /* @var $citationDao CitationDAO */ $nameSchemaName = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema'; $nameDescription = new MetadataDescription($nameSchemaName, ASSOC_TYPE_AUTHOR); $nameDescription->addStatement('given-names', $value = 'Peter'); $nameDescription->addStatement('given-names', $value = 'B'); $nameDescription->addStatement('surname', $value = 'Bork'); $nameDescription->addStatement('prefix', $value = 'Mr.'); $citationSchemaName = 'lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema'; $citationDescription = new MetadataDescription($citationSchemaName, ASSOC_TYPE_CITATION); $citationDescription->addStatement('person-group[@person-group-type="author"]', $nameDescription); $citationDescription->addStatement('article-title', $value = 'PHPUnit in a nutshell', 'en_US'); $citationDescription->addStatement('article-title', $value = 'PHPUnit in Kürze', 'de_DE'); $citationDescription->addStatement('date', $value = '2009-08-17'); $citationDescription->addStatement('size', $value = 320); $citationDescription->addStatement('uri', $value = 'http://phpunit.org/nutshell'); // Add a simple source description. $sourceDescription = new MetadataDescription($citationSchemaName, ASSOC_TYPE_CITATION); $sourceDescription->setDisplayName('test'); $sourceDescription->addStatement('article-title', $value = 'a simple source description', 'en_US'); $sourceDescription->setSeq(0); $citation = new Citation('raw citation'); $citation->setAssocType(ASSOC_TYPE_ARTICLE); $citation->setAssocId(999999); $citation->setSeq(50); $citation->addSourceDescription($sourceDescription); $citation->injectMetadata($citationDescription); // Create citation. $citationId = $citationDao->insertObject($citation); self::assertTrue(is_numeric($citationId)); self::assertTrue($citationId > 0); // Retrieve citation. $citationById = $citationDao->getObjectById($citationId); // Fix state differences for comparison. $citation->removeSupportedMetadataAdapter($citationSchemaName); $citationById->removeSupportedMetadataAdapter($citationSchemaName); $citationById->_extractionAdaptersLoaded = true; $citationById->_injectionAdaptersLoaded = true; $sourceDescription->setAssocId($citationId); $sourceDescription->removeSupportedMetadataAdapter($citationSchemaName); $sourceDescriptions = $citationById->getSourceDescriptions(); $sourceDescriptions['test']->getMetadataSchema(); // this will instantiate the meta-data schema internally. self::assertEquals($citation, $citationById); $citationsByAssocIdDaoFactory = $citationDao->getObjectsByAssocId(ASSOC_TYPE_ARTICLE, 999999); $citationsByAssocId = $citationsByAssocIdDaoFactory->toArray(); self::assertEquals(1, count($citationsByAssocId)); // Fix state differences for comparison. $citationsByAssocId[0]->_extractionAdaptersLoaded = true; $citationsByAssocId[0]->_injectionAdaptersLoaded = true; $citationsByAssocId[0]->removeSupportedMetadataAdapter($citationSchemaName); $sourceDescriptionsByAssocId = $citationsByAssocId[0]->getSourceDescriptions(); $sourceDescriptionsByAssocId['test']->getMetadataSchema(); // this will instantiate the meta-data schema internally. self::assertEquals($citation, $citationsByAssocId[0]); // Update citation. $citationDescription->removeStatement('date'); $citationDescription->addStatement('article-title', $value = 'PHPUnit rápido', 'pt_BR'); // Update source descriptions. $sourceDescription->addStatement('article-title', $value = 'edited source description', 'en_US', true); $updatedCitation = new Citation('another raw citation'); $updatedCitation->setId($citationId); $updatedCitation->setAssocType(ASSOC_TYPE_ARTICLE); $updatedCitation->setAssocId(999998); $updatedCitation->setSeq(50); $updatedCitation->addSourceDescription($sourceDescription); $updatedCitation->injectMetadata($citationDescription); $citationDao->updateObject($updatedCitation); $citationAfterUpdate = $citationDao->getObjectById($citationId); // Fix state differences for comparison. $updatedCitation->removeSupportedMetadataAdapter($citationSchemaName); $citationAfterUpdate->removeSupportedMetadataAdapter($citationSchemaName); $citationAfterUpdate->_extractionAdaptersLoaded = true; $citationAfterUpdate->_injectionAdaptersLoaded = true; $sourceDescriptionsAfterUpdate = $citationAfterUpdate->getSourceDescriptions(); $sourceDescriptionsAfterUpdate['test']->getMetadataSchema(); // this will instantiate the meta-data schema internally. $sourceDescription->removeSupportedMetadataAdapter($citationSchemaName); self::assertEquals($updatedCitation, $citationAfterUpdate); // Delete citation $citationDao->deleteObjectsByAssocId(ASSOC_TYPE_ARTICLE, 999998); self::assertNull($citationDao->getObjectById($citationId)); }
/** * Map NLM properties to OpenURL properties. * NB: OpenURL has no i18n so we use the default * locale when mapping. * @see Filter::process() * @param $input MetadataDescription * @return MetadataDescription */ function &process(&$input) { $nullVar = null; // Identify the genre of the target record and // instantiate the target description. $publicationType = $input->getStatement('[@publication-type]'); switch ($publicationType) { case NLM30_PUBLICATION_TYPE_JOURNAL: case NLM30_PUBLICATION_TYPE_CONFPROC: $outputSchemaName = 'lib.pkp.plugins.metadata.openurl10.schema.Openurl10JournalSchema'; break; case NLM30_PUBLICATION_TYPE_BOOK: $outputSchemaName = 'lib.pkp.plugins.metadata.openurl10.schema.Openurl10BookSchema'; break; case NLM30_PUBLICATION_TYPE_THESIS: $outputSchemaName = 'lib.pkp.plugins.metadata.openurl10.schema.Openurl10DissertationSchema'; break; default: // Unsupported type return $nullVar; } // Create the target description $output = new MetadataDescription($outputSchemaName, $input->getAssocType()); // Transform authors import('lib.pkp.plugins.metadata.nlm30.filter.Nlm30NameSchemaPersonStringFilter'); $personStringFilter = new Nlm30NameSchemaPersonStringFilter(); $authors =& $input->getStatement('person-group[@person-group-type="author"]'); if (is_array($authors) && count($authors)) { $aulast = $authors[0]->hasStatement('prefix') ? $authors[0]->getStatement('prefix') . ' ' : ''; $aulast .= $authors[0]->getStatement('surname'); if (!empty($aulast)) { $success = $output->addStatement('aulast', $aulast); assert($success); } $givenNames = $authors[0]->getStatement('given-names'); if (is_array($givenNames) && count($givenNames)) { $aufirst = implode(' ', $givenNames); if (!empty($aufirst)) { $success = $output->addStatement('aufirst', $aufirst); assert($success); } $initials = array(); foreach ($givenNames as $givenName) { $initials[] = substr($givenName, 0, 1); } $auinit1 = array_shift($initials); if (!empty($auinit1)) { $success = $output->addStatement('auinit1', $auinit1); assert($success); } $auinitm = implode('', $initials); if (!empty($auinitm)) { $success = $output->addStatement('auinitm', $auinitm); assert($success); } $auinit = $auinit1 . $auinitm; if (!empty($auinit)) { $success = $output->addStatement('auinit', $auinit); assert($success); } } $ausuffix = $authors[0]->getStatement('suffix'); if (!empty($ausuffix)) { $success = $output->addStatement('ausuffix', $ausuffix); assert($success); } foreach ($authors as $author) { if ($author == PERSON_STRING_FILTER_ETAL) { $au = $author; } else { $au = $personStringFilter->execute($author); } $success = $output->addStatement('au', $au); assert($success); unset($au); } } // Genre: Guesswork if (is_a($output->getMetadataSchema(), 'Openurl10JournalBookBaseSchema')) { switch ($publicationType) { case NLM30_PUBLICATION_TYPE_JOURNAL: $genre = $input->hasProperty('article-title') ? OPENURL10_GENRE_ARTICLE : OPENURL10_GENRE_JOURNAL; break; case NLM30_PUBLICATION_TYPE_CONFPROC: $genre = $input->hasProperty('article-title') ? OPENURL10_GENRE_PROCEEDING : OPENURL10_GENRE_CONFERENCE; break; case NLM30_PUBLICATION_TYPE_BOOK: $genre = $input->hasProperty('article-title') ? OPENURL10_GENRE_BOOKITEM : OPENURL10_GENRE_BOOK; break; } assert(!empty($genre)); $success = $output->addStatement('genre', $genre); assert($success); } // Map remaining properties (NLM => OpenURL) $propertyMap =& $this->nlmOpenurl10Mapping($publicationType, $output->getMetadataSchema()); // Transfer mapped properties with default locale foreach ($propertyMap as $nlm30Property => $openurl10Property) { if ($input->hasStatement($nlm30Property)) { $success = $output->addStatement($openurl10Property, $input->getStatement($nlm30Property)); assert($success); } } return $output; }
/** * Take an array of citation parse/lookup results and derive a citation * with one "best" set of values. * * We determine the best values within the citations that have a score above * the given threshold. Citations with a score below the threshold will be * ignored. * * For these citations we count the frequency of values per meta-data property. * The most frequent value will be chosen as "best" value. * * If two values have the same frequency then decide based on the score. If * this is still ambivalent then return the first of the remaining values. * * @param $scoredCitations * @param $scoreThreshold integer a number between 0 (=no threshold) and 100 * @return Citation one citation with the "best" values set */ function &_guessValues(&$scoredCitations, $scoreThreshold) { assert($scoreThreshold >= 0 && $scoreThreshold <= 100); // Create the target citation description. $targetDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema', ASSOC_TYPE_CITATION); // Step 1: List all values and max scores that have been identified for a given element // but only include values from results above a given scoring threshold // Initialize variables for the first step. $valuesByPropertyName = array(); $maxScoresByPropertyNameAndValue = array(); // Sort the scored citations by score with the highest score first. krsort($scoredCitations); foreach ($scoredCitations as $currentScore => $citationsForCurrentScore) { // Check whether the current score is below the threshold, if so // stop the loop. We've sorted our citations by score so the remaining // citations all have scores below the threshold and we can forget // about them. if ($currentScore < $scoreThreshold) { break; } foreach ($citationsForCurrentScore as $citationForCurrentScore) { $statements = $citationForCurrentScore->getStatements(); // Add the property values and scores of this citation // to the overall property lists foreach ($statements as $propertyName => $value) { // Initialize sub-arrays if necessary if (!isset($valuesByPropertyName[$propertyName])) { $valuesByPropertyName[$propertyName] = array(); } if (!isset($maxScoresByPropertyNameAndValue[$propertyName])) { $maxScoresByPropertyNameAndValue[$propertyName] = array(); } // Add the value for the given property, as we want to count // value frequencies later, we explicitly allow duplicates. $serializedValue = serialize($value); $valuesByPropertyName[$propertyName][] = $serializedValue; // As we have ordered our citations descending by score, the // first score found for a value is also the maximum score. if (!isset($maxScoresByPropertyNameAndValue[$propertyName][$serializedValue])) { $maxScoresByPropertyNameAndValue[$propertyName][$serializedValue] = $currentScore; } } } } // Step 2: Find out the values that occur most frequently for each element // and order these by score. foreach ($valuesByPropertyName as $propertyName => $values) { // Count the occurrences of each value within the given element $valueFrequencies = array_count_values($values); // Order the most frequent values to the beginning of the array arsort($valueFrequencies); // Get the most frequent values (may be several if there are more than one // with the same frequency). $scoresOfMostFrequentValues = array(); $previousValueFrequency = 0; foreach ($valueFrequencies as $value => $valueFrequency) { // Only extract the most frequent values, jump out of the // loop when less frequent values start. if ($previousValueFrequency > $valueFrequency) { break; } $previousValueFrequency = $valueFrequency; $scoresOfMostFrequentValues[$value] = $maxScoresByPropertyNameAndValue[$propertyName][$value]; } // Now we can order the most frequent values by score, starting // with the highest score. arsort($scoresOfMostFrequentValues); // Now get the first key which represents the value with the // highest frequency and the highest score. reset($scoresOfMostFrequentValues); $bestValue = unserialize(key($scoresOfMostFrequentValues)); // Set the found "best" element value in the result citation. $statements = array($propertyName => $bestValue); $success = $targetDescription->setStatements($statements); assert($success); } // Instantiate the target citation $targetCitation = new Citation(); $targetCitation->injectMetadata($targetDescription); return $targetCitation; }
/** * Adds the data of an array of property/value pairs * as statements to an NLM citation description. * If no citation description is given, a new one will * be instantiated. * @param $metadataArray array * @param $citationDescription MetadataDescription * @return MetadataDescription */ function &addMetadataArrayToNlmCitationDescription(&$metadataArray, $citationDescription = null) { // Create a new citation description if no one was given if (is_null($citationDescription)) { $metadataSchema = new NlmCitationSchema(); $citationDescription = new MetadataDescription($metadataSchema, ASSOC_TYPE_CITATION); } // Add the meta-data to the description if (!$citationDescription->setStatements($metadataArray)) { $nullVar = null; return $nullVar; } return $citationDescription; }
/** * Save citation */ function execute() { $citation =& $this->getCitation(); $citation->setEditedCitation($this->getData('editedCitation')); if (in_array($this->getData('citationState'), Citation::_getSupportedCitationStates())) { $citation->setCitationState($this->getData('citationState')); } // Extract data from citation form fields and inject it into the citation $metadataAdapters = $citation->getSupportedMetadataAdapters(); foreach ($metadataAdapters as $metadataAdapter) { // Instantiate a meta-data description for the given schema $metadataSchema =& $metadataAdapter->getMetadataSchema(); import('metadata.MetadataDescription'); $metadataDescription = new MetadataDescription($metadataSchema, ASSOC_TYPE_CITATION); // Set the meta-data statements $metadataSchemaNamespace = $metadataSchema->getNamespace(); foreach ($metadataSchema->getProperties() as $propertyName => $property) { $fieldName = $metadataSchema->getNamespacedPropertyId($propertyName); $fieldValue = trim($this->getData($fieldName)); if (empty($fieldValue)) { $metadataDescription->removeStatement($propertyName); } else { $foundValidType = false; foreach ($property->getTypes() as $type) { // Some property types need to be converted first switch ($type) { // We currently only support name composites case array(METADATA_PROPERTY_TYPE_COMPOSITE => ASSOC_TYPE_AUTHOR): case array(METADATA_PROPERTY_TYPE_COMPOSITE => ASSOC_TYPE_EDITOR): import('metadata.nlm.PersonStringNlmNameSchemaFilter'); $personStringFilter = new PersonStringNlmNameSchemaFilter($type[METADATA_PROPERTY_TYPE_COMPOSITE], PERSON_STRING_FILTER_MULTIPLE); assert($personStringFilter->supportsAsInput($fieldValue)); $fieldValue =& $personStringFilter->execute($fieldValue); $foundValidType = true; break; case METADATA_PROPERTY_TYPE_INTEGER: $fieldValue = array((int) $fieldValue); $foundValidType = true; break; case METADATA_PROPERTY_TYPE_DATE: import('metadata.DateStringNormalizerFilter'); $dateStringFilter = new DateStringNormalizerFilter(); assert($dateStringFilter->supportsAsInput($fieldValue)); $fieldValue = array($dateStringFilter->execute($fieldValue)); $foundValidType = true; break; default: if ($property->isValid($fieldValue)) { $fieldValue = array($fieldValue); $foundValidType = true; break; } } // Break the outer loop once we found a valid // interpretation for our form field. if ($foundValidType) { break; } } foreach ($fieldValue as $fieldValueStatement) { $metadataDescription->addStatement($propertyName, $fieldValueStatement); unset($fieldValueStatement); } } } // Inject the meta-data into the citation $citation->injectMetadata($metadataDescription, true); } // Persist citation $citationDAO =& DAORegistry::getDAO('CitationDAO'); if (is_numeric($citation->getId())) { $citationDAO->updateCitation($citation); } else { $citationDAO->insertCitation($citation); } return true; }
/** * Instantiate an NLM name description from an array. * @param $personArray array * @param $assocType integer * @return MetadataDescription */ private function &instantiateNlm30NameDescriptions(&$personArray, $assocType) { $personDescriptions = array(); foreach ($personArray as $key => $person) { if ($person == PERSON_STRING_FILTER_ETAL) { $personDescription = 'et-al'; } else { // Create a new NLM name description and fill it // with the values from the test array. $personDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema', $assocType); self::assertTrue($personDescription->setStatements($person)); } // Add the result to the descriptions list $personDescriptions[$key] = $personDescription; } return $personDescriptions; }
/** * Converts a string with a single person * to an NLM name description. * * TODO: add initials from all given names to initials * element * * @param $personString string * @param $title boolean true to parse for title * @param $degrees boolean true to parse for degrees * @return MetadataDescription an NLM name description or null * if the string could not be converted */ function &_parsePersonString($personString, $title, $degrees) { // Expressions to parse person strings, ported from CiteULike person // plugin, see http://svn.citeulike.org/svn/plugins/person.tcl static $personRegex = array('title' => '(?:His (?:Excellency|Honou?r)\\s+|Her (?:Excellency|Honou?r)\\s+|The Right Honou?rable\\s+|The Honou?rable\\s+|Right Honou?rable\\s+|The Rt\\.? Hon\\.?\\s+|The Hon\\.?\\s+|Rt\\.? Hon\\.?\\s+|Mr\\.?\\s+|Ms\\.?\\s+|M\\/s\\.?\\s+|Mrs\\.?\\s+|Miss\\.?\\s+|Dr\\.?\\s+|Sir\\s+|Dame\\s+|Prof\\.?\\s+|Professor\\s+|Doctor\\s+|Mister\\s+|Mme\\.?\\s+|Mast(?:\\.|er)?\\s+|Lord\\s+|Lady\\s+|Madam(?:e)?\\s+|Priv\\.-Doz\\.\\s+)+', 'degrees' => '(,\\s+(?:[A-Z\\.]+))+', 'initials' => '(?:(?:[A-Z]\\.){1,3}[A-Z]\\.?)|(?:(?:[A-Z]\\.\\s){1,3}[A-Z]\\.?)|(?:[A-Z]{1,4})|(?:(?:[A-Z]\\.-?){1,4})|(?:(?:[A-Z]\\.-?){1,3}[A-Z]\\.?)|(?:(?:[A-Z]-){1,3}[A-Z])|(?:(?:[A-Z]\\s){1,3}[A-Z]\\.?)|(?:(?:[A-Z]-){1,3}[A-Z]\\.?)', 'prefix' => 'Dell(?:[a|e])?(?:\\s|$)|Dalle(?:\\s|$)|D[a|e]ll\'(?:\\s|$)|Dela(?:\\s|$)|Del(?:\\s|$)|[Dd]e(?:\\s|$)(?:La(?:\\s|$)|Los(?:\\s|$))?|[Dd]e(?:\\s|$)|[Dd][a|i|u](?:\\s|$)|L[a|e|o](?:\\s|$)|[D|L|O]\'|St\\.?(?:\\s|$)|San(?:\\s|$)|[Dd]en(?:\\s|$)|[Vv]on(?:\\s|$)(?:[Dd]er(?:\\s|$))?|(?:[Ll][ea](?:\\s|$))?[Vv]an(?:\\s|$)(?:[Dd]e(?:n|r)?(?:\\s|$))?', 'givenName' => '(?:[^ \\t\\n\\r\\f\\v,.;()]{2,}|[^ \\t\\n\\r\\f\\v,.;()]{2,}\\-[^ \\t\\n\\r\\f\\v,.;()]{2,})'); // The expressions for given name, suffix and surname are the same $personRegex['surname'] = $personRegex['suffix'] = $personRegex['givenName']; $personRegex['double-surname'] = "(?:" . $personRegex['surname'] . "\\s)*" . $personRegex['surname']; // Shortcut for prefixed surname $personRegexPrefixedSurname = "(?P<prefix>(?:" . $personRegex['prefix'] . ")?)(?P<surname>" . $personRegex['surname'] . ")"; $personRegexPrefixedDoubleSurname = "(?P<prefix>(?:" . $personRegex['prefix'] . ")?)(?P<surname>" . $personRegex['double-surname'] . ")"; // Instantiate the target person description $personDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema', $this->_assocType); // Clean the person string $personString = trim($personString); // 1. Extract title and degree from the person string and use this as suffix $suffixString = ''; $results = array(); if ($title && String::regexp_match_get('/^(' . $personRegex['title'] . ')/i', $personString, $results)) { $suffixString = trim($results[1], ',:; '); $personString = String::regexp_replace('/^(' . $personRegex['title'] . ')/i', '', $personString); } if ($degrees && String::regexp_match_get('/(' . $personRegex['degrees'] . ')$/i', $personString, $results)) { $degreesArray = explode(',', trim($results[1], ',')); foreach ($degreesArray as $key => $degree) { $degreesArray[$key] = String::trimPunctuation($degree); } $suffixString .= ' - ' . implode('; ', $degreesArray); $personString = String::regexp_replace('/(' . $personRegex['degrees'] . ')$/i', '', $personString); } if (!empty($suffixString)) { $personDescription->addStatement('suffix', $suffixString); } // Space initials when followed by a given name or last name. $personString = String::regexp_replace('/([A-Z])\\.([A-Z][a-z])/', '\\1. \\2', $personString); // 2. Extract names and initials from the person string // The parser expressions are ordered by specificity. The most specific expressions // come first. Only if these specific expressions don't work will we turn to less // specific ones. This avoids parsing errors. It also explains why we don't use the // ?-quantifier for optional elements like initials or middle name where they could // be misinterpreted. $personExpressions = array('/^' . $personRegexPrefixedSurname . '$/i', '/^(?P<initials>' . $personRegex['initials'] . ')\\s' . $personRegexPrefixedSurname . '$/', '/^' . $personRegexPrefixedSurname . ',?\\s(?P<initials>' . $personRegex['initials'] . ')$/', '/^' . $personRegexPrefixedDoubleSurname . ',\\s(?P<givenName>' . $personRegex['givenName'] . ')\\s(?P<initials>' . $personRegex['initials'] . ')$/', '/^(?P<givenName>' . $personRegex['givenName'] . ')\\s(?P<initials>' . $personRegex['initials'] . ')\\s' . $personRegexPrefixedSurname . '$/', '/^' . $personRegexPrefixedDoubleSurname . ',\\s(?P<givenName>(?:' . $personRegex['givenName'] . '\\s)+)(?P<initials>' . $personRegex['initials'] . ')$/', '/^(?P<givenName>(?:' . $personRegex['givenName'] . '\\s)+)(?P<initials>' . $personRegex['initials'] . ')\\s' . $personRegexPrefixedSurname . '$/', '/^' . $personRegexPrefixedDoubleSurname . ',(?P<givenName>(?:\\s' . $personRegex['givenName'] . ')+)$/', '/^(?P<givenName>(?:' . $personRegex['givenName'] . '\\s)+)' . $personRegexPrefixedSurname . '$/', '/^\\s*(?P<surname>' . $personRegex['surname'] . ')(?P<suffix>(?:\\s+' . $personRegex['suffix'] . ')?)\\s*,\\s*(?P<initials>(?:' . $personRegex['initials'] . ')?)\\s*\\((?P<givenName>(?:\\s*' . $personRegex['givenName'] . ')+)\\s*\\)\\s*(?P<prefix>(?:' . $personRegex['prefix'] . ')?)$/', '/^(?P<givenName>' . $personRegex['givenName'] . ')\\.(?P<surname>' . $personRegex['double-surname'] . ')$/', '/^(?P<surname>.*)$/'); $results = array(); foreach ($personExpressions as $expressionId => $personExpression) { if ($nameFound = String::regexp_match_get($personExpression, $personString, $results)) { // Given names if (!empty($results['givenName'])) { // Split given names $givenNames = explode(' ', trim($results['givenName'])); foreach ($givenNames as $givenName) { $personDescription->addStatement('given-names', $givenName); unset($givenName); } } // Initials (will also be saved as given names) if (!empty($results['initials'])) { $results['initials'] = str_replace(array('.', '-', ' '), array('', '', ''), $results['initials']); for ($initialNum = 0; $initialNum < String::strlen($results['initials']); $initialNum++) { $initial = $results['initials'][$initialNum]; $personDescription->addStatement('given-names', $initial); unset($initial); } } // Surname if (!empty($results['surname'])) { // Correct all-upper surname if (strtoupper($results['surname']) == $results['surname']) { $results['surname'] = ucwords(strtolower($results['surname'])); } $personDescription->addStatement('surname', $results['surname']); } // Prefix/Suffix foreach (array('prefix', 'suffix') as $propertyName) { if (!empty($results[$propertyName])) { $results[$propertyName] = trim($results[$propertyName]); $personDescription->addStatement($propertyName, $results[$propertyName]); } } break; } } return $personDescription; }
/** * @see Filter::process() * @param $citationString string * @return MetadataDescription */ function &process($citationString) { $nullVar = null; // Check the availability of perl $perlCommand = Config::getVar('cli', 'perl'); if (empty($perlCommand) || !file_exists($perlCommand)) { return $nullVar; } // Convert to ASCII - Paracite doesn't handle UTF-8 well $citationString = String::utf8_to_ascii($citationString); // Call the paracite parser $wrapperScript = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'paracite.pl'; $paraciteCommand = $perlCommand . ' ' . escapeshellarg($wrapperScript) . ' ' . $this->getCitationModule() . ' ' . escapeshellarg($citationString); $xmlResult = shell_exec($paraciteCommand); if (empty($xmlResult)) { return $nullVar; } if (Config::getVar('i18n', 'charset_normalization') == 'On' && !String::utf8_compliant($xmlResult)) { $xmlResult = String::utf8_normalize($xmlResult); } // Create a temporary DOM document $resultDOM = new DOMDocument(); $resultDOM->recover = true; $resultDOM->loadXML($xmlResult); // Extract the parser results as an array $xmlHelper = new XMLHelper(); $metadata = $xmlHelper->xmlToArray($resultDOM->documentElement); // We have to merge subtitle and title as neither OpenURL // nor NLM can handle subtitles. if (isset($metadata['subtitle'])) { $metadata['title'] .= '. ' . $metadata['subtitle']; unset($metadata['subtitle']); } // Break up the authors field if (isset($metadata['authors'])) { $metadata['authors'] = String::trimPunctuation($metadata['authors']); $metadata['authors'] = String::iterativeExplode(array(':', ';'), $metadata['authors']); } // Convert pages to integers foreach (array('spage', 'epage') as $pageProperty) { if (isset($metadata[$pageProperty])) { $metadata[$pageProperty] = (int) $metadata[$pageProperty]; } } // Convert titles to title case foreach (array('title', 'chapter', 'publication') as $titleProperty) { if (isset($metadata[$titleProperty])) { $metadata[$titleProperty] = String::titleCase($metadata[$titleProperty]); } } // Map ParaCite results to OpenURL - null means // throw the value away. $metadataMapping = array('genre' => 'genre', '_class' => null, 'any' => null, 'authors' => 'au', 'aufirst' => 'aufirst', 'aufull' => null, 'auinit' => 'auinit', 'aulast' => 'aulast', 'atitle' => 'atitle', 'cappublication' => null, 'captitle' => null, 'date' => 'date', 'epage' => 'epage', 'featureID' => null, 'id' => null, 'issue' => 'issue', 'jnl_epos' => null, 'jnl_spos' => null, 'match' => null, 'marked' => null, 'num_of_fig' => null, 'pages' => 'pages', 'publisher' => 'pub', 'publoc' => 'place', 'ref' => null, 'rest_text' => null, 'spage' => 'spage', 'targetURL' => 'url', 'text' => null, 'ucpublication' => null, 'uctitle' => null, 'volume' => 'volume', 'year' => 'date'); // Ignore 'year' if 'date' is set if (isset($metadata['date'])) { $metadataMapping['year'] = null; } // Set default genre if (empty($metadata['genre'])) { $metadata['genre'] = OPENURL_GENRE_ARTICLE; } // Handle title, chapter and publication depending on // the (inferred) genre. Also instantiate the target schema. switch ($metadata['genre']) { case OPENURL_GENRE_BOOK: case OPENURL_GENRE_BOOKITEM: case OPENURL_GENRE_REPORT: case OPENURL_GENRE_DOCUMENT: $metadataMapping += array('publication' => 'btitle', 'chapter' => 'atitle'); if (isset($metadata['title'])) { if (!isset($metadata['publication'])) { $metadata['publication'] = $metadata['title']; } elseif (!isset($metadata['chapter'])) { $metadata['chapter'] = $metadata['title']; } unset($metadata['title']); } $openUrlSchemaName = 'lib.pkp.classes.metadata.openurl.OpenUrlBookSchema'; $openUrlSchemaClass = 'OpenUrlBookSchema'; break; case OPENURL_GENRE_ARTICLE: case OPENURL_GENRE_JOURNAL: case OPENURL_GENRE_ISSUE: case OPENURL_GENRE_CONFERENCE: case OPENURL_GENRE_PROCEEDING: case OPENURL_GENRE_PREPRINT: default: $metadataMapping += array('publication' => 'jtitle'); if (isset($metadata['title'])) { if (!isset($metadata['publication'])) { $metadata['publication'] = $metadata['title']; } elseif (!isset($metadata['atitle'])) { $metadata['atitle'] = $metadata['title']; } unset($metadata['title']); } $openUrlSchemaName = 'lib.pkp.classes.metadata.openurl.OpenUrlJournalSchema'; $openUrlSchemaClass = 'OpenUrlJournalSchema'; break; } // Instantiate an OpenURL description $openUrlDescription = new MetadataDescription($openUrlSchemaName, ASSOC_TYPE_CITATION); $openUrlSchema = new $openUrlSchemaClass(); // Map the ParaCite result to OpenURL foreach ($metadata as $paraciteElementName => $paraciteValue) { if (!empty($paraciteValue)) { // Trim punctuation if (is_string($paraciteValue)) { $paraciteValue = String::trimPunctuation($paraciteValue); } // Transfer the value to the OpenURL result array assert(array_key_exists($paraciteElementName, $metadataMapping)); $openUrlPropertyName = $metadataMapping[$paraciteElementName]; if (!is_null($openUrlPropertyName) && $openUrlSchema->hasProperty($openUrlPropertyName)) { if (is_array($paraciteValue)) { foreach ($paraciteValue as $singleValue) { $success = $openUrlDescription->addStatement($openUrlPropertyName, $singleValue); assert($success); } } else { $success = $openUrlDescription->addStatement($openUrlPropertyName, $paraciteValue); assert($success); } } } } // Crosswalk to NLM $crosswalkFilter = new OpenUrlNlmCitationSchemaCrosswalkFilter(); $nlmDescription =& $crosswalkFilter->execute($openUrlDescription); assert(is_a($nlmDescription, 'MetadataDescription')); // Add 'rest_text' as NLM comment (if given) if (isset($metadata['rest_text'])) { $nlmDescription->addStatement('comment', String::trimPunctuation($metadata['rest_text'])); } // Set display name and sequence id in the meta-data description // to the corresponding values from the filter. This is important // so that we later know which result came from which filter. $nlmDescription->setDisplayName($this->getDisplayName()); $nlmDescription->setSeq($this->getSeq()); return $nlmDescription; }
/** * @see MetadataDataObjectAdapter::extractMetadataFromDataObject() * @param $dataObject Citation * @return MetadataDescription */ function &extractMetadataFromDataObject(&$dataObject) { $metadataDescription =& $this->instantiateMetadataDescription(); // Identify the length of the name space prefix $namespacePrefixLength = strlen($this->getMetadataNamespace()) + 1; // Get all meta-data field names $fieldNames = array_merge($this->getDataObjectMetadataFieldNames(false), $this->getDataObjectMetadataFieldNames(true)); // Retrieve the statements from the data object $statements = array(); $nameSchema = new NlmNameSchema(); foreach ($fieldNames as $fieldName) { if ($dataObject->hasData($fieldName)) { // Remove the name space prefix $propertyName = substr($fieldName, $namespacePrefixLength); if (in_array($propertyName, array('person-group[@person-group-type="author"]', 'person-group[@person-group-type="editor"]'))) { // Convert key/value arrays to MetadataDescription objects. $names =& $dataObject->getData($fieldName); foreach ($names as $key => $name) { switch ($propertyName) { case 'person-group[@person-group-type="author"]': $assocType = ASSOC_TYPE_AUTHOR; break; case 'person-group[@person-group-type="editor"]': $assocType = ASSOC_TYPE_EDITOR; break; } $nameDescription = new MetadataDescription($nameSchema, $assocType); $nameDescription->setStatements($name); $names[$key] =& $nameDescription; unset($nameDescription); } $statements[$propertyName] =& $names; } else { $statements[$propertyName] =& $dataObject->getData($fieldName); } } } // Set the statements in the meta-data description $metadataDescription->setStatements($statements); return $metadataDescription; }
/** * @covers MetadataDescriptionDAO * * FIXME: The test data used here and in the CitationDAOTest * are very similar. We should find a way to not duplicate this * test data. */ public function testMetadataDescriptionCrud() { $metadataDescriptionDao = DAORegistry::getDAO('MetadataDescriptionDAO'); $nameDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30NameSchema', ASSOC_TYPE_AUTHOR); $nameDescription->addStatement('given-names', $value = 'Peter'); $nameDescription->addStatement('given-names', $value = 'B'); $nameDescription->addStatement('surname', $value = 'Bork'); $nameDescription->addStatement('prefix', $value = 'Mr.'); $testDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema', ASSOC_TYPE_CITATION); $testDescription->setAssocId(999999); $testDescription->setDisplayName('test meta-data description'); $testDescription->setSeq(5); $testDescription->addStatement('person-group[@person-group-type="author"]', $nameDescription); $testDescription->addStatement('article-title', $value = 'PHPUnit in a nutshell', 'en_US'); $testDescription->addStatement('article-title', $value = 'PHPUnit in Kürze', 'de_DE'); $testDescription->addStatement('date', $value = '2009-08-17'); $testDescription->addStatement('size', $value = 320); $testDescription->addStatement('uri', $value = 'http://phpunit.org/nutshell'); // Create meta-data description $metadataDescriptionId = $metadataDescriptionDao->insertObject($testDescription); self::assertTrue(is_numeric($metadataDescriptionId)); self::assertTrue($metadataDescriptionId > 0); // Retrieve meta-data description by id $metadataDescriptionById = $metadataDescriptionDao->getObjectById($metadataDescriptionId); $testDescription->removeSupportedMetadataAdapter('lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema'); // Required for comparison $metadataDescriptionById->getMetadataSchema(); // Instantiates the internal metadata-schema. self::assertEquals($testDescription, $metadataDescriptionById); $metadataDescriptionsByAssocIdDaoFactory = $metadataDescriptionDao->getObjectsByAssocId(ASSOC_TYPE_CITATION, 999999); $metadataDescriptionsByAssocId = $metadataDescriptionsByAssocIdDaoFactory->toArray(); self::assertEquals(1, count($metadataDescriptionsByAssocId)); $metadataDescriptionsByAssocId[0]->getMetadataSchema(); // Instantiates the internal metadata-schema. self::assertEquals($testDescription, $metadataDescriptionsByAssocId[0]); // Update meta-data description $testDescription->removeStatement('date'); $testDescription->addStatement('article-title', $value = 'PHPUnit rápido', 'pt_BR'); $metadataDescriptionDao->updateObject($testDescription); $testDescription->removeSupportedMetadataAdapter('lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema'); // Required for comparison $metadataDescriptionAfterUpdate = $metadataDescriptionDao->getObjectById($metadataDescriptionId); $metadataDescriptionAfterUpdate->getMetadataSchema(); // Instantiates the internal metadata-schema. self::assertEquals($testDescription, $metadataDescriptionAfterUpdate); // Delete meta-data description $metadataDescriptionDao->deleteObjectsByAssocId(ASSOC_TYPE_CITATION, 999999); self::assertNull($metadataDescriptionDao->getObjectById($metadataDescriptionId)); }
/** * Creates a new NLM citation description and adds the data * of an array of property/value pairs as statements. * @param $metadataArray array * @return MetadataDescription */ function &getNlm30CitationDescriptionFromMetadataArray(&$metadataArray) { // Create a new citation description $citationDescription = new MetadataDescription('lib.pkp.plugins.metadata.nlm30.schema.Nlm30CitationSchema', ASSOC_TYPE_CITATION); // Add the meta-data to the description $metadataArray = arrayClean($metadataArray); if (!$citationDescription->setStatements($metadataArray)) { $translationParams = array('filterName' => $this->getDisplayName()); $this->addError(__('submission.citations.filter.invalidMetadata', $translationParams)); $nullVar = null; return $nullVar; } // Set display name in the meta-data description // to the corresponding value from the filter. This is important // so that we later know which result came from which filter. $citationDescription->setDisplayName($this->getDisplayName()); return $citationDescription; }
/** * Prepare a MODS description that covers as much data as possible. * @return MetadataDescription */ public function getMods34Description() { // Author $authorDescription = new MetadataDescription('lib.pkp.plugins.metadata.mods34.schema.Mods34NameSchema', ASSOC_TYPE_AUTHOR); self::assertTrue($authorDescription->addStatement('[@type]', $nameType = 'personal')); self::assertTrue($authorDescription->addStatement('namePart[@type="family"]', $familyName = 'some family name')); self::assertTrue($authorDescription->addStatement('namePart[@type="given"]', $givenName = 'given names')); self::assertTrue($authorDescription->addStatement('namePart[@type="termsOfAddress"]', $terms = 'Jr')); self::assertTrue($authorDescription->addStatement('namePart[@type="date"]', $date = '1900-1988')); self::assertTrue($authorDescription->addStatement('affiliation', $affiliation = 'affiliation')); self::assertTrue($authorDescription->addStatement('role/roleTerm[@type="code" @authority="marcrelator"]', $authorRole = 'aut')); // Sponsor $sponsorDescription = new MetadataDescription('lib.pkp.plugins.metadata.mods34.schema.Mods34NameSchema', ASSOC_TYPE_AUTHOR); self::assertTrue($sponsorDescription->addStatement('[@type]', $nameType = 'corporate')); self::assertTrue($sponsorDescription->addStatement('namePart', $namePart = 'Some Sponsor')); self::assertTrue($sponsorDescription->addStatement('role/roleTerm[@type="code" @authority="marcrelator"]', $sponsorRole = 'spn')); $mods34Description = new MetadataDescription('plugins.metadata.mods34.schema.Mods34Schema', ASSOC_TYPE_CITATION); self::assertTrue($mods34Description->addStatement('titleInfo/nonSort', $titleNonSort = 'the')); self::assertTrue($mods34Description->addStatement('titleInfo/title', $title = 'new submission title')); self::assertTrue($mods34Description->addStatement('titleInfo/subTitle', $subTitle = 'subtitle')); self::assertTrue($mods34Description->addStatement('titleInfo/partNumber', $partNumber = 'part I')); self::assertTrue($mods34Description->addStatement('titleInfo/partName', $partName = 'introduction')); self::assertTrue($mods34Description->addStatement('titleInfo/nonSort', $titleNonSort = 'ein', 'de_DE')); self::assertTrue($mods34Description->addStatement('titleInfo/title', $title = 'neuer Titel', 'de_DE')); self::assertTrue($mods34Description->addStatement('titleInfo/subTitle', $subTitle = 'Subtitel', 'de_DE')); self::assertTrue($mods34Description->addStatement('titleInfo/partNumber', $partNumber = 'Teil I', 'de_DE')); self::assertTrue($mods34Description->addStatement('titleInfo/partName', $partName = 'Einführung', 'de_DE')); self::assertTrue($mods34Description->addStatement('name', $authorDescription)); self::assertTrue($mods34Description->addStatement('name', $sponsorDescription)); self::assertTrue($mods34Description->addStatement('typeOfResource', $typeOfResource = 'text')); self::assertTrue($mods34Description->addStatement('genre[@authority="marcgt"]', $marcGenre = 'book')); self::assertTrue($mods34Description->addStatement('originInfo/place/placeTerm[@type="text"]', $publisherPlace = 'Vancouver')); self::assertTrue($mods34Description->addStatement('originInfo/place/placeTerm[@type="code" @authority="iso3166"]', $publisherCountry = 'CA')); self::assertTrue($mods34Description->addStatement('originInfo/publisher', $publisherName = 'Public Knowledge Project')); self::assertTrue($mods34Description->addStatement('originInfo/dateIssued[@keyDate="yes" @encoding="w3cdtf"]', $publicationDate = '2010-09')); self::assertTrue($mods34Description->addStatement('originInfo/dateCreated[@encoding="w3cdtf"]', $publisherName = '2010-07-07')); self::assertTrue($mods34Description->addStatement('originInfo/copyrightDate[@encoding="w3cdtf"]', $publisherName = '2010')); self::assertTrue($mods34Description->addStatement('originInfo/edition', $edition = 'second revised edition')); self::assertTrue($mods34Description->addStatement('originInfo/edition', $edition = 'zweite überarbeitete Ausgabe', 'de_DE')); self::assertTrue($mods34Description->addStatement('language/languageTerm[@type="code" @authority="iso639-2b"]', $submissionLanguage = 'eng')); self::assertTrue($mods34Description->addStatement('physicalDescription/form[@authority="marcform"]', $publicationForm = 'electronic')); self::assertTrue($mods34Description->addStatement('physicalDescription/internetMediaType', $mimeType = 'application/pdf')); self::assertTrue($mods34Description->addStatement('physicalDescription/extent', $pages = 215)); self::assertTrue($mods34Description->addStatement('abstract', $abstract1 = 'some abstract')); self::assertTrue($mods34Description->addStatement('abstract', $abstract2 = 'eine Zusammenfassung', 'de_DE')); self::assertTrue($mods34Description->addStatement('note', $note1 = 'some note')); self::assertTrue($mods34Description->addStatement('note', $note2 = 'another note')); self::assertTrue($mods34Description->addStatement('note', $note3 = 'übersetzte Anmerkung', 'de_DE')); self::assertTrue($mods34Description->addStatement('subject/topic', $topic1 = 'some subject')); self::assertTrue($mods34Description->addStatement('subject/topic', $topic2 = 'some other subject')); self::assertTrue($mods34Description->addStatement('subject/topic', $topic3 = 'ein Thema', 'de_DE')); self::assertTrue($mods34Description->addStatement('subject/geographic', $geography = 'some geography')); self::assertTrue($mods34Description->addStatement('subject/temporal[@encoding="w3cdtf" @point="start"]', $timeStart = '1950')); self::assertTrue($mods34Description->addStatement('subject/temporal[@encoding="w3cdtf" @point="end"]', $timeEnd = '1954')); self::assertTrue($mods34Description->addStatement('identifier[@type="isbn"]', $isbn = '01234567890123')); self::assertTrue($mods34Description->addStatement('identifier[@type="doi"]', $doi = '40/2010ff')); self::assertTrue($mods34Description->addStatement('identifier[@type="uri"]', $uri = 'urn://xyz.resolver.org/12345')); self::assertTrue($mods34Description->addStatement('location/url[@usage="primary display"]', $url = 'http://www.sfu.ca/test-article')); self::assertTrue($mods34Description->addStatement('recordInfo/recordCreationDate[@encoding="w3cdtf"]', $recordDate = '2010-12-24')); self::assertTrue($mods34Description->addStatement('recordInfo/recordIdentifier[@source="pkp"]', $articleId = '3049')); self::assertTrue($mods34Description->addStatement('recordInfo/languageOfCataloging/languageTerm[@authority="iso639-2b"]', $languageOfCataloging = 'eng')); return $mods34Description; }