setDisplayName('mEDRA XML article export'); parent::__construct($filterGroup); } /** * @copydoc O4DOIXmlFilter::isWork() */ function isWork($context, $plugin) { return true; } /** * @copydoc O4DOIXmlFilter::getRootNodeName */ function getRootNodeName() { return 'ONIXDOISerialArticleWorkRegistrationMessage'; } // // Implement template methods from PersistableFilter // /** * @copydoc PersistableFilter::getClassName() */ function getClassName() { return 'plugins.importexport.medra.filter.ArticleMedraXmlFilter'; } // // Implement template methods from Filter // /** * @see Filter::process() * @param $pubObjects array Array of PublishedArticles or ArticleGalleys * @return DOMDocument */ function &process(&$pubObjects) { // Create the XML document $doc = new DOMDocument('1.0', 'utf-8'); $doc->preserveWhiteSpace = false; $doc->formatOutput = true; $deployment = $this->getDeployment(); $context = $deployment->getContext(); // Create the root node $rootNode = $this->createRootNode($doc, $this->getRootNodeName()); $doc->appendChild($rootNode); // Create and appet the header node and all parts inside it $rootNode->appendChild($this->createHeadNode($doc)); // Create and append the article nodes, // containing all article information foreach($pubObjects as $pubObject) { $rootNode->appendChild($this->createArticleNode($doc, $pubObject)); } return $doc; } /** * Create and return the article (as work or as manifestation) node. * @param $doc DOMDocument * @param $pubObject PublishedArticle|ArticleGalley * @return DOMElement */ function createArticleNode($doc, $pubObject) { $deployment = $this->getDeployment(); $context = $deployment->getContext(); $cache = $deployment->getCache(); $plugin = $deployment->getPlugin(); $request = Application::getRequest(); $router = $request->getRouter(); assert ((is_a($pubObject, 'PublishedArticle') && $this->isWork($context, $plugin)) || (is_a($pubObject, 'ArticleGalley') && !$this->isWork($context, $plugin))); if (is_a($pubObject, 'PublishedArticle')) { $galley = null; $article = $pubObject; if (!$cache->isCached('articles', $article->getId())) { $cache->add($article, null); } $articleNodeName = 'DOISerialArticleWork'; $workOrProduct = 'Work'; $epubFormat = O4DOI_EPUB_FORMAT_HTML; } else { $galley = $pubObject; if ($cache->isCached('articles', $galley->getSubmissionId())) { $article = $cache->get('articles', $galley->getSubmissionId()); } else { $publishedArticleDao = DAORegistry::getDAO('PublishedArticleDAO'); /* @var $publishedArticleDao PublishedArticleDAO */ $article = $publishedArticleDao->getByArticleId($galley->getSubmissionId()); if ($article) $cache->add($article, null); } $articleNodeName = 'DOISerialArticleVersion'; $workOrProduct = 'Product'; $epubFormat = null; if ($galley->isPdfGalley()) { $epubFormat = O4DOI_EPUB_FORMAT_PDF; } else if ($galley->getRemoteURL() || $galley->getFileType() == 'text/html') { $epubFormat = O4DOI_EPUB_FORMAT_HTML; } } $articleNode = $doc->createElementNS($deployment->getNamespace(), $articleNodeName); // Notification type (mandatory) $doi = $pubObject->getStoredPubId('doi'); $registeredDoi = $pubObject->getData('medra::registeredDoi'); assert(empty($registeredDoi) || $registeredDoi == $doi); $notificationType = (empty($registeredDoi) ? O4DOI_NOTIFICATION_TYPE_NEW : O4DOI_NOTIFICATION_TYPE_UPDATE); $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'NotificationType', $notificationType)); // DOI (mandatory) $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'DOI', htmlspecialchars($doi, ENT_COMPAT, 'UTF-8'))); // DOI URL (mandatory) $urlPath = $article->getBestArticleId(); if ($galley) $urlPath = array($article->getBestArticleId(), $galley->getBestGalleyId()); $url = $router->url($request, $context->getPath(), 'article', 'view', $urlPath, null, null, true); if ($plugin->isTestMode($context)) { // Change server domain for testing. $url = PKPString::regexp_replace('#://[^\s]+/index.php#', '://example.com/index.php', $url); } $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'DOIWebsiteLink', $url)); // DOI strucural type $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'DOIStructuralType', $this->getDOIStructuralType())); // Registrant (mandatory) $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'RegistrantName', htmlspecialchars($plugin->getSetting($context->getId(), 'registrantName'), ENT_COMPAT, 'UTF-8'))); // Registration authority (mandatory) $articleNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'RegistrationAuthority', 'mEDRA')); // WorkIdentifier - proprietary ID $pubObjectProprietaryId = $context->getId() . '-' . $article->getIssueId() . '-' . $article->getId(); if ($galley) $pubObjectProprietaryId .= '-g' . $galley->getId(); $articleNode->appendChild($this->createIdentifierNode($doc, $workOrProduct, O4DOI_ID_TYPE_PROPRIETARY, $pubObjectProprietaryId)); // Issue/journal locale precedence. $journalLocalePrecedence = $this->getObjectLocalePrecedence($context, null, null); // Serial Publication (mandatory) $articleNode->appendChild($this->createSerialPublicationNode($doc, $journalLocalePrecedence, $epubFormat)); // Journal Issue (mandatory) $issueId = $article->getIssueId(); if ($cache->isCached('issues', $issueId)) { $issue = $cache->get('issues', $issueId); } else { $issueDao = DAORegistry::getDAO('IssueDAO'); /* @var $issueDao IssueDAO */ $issue = $issueDao->getById($issueId, $context->getId()); if ($issue) $cache->add($issue, null); } $articleNode->appendChild($this->createJournalIssueNode($doc, $issue, $journalLocalePrecedence)); // Object locale precedence. $objectLocalePrecedence = $this->getObjectLocalePrecedence($context, $article, $galley); // Content Item (mandatory for articles) $articleNode->appendChild($this->createContentItemNode($doc, $issue, $article, $galley, $objectLocalePrecedence)); return $articleNode; } /** * Create a content item node. * @param $doc DOMDocument * @param $issue Issue * @param $article PublishedArticle * @param $galley ArticleGalley * @param $objectLocalePrecedence array * @return DOMElement */ function createContentItemNode($doc, $issue, $article, $galley, $objectLocalePrecedence) { $deployment = $this->getDeployment(); $context = $deployment->getContext(); $plugin = $deployment->getPlugin(); $contentItemNode = $doc->createElementNS($deployment->getNamespace(), 'ContentItem'); // Sequence number $seq = $article->getSequence(); assert(!empty($seq)); $contentItemNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SequenceNumber', $seq)); // Describe page runs $pages = $article->getPageArray(); if ($pages) { $textItemNode = $doc->createElementNS($deployment->getNamespace(), 'TextItem'); foreach ($pages as $range) { $pageRunNode = $doc->createElementNS($deployment->getNamespace(), 'PageRun'); $node = $doc->createElementNS($deployment->getNamespace(), 'FirstPageNumber', htmlspecialchars($range[0])); $pageRunNode->appendChild($node); if (isset($range[1])) { $node = $doc->createElementNS($deployment->getNamespace(), 'LastPageNumber', htmlspecialchars($range[1])); $pageRunNode->appendChild($node); } $textItemNode->appendChild($pageRunNode); } $contentItemNode->appendChild($textItemNode); } // Extent (for article-as-manifestation only) if ($galley && !$galley->getRemoteURL()) { $galleyFile = $galley->getFile(); if ($galleyFile) $contentItemNode->appendChild($this->createExtentNode($doc, $galleyFile)); } // Article Title (mandatory) $titles = $this->getTranslationsByPrecedence($article->getTitle(null), $objectLocalePrecedence); assert(!empty($titles)); foreach ($titles as $locale => $title) { $contentItemNode->appendChild($this->createTitleNode($doc, $locale, $title, O4DOI_TITLE_TYPE_FULL)); } // Contributors $authors = $article->getAuthors(); assert(!empty($authors)); foreach ($authors as $author) { $contentItemNode->appendChild($this->createContributorNode($doc, $author, $objectLocalePrecedence)); } // Language $languageCode = AppLocale::get3LetterIsoFromLocale($objectLocalePrecedence[0]); assert(!empty($languageCode)); $languageNode = $doc->createElementNS($deployment->getNamespace(), 'Language'); $languageNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'LanguageRole', O4DOI_LANGUAGE_ROLE_LANGUAGE_OF_TEXT)); $languageNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'LanguageCode', $languageCode)); $contentItemNode->appendChild($languageNode); // Article keywords // SubjectClass will be left out here, because we don't know the scheme/classification name $submissionKeywordDao = DAORegistry::getDAO('SubmissionKeywordDAO'); $allKeywords = $submissionKeywordDao->getKeywords($article->getId(), $context->getSupportedSubmissionLocales()); $keywords = $this->getPrimaryTranslation($allKeywords, $objectLocalePrecedence); if (!empty($keywords)) { $keywordsString = implode(';', $keywords); $contentItemNode->appendChild($this->createSubjectNode($doc, O4DOI_SUBJECT_SCHEME_PUBLISHER, $keywordsString)); } // Object Description 'OtherText' $descriptions = $this->getTranslationsByPrecedence($article->getAbstract(null), $objectLocalePrecedence); foreach ($descriptions as $locale => $description) { $contentItemNode->appendChild($this->createOtherTextNode($doc, $locale, $description)); } // Article Publication Date $datePublished = $article->getDatePublished(); if (!empty($datePublished)) { $contentItemNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'PublicationDate', date('Ymd', strtotime($datePublished)))); } // Relations // Issue if ($plugin->getSetting($context->getId(), 'exportIssuesAs') == O4DOI_ISSUE_AS_WORK) { // related work: // - is part of issue-as-work $issueWorkOrProduct = 'Work'; } else { // related product: // - is part of issue-as-manifestation $issueWorkOrProduct = 'Product'; } $issueProprietaryId = $context->getId() . '-' . $issue->getId(); $relatedIssueIds = array(O4DOI_ID_TYPE_PROPRIETARY => $issueProprietaryId); $issueDoi = $issue->getStoredPubId('doi'); if (!empty($issueDoi)) $relatedIssueIds[O4DOI_ID_TYPE_DOI] = $issueDoi; $relatedIssueNode = $this->createRelatedNode($doc, $issueWorkOrProduct, O4DOI_RELATION_IS_PART_OF, $relatedIssueIds); // Galleys $galleyDao = DAORegistry::getDAO('ArticleGalleyDAO'); /* @var $galleyDao ArticleGalleyDAO */ $galleysByArticle = $galleyDao->getBySubmissionId($article->getId())->toArray(); if (!$galley) { // if exporting object is an article $contentItemNode->appendChild($relatedIssueNode); // related products: // - is manifested in articles-as-manifestation foreach($galleysByArticle as $relatedGalley) { $galleyProprietaryId = $context->getId() . '-' . $issue->getId() . '-' . $article->getId() . '-g' . $relatedGalley->getId(); $relatedGalleyIds = array(O4DOI_ID_TYPE_PROPRIETARY => $galleyProprietaryId); $galleyDoi = $relatedGalley->getStoredPubId('doi'); if (!empty($galleyDoi)) $relatedGalleyIds[O4DOI_ID_TYPE_DOI] = $galleyDoi; $contentItemNode->appendChild($this->createRelatedNode($doc, 'Product', O4DOI_RELATION_IS_MANIFESTED_IN, $relatedGalleyIds)); unset($relatedGalley, $relatedGalleyIds, $galleyProprietaryId, $galleyDoi); } } else { // Include issue-as-work before article-as-work. if ($issueWorkOrProduct == 'Work') $contentItemNode->appendChild($relatedIssueNode); // related work: // - is a manifestation of article-as-work $articleProprietaryId = $context->getId() . '-' . $article->getIssueId() . '-' . $article->getId(); $relatedArticleIds = array(O4DOI_ID_TYPE_PROPRIETARY => $articleProprietaryId); $doi = $article->getStoredPubId('doi'); if (!empty($doi)) $relatedArticleIds[O4DOI_ID_TYPE_DOI] = $doi; $contentItemNode->appendChild($this->createRelatedNode($doc, 'Work', O4DOI_RELATION_IS_A_MANIFESTATION_OF, $relatedArticleIds)); unset($relatedArticleIds); // Include issue-as-manifestation after article-as-work. if ($issueWorkOrProduct == 'Product')$contentItemNode->appendChild($relatedIssueNode); // related products: foreach($galleysByArticle as $relatedGalley) { $galleyProprietaryId = $context->getId() . '-' . $issue->getId() . '-' . $article->getId() . '-g' . $relatedGalley->getId(); $relatedGalleyIds = array(O4DOI_ID_TYPE_PROPRIETARY => $galleyProprietaryId); $galleyDoi = $relatedGalley->getStoredPubId('doi'); if (!empty($galleyDoi)) $relatedGalleyIds[O4DOI_ID_TYPE_DOI] = $galleyDoi; // - is a different form of all other articles-as-manifestation // with the same article id and language but different form if ($galley->getLocale() == $relatedGalley->getLocale() && $galley->getLabel() != $relatedGalley->getLabel()) { $contentItemNode->appendChild($this->createRelatedNode($doc, 'Product', O4DOI_RELATION_IS_A_DIFFERENT_FORM_OF, $relatedGalleyIds)); } // - is a different language version of all other articles-as-manifestation // with the same article id and form/label but different language if ($galley->getLabel() == $relatedGalley->getLabel() && $galley->getLocale() != $relatedGalley->getLocale()) { $contentItemNode->appendChild($this->createRelatedNode($doc, 'Product', O4DOI_RELATION_IS_A_LANGUAGE_VERSION_OF, $relatedGalleyIds)); } unset($relatedGalley, $relatedGalleyIds, $galleyProprietaryId, $galleyDoi); } } return $contentItemNode; } /** * Create a contributor node. * @param $doc DOMDocument * @param $author Author * @param $objectLocalePrecedence array * @return DOMElement */ function createContributorNode($doc, $author, $objectLocalePrecedence) { $deployment = $this->getDeployment(); $contributorNode = $doc->createElementNS($deployment->getNamespace(), 'Contributor'); // Sequence number $seq = $author->getSequence(); assert(!empty($seq)); $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SequenceNumber', $seq)); // Contributor role (mandatory) $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'ContributorRole', O4DOI_CONTRIBUTOR_ROLE_ACTUAL_AUTHOR)); // Person name (mandatory) $personName = $author->getFullName(); assert(!empty($personName)); $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'PersonName', htmlspecialchars($personName, ENT_COMPAT, 'UTF-8'))); // Inverted person name $invertedPersonName = $author->getFullName(true); assert(!empty($invertedPersonName)); $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'PersonNameInverted', htmlspecialchars($invertedPersonName, ENT_COMPAT, 'UTF-8'))); // Affiliation $affiliation = $this->getPrimaryTranslation($author->getAffiliation(null), $objectLocalePrecedence); if (!empty($affiliation)) { $affiliationNode = $doc->createElementNS($deployment->getNamespace(), 'ProfessionalAffiliation'); $affiliationNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'Affiliation', htmlspecialchars($affiliation, ENT_COMPAT, 'UTF-8'))); $contributorNode->appendChild($affiliationNode); } // Biographical note $bioNote = $this->getPrimaryTranslation($author->getBiography(null), $objectLocalePrecedence); if (!empty($bioNote)) { $contributorNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'BiographicalNote', htmlspecialchars(PKPString::html2text($bioNote), ENT_COMPAT, 'UTF-8'))); } return $contributorNode; } /** * Create a subject node. * @param $doc DOMDocument * @param $subjectSchemeId string One of the O4DOI_SUBJECT_SCHEME_* constants. * @param $subjectHeadingOrCode string The subject. * @param $subjectSchemeName string|null A subject scheme name. * @return DOMElement */ function createSubjectNode($doc, $subjectSchemeId, $subjectHeadingOrCode, $subjectSchemeName = null) { $deployment = $this->getDeployment(); $subjectNode = $doc->createElementNS($deployment->getNamespace(), 'Subject'); // Subject Scheme Identifier $subjectNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SubjectSchemeIdentifier', $subjectSchemeId)); if (is_null($subjectSchemeName)) { // Subject Heading $subjectNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SubjectHeadingText', htmlspecialchars($subjectHeadingOrCode, ENT_COMPAT, 'UTF-8'))); } else { // Subject Scheme Name $subjectNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SubjectSchemeName', htmlspecialchars($subjectSchemeName, ENT_COMPAT, 'UTF-8'))); // Subject Code $subjectNode->appendChild($node = $doc->createElementNS($deployment->getNamespace(), 'SubjectCode', htmlspecialchars($subjectHeadingOrCode, ENT_COMPAT, 'UTF-8'))); } return $subjectNode; } } ?>