/** * Takes the raw xml result of a web service and * transforms it via XSL to a (preliminary) XML similar * to NLM which is then re-encoded into an array. Finally * some typical post-processing is performed. * FIXME: Rewrite parser/lookup filter XSL to produce real NLM * element-citation XML and factor this code into an NLM XML to * NLM description filter. * @param $xmlResult string or DOMDocument * @param $xslFileName string * @return array a metadata array */ function &transformWebServiceResults(&$xmlResult, $xslFileName) { // Send the result through the XSL to generate a (preliminary) NLM XML. $xslFilter = new XSLTransformationFilter(PersistableFilter::tempGroup('xml::*', 'xml::*'), 'Web Service Transformation'); $xslFilter->setXSLFilename($xslFileName); $xslFilter->setResultType(XSL_TRANSFORMER_DOCTYPE_DOM); $preliminaryNlm30DOM =& $xslFilter->execute($xmlResult); if (is_null($preliminaryNlm30DOM) || is_null($preliminaryNlm30DOM->documentElement)) { $translationParams = array('filterName' => $this->getDisplayName()); $this->addError(__('submission.citations.filter.webserviceResultTransformationError', $translationParams)); $nullVar = null; return $nullVar; } // Transform the result to an array. $xmlHelper = new XMLHelper(); $preliminaryNlm30Array = $xmlHelper->xmlToArray($preliminaryNlm30DOM->documentElement); $preliminaryNlm30Array =& $this->postProcessMetadataArray($preliminaryNlm30Array); return $preliminaryNlm30Array; }
/** * @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); }
/** * Takes the raw xml result of a web service and * transforms it via XSL to a (preliminary) XML similar * to NLM which is then re-encoded into an array. Finally * some typical post-processing is performed. * FIXME: Rewrite parser/lookup filter XSL to produce real NLM * element-citation XML and factor this code into an NLM XML to * NLM description filter. * @param $xmlResult string or DOMDocument * @param $xslFileName string * @return array a metadata array */ function &transformWebServiceResults(&$xmlResult, $xslFileName) { // Send the result through the XSL to generate a (preliminary) NLM XML. $xslFilter = new XSLTransformationFilter(); $xslFilter->setXSLFilename($xslFileName); $xslFilter->setResultType(XSL_TRANSFORMER_DOCTYPE_DOM); $preliminaryNlmDOM =& $xslFilter->execute($xmlResult); if (is_null($preliminaryNlmDOM)) { return $preliminaryNlmDOM; } // Transform the result to an array. $xmlHelper = new XMLHelper(); $preliminaryNlmArray = $xmlHelper->xmlToArray($preliminaryNlmDOM->documentElement); $preliminaryNlmArray =& $this->postProcessMetadataArray($preliminaryNlmArray); return $preliminaryNlmArray; }
/** * @see OAIMetadataFormat#toXml * TODO: * <copyright-holder> * In Isabelle's mapping document: * Article order in the issue's Table of Contents */ function toXml(&$record, $format = null) { $article =& $record->getData('article'); $journal =& $record->getData('journal'); $section =& $record->getData('section'); $issue =& $record->getData('issue'); $galleys =& $record->getData('galleys'); $articleId = $article->getId(); // Cache issue ordering information. static $issueId; static $sectionSeq; if (!isset($issueId) || $issueId != $issue->getId()) { $sectionDao =& DAORegistry::getDAO('SectionDAO'); $issueId = $issue->getId(); $sections =& $sectionDao->getSectionsForIssue($issueId); $sectionSeq = array(); $i = 0; foreach ($sections as $thisSection) { $sectionSeq[$thisSection->getSectionId()] = $i++; } unset($sections); } $abbreviation = $journal->getLocalizedSetting('abbreviation'); $printIssn = $journal->getSetting('printIssn'); $onlineIssn = $journal->getSetting('onlineIssn'); $primaryLocale = $journal->getPrimaryLocale(); $publisherInstitution = $journal->getSetting('publisherInstitution'); $datePublished = $article->getDatePublished(); if (!$datePublished) { $datePublished = $issue->getDatePublished(); } if ($datePublished) { $datePublished = strtotime($datePublished); } $response = "<article\n" . "\txmlns=\"http://dtd.nlm.nih.gov/publishing/2.3\"\n" . "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n" . "\txmlns:mml=\"http://www.w3.org/1998/Math/MathML\"\n" . "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" . "\txsi:schemaLocation=\"http://dtd.nlm.nih.gov/publishing/2.3\n" . "\thttp://dtd.nlm.nih.gov/publishing/2.3/xsd/journalpublishing.xsd\"\n" . (($s = $section->getSectionIdentifyType()) != '' ? "\tarticle-type=\"" . htmlspecialchars(Core::cleanVar($s)) . "\"" : '') . "\txml:lang=\"" . strtoupper(substr($primaryLocale, 0, 2)) . "\">\n" . "\t<front>\n" . "\t\t<journal-meta>\n" . "\t\t\t<journal-id journal-id-type=\"other\">" . htmlspecialchars(Core::cleanVar(($s = Config::getVar('oai', 'nlm_journal_id')) != '' ? $s : $journal->getPath())) . "</journal-id>\n" . "\t\t\t<journal-title>" . htmlspecialchars(Core::cleanVar($journal->getJournalTitle())) . "</journal-title>\n"; // Include translated journal titles foreach ($journal->getTitle(null) as $locale => $title) { if ($locale == $primaryLocale) { continue; } $response .= "\t\t\t<trans-title xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">" . htmlspecialchars(Core::cleanVar($title)) . "</trans-title>\n"; } $response .= (!empty($onlineIssn) ? "\t\t\t<issn pub-type=\"epub\">" . htmlspecialchars(Core::cleanVar($onlineIssn)) . "</issn>" : '') . (!empty($printIssn) ? "\t\t\t<issn pub-type=\"ppub\">" . htmlspecialchars(Core::cleanVar($printIssn)) . "</issn>" : '') . ($publisherInstitution != '' ? "\t\t\t<publisher><publisher-name>" . htmlspecialchars(Core::cleanVar($publisherInstitution)) . "</publisher-name></publisher>\n" : '') . "\t\t</journal-meta>\n" . "\t\t<article-meta>\n" . "\t\t\t<article-id pub-id-type=\"other\">" . htmlspecialchars(Core::cleanVar($article->getBestArticleId())) . "</article-id>\n" . (($s = $article->getDOI()) != '' ? "\t\t\t<article-id pub-id-type=\"doi\">" . htmlspecialchars(Core::cleanVar($s)) . "</article-id>\n" : '') . "\t\t\t<article-categories><subj-group subj-group-type=\"heading\"><subject>" . htmlspecialchars(Core::cleanVar($section->getSectionTitle())) . "</subject></subj-group></article-categories>\n" . "\t\t\t<title-group>\n" . "\t\t\t\t<article-title>" . htmlspecialchars(Core::cleanVar(strip_tags($article->getArticleTitle()))) . "</article-title>\n"; // Include translated journal titles foreach ($article->getTitle(null) as $locale => $title) { if ($locale == $primaryLocale) { continue; } $response .= "\t\t\t\t<trans-title xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">" . htmlspecialchars(Core::cleanVar(strip_tags($title))) . "</trans-title>\n"; } $response .= "\t\t\t</title-group>\n" . "\t\t\t<contrib-group>\n"; // Include authors foreach ($article->getAuthors() as $author) { $response .= "\t\t\t\t<contrib " . ($author->getPrimaryContact() ? 'corresp="yes" ' : '') . "contrib-type=\"author\">\n" . "\t\t\t\t\t<name name-style=\"western\">\n" . "\t\t\t\t\t\t<surname>" . htmlspecialchars(Core::cleanVar($author->getLastName())) . "</surname>\n" . "\t\t\t\t\t\t<given-names>" . htmlspecialchars(Core::cleanVar($author->getFirstName()) . (($s = $author->getMiddleName()) != '' ? " {$s}" : '')) . "</given-names>\n" . "\t\t\t\t\t</name>\n" . (($s = $author->getLocalizedAffiliation()) != '' ? "\t\t\t\t\t<aff>" . htmlspecialchars(Core::cleanVar($s)) . "</aff>\n" : '') . "\t\t\t\t\t<email>" . htmlspecialchars(Core::cleanVar($author->getEmail())) . "</email>\n" . (($s = $author->getUrl()) != '' ? "\t\t\t\t\t<uri>" . htmlspecialchars(Core::cleanVar($s)) . "</uri>\n" : '') . "\t\t\t\t</contrib>\n"; } // Include editorships (optimized) $response .= $this->getEditorialInfo($journal->getId()); $response .= "\t\t\t</contrib-group>\n"; if ($datePublished) { $response .= "\t\t\t<pub-date pub-type=\"epub\">\n" . "\t\t\t\t<day>" . strftime('%d', $datePublished) . "</day>\n" . "\t\t\t\t<month>" . strftime('%m', $datePublished) . "</month>\n" . "\t\t\t\t<year>" . strftime('%Y', $datePublished) . "</year>\n" . "\t\t\t</pub-date>\n"; } $response .= ($issue->getShowYear() ? "\t\t\t<pub-date pub-type=\"collection\"><year>" . htmlspecialchars(Core::cleanVar($issue->getYear())) . "</year></pub-date>\n" : '') . ($issue->getShowVolume() ? "\t\t\t<volume>" . htmlspecialchars(Core::cleanVar($issue->getVolume())) . "</volume>\n" : '') . ($issue->getShowNumber() ? "\t\t\t<issue seq=\"" . htmlspecialchars(Core::cleanVar($sectionSeq[$section->getId()] * 100 + $article->getSeq())) . "\">" . htmlspecialchars(Core::cleanVar($issue->getNumber())) . "</issue>\n" : '') . "\t\t\t<issue-id pub-id-type=\"other\">" . htmlspecialchars(Core::cleanVar($issue->getBestIssueId())) . "</issue-id>\n" . ($issue->getShowTitle() ? "\t\t\t<issue-title>" . htmlspecialchars(Core::cleanVar($issue->getIssueTitle())) . "</issue-title>\n" : ''); // Include page info, if available and parseable. $matches = null; if (String::regexp_match_get('/^[Pp][Pp]?[.]?[ ]?(\\d+)$/', $article->getPages(), $matches)) { $matchedPage = htmlspecialchars(Core::cleanVar($matches[1])); $response .= "\t\t\t\t<fpage>{$matchedPage}</fpage><lpage>{$matchedPage}</lpage>\n"; $pageCount = 1; } elseif (String::regexp_match_get('/^[Pp][Pp]?[.]?[ ]?(\\d+)[ ]?-[ ]?([Pp][Pp]?[.]?[ ]?)?(\\d+)$/', $article->getPages(), $matches)) { $matchedPageFrom = htmlspecialchars(Core::cleanVar($matches[1])); $matchedPageTo = htmlspecialchars(Core::cleanVar($matches[3])); $response .= "\t\t\t\t<fpage>{$matchedPageFrom}</fpage>\n" . "\t\t\t\t<lpage>{$matchedPageTo}</lpage>\n"; $pageCount = $matchedPageTo - $matchedPageFrom + 1; } $response .= "\t\t\t<permissions>\n" . (($s = $journal->getLocalizedSetting('copyrightNotice')) != '' ? "\t\t\t\t<copyright-statement>" . htmlspecialchars(Core::cleanVar($s)) . "</copyright-statement>\n" : '') . ($datePublished ? "\t\t\t\t<copyright-year>" . strftime('%Y', $datePublished) . "</copyright-year>\n" : '') . "\t\t\t</permissions>\n" . "\t\t\t<self-uri xlink:href=\"" . htmlspecialchars(Core::cleanVar(Request::url($journal->getPath(), 'article', 'view', $article->getBestArticleId()))) . "\" />\n"; // Include galley links foreach ($article->getGalleys() as $galley) { $response .= "\t\t\t<self-uri content-type=\"" . htmlspecialchars(Core::cleanVar($galley->getFileType())) . "\" xlink:href=\"" . htmlspecialchars(Core::cleanVar(Request::url($journal->getPath(), 'article', 'view', array($article->getBestArticleId(), $galley->getId())))) . "\" />\n"; } // Include abstract(s) $abstract = htmlspecialchars(Core::cleanVar(strip_tags($article->getArticleAbstract()))); if (!empty($abstract)) { $abstract = "<p>{$abstract}</p>"; // $abstract = '<p>' . String::regexp_replace('/\n+/', '</p><p>', $abstract) . '</p>'; $response .= "\t\t\t<abstract xml:lang=\"" . strtoupper(substr($primaryLocale, 0, 2)) . "\">{$abstract}</abstract>\n"; } if (is_array($article->getAbstract(null))) { foreach ($article->getAbstract(null) as $locale => $abstract) { if ($locale == $primaryLocale || empty($abstract)) { continue; } $abstract = htmlspecialchars(Core::cleanVar(strip_tags($abstract))); if (empty($abstract)) { continue; } $abstract = "<p>{$abstract}</p>"; //$abstract = '<p>' . String::regexp_replace('/\n+/', '</p><p>', $abstract) . '</p>'; $response .= "\t\t\t<abstract-trans xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">{$abstract}</abstract-trans>\n"; } } $subjects = array(); if (is_array($article->getSubject(null))) { foreach ($article->getSubject(null) as $locale => $subject) { $s = array_map('trim', explode(';', Core::cleanVar($subject))); if (!empty($s)) { $subjects[$locale] = $s; } } } if (!empty($subjects)) { foreach ($subjects as $locale => $s) { $response .= "\t\t\t<kwd-group xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">\n"; foreach ($s as $subject) { $response .= "\t\t\t\t<kwd>" . htmlspecialchars($subject) . "</kwd>\n"; } $response .= "\t\t\t</kwd-group>\n"; } } $response .= (isset($pageCount) ? "\t\t\t<counts><page-count count=\"" . (int) $pageCount . "\" /></counts>\n" : '') . "\t\t</article-meta>\n" . "\t</front>\n"; // Include body text (for search indexing only) import('classes.search.ArticleSearchIndex'); $text = ''; $galleys = $article->getGalleys(); // Give precedence to HTML galleys, as they're quickest to parse usort($galleys, create_function('$a, $b', 'return $a->isHtmlGalley()?-1:1;')); // Determine any access limitations. If there are, do not // provide the full-text. import('classes.issue.IssueAction'); $subscriptionRequired = IssueAction::subscriptionRequired($issue); $isSubscribedDomain = IssueAction::subscribedDomain($journal, $issue->getId(), $article->getId()); if (!$subscriptionRequired || $isSubscribedDomain) { foreach ($galleys as $galley) { $parser =& SearchFileParser::fromFile($galley); if ($parser && $parser->open()) { while (($s = $parser->read()) !== false) { $text .= $s; } $parser->close(); } if ($galley->isHtmlGalley()) { $text = strip_tags($text); } unset($galley); // Use the first parseable galley. if (!empty($text)) { break; } } } if (!empty($text)) { $response .= "\t<body><p>" . htmlspecialchars(Core::cleanVar(Core::cleanVar($text))) . "</p></body>\n"; } // Add NLM citation info import('lib.pkp.classes.importexport.nlm.PKPSubmissionNlmXmlFilter'); $nlmFilter = new PKPSubmissionNlmXmlFilter(); $nlmXml = $nlmFilter->execute($article); // Downgrade to an NLM 2.3 ref-list import('lib.pkp.classes.xslt.XSLTransformationFilter'); $downgradeFilter = new XSLTransformationFilter('NLM 3.0 to 2.3 ref-list downgrade', array('xml::*', 'xml::*')); $downgradeFilter->setXSLFilename('lib/pkp/classes/importexport/nlm/nlm-ref-list-30-to-23.xsl'); // To suppress the XML header, get the DOM and convert it to // string explicitly. (Also check for empty node.) $downgradeFilter->setResultType(XSL_TRANSFORMER_DOCTYPE_DOM); $nlmXmlDom = $downgradeFilter->execute($nlmXml); $documentElement =& $nlmXmlDom->documentElement; // Work-around for hasChildNodes being stupid about whitespace. $hasChildren = false; if (isset($documentElement->childNodes)) { foreach ($documentElement->childNodes as $c) { if ($c->nodeType == XML_ELEMENT_NODE) { $hasChildren = true; } } } // If there were any citations, include them. if ($hasChildren) { $nlmXml = $nlmXmlDom->saveXML($documentElement); $response .= "<back>{$nlmXml}</back>\n"; } $response .= "</article>"; return $response; }