You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
604 lines
19 KiB
604 lines
19 KiB
<?php |
|
|
|
/** |
|
* @file |
|
* The EBSCO Response object. |
|
* |
|
* PHP version 5 |
|
* |
|
* Copyright [2017] [EBSCO Information Services] |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
require_once 'sanitizer.class.php'; |
|
|
|
/** |
|
* EBSCOResponse class. |
|
*/ |
|
class EBSCOResponse { |
|
|
|
/** |
|
* A SimpleXml object. |
|
* |
|
* @global object |
|
*/ |
|
private $response; |
|
|
|
/** |
|
* Constructor. |
|
* |
|
* Sets up the EBSCO Response. |
|
* |
|
* @param none |
|
* |
|
* @access public |
|
*/ |
|
public function __construct($response) { |
|
$this->response = $response; |
|
} |
|
|
|
/** |
|
* Returns the XML as an associative array of data. |
|
* |
|
* @param none |
|
* |
|
* @return array An associative array of data |
|
* |
|
* @access public |
|
*/ |
|
public function result() { |
|
if (!empty($this->response->AuthToken)) { |
|
return $this->buildAuthenticationToken(); |
|
} |
|
elseif (!empty($this->response->SessionToken)) { |
|
return (string) $this->response->SessionToken; |
|
} |
|
elseif (!empty($this->response->SearchResult)) { |
|
return $this->buildSearch(); |
|
} |
|
elseif (!empty($this->response->Record)) { |
|
return $this->buildRetrieve(); |
|
} |
|
elseif (!empty($this->response->AvailableSearchCriteria)) { |
|
return $this->buildInfo(); |
|
} |
|
// Should not happen, it may be an exception. |
|
else { |
|
return $this->response; |
|
} |
|
} |
|
|
|
/** |
|
* Parse the SimpleXml object when an AuthenticationToken API call was executed. |
|
* |
|
* @param none |
|
* |
|
* @return array An associative array of data |
|
* |
|
* @access private |
|
*/ |
|
private function buildAuthenticationToken() { |
|
$token = (string) $this->response->AuthToken; |
|
$timeout = (integer) $this->response->AuthTimeout; |
|
|
|
$result = array( |
|
'authenticationToken' => $token, |
|
'authenticationTimeout' => $timeout, |
|
); |
|
|
|
return $result; |
|
} |
|
|
|
/** |
|
* Parse a SimpleXml object and |
|
* return it as an associative array. |
|
* |
|
* @param none |
|
* |
|
* @return array An associative array of data |
|
* |
|
* @access private |
|
*/ |
|
private function buildSearch() { |
|
$hits = (integer) $this->response->SearchResult->Statistics->TotalHits; |
|
$searchTime = (integer) $this->response->SearchResult->Statistics->TotalSearchTime / 1000; |
|
$records = array(); |
|
$facets = array(); |
|
if ($hits > 0) { |
|
$records = $this->buildRecords(); |
|
$facets = $this->buildFacets(); |
|
} |
|
|
|
// Research Starters & emp. |
|
$relatedC = NULL; |
|
if ($this->response->SearchResult->RelatedContent) { |
|
$result = json_decode(json_encode($this->response->SearchResult->RelatedContent), TRUE);; |
|
$relatedC = $result; |
|
} |
|
|
|
// Did you mean / auto suggest. |
|
$autoSuggestTerms = NULL; |
|
if ($this->response->SearchResult->AutoSuggestedTerms) { |
|
$result = json_decode(json_encode($this->response->SearchResult->AutoSuggestedTerms), TRUE);; |
|
$autoSuggestTerms = $result; |
|
} |
|
|
|
$results = array( |
|
'recordCount' => $hits, |
|
'searchTime' => $searchTime, |
|
'numFound' => $hits, |
|
'start' => 0, |
|
'documents' => $records, |
|
'relatedContent' => $relatedC, |
|
'autoSuggestTerms' => $autoSuggestTerms, |
|
'facets' => $facets, |
|
); |
|
|
|
return $results; |
|
} |
|
|
|
/** |
|
* Parse a SimpleXml object and |
|
* return it as an associative array. |
|
* |
|
* @param none |
|
* |
|
* @return array An associative array of data |
|
* |
|
* @access private |
|
*/ |
|
private function buildRecords() { |
|
$results = array(); |
|
|
|
$records = $this->response->SearchResult->Data->Records->Record; |
|
foreach ($records as $record) { |
|
$result = array(); |
|
// var_dump($record); |
|
$result['ResultId'] = $record->ResultId ? (integer) $record->ResultId : ''; |
|
$result['DbId'] = $record->Header->DbId ? (string) $record->Header->DbId : ''; |
|
$result['DbLabel'] = $record->Header->DbLabel ? (string) $record->Header->DbLabel : ''; |
|
$result['An'] = $record->Header->An ? (string) $record->Header->An : ''; |
|
$result['PubType'] = $record->Header->PubType ? (string) $record->Header->PubType : ''; |
|
$result['AccessLevel'] = $record->Header->AccessLevel ? (string) $record->Header->AccessLevel : ''; |
|
$result['id'] = $result['An'] . '|' . $result['DbId']; |
|
$result['PLink'] = $record->PLink ? (string) $record->PLink : ''; |
|
if (!empty($record->ImageInfo->CoverArt)) { |
|
foreach ($record->ImageInfo->CoverArt as $image) { |
|
$size = (string) $image->Size; |
|
$target = (string) $image->Target; |
|
$result['ImageInfo'][$size] = $target; |
|
} |
|
} |
|
else { |
|
$result['ImageInfo'] = ''; |
|
} |
|
|
|
if ($record->FullText) { |
|
$availability = (integer) $record->FullText->Text->Availability == 1; |
|
$links = array(); |
|
// RF 2012-12-18. |
|
if (isset($record->FullText->Links)) { |
|
foreach ($record->FullText->Links->Link as $link) { |
|
$type = (string) $link->Type; |
|
$url = (string) $link->Url; |
|
// If we have an empty url when type is pdflink then just return something so |
|
// that the UI check for empty string will pass. |
|
$url = empty($url) && $type == 'pdflink' ? 'http://content.ebscohost.com' : $url; |
|
$links[$type] = $url; |
|
} |
|
} |
|
$result['FullText'] = array( |
|
'Availability' => $availability, |
|
'Links' => $links, |
|
); |
|
} |
|
|
|
if ($record->CustomLinks) { |
|
$result['CustomLinks'] = array(); |
|
foreach ($record->CustomLinks->CustomLink as $customLink) { |
|
$category = $customLink->Category ? (string) $customLink->Category : ''; |
|
$icon = $customLink->Icon ? (string) $customLink->Icon : ''; |
|
$mouseOverText = $customLink->MouseOverText ? (string) $customLink->MouseOverText : ''; |
|
$name = $customLink->Name ? (string) $customLink->Name : ''; |
|
$text = $customLink->Text ? (string) $customLink->Text : ''; |
|
$url = $customLink->Url ? (string) $customLink->Url : ''; |
|
$result['CustomLinks'][] = array( |
|
'Category' => $category, |
|
'Icon' => $icon, |
|
'MouseOverText' => $mouseOverText, |
|
'Name' => $name, |
|
'Text' => $text, |
|
'Url' => $url, |
|
); |
|
} |
|
} |
|
|
|
if ($record->Items) { |
|
$result['Items'] = array(); |
|
foreach ($record->Items->Item as $item) { |
|
$name = $item->Name ? (string) $item->Name : ''; |
|
$label = $item->Label ? (string) $item->Label : ''; |
|
$group = $item->Group ? (string) $item->Group : ''; |
|
$data = $item->Data ? (string) $item->Data : ''; |
|
$result['Items'][$name] = array( |
|
'Name' => $name, |
|
'Label' => $label, |
|
'Group' => $group, |
|
'Data' => $this->toHTML($data, $group), |
|
); |
|
} |
|
} |
|
|
|
$results[] = $result; |
|
} |
|
|
|
return $results; |
|
} |
|
|
|
/** |
|
* Parse a SimpleXml object and |
|
* return it as an associative array. |
|
* |
|
* @param none |
|
* |
|
* @return array An associative array of data |
|
* |
|
* @access private |
|
*/ |
|
private function buildFacets() { |
|
$results = array(); |
|
|
|
$facets = $this->response->SearchResult->AvailableFacets->AvailableFacet; |
|
if ($facets) { |
|
foreach ($facets as $facet) { |
|
$values = array(); |
|
foreach ($facet->AvailableFacetValues->AvailableFacetValue as $value) { |
|
$this_value = (string) $value->Value; |
|
$this_value = str_replace(array('\(', '\)'), array('(', ')'), $this_value); |
|
$this_action = (string) $value->AddAction; |
|
$this_action = str_replace(array('\(', '\)'), array('(', ')'), $this_action); |
|
$values[] = array( |
|
'Value' => $this_value, |
|
'Action' => $this_action, |
|
'Count' => (string) $value->Count, |
|
); |
|
} |
|
$id = (string) $facet->Id; |
|
$label = (string) $facet->Label; |
|
if (!empty($label)) { |
|
$results[] = array( |
|
'Id' => $id, |
|
'Label' => $label, |
|
'Values' => $values, |
|
'isApplied' => FALSE, |
|
); |
|
} |
|
} |
|
} |
|
|
|
return $results; |
|
} |
|
|
|
/** |
|
* Parse a SimpleXml object and |
|
* return it as an associative array. |
|
* |
|
* @param none |
|
* |
|
* @return array An associative array of data |
|
* |
|
* @access private |
|
*/ |
|
private function buildInfo() { |
|
// Sort options. |
|
$elements = $this->response->AvailableSearchCriteria->AvailableSorts->AvailableSort; |
|
$sort = array(); |
|
foreach ($elements as $element) { |
|
$sort[] = array( |
|
'Id' => (string) $element->Id, |
|
'Label' => (string) $element->Label, |
|
'Action' => (string) $element->AddAction, |
|
); |
|
} |
|
|
|
// Search fields. |
|
$elements = $this->response->AvailableSearchCriteria->AvailableSearchFields->AvailableSearchField; |
|
$tags = array(); |
|
foreach ($elements as $element) { |
|
$tags[] = array( |
|
'Label' => (string) $element->Label, |
|
'Code' => (string) $element->FieldCode, |
|
); |
|
} |
|
|
|
// Expanders. |
|
$elements = $this->response->AvailableSearchCriteria->AvailableExpanders->AvailableExpander; |
|
$expanders = array(); |
|
foreach ($elements as $element) { |
|
$expanders[] = array( |
|
'Id' => (string) $element->Id, |
|
'Label' => (string) $element->Label, |
|
'Action' => (string) $element->AddAction, |
|
// Added because of the checkboxes. |
|
'selected' => FALSE, |
|
); |
|
} |
|
|
|
// RelatedContent. |
|
$elements = $this->response->AvailableSearchCriteria->AvailableRelatedContent->AvailableRelatedContent; |
|
$relatedContent = array(); |
|
foreach ($elements as $element) { |
|
$relatedContent[] = array( |
|
'Type' => (string) $element->Type, |
|
'Label' => (string) $element->Label, |
|
'Action' => (string) $element->AddAction, |
|
'DefaultOn' => (string) $element->DefaultOn, |
|
); |
|
} |
|
|
|
// Did you mean. |
|
$elements = $this->response->AvailableSearchCriteria->AvailableDidYouMeanOptions->AvailableDidYouMeanOption; |
|
$didYouMean = array(); |
|
foreach ($elements as $element) { |
|
$didYouMean[] = array( |
|
'Id' => (string) $element->Id, |
|
'Label' => (string) $element->Label, |
|
'DefaultOn' => (string) $element->DefaultOn, |
|
); |
|
} |
|
|
|
// Limiters. |
|
$elements = $this->response->AvailableSearchCriteria->AvailableLimiters->AvailableLimiter; |
|
$limiters = array(); |
|
$values = array(); |
|
foreach ($elements as $element) { |
|
if ($element->LimiterValues) { |
|
$items = $element->LimiterValues->LimiterValue; |
|
foreach ($items as $item) { |
|
$values[] = array( |
|
'Value' => (string) $item->Value, |
|
'Action' => (string) $item->AddAction, |
|
// Added because of the checkboxes. |
|
'selected' => FALSE, |
|
); |
|
} |
|
} |
|
$limiters[] = array( |
|
'Id' => (string) $element->Id, |
|
'Label' => (string) $element->Label, |
|
'Action' => (string) $element->AddAction, |
|
'Type' => (string) $element->Type, |
|
'Values' => $values, |
|
'selected' => FALSE, |
|
); |
|
} |
|
|
|
$result = array( |
|
'sort' => $sort, |
|
'tags' => $tags, |
|
'expanders' => $expanders, |
|
'limiters' => $limiters, |
|
'relatedContent' => $relatedContent, |
|
'didYouMean' => $didYouMean, |
|
); |
|
|
|
return $result; |
|
} |
|
|
|
/** |
|
* Parse a SimpleXml object and |
|
* return it as an associative array. |
|
* |
|
* @param none |
|
* |
|
* @return array An associative array of data |
|
* |
|
* @access private |
|
*/ |
|
private function buildRetrieve() { |
|
$record = $this->response->Record; |
|
if ($record) { |
|
// There is only one record. |
|
$record = $record[0]; |
|
} |
|
|
|
$result = array(); |
|
$result['DbId'] = $record->Header->DbId ? (string) $record->Header->DbId : ''; |
|
$result['DbLabel'] = $record->Header->DbLabel ? (string) $record->Header->DbLabel : ''; |
|
$result['An'] = $record->Header->An ? (string) $record->Header->An : ''; |
|
$result['id'] = $result['An'] . '|' . $result['DbId']; |
|
$result['PubType'] = $record->Header->PubType ? (string) $record->Header->PubType : ''; |
|
$result['AccessLevel'] = $record->Header->AccessLevel ? (string) $record->Header->AccessLevel : ''; |
|
$result['PLink'] = $record->PLink ? (string) $record->PLink : ''; |
|
if (!empty($record->ImageInfo->CoverArt)) { |
|
foreach ($record->ImageInfo->CoverArt as $image) { |
|
$size = (string) $image->Size; |
|
$target = (string) $image->Target; |
|
$result['ImageInfo'][$size] = $target; |
|
} |
|
} |
|
else { |
|
$result['ImageInfo'] = ''; |
|
} |
|
|
|
if ($record->FullText) { |
|
$availability = (integer) ($record->FullText->Text->Availability) == 1; |
|
$links = array(); |
|
foreach ($record->FullText->Links->Link as $link) { |
|
$type = (string) $link->Type; |
|
$url = (string) $link->Url; |
|
// If we have an empty url when type is pdflink then just return something so |
|
// that the UI check for empty string will pass. |
|
$url = empty($url) && $type == 'pdflink' ? 'http://content.ebscohost.com' : $url; |
|
$links[$type] = $url; |
|
} |
|
$value = $this->toHTML($record->FullText->Text->Value); |
|
$result['FullText'] = array( |
|
'Availability' => $availability, |
|
'Links' => $links, |
|
'Value' => $value, |
|
); |
|
} |
|
|
|
if ($record->CustomLinks) { |
|
$result['CustomLinks'] = array(); |
|
foreach ($record->CustomLinks->CustomLink as $customLink) { |
|
$category = $customLink->Category ? (string) $customLink->Category : ''; |
|
$icon = $customLink->Icon ? (string) $customLink->Icon : ''; |
|
$mouseOverText = $customLink->MouseOverText ? (string) $customLink->MouseOverText : ''; |
|
$name = $customLink->Name ? (string) $customLink->Name : ''; |
|
$text = $customLink->Text ? (string) $customLink->Text : ''; |
|
$url = $customLink->Url ? (string) $customLink->Url : ''; |
|
$result['CustomLinks'][] = array( |
|
'Category' => $category, |
|
'Icon' => $icon, |
|
'MouseOverText' => $mouseOverText, |
|
'Name' => $name, |
|
'Text' => $text, |
|
'Url' => $url, |
|
); |
|
} |
|
} |
|
|
|
if ($record->Items) { |
|
$result['Items'] = array(); |
|
foreach ($record->Items->Item as $item) { |
|
$name = $item->Name ? (string) $item->Name : ''; |
|
$label = $item->Label ? (string) $item->Label : ''; |
|
$group = $item->Group ? (string) $item->Group : ''; |
|
$data = $item->Data ? (string) $item->Data : ''; |
|
$result['Items'][$name] = array( |
|
'Name' => $name, |
|
'Label' => $label, |
|
'Group' => $group, |
|
'Data' => $this->toHTML($data, $group), |
|
); |
|
} |
|
} |
|
|
|
return $result; |
|
} |
|
|
|
/** |
|
* Parse a SimpleXml element and |
|
* return it's inner XML as an HTML string. |
|
* |
|
* @param SimpleXml $element |
|
* A SimpleXml DOM. |
|
* |
|
* @return string The HTML string |
|
* |
|
* @access protected |
|
*/ |
|
private function toHTML($data, $group = NULL) { |
|
// Any group can be added here, but we only use Au (Author) |
|
// Other groups, not present here, won't be transformed to HTML links. |
|
$allowed_searchlink_groups = array('au'); |
|
|
|
// Map xml tags to the HTML tags |
|
// This is just a small list, the total number of xml tags is far more greater. |
|
$xml_to_html_tags = array( |
|
'<jsection' => '<section', |
|
'</jsection' => '</section', |
|
'<highlight' => '<span class="highlight"', |
|
// Temporary bug fix. |
|
'<highligh' => '<span class="highlight"', |
|
// Temporary bug fix. |
|
'</highlight>' => '</span>', |
|
'</highligh' => '</span>', |
|
'<text' => '<div', |
|
'</text' => '</div', |
|
'<title' => '<h2', |
|
'</title' => '</h2', |
|
'<anid' => '<p', |
|
'</anid' => '</p', |
|
'<aug' => '<p class="aug"', |
|
'</aug' => '</p', |
|
'<hd' => '<h3', |
|
'</hd' => '</h3', |
|
'<linebr' => '<br', |
|
'</linebr' => '', |
|
'<olist' => '<ol', |
|
'</olist' => '</ol', |
|
'<reflink' => '<a', |
|
'</reflink' => '</a', |
|
'<blist' => '<p class="blist"', |
|
'</blist' => '</p', |
|
'<bibl' => '<a', |
|
'</bibl' => '</a', |
|
'<bibtext' => '<span', |
|
'</bibtext' => '</span', |
|
'<ref' => '<div class="ref"', |
|
'</ref' => '</div', |
|
'<ulink' => '<a', |
|
'</ulink' => '</a', |
|
'<superscript' => '<sup', |
|
'</superscript' => '</sup', |
|
'<relatesTo' => '<sup', |
|
'</relatesTo' => '</sup', |
|
); |
|
|
|
// Map xml types to Search types used by the UI. |
|
$xml_to_search_types = array( |
|
'au' => 'Author', |
|
'su' => 'Subject', |
|
); |
|
|
|
// The XML data is XML escaped, let's unescape html entities (e.g. < => <) |
|
$data = html_entity_decode($data); |
|
|
|
// Start parsing the xml data. |
|
if (!empty($data)) { |
|
// Replace the XML tags with HTML tags. |
|
$search = array_keys($xml_to_html_tags); |
|
$replace = array_values($xml_to_html_tags); |
|
$data = str_replace($search, $replace, $data); |
|
|
|
// Temporary : fix unclosed tags. |
|
$data = preg_replace('/<\/highlight/', '</span>', $data); |
|
$data = preg_replace('/<\/span>>/', '</span>', $data); |
|
$data = preg_replace('/<\/searchLink/', '</searchLink>', $data); |
|
$data = preg_replace('/<\/searchLink>>/', '</searchLink>', $data); |
|
|
|
// Parse searchLinks. |
|
if (!empty($group)) { |
|
$group = strtolower($group); |
|
if (in_array($group, $allowed_searchlink_groups)) { |
|
$type = $xml_to_search_types[$group]; |
|
$path = url('ebsco/results', array('query' => array('type' => $type))); |
|
$link_xml = '/<searchLink fieldCode="([^\"]*)" term="%22([^\"]*)%22">/'; |
|
$link_html = "<a href=\"{$path}&lookfor=$2\">"; |
|
$data = preg_replace($link_xml, $link_html, $data); |
|
$data = str_replace('</searchLink>', '</a>', $data); |
|
} |
|
} |
|
|
|
// Replace the rest of searchLinks with simple spans. |
|
$link_xml = '/<searchLink fieldCode="([^\"]*)" term="%22([^\"]*)%22">/'; |
|
$link_html = '<span>'; |
|
$data = preg_replace($link_xml, $link_html, $data); |
|
$data = str_replace('</searchLink>', '</span>', $data); |
|
|
|
// Parse bibliography (anchors and links) |
|
$data = preg_replace('/<a idref="([^\"]*)"/', '<a href="#$1"', $data); |
|
$data = preg_replace('/<a id="([^\"]*)" idref="([^\"]*)" type="([^\"]*)"/', '<a id="$1" href="#$2"', $data); |
|
} |
|
|
|
$sanitizer = new HTML_Sanitizer(); |
|
$data = $sanitizer->sanitize($data); |
|
|
|
return $data; |
|
} |
|
|
|
}
|
|
|