Commit e63753db authored by mtwesley's avatar mtwesley

Merge branch 'kyushu' of git.drupal.org:project/xc into kyushu

parents 03368569 a0d714ed
......@@ -680,7 +680,7 @@ function ezproxy_url_rewrite_url_outbound_alter(&$path, &$options, $original_pat
// Finally, if you made it this far, do the rewriting
// Break new absolute URL into parts and form a new absolute URL, including
// the new prefix, infix, and suffix
$_absolute = $prefix.(empty($url['scheme']) ? '' : $url['scheme'].'://').$url['host'].$infix.(empty($url['port']) ? '' : ':'.$url['port']).$url['path'].(empty($url['query']) ? '' : '?'.$url['query']).(empty($url['fragment']) ? '' : '#'.$url['fragment']).$suffix;
$_absolute = $prefix . (empty($url['scheme']) ? '' : $url['scheme'] . '://') . $url['host'] . $infix . (empty($url['port']) ? '' : ':' . $url['port']) . $url['path'] . (empty($url['query']) ? '' : '?' . $url['query']) . (empty($url['fragment']) ? '' : '#' . $url['fragment']) . $suffix;
$_url = parse_url($_absolute);
// Finally, turn the new rewritten URL back into the format necessary
......@@ -701,7 +701,7 @@ function ezproxy_url_rewrite_url_outbound_alter(&$path, &$options, $original_pat
. (empty($_url['port']) ? '' : ':' . $_url['port']);
$options['query'] = $_url['query'];
$options['fragment'] = (empty($_url['fragment']) ? ''
: '#' .$_url['fragment']);
: '#' . $_url['fragment']);
$options['absolute'] = TRUE;
}
}
......
......@@ -35,8 +35,7 @@ The NCIP module provides an API for creating and managing NCIP applications,
connections, and messages:
- An application initiates or responds to connections to communicate with
other applications
- A connection is either a single TCP connection or a collection of HTTP
requests between two applications
- A connection is a collection of HTTP requests between two applications
- A message is an XML document encoded according to UTF-8 specifications
and streamed as-is over a connection
......@@ -47,67 +46,45 @@ three classes are:
- NCIPConnection
- NCIPMessage
NCIPApplication objects manage a collection of connections and stores specific
properties of the application, such as its “from” agency and system ID and
authentication, application profile type, and whether it will initiate or
respond to messages sent over a connection.
NCIPApplication objects manage a collection of connections and stores
specific properties of the application, such as the supported NCIP version,
“from” agency and system ID, and other message header options for authentication
and application profile type.
NCIPConnection objects belong to an NCIPApplication object and manage and
facilitate the transport of a collection of messages and stores specific
properties of the application on the opposite end, such as its “to” agency
and system ID and authentication and whether it will initiate or respond to
messages sent over the connection.
NCIPConnection objects belong to an NCIPApplication object and are of a
particular type specifying whether it is initiating or responding. These
objects facilitate the transport of messages to and from applications, and
store specific properties of the connected application, such as its “to” agency
and system ID and other message header options for authentication.
NCIPMessage objects should belong to an NCIPConnection object, but in rare
situations may not. A message gone rouge can exist outside the scope of an
NCIPConnection object, and therefore, completely outside the scope of an
NCIPApplication object.
situations, they may not. These objects manage the content of an XML document,
allowing it to be edited in a more intuitive manner and transformed to and from
an XML string, SimpleXMLElement object, DOMDocument object, or NCIPMessage
object.
NCIPMessage objects manage the content of the XML document, allowing it to be
edited in a more intuitive manner and transformed to and from an XML string,
XML array structure, DOMDocument object, or another NCIPMessage object.
Implementation Profiles
-----------------------
On its own, the NCIP module does not implement any NCIP services (or verbs); it
only facilitates the processes necessary to implement those services. This work
must be done by other modules that take advantage of the NCIP module’s features
and API. An example of such module is the NCIP Provider module, included with
the Drupal Toolkit.
Implementation profiles would allow the NCIP module to automatically support
multiple NCIP services, data elements, and schemes as well as multiple versions
of the NCIP protocol.
These configuration scripts are made up of namespaced functions, similar to
Drupal hooks. These functions should be within [profile_name].inc files that
are manually placed in the /ncip/profiles folder.
Two implementation profiles come with the NCIP module by default:
- NCIP Z39-83
- XC NCIP Implementation
Each function within the profile returns a complex array structure either
specifying information about the profile or returning information about the
profile’s services, data elements, or schemes.
Currently, the two profiles serve as an example for future profile structures;
however, they are not used at all in the NCIP module. This feature may perhaps
show up in future versions of the NCIP module.
Implementation
--------------
On its own, the NCIP module does not implement any NCIP services (or verbs);
it only builds the foundation necessary to communicate over this protocol in
Drupal. Other modules must then take advantage of the NCIP module's features
and API to construct or parse messages sent or received to and from NCIP
applications. An example of such module is the NCIP Provider module, included
with the Drupal Toolkit.
Current Features
----------------
The module currently acts as an initiating application, with the capabilities
to send and receive messages to and from applications over an HTTP connection.
The module currently can create applications only with initiating connections
that expect a response after messages have been sent via HTTP. It supports all
current versions of the NCIP protocol.
Future Features
---------------
In the future, the NCIP module would likely be able to act as both an initiating
and responding application, support HTTP 1.1 and TCP connections, and make more
use of implementation profiles.
In the future, the NCIP module may support both an initiating and responding
connections, connect via TCP, or make use of implementation profiles.
Developer Information
......
......@@ -6,8 +6,6 @@
* @copyright (c) 2010-2011 eXtensible Catalog Organization
*/
require_once('NCIPHTTPClient.php');
class NCIPConnection {
const NCIP_SELF_SERVICE_CONNECTION = 0x0000;
const NCIP_INITIATING_CONNECTION = 0x0001;
......@@ -294,58 +292,7 @@ class NCIPConnection {
}
/** Supported protocol implementations **/
private function &_ncip_http_old_connect($connect = TRUE) {
static $http = array();
if (is_null($http[$this->connection_id]) && $connect) {
$http[$this->connection_id] = new NCIPHTTPClient($this->host, $this->port);
$http[$this->connection_id]->cookie_host = $this->host;
$http[$this->connection_id]->set_debug(variable_get('ncip_debugging', 0));
$http[$this->connection_id]->use_gzip = FALSE;
$http[$this->connection_id]->timeout = $this->timeout;
$http[$this->connection_id]->content_type = 'application/xml; charset="utf-8"';
}
if ($this->use_cookies) {
$http[$this->connection_id]->set_cookies($this->cookies);
}
return $http[$this->connection_id];
}
private function _ncip_http_old_disconnect() {
$http = &$this->_ncip_http_old_connect(FALSE);
if ($http) {
unset($http);
}
}
private function _ncip_http_old_send(NCIPMessage $message) {
// Retrieve static HTTPClient object from _ncip_http_old_connect()
$http = &$this->_ncip_http_old_connect();
$http->set_cookies($this->cookies);
// POST message to server and receive XML response or return FALSE
if (!$http->post($this->path, $message->to_xml())) {
$this->errormsg = $http->errormsg;
return FALSE;
}
// Parse into an NCIPMessage object and push into message stack
$this->raw_response = $http->get_content();
$response = NCIPMessage::from_xml($this->raw_response);
array_push($this->messages, $response);
if ($this->use_cookies) {
$this->cookies = $http->get_cookies();
}
return TRUE;
}
private function _ncip_http_old_receive() {
return array_shift($this->messages);
}
private function &_ncip_http_connect($connect = TRUE) {
private function &_ncip_http_connect($connect = TRUE) {
static $curl = array();
if (is_null($curl[$this->connection_id]) && $connect) {
......@@ -428,6 +375,12 @@ class NCIPConnection {
$response = NCIPMessage::from_xml($this->raw_response);
array_push($this->messages, $response);
// Debugging
if (variable_get('ncip_debugging', 0)) {
watchdog('ncip request', htmlspecialchars($message->to_xml()));
watchdog('ncip response', htmlspecialchars($response->to_xml()));
}
// Send was successful, then return TRUE
return TRUE;
}
......
This diff is collapsed.
This diff is collapsed.
name = "NCIP"
description = "Client and library for NISO Circulation Interchange Protocol (NCIP/Z39.83)"
core = "6.x"
package = "eXtensible Catalog (XC) System"
\ No newline at end of file
package = "eXtensible Catalog (XC) System"
dependencies[] = xc_util
\ No newline at end of file
......@@ -135,8 +135,8 @@ function ncip_resource_load($filename) {
$version = number_format($version, 1, '_', '_');
$type = strtolower($type);
if (!in_array($type,array('xml','dtd','xsd','scm'))) {
return false;
if (!in_array($type, array('xml', 'dtd', 'xsd', 'scm'))) {
return FALSE;
}
switch ($type) {
......@@ -159,7 +159,7 @@ function ncip_resource_load($filename) {
* Resource file name
*/
function ncip_schema_load($filename) {
if (preg_match('/^ncip_v([\d_]+)\.(dtd|xsd)$/',$filename)) {
if (preg_match('/^ncip_v([\d_]+)\.(dtd|xsd)$/', $filename)) {
$resource = file_get_contents(drupal_get_path('module', 'ncip') . "/resources/$filename");
}
}
......@@ -171,7 +171,7 @@ function ncip_schema_load($filename) {
* Resource filename
*/
function ncip_scheme_load($filename) {
if (preg_match('/^\w+\.scm$/',$filename)) {
if (preg_match('/^\w+\.scm$/', $filename)) {
$resource = file_get_contents(drupal_get_path('module', 'ncip') . "/resources/$filename");
}
}
......@@ -270,8 +270,8 @@ function ncip_menu() {
}
$items['admin/xc/ncip'] = array(
'title' => 'ILS (NCIP) Servers',
'description' => 'Connect the Drupal Toolkit to your ILS for circ status, circ request forms and authentication. Prerequisite: The NCIP Toolkit is installed and configured alongside your ILS.',
'title' => 'NCIP Servers',
'description' => 'Administer NCIP connected servers',
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('administer ncip'),
'file' => 'system.admin.inc',
......@@ -281,7 +281,7 @@ function ncip_menu() {
);
$items['admin/xc/ncip/settings'] = array(
'title' => 'Debugging and other settings',
'title' => 'Advanced NCIP Settings',
'description' => 'Turn debugging on and off and manage connection timeouts',
'page callback' => 'drupal_get_form',
'page arguments' => array('ncip_settings'),
......@@ -360,7 +360,7 @@ function ncip_settings(&$form_state) {
// TODO: move timeouts to NCIP providers
$form['ncip_debugging'] = array(
'#type' => 'radios',
'#title' => t('NCIP Debugging'),
'#title' => t('NCIP Request and Response Debugging'),
'#options' => array(1 => t('On'), 0 => t('Off')),
'#default_value' => variable_get('ncip_debugging', 0),
);
......@@ -786,12 +786,12 @@ function ncip_application_view($application) {
}
// $rows[] = array(t('Profile'), $profile['name']);
$rows[] = array(t('NCIP version'), $application->get_version());
$rows[] = array(t('From Agency Id'), theme('ncip_scheme_row',$application->get_from_agency_id()));
$rows[] = array(t('From Agency Id'), theme('ncip_scheme_row', $application->get_from_agency_id()));
$rows[] = array(t('From Agency Authentication'), $application->get_from_agency_authentication());
$rows[] = array(t('From System Id'), theme('ncip_scheme_row',$application->get_from_system_id()));
$rows[] = array(t('From System Id'), theme('ncip_scheme_row', $application->get_from_system_id()));
$rows[] = array(t('From System Authentication'), $application->get_from_system_authentication());
$rows[] = array(t('On Behalf of Agency'), theme('ncip_scheme_row',$application->get_on_behalf_of_agency()));
$rows[] = array(t('Application Profile Type'), theme('ncip_scheme_row',$application->get_application_profile_type()));
$rows[] = array(t('On Behalf of Agency'), theme('ncip_scheme_row', $application->get_on_behalf_of_agency()));
$rows[] = array(t('Application Profile Type'), theme('ncip_scheme_row', $application->get_application_profile_type()));
$output = theme('table', $header, $rows);
return $output;
......
@CHARSET "UTF-8";
#time_statistics .collapsed td span { color: cornflowerblue; }
#time_statistics td, #time_statistics th {text-align: right; }
#time_statistics td.label, #time_statistics th.label {text-align: left; }
/**
* Collapses a hierarchial table's rows on click
*/
if (Drupal.jsEnabled) {
$(document).ready(function(){
$('#time_statistics tbody tr').click(function() {
var collapsed = $(this).hasClass('collapsed');
var id = '^' + $(this).attr('id') + '/';
var hasChild = false;
// Finds and hides/shows children. It is a child if it's id starts as the parent's id.
$('#time_statistics tbody tr').each(function (index, domEle) {
if (typeof $(domEle).attr('id') != 'undefined' && $(domEle).attr('id').match(id)) {
hasChild = true;
if (collapsed) {
$(domEle).show();
}
else {
$(domEle).hide();
}
}
});
// Changes its own class.
if (hasChild) {
if (collapsed) {
$(this).removeClass('collapsed');
}
else {
$(this).addClass('collapsed');
}
}
});
});
}
\ No newline at end of file
......@@ -38,4 +38,7 @@ interface IOAIParser {
/** Get the statistics */
public function getStatistics();
/** Get the errors regarding to XML malformadness */
public function getParserErrors();
}
\ No newline at end of file
......@@ -19,17 +19,40 @@ class OAIDomParser implements IOAIParser {
private $httpCode;
private $httpErrorMsg;
private $statistics;
private $parserErrors = array();
function __construct($content, $httpCode = 200) {
$t0 = microtime(TRUE);
$this->httpCode = $httpCode;
if (empty(trim($content))) {
$parserErrors[] = t('The XML to parse is an empty string.');
return;
}
$oaiDom = new SimpleXMLIterator($content);
$this->statistics['response'] = microtime(TRUE) - $t0;
$this->oai = $oaiDom;
$this->httpCode = $httpCode;
if (!$oaiDom) {
$lines = explode("\n", $content);
$errors = libxml_get_errors();
foreach ($errors as $error) {
$output = $lines[$error->line - 1] . "<br/>\n";
$output .= str_repeat('-', $error->column) . "^<br/>\n";
switch ($error->level) {
case LIBXML_ERR_WARNING: $level = t('Warning'); break;
case LIBXML_ERR_ERROR: $level = t('Error'); break;
case LIBXML_ERR_FATAL: $level = t('Fatal error'); break;
}
$output .= $level . ' ' . $error->code . ': ' . $error->message . ' (' . $error->line . ':' . $error->column . ')';
$parserErrors[] = $output;
}
libxml_clear_errors();
}
}
function hasErrors() {
return isset($this->oai->error) || ((int)$this->httpCode != 200);
return isset($this->oai->error);
}
function listErrors() {
......@@ -104,10 +127,14 @@ class OAIDomParser implements IOAIParser {
}
$dom = dom_import_simplexml($record->metadata);
if ($dom === FALSE) {
xc_log_error('DOMParser', sprintf('[id: %s, status: %s] Error while parsing XML "%s"', $identifier, $status, $record->metadata));
$errorMsq = sprintf('[id: %s, status: %s] Error while parsing XML "%s"', $identifier, $status, $record->metadata);
$this->parserErrors[] = $errorMsq;
xc_log_error('DOMParser', $errorMsq);
}
elseif (!$dom->hasChildNodes) {
xc_log_error('DOMParser', sprintf('No children in metadata: [id: %s, status: %s] xml: "%s"', $identifier, $status, htmlentities($record->metadata)));
$errorMsq = sprintf('No children in metadata: [id: %s, status: %s] xml: "%s"', $identifier, $status, htmlentities($record->metadata));
$this->parserErrors[] = $errorMsq;
xc_log_error('DOMParser', $errorMsq);
}
else {
foreach ($dom->childNodes as $childNode) {
......@@ -146,4 +173,7 @@ class OAIDomParser implements IOAIParser {
}
}
function getParserErrors() {
return $this->parserErrors;
}
}
\ No newline at end of file
......@@ -22,6 +22,8 @@ class OAIHarvester {
private $content;
private $hasFetched = FALSE;
private $statistics = array();
private $downloadSize = -1;
private $fileSize = -1;
public function __construct($requestVerb = 'ListRecords', $baseUrl = '', $requestArguments = array(), $http_cache = FALSE) {
$this->requestVerb = $requestVerb;
......@@ -94,16 +96,21 @@ class OAIHarvester {
$this->statistics['fetch']['curl_init'] = microtime(TRUE) - $t0;
$this->content = curl_exec($ch);
$this->httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$download_size = curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD);
$this->downloadSize = curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD);
if (isset($cache_file) && $this->httpCode == 200) {
file_put_contents($cache_file, $this->content);
// put content into the list
$file_list = $this->http_cache . '/list.txt';
$file_info = sprintf("%s\t%s\t%s\n", format_date(time(), 'custom', 'Y-m-d H:i:s'), md5($requestUrl), $requestUrl);
file_put_contents($file_list, $file_info, FILE_APPEND);
unset($list);
if ($this->getSize() == 0) {
$this->error = t('The data provider returned an empty string instead of a valid XML.');
}
else {
file_put_contents($cache_file, $this->content);
// put content into the list
$file_list = $this->http_cache . '/list.txt';
$file_info = sprintf("%s\t%s\t%s\n", format_date(time(), 'custom', 'Y-m-d H:i:s'), md5($requestUrl), $requestUrl);
file_put_contents($file_list, $file_info, FILE_APPEND);
unset($list);
}
}
if (curl_errno($ch)) {
$this->error = curl_error($ch);
......@@ -365,12 +372,12 @@ class OAIHarvester {
return $this->parser->hasRecords();
}
/** Get number of records */
/** Gets number of records */
public function getRecordCount() {
return $this->parser->getRecordCount();
}
/** Get next record */
/** Gets next record */
public function getNextRecord() {
return $this->parser->getNextRecord();
}
......@@ -380,9 +387,13 @@ class OAIHarvester {
return $this->parser->hasResumptionToken();
}
/** Get the resumptionToken */
/** Gets the resumptionToken */
public function getResumptionToken() {
return $this->parser->getResumptionToken();
}
/** Gets the size of downloaded XML file */
public function getSize() {
return strlen(trim($this->content));
}
}
\ No newline at end of file
......@@ -17,7 +17,11 @@ class OAIRegexParser implements IOAIParser {
private $raw_resumption;
private $httpCode;
/** The OAI-PMH error messages */
private $errorMsgs = array();
/** The error messages generated by this parser */
private $parserErrors = array();
private $statistics = array();
private $hasErrors = FALSE;
private $hasListRecords = FALSE;
......@@ -140,43 +144,42 @@ class OAIRegexParser implements IOAIParser {
}
}
$size = drupal_strlen($text);
$text = preg_replace("/^<\?xml[^<>]+\?>/", "", $text);
if ($size == drupal_strlen($text)) {
xc_log_error('regex', 'no sheabang');
$this->errorMsgs[] = 'no sheabang';
$count = 0;
$text = preg_replace("/^<\?xml[^<>]+\?>/", "", $text, -1, $count);
if ($count != 1) {
xc_log_error('regex', 'Malformed XML: no sheabang &mdash; ' . htmlentities($text));
$this->parserErrors[] = 'no sheabang';
}
$size = drupal_strlen($text);
$text = preg_replace("/^\s*<OAI-PMH\b[^<>]+>/s", "", $text);
if ($size == drupal_strlen($text)) {
xc_log_error('regex', 'no &lt;OAI-PMH&gt;');
$this->errorMsgs[] = 'no OAI-PMH';
$count = 0;
$text = preg_replace("/^\s*<OAI-PMH\b[^<>]+>/s", "", $text, -1, $count);
if ($count != 1) {
xc_log_error('regex', 'Malformed XML: no &lt;OAI-PMH&gt; &mdash; ' . htmlentities($text));
$this->parserErrors[] = 'no OAI-PMH';
return;
}
$size = drupal_strlen($text);
$text = preg_replace("/^\s*<responseDate>(.*?)<\/responseDate>/s", "", $text);
if ($size == drupal_strlen($text)) {
xc_log_error('regex', 'no &lt;responseDate&gt;');
$this->errorMsgs[] = 'no responseDate';
$count = 1;
$text = preg_replace("/^\s*<responseDate>(.*?)<\/responseDate>/s", "", $text, -1, $count);
if ($count != 1) {
xc_log_error('regex', 'Malformed XML: no &lt;responseDate&gt; &mdash; ' . htmlentities($text));
$this->parserErrors[] = 'no responseDate';
return;
}
$size = drupal_strlen($text);
$text = preg_replace("/^\s*<request(?: [^<>]+)?>(.*?)<\/request>/s", "", $text);
if ($size == drupal_strlen($text)) {
xc_log_error('regex', 'no &lt;request&gt; element in XML response: '
. htmlentities(substr($text, 0, 50)) . '&hellip;');
$this->errorMsgs[] = 'no request';
$count = 0;
$text = preg_replace("/^\s*<request(?: [^<>]+)?>(.*?)<\/request>/s", "", $text, -1, $count);
if ($count != 1) {
xc_log_error('regex', 'Malformed XML: no &lt;request&gt; element in XML response: ' . htmlentities(substr($text, 0, 50)) . '&hellip;');
$this->parserErrors[] = 'no request element';
return;
}
$this->hasListRecords = FALSE;
$this->hasErrors = FALSE;
$size = drupal_strlen($text);
$text = preg_replace("/^\s*<ListRecords>/", "", $text);
if ($size == drupal_strlen($text)) {
$count = 0;
$text = preg_replace("/^\s*<ListRecords>/", "", $text, -1, $count);
if ($count != 1) {
$errors = '';
$size = drupal_strlen($text);
$text = preg_replace_callback(
......@@ -185,8 +188,8 @@ class OAIRegexParser implements IOAIParser {
$text
);
if ($size == drupal_strlen($text)) {
xc_log_error('regex', 'no ListRecords and error');
$this->errorMsgs[] = 'no ListRecords and error';
xc_log_error('regex', 'Malformed XML: no ListRecords and no error elements &mdash; ' . htmlentities($text));
$this->parserErrors[] = 'no ListRecords and error elements';
}
else {
$this->hasErrors = TRUE;
......@@ -195,6 +198,7 @@ class OAIRegexParser implements IOAIParser {
else {
$this->hasListRecords = TRUE;
}
if (!$this->hasErrors && !$this->need_debug) {
$this->rawContent = '';
}
......@@ -204,10 +208,10 @@ class OAIRegexParser implements IOAIParser {
$records = '';
$is_changed_size = TRUE;
while (!preg_match("/^\s*<\/ListRecords>/", $text) && $is_changed_size) {
$size = drupal_strlen($text);
$text = preg_replace_callback("/^\s*(<record>.*<\/record>)/s", array($this, 'setRecords'), $text);
$count = 0;
$text = preg_replace_callback("/^\s*(<record>.*<\/record>)/s", array($this, 'setRecords'), $text, -1, $count);
if ($size != drupal_strlen($text)) {
if ($count > 0) {
$this->hasRecords = TRUE;
$is_changed_size = TRUE;
// raw_records is initialized by setRecords
......@@ -216,40 +220,42 @@ class OAIRegexParser implements IOAIParser {
$this->recordCount = count($this->records);
$mod_records = '';
$size = drupal_strlen($text);
$count = 0;
$text = preg_replace_callback("/^\s*(<resumptionToken([^<>]*)>(.*?)<\/resumptionToken>|<resumptionToken([^<>]*)\s*\/\s*>)/",
array($this, 'setResumption'), $text);
if ($size != drupal_strlen($text)) {
array($this, 'setResumption'), $text, -1, $count);
if ($count > 0) {
$is_changed_size = TRUE;
// resumption comes from setResumption
//echo 'recCount: ', $this->recordCount, ", resumption: ", $this->resumptionToken['text'], "\n";
}
else {
$is_changed_size = FALSE;
//$this->errorMsgs[] = 'no resumptionToken';
//$this->parserErrors[] = 'no resumptionToken';
}
}
else {
$is_changed_size = FALSE;
$this->errorMsgs[] = 'no records';
$this->parserErrors[] = 'no record elements';
}
} // process inside ListRecords
$size = drupal_strlen($text);
$text = preg_replace('/^\s*<\/ListRecords>/', '', $text);
if ($size == drupal_strlen($text)) {
$this->errorMsgs[] = 'no /ListRecords';
$count = 0;
$text = preg_replace('/^\s*<\/ListRecords>/', '', $text, -1, $count);
if ($count != 1) {
xc_log_error('regex', 'Malformed XML: no /ListRecords &mdash; ' . htmlentities($text));
$this->parserErrors[] = 'no ListRecords closer element';
}
} // has ListRecords
else {
$this->errorMsgs[] = 'no ListRecords';
$this->parserErrors[] = 'no ListRecords element';
}
if ($this->hasListRecords || $this->hasErrors) {
$size = drupal_strlen($text);
$text = preg_replace("/^\s*<\/OAI-PMH>/", '', $text);
if ($size == drupal_strlen($text)) {
$this->errorMsgs[] = 'no /OAI-PMH';
$count = 0;
$text = preg_replace("/^\s*<\/OAI-PMH>/", '', $text, -1, $count);
if ($count != 1) {
xc_log_error('regex', 'Malformed XML: no /OAI-PMH &mdash; ' . htmlentities($text));
$this->parserErrors[] = 'no /OAI-PMH closer element';
}
} // has ListRecords or error
}
......@@ -257,26 +263,31 @@ class OAIRegexParser implements IOAIParser {
/**
* Save the error message come from OAI-PMH data provider
*
* @param $matches (Array)
* @param $matches (array)
* matches[2]: the error code (optional)
* matches[4]: the error message
*
* @return (string)
* An empty string to replace the error message
*/
private function setErrors($matches) {
$msg = t('OAI-PMH data provider sent an error message. %error', array('%error' => $matches[4]));
$msg = array(
'text' => t('OAI-PMH data provider sent an error message. %error', array('%error' => $matches[4]))
);
if (isset($matches[2])) {
$this->errorMsgs[] = array(
'text' => $msg,
'code' => $matches[2],
);
}
else {
$this->errorMsgs[] = $msg;
$msg['code'] = $matches[2];
}
$this->errorMsgs[] = $msg;
return "";
}
public function getParserErrors() {
return $this->parserErrors;
}
private function setRecords($matches) {
$this->raw_records = $matches[1];
return "";
......
......@@ -162,10 +162,14 @@ function hook_oaiharvester_batch_started($parameters) {
}
/**
* Respond to the event that a batch has been processed.
*
* @param $sets