Open Journal Systems  3.3.0
ArticleMedraXmlFilter.inc.php
1 <?php
2 
16 import('plugins.importexport.medra.filter.O4DOIXmlFilter');
17 
18 
24  function __construct($filterGroup) {
25  $this->setDisplayName('mEDRA XML article export');
26  parent::__construct($filterGroup);
27  }
28 
32  function isWork($context, $plugin) {
33  return true;
34  }
35 
39  function getRootNodeName() {
40  return 'ONIXDOISerialArticleWorkRegistrationMessage';
41  }
42 
43  //
44  // Implement template methods from PersistableFilter
45  //
49  function getClassName() {
50  return 'plugins.importexport.medra.filter.ArticleMedraXmlFilter';
51  }
52 
53  //
54  // Implement template methods from Filter
55  //
61  function &process(&$pubObjects) {
62  // Create the XML document
63  $doc = new DOMDocument('1.0', 'utf-8');
64  $doc->preserveWhiteSpace = false;
65  $doc->formatOutput = true;
66  $deployment = $this->getDeployment();
67  $context = $deployment->getContext();
68 
69  // Create the root node
70  $rootNode = $this->createRootNode($doc, $this->getRootNodeName());
71  $doc->appendChild($rootNode);
72 
73  // Create and appet the header node and all parts inside it
74  $rootNode->appendChild($this->createHeadNode($doc));
75 
76  // Create and append the article nodes,
77  // containing all article information
78  foreach($pubObjects as $pubObject) {
79  $rootNode->appendChild($this->createArticleNode($doc, $pubObject));
80  }
81  return $doc;
82  }
83 
90  function createArticleNode($doc, $pubObject) {
91  $deployment = $this->getDeployment();
92  $context = $deployment->getContext();
93  $cache = $deployment->getCache();
94  $plugin = $deployment->getPlugin();
95  $request = Application::get()->getRequest();
96  $router = $request->getRouter();
97 
98  assert ((is_a($pubObject, 'Submission') && $this->isWork($context, $plugin)) ||
99  (is_a($pubObject, 'ArticleGalley') && !$this->isWork($context, $plugin)));
100 
101  if (is_a($pubObject, 'Submission')) {
102  $galley = null;
103  $article = $pubObject;
104  if (!$cache->isCached('articles', $article->getId())) {
105  $cache->add($article, null);
106  }
107  $articleNodeName = 'DOISerialArticleWork';
108  $workOrProduct = 'Work';
109  $epubFormat = O4DOI_EPUB_FORMAT_HTML;
110  } else {
111  $galley = $pubObject;
112  $publication = Services::get('publication')->get($galley->getData('publicationId'));
113  if ($cache->isCached('articles', $publication->getData('submissionId'))) {
114  $article = $cache->get('articles', $publication->getData('submissionId'));
115  } else {
116  $article = Services::get('submission')->get($publication->getData('submissionId'));
117  if ($article && $article->getData('status') === STATUS_PUBLISHED) $cache->add($article, null);
118  }
119  $articleNodeName = 'DOISerialArticleVersion';
120  $workOrProduct = 'Product';
121  $epubFormat = null;
122  if ($galley->isPdfGalley()) {
123  $epubFormat = O4DOI_EPUB_FORMAT_PDF;
124  } else if ($galley->getRemoteURL() || $galley->getFileType() == 'text/html') {
125  $epubFormat = O4DOI_EPUB_FORMAT_HTML;
126  }
127  }
128 
129  $articleNode = $doc->createElementNS($deployment->getNamespace(), $articleNodeName);
130  // Notification type (mandatory)
131  $doi = $pubObject->getStoredPubId('doi');
132  $registeredDoi = $pubObject->getData('medra::registeredDoi');
133  assert(empty($registeredDoi) || $registeredDoi == $doi);
134  $notificationType = (empty($registeredDoi) ? O4DOI_NOTIFICATION_TYPE_NEW : O4DOI_NOTIFICATION_TYPE_UPDATE);
135  $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'NotificationType', $notificationType));
136  // DOI (mandatory)
137  $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'DOI', htmlspecialchars($doi, ENT_COMPAT, 'UTF-8')));
138  // DOI URL (mandatory)
139  $urlPath = $article->getBestId();
140  if ($galley) $urlPath = array($article->getBestId(), $galley->getBestGalleyId());
141  $url = $router->url($request, $context->getPath(), 'article', 'view', $urlPath, null, null, true);
142  if ($plugin->isTestMode($context)) {
143  // Change server domain for testing.
144  $url = PKPString::regexp_replace('#://[^\s]+/index.php#', '://example.com/index.php', $url);
145  }
146  $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'DOIWebsiteLink', $url));
147  // DOI strucural type
148  $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'DOIStructuralType', $this->getDOIStructuralType()));
149  // Registrant (mandatory)
150  $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'RegistrantName', htmlspecialchars($plugin->getSetting($context->getId(), 'registrantName'), ENT_COMPAT, 'UTF-8')));
151  // Registration authority (mandatory)
152  $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'RegistrationAuthority', 'mEDRA'));
153  // WorkIdentifier - proprietary ID
154  $pubObjectProprietaryId = $context->getId() . '-' . $article->getCurrentPublication()->getData('issueId') . '-' . $article->getId();
155  if ($galley) $pubObjectProprietaryId .= '-g' . $galley->getId();
156  $articleNode->appendChild($this->createIdentifierNode($doc, $workOrProduct, O4DOI_ID_TYPE_PROPRIETARY, $pubObjectProprietaryId));
157  // Issue/journal locale precedence.
158  $journalLocalePrecedence = $this->getObjectLocalePrecedence($context, null, null);
159  // Serial Publication (mandatory)
160  $articleNode->appendChild($this->createSerialPublicationNode($doc, $journalLocalePrecedence, $epubFormat));
161  // Journal Issue (mandatory)
162  $issueId = $article->getCurrentPublication()->getData('issueId');
163  if ($cache->isCached('issues', $issueId)) {
164  $issue = $cache->get('issues', $issueId);
165  } else {
166  $issueDao = DAORegistry::getDAO('IssueDAO'); /* @var $issueDao IssueDAO */
167  $issue = $issueDao->getById($issueId, $context->getId());
168  if ($issue) $cache->add($issue, null);
169  }
170  $articleNode->appendChild($this->createJournalIssueNode($doc, $issue, $journalLocalePrecedence));
171 
172  // Object locale precedence.
173  $objectLocalePrecedence = $this->getObjectLocalePrecedence($context, $article, $galley);
174  // Content Item (mandatory for articles)
175  $articleNode->appendChild($this->createContentItemNode($doc, $issue, $article, $galley, $objectLocalePrecedence));
176  return $articleNode;
177  }
178 
188  function createContentItemNode($doc, $issue, $article, $galley, $objectLocalePrecedence) {
189  $deployment = $this->getDeployment();
190  $context = $deployment->getContext();
191  $plugin = $deployment->getPlugin();
192  $contentItemNode = $doc->createElementNS($deployment->getNamespace(), 'ContentItem');
193  // Sequence number
194  $seq = $article->getCurrentPublication()->getData('seq');
195  if ($seq) {
196  $contentItemNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SequenceNumber', $seq));
197  }
198  // Describe page runs
199  $pages = $article->getCurrentPublication()->getPageArray();
200  if ($pages) {
201  $textItemNode = $doc->createElementNS($deployment->getNamespace(), 'TextItem');
202  foreach ($pages as $range) {
203  $pageRunNode = $doc->createElementNS($deployment->getNamespace(), 'PageRun');
204  $node = $doc->createElementNS($deployment->getNamespace(), 'FirstPageNumber', htmlspecialchars($range[0]));
205  $pageRunNode->appendChild($node);
206  if (isset($range[1])) {
207  $node = $doc->createElementNS($deployment->getNamespace(), 'LastPageNumber', htmlspecialchars($range[1]));
208  $pageRunNode->appendChild($node);
209  }
210  $textItemNode->appendChild($pageRunNode);
211  }
212  $contentItemNode->appendChild($textItemNode);
213  }
214  // Extent (for article-as-manifestation only)
215  if ($galley && !$galley->getRemoteURL()) {
216  $galleyFile = $galley->getFile();
217  if ($galleyFile) $contentItemNode->appendChild($this->createExtentNode($doc, $galleyFile));
218  }
219  // Article Title (mandatory)
220  $titles = $this->getTranslationsByPrecedence($article->getCurrentPublication()->getFullTitles(), $objectLocalePrecedence);
221  assert(!empty($titles));
222  foreach ($titles as $locale => $title) {
223  $contentItemNode->appendChild($this->createTitleNode($doc, $locale, $title, O4DOI_TITLE_TYPE_FULL));
224  }
225  // Contributors
226  $authors = $article->getCurrentPublication()->getData('authors');
227  assert(!empty($authors));
228  foreach ($authors as $author) {
229  $contentItemNode->appendChild($this->createContributorNode($doc, $author, $objectLocalePrecedence));
230  }
231  // Language
232  $languageCode = AppLocale::get3LetterIsoFromLocale($objectLocalePrecedence[0]);
233  assert(!empty($languageCode));
234  $languageNode = $doc->createElementNS($deployment->getNamespace(), 'Language');
235  $languageNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'LanguageRole', O4DOI_LANGUAGE_ROLE_LANGUAGE_OF_TEXT));
236  $languageNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'LanguageCode', $languageCode));
237  $contentItemNode->appendChild($languageNode);
238  // Article keywords
239  // SubjectClass will be left out here, because we don't know the scheme/classification name
240  $submissionKeywordDao = DAORegistry::getDAO('SubmissionKeywordDAO'); /* @var $submissionKeywordDao SubmissionKeywordDAO */
241  $allKeywords = $submissionKeywordDao->getKeywords($article->getCurrentPublication()->getId(), $context->getSupportedSubmissionLocales());
242  $keywords = $this->getPrimaryTranslation($allKeywords, $objectLocalePrecedence);
243  if (!empty($keywords)) {
244  $keywordsString = implode(';', $keywords);
245  $contentItemNode->appendChild($this->createSubjectNode($doc, O4DOI_SUBJECT_SCHEME_PUBLISHER, $keywordsString));
246  }
247  // Object Description 'OtherText'
248  $descriptions = $this->getTranslationsByPrecedence($article->getCurrentPublication()->getData('abstract'), $objectLocalePrecedence);
249  foreach ($descriptions as $locale => $description) {
250  $contentItemNode->appendChild($this->createOtherTextNode($doc, $locale, $description));
251  }
252  // Article Publication Date
253  $datePublished = $article->getCurrentPublication()->getData('datePublished');
254  if (!empty($datePublished)) {
255  $contentItemNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'PublicationDate', date('Ymd', strtotime($datePublished))));
256  }
257 
258  // Relations
259  // Issue
260  if ($plugin->getSetting($context->getId(), 'exportIssuesAs') == O4DOI_ISSUE_AS_WORK) {
261  // related work:
262  // - is part of issue-as-work
263  $issueWorkOrProduct = 'Work';
264  } else {
265  // related product:
266  // - is part of issue-as-manifestation
267  $issueWorkOrProduct = 'Product';
268  }
269  $issueProprietaryId = $context->getId() . '-' . $issue->getId();
270  $relatedIssueIds = array(O4DOI_ID_TYPE_PROPRIETARY => $issueProprietaryId);
271  $issueDoi = $issue->getStoredPubId('doi');
272  if (!empty($issueDoi)) $relatedIssueIds[O4DOI_ID_TYPE_DOI] = $issueDoi;
273  $relatedIssueNode = $this->createRelatedNode($doc, $issueWorkOrProduct, O4DOI_RELATION_IS_PART_OF, $relatedIssueIds);
274  // Galleys
275  $galleysByArticle = $article->getCurrentPublication()->getData('galleys');
276  if (!$galley) { // if exporting object is an article
277  $contentItemNode->appendChild($relatedIssueNode);
278  // related products:
279  // - is manifested in articles-as-manifestation
280  foreach($galleysByArticle as $relatedGalley) {
281  $galleyProprietaryId = $context->getId() . '-' . $issue->getId() . '-' . $article->getId() . '-g' . $relatedGalley->getId();
282  $relatedGalleyIds = array(O4DOI_ID_TYPE_PROPRIETARY => $galleyProprietaryId);
283  $galleyDoi = $relatedGalley->getStoredPubId('doi');
284  if (!empty($galleyDoi)) $relatedGalleyIds[O4DOI_ID_TYPE_DOI] = $galleyDoi;
285  $contentItemNode->appendChild($this->createRelatedNode($doc, 'Product', O4DOI_RELATION_IS_MANIFESTED_IN, $relatedGalleyIds));
286  unset($relatedGalley, $relatedGalleyIds, $galleyProprietaryId, $galleyDoi);
287  }
288  } else {
289  // Include issue-as-work before article-as-work.
290  if ($issueWorkOrProduct == 'Work') $contentItemNode->appendChild($relatedIssueNode);
291 
292  // related work:
293  // - is a manifestation of article-as-work
294  $articleProprietaryId = $context->getId() . '-' . $article->getCurrentPublication()->getData('issueId') . '-' . $article->getId();
295  $relatedArticleIds = array(O4DOI_ID_TYPE_PROPRIETARY => $articleProprietaryId);
296  $doi = $article->getCurrentPublication()->getStoredPubId('doi');
297  if (!empty($doi)) $relatedArticleIds[O4DOI_ID_TYPE_DOI] = $doi;
298  $contentItemNode->appendChild($this->createRelatedNode($doc, 'Work', O4DOI_RELATION_IS_A_MANIFESTATION_OF, $relatedArticleIds));
299  unset($relatedArticleIds);
300 
301  // Include issue-as-manifestation after article-as-work.
302  if ($issueWorkOrProduct == 'Product')$contentItemNode->appendChild($relatedIssueNode);
303 
304  // related products:
305  foreach($galleysByArticle as $relatedGalley) {
306  $galleyProprietaryId = $context->getId() . '-' . $issue->getId() . '-' . $article->getId() . '-g' . $relatedGalley->getId();
307  $relatedGalleyIds = array(O4DOI_ID_TYPE_PROPRIETARY => $galleyProprietaryId);
308  $galleyDoi = $relatedGalley->getStoredPubId('doi');
309  if (!empty($galleyDoi)) $relatedGalleyIds[O4DOI_ID_TYPE_DOI] = $galleyDoi;
310 
311  // - is a different form of all other articles-as-manifestation
312  // with the same article id and language but different form
313  if ($galley->getLocale() == $relatedGalley->getLocale() &&
314  $galley->getLabel() != $relatedGalley->getLabel()) {
315 
316  $contentItemNode->appendChild($this->createRelatedNode($doc, 'Product', O4DOI_RELATION_IS_A_DIFFERENT_FORM_OF, $relatedGalleyIds));
317  }
318 
319  // - is a different language version of all other articles-as-manifestation
320  // with the same article id and form/label but different language
321  if ($galley->getLabel() == $relatedGalley->getLabel() &&
322  $galley->getLocale() != $relatedGalley->getLocale()) {
323 
324  $contentItemNode->appendChild($this->createRelatedNode($doc, 'Product', O4DOI_RELATION_IS_A_LANGUAGE_VERSION_OF, $relatedGalleyIds));
325  }
326  unset($relatedGalley, $relatedGalleyIds, $galleyProprietaryId, $galleyDoi);
327  }
328 
329  }
330  return $contentItemNode;
331  }
332 
340  function createContributorNode($doc, $author, $objectLocalePrecedence) {
341  $deployment = $this->getDeployment();
342  $contributorNode = $doc->createElementNS($deployment->getNamespace(), 'Contributor');
343  // Sequence number
344  $seq = $author->getSequence() ?? 0;
345  $seq++; // Sequences must begin with 1, so bump our internal sequence by 1.
346  $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SequenceNumber', $seq));
347  // Contributor role (mandatory)
348  $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'ContributorRole', O4DOI_CONTRIBUTOR_ROLE_ACTUAL_AUTHOR));
349  // Person name (mandatory)
350  $personName = $author->getFullName(false);
351  assert(!empty($personName));
352  $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'PersonName', htmlspecialchars($personName, ENT_COMPAT, 'UTF-8')));
353  // Inverted person name
354  $invertedPersonName = $author->getFullName(false, true);
355  assert(!empty($invertedPersonName));
356  $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'PersonNameInverted', htmlspecialchars($invertedPersonName, ENT_COMPAT, 'UTF-8')));
357  // Affiliation
358  $affiliation = $this->getPrimaryTranslation($author->getAffiliation(null), $objectLocalePrecedence);
359  if (!empty($affiliation)) {
360  $affiliationNode = $doc->createElementNS($deployment->getNamespace(), 'ProfessionalAffiliation');
361  $affiliationNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'Affiliation', htmlspecialchars($affiliation, ENT_COMPAT, 'UTF-8')));
362  $contributorNode->appendChild($affiliationNode);
363  }
364  // Biographical note
365  $bioNote = $this->getPrimaryTranslation($author->getBiography(null), $objectLocalePrecedence);
366  if (!empty($bioNote)) {
367  $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'BiographicalNote', htmlspecialchars(PKPString::html2text($bioNote), ENT_COMPAT, 'UTF-8')));
368  }
369  return $contributorNode;
370  }
371 
380  function createSubjectNode($doc, $subjectSchemeId, $subjectHeadingOrCode, $subjectSchemeName = null) {
381  $deployment = $this->getDeployment();
382  $subjectNode = $doc->createElementNS($deployment->getNamespace(), 'Subject');
383  // Subject Scheme Identifier
384  $subjectNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SubjectSchemeIdentifier', $subjectSchemeId));
385  if (is_null($subjectSchemeName)) {
386  // Subject Heading
387  $subjectNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SubjectHeadingText', htmlspecialchars($subjectHeadingOrCode, ENT_COMPAT, 'UTF-8')));
388  } else {
389  // Subject Scheme Name
390  $subjectNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SubjectSchemeName', htmlspecialchars($subjectSchemeName, ENT_COMPAT, 'UTF-8')));
391  // Subject Code
392  $subjectNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SubjectCode', htmlspecialchars($subjectHeadingOrCode, ENT_COMPAT, 'UTF-8')));
393  }
394  return $subjectNode;
395  }
396 
397 }
398 
399 
ArticleMedraXmlFilter\createSubjectNode
createSubjectNode($doc, $subjectSchemeId, $subjectHeadingOrCode, $subjectSchemeName=null)
Definition: ArticleMedraXmlFilter.inc.php:380
O4DOIXmlFilter\createJournalIssueNode
createJournalIssueNode($doc, $issue, $journalLocalePrecedence)
Definition: O4DOIXmlFilter.inc.php:284
PKPString\regexp_replace
static regexp_replace($pattern, $replacement, $subject, $limit=-1)
Definition: PKPString.inc.php:279
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
O4DOIXmlFilter\createExtentNode
createExtentNode($doc, $file)
Definition: O4DOIXmlFilter.inc.php:369
O4DOIXmlFilter\createOtherTextNode
createOtherTextNode($doc, $locale, $description)
Definition: O4DOIXmlFilter.inc.php:388
O4DOIXmlFilter\getTranslationsByPrecedence
getTranslationsByPrecedence($localizedData, $localePrecedence)
Definition: O4DOIXmlFilter.inc.php:524
ArticleMedraXmlFilter\createContributorNode
createContributorNode($doc, $author, $objectLocalePrecedence)
Definition: ArticleMedraXmlFilter.inc.php:340
PKPLocale\get3LetterIsoFromLocale
static get3LetterIsoFromLocale($locale)
Definition: PKPLocale.inc.php:651
O4DOIXmlFilter\createHeadNode
createHeadNode($doc)
Definition: O4DOIXmlFilter.inc.php:130
O4DOIXmlFilter
Basis class for converting objects (issues, articles, galleys) to a O4DOI XML document.
Definition: O4DOIXmlFilter.inc.php:81
ArticleMedraXmlFilter\getClassName
getClassName()
Definition: ArticleMedraXmlFilter.inc.php:49
NativeImportExportFilter\getDeployment
getDeployment()
Definition: NativeImportExportFilter.inc.php:49
ArticleMedraXmlFilter\process
& process(&$pubObjects)
Definition: ArticleMedraXmlFilter.inc.php:61
O4DOIXmlFilter\getPrimaryTranslation
getPrimaryTranslation($localizedData, $localePrecedence)
Definition: O4DOIXmlFilter.inc.php:494
ArticleMedraXmlFilter\isWork
isWork($context, $plugin)
Definition: ArticleMedraXmlFilter.inc.php:32
O4DOIXmlFilter\createRootNode
createRootNode($doc, $rootNodeName)
Definition: O4DOIXmlFilter.inc.php:117
PKPString\html2text
static html2text($html)
Definition: PKPString.inc.php:395
ArticleMedraXmlFilter\createArticleNode
createArticleNode($doc, $pubObject)
Definition: ArticleMedraXmlFilter.inc.php:90
O4DOIXmlFilter\createSerialPublicationNode
createSerialPublicationNode($doc, $journalLocalePrecedence, $epubFormat=null)
Definition: O4DOIXmlFilter.inc.php:156
O4DOIXmlFilter\getObjectLocalePrecedence
getObjectLocalePrecedence($context, $article, $galley)
Definition: O4DOIXmlFilter.inc.php:428
ArticleMedraXmlFilter\createContentItemNode
createContentItemNode($doc, $issue, $article, $galley, $objectLocalePrecedence)
Definition: ArticleMedraXmlFilter.inc.php:188
O4DOIXmlFilter\createTitleNode
createTitleNode($doc, $locale, $localizedTitle, $titleType)
Definition: O4DOIXmlFilter.inc.php:205
ArticleMedraXmlFilter\getRootNodeName
getRootNodeName()
Definition: ArticleMedraXmlFilter.inc.php:39
O4DOIXmlFilter\createIdentifierNode
createIdentifierNode($doc, $workOrProduct, $idType, $id)
Definition: O4DOIXmlFilter.inc.php:353
ArticleMedraXmlFilter\__construct
__construct($filterGroup)
Definition: ArticleMedraXmlFilter.inc.php:24
PKPApplication\get
static get()
Definition: PKPApplication.inc.php:235
Filter\setDisplayName
setDisplayName($displayName)
Definition: Filter.inc.php:140
ArticleMedraXmlFilter
Class that converts an Article as work to a O4DOI XML document.
Definition: ArticleMedraXmlFilter.inc.php:19
O4DOIXmlFilter\createRelatedNode
createRelatedNode($doc, $workOrProduct, $relationCode, $ids)
Definition: O4DOIXmlFilter.inc.php:333
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49