From aac69993a36ee4f5bc224f96d93f4e2ae1f64f6f Mon Sep 17 00:00:00 2001 From: Daniel Neis Araujo Date: Tue, 14 May 2013 16:46:15 -0300 Subject: [PATCH] Refactoring XML creation --- oai2.php | 56 +++++----- oai2exception.php | 7 +- oai2server.php | 266 +++++++++++++++++++++------------------------- oai2xml.php | 75 +++++++++++-- xml_creater.php | 196 ---------------------------------- 5 files changed, 222 insertions(+), 378 deletions(-) delete mode 100644 xml_creater.php diff --git a/oai2.php b/oai2.php index 1d1e6a1..4b467e6 100644 --- a/oai2.php +++ b/oai2.php @@ -13,10 +13,7 @@ * */ -define('MY_URI', 'dev2.moodle.ufsc.br'); - require_once('oaidp-util.php'); -require_once('xml_creater.php'); require_once('oai2server.php'); /** @@ -47,11 +44,31 @@ $identifyResponse["deletedRecord"] = 'no'; // How your repository handles deleti // maintained. It MAY reveal a deleted status for records. $identifyResponse["granularity"] = 'YYYY-MM-DDThh:mm:ssZ'; -$oai2 = new OAI2Server($_REQUEST, $identifyResponse, +$example_record = array('identifier' => 'dev.testing.pmh', + 'datestamp' => date('Y-m-d-H:s'), + 'set' => 'class:activity', + 'metadata' => array( + 'container_name' => 'oai_dc:dc', + 'container_attributes' => array( + 'xmlns:oai_dc' => "http://www.openarchives.org/OAI/2.0/oai_dc/", + 'xmlns:dc' => "http://purl.org/dc/elements/1.1/", + 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", + 'xsi:schemaLocation' => + 'http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd' + ), + 'fields' => array( + 'dc:title' => 'Testing records', + 'dc:author' => 'Neis' + ) + )); + +$oai2 = new OAI2Server('neis.moodle.ufsc.br', $_GET, $identifyResponse, array( 'ListMetadataFormats' => function($identifier = '') { - // throws new OAI2Exception('idDoesNotExist', '', $identifier) + if ($identifier == 'a.b.c') { + throw new OAI2Exception('idDoesNotExist', '', $identifier); + } return array('rif' => array('metadataPrefix'=>'rif', 'schema'=>'http://services.ands.org.au/sandbox/orca/schemata/registryObjects.xsd', @@ -85,35 +102,22 @@ $oai2 = new OAI2Server($_REQUEST, $identifyResponse, 'ListRecords' => function($metadataPrefix, $from = '', $until = '', $set = '', $count = false, $deliveredRecords = 0, $maxItems = 0) { + global $example_record; // throws new OAI2Exception('noRecordsMatch') // throws new OAI2Exception('noSetHierarchy') if ($count) { - return 10; + return 1; } - return array(); + return array($example_record); }, 'GetRecord' => function($identifier, $metadataPrefix) { - // throws new OAI2Exception('idDoesNotExist', '', $identifier) if record not found - - return array('identifier' => 'dev.testing.pmh', - 'datestamp' => date('Y-m-d-H:s'), - 'set' => 'class:activity', - 'metadata' => array( - 'container_name' => 'oai_dc:dc', - 'container_attributes' => array( - 'xmlns:oai_dc' => "http://www.openarchives.org/OAI/2.0/oai_dc/", - 'xmlns:dc' => "http://purl.org/dc/elements/1.1/", - 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", - 'xsi:schemaLocation' => - 'http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd' - ), - 'fields' => array( - 'dc:title' => 'Testing records', - 'dc:author' => 'Neis' - ) - )); + global $example_record; + if ($identifier == 'a.b.c') { + throw new OAI2Exception('idDoesNotExist', '', $identifier); + } + return $example_record; }, ) ); diff --git a/oai2exception.php b/oai2exception.php index 600fc3e..16b90f7 100644 --- a/oai2exception.php +++ b/oai2exception.php @@ -73,6 +73,11 @@ class OAI2Exception extends Exception { 'code' => 'badArgument', ) ); - parent::__construct($this->errorTable[$code]['text'], $code); + parent::__construct($this->errorTable[$code]['text']); + $this->code = $code; + } + + public function getOAI2Code() { + return $this->code; } } diff --git a/oai2server.php b/oai2server.php index 7875c50..ef0ef8c 100644 --- a/oai2server.php +++ b/oai2server.php @@ -18,55 +18,69 @@ define('TOKEN_PREFIX','/tmp/oai_pmh-'); class OAI2Server { public $errors = array(); + private $args = array(); + private $verb = ''; - function __construct($args, $identifyResponse, $callbacks) { + function __construct($uri, $args, $identifyResponse, $callbacks) { + if (!isset($args['verb']) || empty($args['verb'])) { + $this->errors[] = new OAI2Exception('noVerb'); + $this->errorResponse(); + } + + $this->verb = $args['verb']; + unset($args['verb']); $this->args = $args; + + $this->uri = $uri; + $this->identifyResponse = $identifyResponse; + $this->listMetadataFormatsCallback = $callbacks['ListMetadataFormats']; $this->listSetsCallback = $callbacks['ListSets']; $this->listRecordsCallback = $callbacks['ListRecords']; $this->getRecordCallback = $callbacks['GetRecord']; + + $this->response = new OAI2XMLResponse($this->uri, $this->verb, $this->args); + $this->respond(); } private function respond() { - if (!isset($this->args['verb']) || empty($this->args['verb'])) { - $this->errors[] = new OAI2Exception('noVerb'); - } else { - switch ($this->args['verb']) { - case 'Identify': $this->identify(); break; + switch ($this->verb) { - case 'ListMetadataFormats': $this->listMetadataFormats(); break; + case 'Identify': $this->identify(); break; - case 'ListSets': $this->listSets(); break; + case 'ListMetadataFormats': $this->listMetadataFormats(); break; - case 'ListIdentifiers': - case 'ListRecords': $this->listRecords(); break; + case 'ListSets': $this->listSets(); break; - case 'GetRecord': $this->getRecord(); break; + case 'ListIdentifiers': + case 'ListRecords': $this->listRecords(); break; - default: $this->errors[] = new OAI2Exception('badVerb', $this->args['verb']); - } + case 'GetRecord': $this->getRecord(); break; + + default: $this->errors[] = new OAI2Exception('badVerb', $this->args['verb']); } - if (empty($this->errors)) { - if (isset($this->outputObj)) { - header(CONTENT_TYPE); - $this->outputObj->display(); - } else { - exit("Nothing to output. May be a bug."); - } + if (empty($this->errors)) { + header(CONTENT_TYPE); + $this->response->display(); } else { $this->errorResponse(); } } private function errorResponse() { - $e = new OAI2XMLError($this->args,$this->errors); + $errorResponse = new OAI2XMLResponse($this->uri, $this->verb, $this->args); + $oai_node = $errorResponse->doc->documentElement; + foreach($this->errors as $e) { + $node = $errorResponse->addChild($oai_node,"error",$e->getMessage()); + $node->setAttribute("code",$e->getOAI2Code()); + } header(CONTENT_TYPE); - $e->display(); + $errorResponse->display(); exit(); } @@ -79,17 +93,15 @@ class OAI2Server { */ public function identify() { - if (count($this->args) > 1) { + if (count($this->args) > 0) { foreach($args as $key => $val) { - if(strcmp($key,"verb")!=0) { - $this->errors[] = new OAI2Exception('badArgument', $key, $val); - } + $this->errors[] = new OAI2Exception('badArgument', $key, $val); } + $this->errorResponse(); } - $this->outputObj = new ANDS_Response_XML($this->args); foreach($this->identifyResponse as $key => $val) { - $this->outputObj->add2_verbNode($key, $val); + $this->response->addToVerbNode($key, $val); } } @@ -100,21 +112,26 @@ class OAI2Server { */ public function listMetadataFormats() { - $checkList = array("ops"=>array("identifier")); - $this->checkArgs($checkList); + foreach ($this->args as $argument => $value) { + if ($argument != 'identifier') { + $this->errors[] = new OAI2Exception('badArgument', $argument, $value); + } + } + if (!empty($this->errors)) { + $this->errorResponse(); + } try { if ($formats = call_user_func($this->listMetadataFormatsCallback, $this->args['identifier'])) { - $this->outputObj = new ANDS_Response_XML($this->args); foreach($formats as $key => $val) { - $cmf = $this->outputObj->add2_verbNode("metadataFormat"); - $this->outputObj->addChild($cmf,'metadataPrefix',$key); - $this->outputObj->addChild($cmf,'schema',$val['schema']); - $this->outputObj->addChild($cmf,'metadataNamespace',$val['metadataNamespace']); + $cmf = $this->response->addToVerbNode("metadataFormat"); + $this->response->addChild($cmf,'metadataPrefix',$key); + $this->response->addChild($cmf,'schema',$val['schema']); + $this->response->addChild($cmf,'metadataNamespace',$val['metadataNamespace']); } - return $outputObj; + } else { + $this->errors[] = new OAI2Exception('noMetadataFormats'); } - $this->errors[] = new OAI2Exception('noMetadataFormats'); } catch (OAI2Exception $e) { $this->errors[] = $e; } @@ -128,27 +145,33 @@ class OAI2Server { */ public function listSets() { - if (isset($this->args['resumptionToken']) && count($this->args) > 2) { - $this->errors[] = new OAI2Exception('exclusiveArgument'); + if (isset($this->args['resumptionToken'])) { + if (count($this->args) > 1) { + $this->errors[] = new OAI2Exception('exclusiveArgument'); + } else { + if ((int)$val+TOKEN_VALID < time()) { + $this->errors[] = new OAI2Exception('badResumptionToken'); + } + } + } + if (!empty($this->errors)) { + $this->errorResponse(); } - $checkList = array("ops"=>array("resumptionToken")); - $this->checkArgs($checkList); if ($sets = call_user_func($this->listSetsCallback)) { - $this->outputObj = new ANDS_Response_XML($this->args); foreach($sets as $set) { - $setNode = $this->outputObj->add2_verbNode("set"); + $setNode = $this->response->addToVerbNode("set"); foreach($set as $key => $val) { if($key=='setDescription') { - $desNode = $this->outputObj->addChild($setNode,$key); - $des = $this->outputObj->doc->createDocumentFragment(); + $desNode = $this->response->addChild($setNode,$key); + $des = $this->response->doc->createDocumentFragment(); $des->appendXML($val); $desNode->appendChild($des); } else { - $this->outputObj->addChild($setNode,$key,$val); + $this->response->addChild($setNode,$key,$val); } } } @@ -168,19 +191,23 @@ class OAI2Server { */ public function getRecord() { - $checkList = array("required"=>array("metadataPrefix","identifier")); - $this->checkArgs($checkList); - - $metadataPrefix = $this->args['metadataPrefix']; - - $metadataFormats = call_user_func($this->listMetadataFormatsCallback); - - if (!isset($metadataFormats[$metadataPrefix])) { - $this->errors[] = new OAI2Exception('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix); + if (!isset($this->args['metadataPrefix'])) { + $this->errors[] = new OAI2Exception('missingArgument', 'metadataPrefix'); + } else { + $metadataFormats = call_user_func($this->listMetadataFormatsCallback); + if (!isset($metadataFormats[$this->args['metadataPrefix']])) { + $this->errors[] = new OAI2Exception('cannotDisseminateFormat', 'metadataPrefix', $this->args['metadataPrefix']); + } + } + if (!isset($this->args['identifier'])) { + $this->errors[] = new OAI2Exception('missingArgument', 'identifier'); + } + if (!empty($this->errors)) { + $this->errorResponse(); } try { - if ($record = call_user_func($this->getRecordCallback, $this->args['identifier'], $metadataPrefix)) { + if ($record = call_user_func($this->getRecordCallback, $this->args['identifier'], $this->args['metadataPrefix'])) { $identifier = $record['identifier']; @@ -192,14 +219,12 @@ class OAI2Server { (($this->identifyResponse['deletedRecord'] == 'transient') || ($this->identifyResponse['deletedRecord'] == 'persistent'))); - $this->outputObj = new ANDS_Response_XML($this->args); - $cur_record = $this->outputObj->create_record(); - $cur_header = $this->outputObj->create_header($identifier, $datestamp, $set, $cur_record); + $cur_record = $this->response->addToVerbNode('record'); + $cur_header = $this->response->createHeader($identifier, $datestamp, $set, $cur_record); if ($status_deleted) { $cur_header->setAttribute("status","deleted"); } else { $this->add_metadata($cur_record, $record); - } } } catch (OAI2Exception $e) { @@ -218,18 +243,36 @@ class OAI2Server { public function listRecords() { if (isset($this->args['resumptionToken'])) { - if (count($this->args) > 2) { + if (count($this->args) > 1) { $this->errors[] = new OAI2Exception('exclusiveArgument'); + } else { + if ((int)$val+TOKEN_VALID < time()) { + $this->errors[] = new OAI2Exception('badResumptionToken'); + } } - $checkList = array("ops"=>array("resumptionToken")); } else { - $checkList = array("required"=>array("metadataPrefix"),"ops"=>array("from","until","set")); + if (!isset($this->args['metadataPrefix'])) { + $this->errors[] = new OAI2Exception('missingArgument', 'metadataPrefix'); + } else { + $metadataFormats = call_user_func($this->listMetadataFormatsCallback); + if (!isset($metadataFormats[$this->args['metadataPrefix']])) { + $this->errors[] = new OAI2Exception('cannotDisseminateFormat', 'metadataPrefix', $this->args['metadataPrefix']); + } + } + if (isset($this->args['from'])) { + if(!checkDateFormat($this->args['from'])) { + $this->errors[] = new OAI2Exception('badGranularity', 'from', $this->args['from']); + } + } + if (isset($this->args['until'])) { + if(!checkDateFormat($this->args['until'])) { + $this->errors[] = new OAI2Exception('badGranularity', 'until', $this->args['until']); + } + } } - $this->checkArgs($checkList); - $metadataFormats = call_user_func($this->listMetadataFormatsCallback, $this->args); - if (!isset($metadataFormats[$this->args['metadataPrefix']])) { - $this->errors[] = new OAI2Exception('cannotDisseminateFormat', 'metadataPrefix', $this->args['metadataPrefix']); + if (!empty($this->errors)) { + $this->errorResponse(); } // Resume previous session? @@ -247,6 +290,10 @@ class OAI2Server { } + if (!empty($this->errors)) { + $this->errorResponse(); + } + } else { $deliveredRecords = 0; $metadataPrefix = $this->args['metadataPrefix']; @@ -255,10 +302,6 @@ class OAI2Server { $set = isset($this->args['set']) ? $this->args['set'] : ''; } - if (!empty($this->errors)) { - $this->errorResponse(); - } - $maxItems = 1000; try { @@ -266,25 +309,24 @@ class OAI2Server { $records = call_user_func($this->listRecordsCallback, $metadataPrefix, $from, $until, $set, false, $deliveredRecords, $maxItems); - $this->outputObj = new ANDS_Response_XML($this->args); foreach ($records as $record) { $identifier = $record['identifier']; $datestamp = formatDatestamp($record['datestamp']); - $setspec = $record[$SQL['set']]; + $setspec = $record['set']; $status_deleted = (isset($record['deleted']) && ($record['deleted'] === true) && (($this->identifyResponse['deletedRecord'] == 'transient') || ($this->identifyResponse['deletedRecord'] == 'persistent'))); if($this->args['verb'] == 'ListRecords') { - $cur_record = $this->outputObj->create_record(); - $cur_header = $this->outputObj->create_header($identifier, $datestamp,$setspec,$cur_record); + $cur_record = $this->response->createToVerNode('record'); + $cur_header = $this->response->createHeader($identifier, $datestamp,$setspec,$cur_record); if (!$status_deleted) { $this->add_metadata($cur_record, $record); } } else { // for ListIdentifiers, only identifiers will be returned. - $cur_header = $this->outputObj->create_header($identifier, $datestamp,$setspec); + $cur_header = $this->response->createHeader($identifier, $datestamp,$setspec); } if ($status_deleted) { $cur_header->setAttribute("status","deleted"); @@ -306,7 +348,7 @@ class OAI2Server { } if (isset($restoken)) { - $this->outputObj->create_resumpToken($restoken,$expirationDatetime,$records_count,$deliveredRecords); + $this->response->createResumptionToken($restoken,$expirationDatetime,$records_count,$deliveredRecords); } } catch (OAI2Exception $e) { @@ -316,78 +358,14 @@ class OAI2Server { private function add_metadata($cur_record, $record) { - $meta_node = $this->outputObj->addChild($cur_record ,"metadata"); + $meta_node = $this->response->addChild($cur_record ,"metadata"); - $schema_node = $this->outputObj->addChild($meta_node, $record['metadata']['container_name']); + $schema_node = $this->response->addChild($meta_node, $record['metadata']['container_name']); foreach ($record['metadata']['container_attributes'] as $name => $value) { $schema_node->setAttribute($name, $value); } foreach ($record['metadata']['fields'] as $name => $value) { - $this->outputObj->addChild($schema_node, $name, $value); - } - } - - /** Check if provided correct arguments for a request. - * - * Only number of parameters is checked. - * metadataPrefix has to be checked before it is used. - * set has to be checked before it is used. - * resumptionToken has to be checked before it is used. - * from and until can easily checked here because no extra information - * is needed. - */ - private function checkArgs($checkList) { - - $metadataFormats = call_user_func($this->listMetadataFormatsCallback); - - // "verb" has been checked before, no further check is needed - $verb = $this->args["verb"]; - - $test_args = $this->args; - unset($test_args["verb"]); - - if(isset($checkList['required'])) { - for($i = 0; $i < count($checkList["required"]); $i++) { - - if (isset($test_args[$checkList['required'][$i]]) == false) { - $this->errors[] = new OAI2Exception('missingArgument', $checkList["required"][$i]); - } else { - // if metadataPrefix is set, it is in required section - if(isset($test_args['metadataPrefix'])) { - $metadataPrefix = $test_args['metadataPrefix']; - if (!isset($metadataFormats[$metadataPrefix])) { - $this->errors[] = new OAI2Exception('cannotDisseminateFormat', 'metadataPrefix', $metadataPrefix); - } - } - unset($test_args[$checkList["required"][$i]]); - } - } - } - - // check to see if there is unwanted - foreach($test_args as $key => $val) { - - if(!in_array($key, $checkList["ops"])) { - $this->errors[] = new OAI2Exception('badArgument', $key, $val); - } - switch ($key) { - case 'from': - case 'until': - if(!checkDateFormat($val)) { - $this->errors[] = new OAI2Exception('badGranularity', $key, $val); - } - break; - - case 'resumptionToken': - // only check for expiration - if((int)$val+TOKEN_VALID < time()) - $this->errors[] = new OAI2Exception('badResumptionToken'); - break; - } - } - - if (!empty($this->errors)) { - $this->errorResponse(); + $this->response->addChild($schema_node, $name, $value); } } diff --git a/oai2xml.php b/oai2xml.php index 4fa7b1c..3f70ccf 100644 --- a/oai2xml.php +++ b/oai2xml.php @@ -4,8 +4,9 @@ class OAI2XML { public $doc; // DOMDocument. Handle of current XML Document object - function __construct($request_args) { + function __construct($uri, $verb, $request_args) { + $this->verb = $verb; $this->doc = new DOMDocument("1.0","UTF-8"); $oai_node = $this->doc->createElement("OAI-PMH"); $oai_node->setAttribute("xmlns","http://www.openarchives.org/OAI/2.0/"); @@ -14,7 +15,8 @@ class OAI2XML { $this->addChild($oai_node,"responseDate",gmdate("Y-m-d\TH:i:s\Z")); $this->doc->appendChild($oai_node); - $request = $this->addChild($this->doc->documentElement,"request",MY_URI); + $request = $this->addChild($this->doc->documentElement,"request",$uri); + $request->setAttribute('verb', $this->verb); foreach($request_args as $key => $value) { $request->setAttribute($key,$value); } @@ -52,16 +54,67 @@ class OAI2XML { } } -class OAI2XMLError extends OAI2XML { +class OAI2XMLResponse extends OAI2XML { - function __construct($request_args, $errors) { - parent::__construct($request_args); - - $oai_node = $this->doc->documentElement; - foreach($errors as $e) { - $node = $this->addChild($oai_node,"error",$e->getMessage()); - $node->setAttribute("code",$e->getCode()); - } + function __construct($verb, $request_args) { + parent::__construct($verb, $request_args); + $this->verbNode = $this->addChild($this->doc->documentElement,$this->verb); } + /** + * Add direct child nodes to verb node (OAI-PMH), e.g. response to ListMetadataFormats. + * Different verbs can have different required child nodes. + * \see create_record, create_header + * + * \param $nodeName Type: string. The name of appending node. + * \param $value Type: string. The content of appending node. + */ + function addToVerbNode($nodeName, $value=null) { + return $this->addChild($this->verbNode,$nodeName,$value); + } + + /** + * Headers are enclosed inside of \ to the query of ListRecords, ListIdentifiers and etc. + * + * \param $identifier Type: string. The identifier string for node \. + * \param $timestamp Type: timestamp. Timestapme in UTC format for node \. + * \param $ands_class Type: mix. Can be an array or just a string. Content of \. + * \param $add_to_node Type: DOMElement. Default value is null. + * In normal cases, $add_to_node is the \ node created previously. When it is null, the newly created header node is attatched to $this->verbNode. + * Otherwise it will be attatched to the desired node defined in $add_to_node. + */ + function createHeader($identifier,$timestamp,$ands_class, $add_to_node=null) { + if(is_null($add_to_node)) { + $header_node = $this->addToVerbNode("header"); + } else { + $header_node = $this->addChild($add_to_node,"header"); + } + $this->addChild($header_node,"identifier",$identifier); + $this->addChild($header_node,"datestamp",$timestamp); + if (is_array($ands_class)) { + foreach ($ands_class as $setspec) { + $this->addChild($header_node,"setSpec",$setspec); + } + } else { + $this->addChild($header_node,"setSpec",$ands_class); + } + return $header_node; + } + + /** + * If there are too many records request could not finished a resumpToken is generated to let harvester know + * + * \param $token Type: string. A random number created somewhere? + * \param $expirationdatetime Type: string. A string representing time. + * \param $num_rows Type: integer. Number of records retrieved. + * \param $cursor Type: string. Cursor can be used for database to retrieve next time. + */ + function createResumptionToken($token, $expirationdatetime, $num_rows, $cursor=null) { + $resump_node = $this->addChild($this->verbNode,"resumptionToken",$token); + if(isset($expirationdatetime)) { + $resump_node->setAttribute("expirationDate",$expirationdatetime); + } + $resump_node->setAttribute("completeListSize",$num_rows); + $resump_node->setAttribute("cursor",$cursor); + } } diff --git a/xml_creater.php b/xml_creater.php deleted file mode 100644 index a2f0382..0000000 --- a/xml_creater.php +++ /dev/null @@ -1,196 +0,0 @@ -"ListRecords","resumptionToken"=>"9CD1DA87F59C3E960871F4F3C9D093887C17D174"); - * $test = new ANDS_Response_XML($par_array); - * $record_node = $test->create_record(); - * $test->create_header("function: identifier string",gmdate("Y-m-d\TH:i:s\Z"),"collection",$record_node); - * $test->create_metadata($record_node); - * $test->display(); - */ - -/** - * A wraper of DOMDocument for data provider - */ -class ANDS_XML { - - public $doc; /**< Type: DOMDocument. Handle of current XML Document object */ - - /** - * Constructs an ANDS_XML object. - * - * @param $par_array Type: array. - * Array of request parameters for creating an ANDS_XML object. - * \see create_request. - */ - function __construct($par_array) { - $this->doc = new DOMDocument("1.0","UTF-8"); - // oai_node equals to $this->doc->documentElement; - $oai_node = $this->doc->createElement("OAI-PMH"); - $oai_node->setAttribute("xmlns","http://www.openarchives.org/OAI/2.0/"); - $oai_node->setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); - $oai_node->setAttribute("xsi:schemaLocation","http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd"); - $this->addChild($oai_node,"responseDate",gmdate("Y-m-d\TH:i:s\Z")); - $this->doc->appendChild($oai_node); - $this->create_request($par_array); - } - - /** - * Add a child node to a parent node on a XML Doc: a worker function. - * - * @param $mom_node - * Type: DOMNode. The target node. - * - * @param $name - * Type: string. The name of child nade is being added - * - * @param $value - * Type: string. Text for the adding node if it is a text node. - * - * @return DOMElement $added_node - * The newly created node, can be used for further expansion. - * If no further expansion is expected, return value can be igored. - */ - - function addChild($mom_node,$name, $value='') { - $added_node = $this->doc->createElement($name,$value); - $added_node = $mom_node->appendChild($added_node); - return $added_node; - } - - /** - * Create an OAI request node. - * - * @param $par_array Type: array - * The attributes of a request node. They describe the verb of the request and other associated parameters used in the request. - * Keys of the array define attributes, and values are their content. - */ - - function create_request($par_array) { - $request = $this->addChild($this->doc->documentElement,"request",MY_URI); - foreach($par_array as $key => $value) { - $request->setAttribute($key,$value); - } - } - - /** - * Display a doc in a readable, well-formatted way for display or saving - */ - function display() { - $pr = new DOMDocument(); - $pr->preserveWhiteSpace = false; - $pr->formatOutput = true; - $pr->loadXML($this->doc->saveXML()); - echo $pr->saveXML(); - } -} - -/** - * Generate an XML response when a request cannot be finished - * - * It has only one derived member function - */ -class ANDS_Error_XML extends ANDS_XML { - function __construct($par_array, $error_array) { - parent::__construct($par_array); - - $oai_node = $this->doc->documentElement; - foreach($error_array as $e) { - list($code, $value) = explode("|", $e); - $node = $this->addChild($oai_node,"error",$value); - $node->setAttribute("code",$code); - } - } -} - -/** - * Generate an XML response to a request if no error has occured - * - * This is the class to further develop to suits a publication need - */ -class ANDS_Response_XML extends ANDS_XML { - public $verbNode; /**< Type: DOMElement. Verb node itself. */ - protected $verb; /**< Type: string. The verb in the request */ - - function __construct($par_array) { - parent::__construct($par_array); - $this->verb = $par_array["verb"]; - $this->verbNode = $this->addChild($this->doc->documentElement,$this->verb); - } - - /** Add direct child nodes to verb node (OAI-PMH), e.g. response to ListMetadataFormats. - * Different verbs can have different required child nodes. - * \see create_record, create_header - * \see http://www.openarchives.org/OAI/2.0/openarchivesprotocol.htm. - * - * \param $nodeName Type: string. The name of appending node. - * \param $value Type: string. The content of appending node. - */ - function add2_verbNode($nodeName, $value=null) { - return $this->addChild($this->verbNode,$nodeName,$value); - } - - /** - * Create an empty \ node. Other nodes will be appended to it later. - */ - function create_record() { - return $this->add2_verbNode("record"); - } - - /** Headers are enclosed inside of \ to the query of ListRecords, ListIdentifiers and etc. - * - * \param $identifier Type: string. The identifier string for node \. - * \param $timestamp Type: timestamp. Timestapme in UTC format for node \. - * \param $ands_class Type: mix. Can be an array or just a string. Content of \. - * \param $add_to_node Type: DOMElement. Default value is null. - * In normal cases, $add_to_node is the \ node created previously. When it is null, the newly created header node is attatched to $this->verbNode. - * Otherwise it will be attatched to the desired node defined in $add_to_node. - */ - function create_header($identifier,$timestamp,$ands_class, $add_to_node=null) { - if(is_null($add_to_node)) { - $header_node = $this->add2_verbNode("header"); - } else { - $header_node = $this->addChild($add_to_node,"header"); - } - $this->addChild($header_node,"identifier",$identifier); - $this->addChild($header_node,"datestamp",$timestamp); - if (is_array($ands_class)) { - foreach ($ands_class as $setspec) { - $this->addChild($header_node,"setSpec",$setspec); - } - } else { $this->addChild($header_node,"setSpec",$ands_class); } - return $header_node; - } - - /** Create metadata node for holding metadata. This is always added to \ node. - * - * \param $mom_record_node DOMElement. A node acts as the parent node. - * - * @return $meta_node Type: DOMElement. - * The newly created registryObject node which will be used for further expansion. - * metadata node itself is maintained by internally by the Class. - */ - function create_metadata($mom_record_node) { - $meta_node = $this->addChild($mom_record_node,"metadata"); - return $meta_node; - } - - /** If there are too many records request could not finished a resumpToken is generated to let harvester know - * - * \param $token Type: string. A random number created somewhere? - * \param $expirationdatetime Type: string. A string representing time. - * \param $num_rows Type: integer. Number of records retrieved. - * \param $cursor Type: string. Cursor can be used for database to retrieve next time. - */ - function create_resumpToken($token, $expirationdatetime, $num_rows, $cursor=null) { - $resump_node = $this->addChild($this->verbNode,"resumptionToken",$token); - if(isset($expirationdatetime)) { - $resump_node->setAttribute("expirationDate",$expirationdatetime); - } - $resump_node->setAttribute("completeListSize",$num_rows); - $resump_node->setAttribute("cursor",$cursor); - } -} -