PageRenderTime 50ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/oaiMetadataFormats/nlm/OAIMetadataFormat_NLM.inc.php

https://github.com/budalokko/ojs
PHP | 278 lines | 199 code | 36 blank | 43 comment | 37 complexity | a216fd583f4a182d214e4a488c9fa4e0 MD5 | raw file
  1. <?php
  2. /**
  3. * @defgroup oai_format_nlm
  4. */
  5. /**
  6. * @file classes/oai/format/OAIMetadataFormat_NLM.inc.php
  7. *
  8. * Copyright (c) 2003-2010 John Willinsky
  9. * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
  10. *
  11. * @class OAIMetadataFormat_NLM
  12. * @ingroup oai_format
  13. * @see OAI
  14. *
  15. * @brief OAI metadata format class -- NLM 2.3
  16. */
  17. class OAIMetadataFormat_NLM extends OAIMetadataFormat {
  18. /**
  19. * @see OAIMetadataFormat#toXml
  20. * TODO:
  21. * <copyright-holder>
  22. * In Isabelle's mapping document:
  23. * Article order in the issue's Table of Contents
  24. */
  25. function toXml(&$record, $format = null) {
  26. $article =& $record->getData('article');
  27. $journal =& $record->getData('journal');
  28. $section =& $record->getData('section');
  29. $issue =& $record->getData('issue');
  30. $galleys =& $record->getData('galleys');
  31. $articleId = $article->getId();
  32. // Cache issue ordering information.
  33. static $issueId;
  34. static $sectionSeq;
  35. if (!isset($issueId) || $issueId != $issue->getId()) {
  36. $sectionDao =& DAORegistry::getDAO('SectionDAO');
  37. $issueId = $issue->getId();
  38. $sections =& $sectionDao->getSectionsForIssue($issueId);
  39. $sectionSeq = array();
  40. $i=0;
  41. foreach ($sections as $thisSection) {
  42. $sectionSeq[$thisSection->getSectionId()] = $i++;
  43. }
  44. unset($sections);
  45. }
  46. $abbreviation = $journal->getLocalizedSetting('abbreviation');
  47. $printIssn = $journal->getSetting('printIssn');
  48. $onlineIssn = $journal->getSetting('onlineIssn');
  49. $primaryLocale = $journal->getPrimaryLocale();
  50. $publisherInstitution = $journal->getSetting('publisherInstitution');
  51. $datePublished = strtotime($article->getDatePublished());
  52. $response = "<article\n" .
  53. "\txmlns=\"http://dtd.nlm.nih.gov/publishing/2.3\"\n" .
  54. "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n" .
  55. "\txmlns:mml=\"http://www.w3.org/1998/Math/MathML\"\n" .
  56. "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" .
  57. "\txsi:schemaLocation=\"http://dtd.nlm.nih.gov/publishing/2.3\n" .
  58. "\thttp://dtd.nlm.nih.gov/publishing/2.3/xsd/journalpublishing.xsd\"\n" .
  59. (($s = $section->getSectionIdentifyType())!=''?"\tarticle-type=\"" . htmlspecialchars(Core::cleanVar($s)) . "\"":'') .
  60. "\txml:lang=\"" . strtoupper(substr($primaryLocale, 0, 2)) . "\">\n" .
  61. "\t<front>\n" .
  62. "\t\t<journal-meta>\n" .
  63. "\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" .
  64. "\t\t\t<journal-title>" . htmlspecialchars(Core::cleanVar($journal->getJournalTitle())) . "</journal-title>\n";
  65. // Include translated journal titles
  66. foreach ($journal->getTitle(null) as $locale => $title) {
  67. if ($locale == $primaryLocale) continue;
  68. $response .= "\t\t\t<trans-title xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">" . htmlspecialchars(Core::cleanVar($title)) . "</trans-title>\n";
  69. }
  70. $response .=
  71. (!empty($onlineIssn)?"\t\t\t<issn pub-type=\"epub\">" . htmlspecialchars(Core::cleanVar($onlineIssn)) . "</issn>":'') .
  72. (!empty($printIssn)?"\t\t\t<issn pub-type=\"ppub\">" . htmlspecialchars(Core::cleanVar($printIssn)) . "</issn>":'') .
  73. ($publisherInstitution != ''?"\t\t\t<publisher><publisher-name>" . htmlspecialchars(Core::cleanVar($publisherInstitution)) . "</publisher-name></publisher>\n":'') .
  74. "\t\t</journal-meta>\n" .
  75. "\t\t<article-meta>\n" .
  76. "\t\t\t<article-id pub-id-type=\"other\">" . htmlspecialchars(Core::cleanVar($article->getBestArticleId())) . "</article-id>\n" .
  77. (($s = $article->getDOI()) != ''?"\t\t\t<article-id pub-id-type=\"doi\">" . htmlspecialchars(Core::cleanVar($s)) . "</article-id>\n":'') .
  78. "\t\t\t<article-categories><subj-group subj-group-type=\"heading\"><subject>" . htmlspecialchars(Core::cleanVar($section->getSectionTitle())) . "</subject></subj-group></article-categories>\n" .
  79. "\t\t\t<title-group>\n" .
  80. "\t\t\t\t<article-title>" . htmlspecialchars(Core::cleanVar(strip_tags($article->getArticleTitle()))) . "</article-title>\n";
  81. // Include translated journal titles
  82. foreach ($article->getTitle(null) as $locale => $title) {
  83. if ($locale == $primaryLocale) continue;
  84. $response .= "\t\t\t\t<trans-title xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">" . htmlspecialchars(Core::cleanVar(strip_tags($title))) . "</trans-title>\n";
  85. }
  86. $response .=
  87. "\t\t\t</title-group>\n" .
  88. "\t\t\t<contrib-group>\n";
  89. // Include authors
  90. foreach ($article->getAuthors() as $author) {
  91. $response .=
  92. "\t\t\t\t<contrib " . ($author->getPrimaryContact()?'corresp="yes" ':'') . "contrib-type=\"author\">\n" .
  93. "\t\t\t\t\t<name name-style=\"western\">\n" .
  94. "\t\t\t\t\t\t<surname>" . htmlspecialchars(Core::cleanVar($author->getLastName())) . "</surname>\n" .
  95. "\t\t\t\t\t\t<given-names>" . htmlspecialchars(Core::cleanVar($author->getFirstName()) . (($s = $author->getMiddleName()) != ''?" $s":'')) . "</given-names>\n" .
  96. "\t\t\t\t\t</name>\n" .
  97. (($s = $author->getLocalizedAffiliation()) != ''?"\t\t\t\t\t<aff>" . htmlspecialchars(Core::cleanVar($s)) . "</aff>\n":'') .
  98. "\t\t\t\t\t<email>" . htmlspecialchars(Core::cleanVar($author->getEmail())) . "</email>\n" .
  99. (($s = $author->getUrl()) != ''?"\t\t\t\t\t<uri>" . htmlspecialchars(Core::cleanVar($s)) . "</uri>\n":'') .
  100. "\t\t\t\t</contrib>\n";
  101. }
  102. // Include editorships (optimized)
  103. $response .= $this->getEditorialInfo($journal->getId());
  104. $response .=
  105. "\t\t\t</contrib-group>\n" .
  106. "\t\t\t<pub-date pub-type=\"epub\">\n" .
  107. "\t\t\t\t<day>" . strftime('%d', $datePublished) . "</day>\n" .
  108. "\t\t\t\t<month>" . strftime('%m', $datePublished) . "</month>\n" .
  109. "\t\t\t\t<year>" . strftime('%Y', $datePublished) . "</year>\n" .
  110. "\t\t\t</pub-date>\n" .
  111. ($issue->getShowYear()?"\t\t\t<pub-date pub-type=\"collection\"><year>" . htmlspecialchars(Core::cleanVar($issue->getYear())) . "</year></pub-date>\n":'') .
  112. ($issue->getShowVolume()?"\t\t\t<volume>" . htmlspecialchars(Core::cleanVar($issue->getVolume())) . "</volume>\n":'') .
  113. ($issue->getShowNumber()?"\t\t\t<issue seq=\"" . htmlspecialchars(Core::cleanVar(($sectionSeq[$section->getId()]*100) + $article->getSeq())) . "\">" . htmlspecialchars(Core::cleanVar($issue->getNumber())) . "</issue>\n":'') .
  114. "\t\t\t<issue-id pub-id-type=\"other\">" . htmlspecialchars(Core::cleanVar($issue->getBestIssueId())) . "</issue-id>\n" .
  115. ($issue->getShowTitle()?"\t\t\t<issue-title>" . htmlspecialchars(Core::cleanVar($issue->getIssueTitle())) . "</issue-title>\n":'');
  116. // Include page info, if available and parseable.
  117. $matches = null;
  118. if (String::regexp_match_get('/^[Pp][Pp]?[.]?[ ]?(\d+)$/', $article->getPages(), $matches)) {
  119. $matchedPage = htmlspecialchars(Core::cleanVar($matches[1]));
  120. $response .= "\t\t\t\t<fpage>$matchedPage</fpage><lpage>$matchedPage</lpage>\n";
  121. $pageCount = 1;
  122. } elseif (String::regexp_match_get('/^[Pp][Pp]?[.]?[ ]?(\d+)[ ]?-[ ]?([Pp][Pp]?[.]?[ ]?)?(\d+)$/', $article->getPages(), $matches)) {
  123. $matchedPageFrom = htmlspecialchars(Core::cleanVar($matches[1]));
  124. $matchedPageTo = htmlspecialchars(Core::cleanVar($matches[3]));
  125. $response .=
  126. "\t\t\t\t<fpage>$matchedPageFrom</fpage>\n" .
  127. "\t\t\t\t<lpage>$matchedPageTo</lpage>\n";
  128. $pageCount = $matchedPageTo - $matchedPageFrom + 1;
  129. }
  130. $response .=
  131. "\t\t\t<permissions>\n" .
  132. ((($s = $journal->getLocalizedSetting('copyrightNotice')) != '')?"\t\t\t\t<copyright-statement>" . htmlspecialchars(Core::cleanVar($s)) . "</copyright-statement>\n":'') .
  133. "\t\t\t\t<copyright-year>" . strftime('%Y', $datePublished) . "</copyright-year>\n" .
  134. "\t\t\t</permissions>\n" .
  135. "\t\t\t<self-uri xlink:href=\"" . htmlspecialchars(Core::cleanVar(Request::url($journal->getPath(), 'article', 'view', $article->getBestArticleId()))) . "\" />\n";
  136. // Include galley links
  137. foreach ($article->getGalleys() as $galley) {
  138. $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";
  139. }
  140. // Include abstract(s)
  141. $abstract = htmlspecialchars(Core::cleanVar(strip_tags($article->getArticleAbstract())));
  142. if (!empty($abstract)) {
  143. $abstract = "<p>$abstract</p>";
  144. // $abstract = '<p>' . String::regexp_replace('/\n+/', '</p><p>', $abstract) . '</p>';
  145. $response .= "\t\t\t<abstract xml:lang=\"" . strtoupper(substr($primaryLocale, 0, 2)) . "\">$abstract</abstract>\n";
  146. }
  147. if (is_array($article->getAbstract(null))) foreach ($article->getAbstract(null) as $locale => $abstract) {
  148. if ($locale == $primaryLocale || empty($abstract)) continue;
  149. $abstract = htmlspecialchars(Core::cleanVar(strip_tags($abstract)));
  150. if (empty($abstract)) continue;
  151. $abstract = "<p>$abstract</p>";
  152. //$abstract = '<p>' . String::regexp_replace('/\n+/', '</p><p>', $abstract) . '</p>';
  153. $response .= "\t\t\t<abstract-trans xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">$abstract</abstract-trans>\n";
  154. }
  155. $subjects = array();
  156. if (is_array($article->getSubject(null))) foreach ($article->getSubject(null) as $locale => $subject) {
  157. $s = array_map('trim', explode(';', Core::cleanVar($subject)));
  158. if (!empty($s)) $subjects[$locale] = $s;
  159. }
  160. if (!empty($subjects)) foreach ($subjects as $locale => $s) {
  161. $response .= "\t\t\t<kwd-group xml:lang=\"" . strtoupper(substr($locale, 0, 2)) . "\">\n";
  162. foreach ($s as $subject) $response .= "\t\t\t\t<kwd>" . htmlspecialchars($subject) . "</kwd>\n";
  163. $response .= "\t\t\t</kwd-group>\n";
  164. }
  165. $response .=
  166. (isset($pageCount)?"\t\t\t<counts><page-count count=\"" . (int) $pageCount. "\" /></counts>\n":'') .
  167. "\t\t</article-meta>\n" .
  168. "\t</front>\n";
  169. // Include body text (for search indexing only)
  170. import('classes.search.ArticleSearchIndex');
  171. $text = '';
  172. $galleys = $article->getGalleys();
  173. // Give precedence to HTML galleys, as they're quickest to parse
  174. usort($galleys, create_function('$a, $b', 'return $a->isHtmlGalley()?-1:1;'));
  175. // Determine any access limitations. If there are, do not
  176. // provide the full-text.
  177. import('classes.issue.IssueAction');
  178. $subscriptionRequired = IssueAction::subscriptionRequired($issue);
  179. $isSubscribedDomain = IssueAction::subscribedDomain($journal, $issue->getId(), $article->getId());
  180. if (!$subscriptionRequired || $isSubscribedDomain) foreach ($galleys as $galley) {
  181. $parser =& SearchFileParser::fromFile($galley);
  182. if ($parser && $parser->open()) {
  183. while(($s = $parser->read()) !== false) $text .= $s;
  184. $parser->close();
  185. }
  186. if ($galley->isHtmlGalley()) $text = strip_tags($text);
  187. unset($galley);
  188. // Use the first parseable galley.
  189. if (!empty($text)) break;
  190. }
  191. if (!empty($text)) $response .= "\t<body><p>" . htmlspecialchars(Core::cleanVar(Core::cleanVar($text))) . "</p></body>\n";
  192. // Add NLM citation info
  193. import('lib.pkp.classes.importexport.nlm.PKPSubmissionNlmXmlFilter');
  194. $nlmFilter = new PKPSubmissionNlmXmlFilter();
  195. $nlmXml = $nlmFilter->execute($article);
  196. // Downgrade to an NLM 2.3 ref-list
  197. import('lib.pkp.classes.xslt.XSLTransformationFilter');
  198. $downgradeFilter = new XSLTransformationFilter('NLM 3.0 to 2.3 ref-list downgrade', array('xml::*', 'xml::*'));
  199. $downgradeFilter->setXSLFilename('lib/pkp/classes/importexport/nlm/nlm-ref-list-30-to-23.xsl');
  200. // To suppress the XML header, get the DOM and convert it to
  201. // string explicitly. (Also check for empty node.)
  202. $downgradeFilter->setResultType(XSL_TRANSFORMER_DOCTYPE_DOM);
  203. $nlmXmlDom = $downgradeFilter->execute($nlmXml);
  204. $documentElement =& $nlmXmlDom->documentElement;
  205. // Work-around for hasChildNodes being stupid about whitespace.
  206. $hasChildren = false;
  207. if (isset($documentElement->childNodes)) foreach ($documentElement->childNodes as $c) {
  208. if ($c->nodeType == XML_ELEMENT_NODE) $hasChildren = true;
  209. }
  210. // If there were any citations, include them.
  211. if ($hasChildren) {
  212. $nlmXml = $nlmXmlDom->saveXML($documentElement);
  213. $response .= "<back>$nlmXml</back>\n";
  214. }
  215. $response .= "</article>";
  216. return $response;
  217. }
  218. function getEditorialInfo($journalId) {
  219. static $editorialInfo = array();
  220. if (isset($editorialInfo[$journalId])) return $editorialInfo[$journalId];
  221. $response = '';
  222. $roleDao =& DAORegistry::getDAO('RoleDAO');
  223. $roleMap = array(ROLE_ID_EDITOR => 'editor', ROLE_ID_SECTION_EDITOR> 'secteditor', ROLE_ID_JOURNAL_MANAGER => 'jmanager');
  224. foreach ($roleMap as $roleId => $roleName) {
  225. $users =& $roleDao->getUsersByRoleId($roleId, $journalId);
  226. $isFirst = true;
  227. while ($user =& $users->next()) {
  228. $response .= "\t\t\t\t<contrib contrib-type=\"$roleName\">\n" .
  229. "\t\t\t\t\t<name>\n" .
  230. "\t\t\t\t\t\t<surname>" . htmlspecialchars(Core::cleanVar($user->getLastName())) . "</surname>\n" .
  231. "\t\t\t\t\t\t<given-names>" . htmlspecialchars(Core::cleanVar($user->getFirstName() . ($user->getMiddleName() != ''?' ' . $user->getMiddleName():''))) . "</given-names>\n" .
  232. "\t\t\t\t\t</name>\n" .
  233. "\t\t\t\t</contrib>\n";
  234. unset($user);
  235. }
  236. unset($users);
  237. }
  238. $editorialInfo[$journalId] =& $response;
  239. return $response;
  240. }
  241. }
  242. ?>