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.

696 lines
37 KiB

  1. <?php
  2. // Project: Web Reference Database (refbase) <http://www.refbase.net>
  3. // Copyright: Matthias Steffens <mailto:refbase@extracts.de> and the file's
  4. // original author(s).
  5. //
  6. // This code is distributed in the hope that it will be useful,
  7. // but WITHOUT ANY WARRANTY. Please see the GNU General Public
  8. // License for more details.
  9. //
  10. // File: ./includes/srwxml.inc.php
  11. // Repository: $HeadURL: file:///svn/p/refbase/code/branches/bleeding-edge/includes/srwxml.inc.php $
  12. // Author(s): Matthias Steffens <mailto:refbase@extracts.de> and
  13. // Richard Karnesky <mailto:karnesky@gmail.com>
  14. //
  15. // Created: 17-May-05, 16:38
  16. // Modified: $Date: 2017-04-13 02:00:18 +0000 (Thu, 13 Apr 2017) $
  17. // $Author: karnesky $
  18. // $Revision: 1416 $
  19. // This include file contains functions that'll export records to SRW XML.
  20. // Requires ActiveLink PHP XML Package, which is available under the GPL from:
  21. // <http://www.active-link.com/software/>. See 'sru.php' for more info.
  22. // Incorporate some include files:
  23. include_once 'includes/webservice.inc.php'; // include functions that are commonly used with the refbase webservices
  24. // Import the ActiveLink Packages
  25. require_once("classes/include.php");
  26. import("org.active-link.xml.XML");
  27. import("org.active-link.xml.XMLDocument");
  28. // --------------------------------------------------------------------
  29. // Return DC XML or MODS XML records wrapped into SRW XML ('searchRetrieveResponse'):
  30. function srwCollection($result, $rowOffset, $showRows, $exportStylesheet, $displayType)
  31. {
  32. global $contentTypeCharset; // these variables are defined in 'ini.inc.php'
  33. global $convertExportDataToUTF8;
  34. global $exportFormat; // this is needed so that we can distinguish between "SRW_DC XML" and "SRW_MODS XML" record formats
  35. // The array '$transtab_refbase_unicode' contains search & replace patterns
  36. // for conversion from refbase markup to Unicode entities.
  37. global $transtab_refbase_unicode; // defined in 'transtab_refbase_unicode.inc.php'
  38. global $fieldSpecificSearchReplaceActionsArray;
  39. // Individual records are objects and collections of records are strings
  40. // Defines field-specific search & replace 'actions' that will be applied to all those refbase fields that are listed in the corresponding 'fields' element:
  41. // (If you don't want to perform any search and replace actions, specify an empty array, like: '$fieldSpecificSearchReplaceActionsArray = array();'.
  42. // Note that the search patterns MUST include the leading & trailing slashes -- which is done to allow for mode modifiers such as 'imsxU'.)
  43. // "/Search Pattern/" => "Replace Pattern"
  44. $fieldSpecificSearchReplaceActionsArray = array();
  45. if ($convertExportDataToUTF8 == "yes")
  46. $fieldSpecificSearchReplaceActionsArray[] = array('fields' => array("title", "publication", "abbrev_journal", "address", "keywords", "abstract", "orig_title", "series_title", "abbrev_series_title", "notes"),
  47. 'actions' => $transtab_refbase_unicode
  48. );
  49. $srwCollectionDoc = new XMLDocument();
  50. if (($convertExportDataToUTF8 == "yes") AND ($contentTypeCharset != "UTF-8"))
  51. $srwCollectionDoc->setEncoding("UTF-8");
  52. else
  53. $srwCollectionDoc->setEncoding($contentTypeCharset);
  54. $srwCollection = srwGenerateBaseTags("searchRetrieveResponse");
  55. $showRowsOriginal = $showRows; // save original value of '$showRows' (which may get modified by the 'seekInMySQLResultsToOffset()' function below)
  56. // Find out how many rows are available and (if there were rows found) seek to the current offset:
  57. // function 'seekInMySQLResultsToOffset()' is defined in 'include.inc.php'
  58. list($result, $rowOffset, $showRows, $rowsFound, $previousOffset, $nextOffset, $showMaxRow) = seekInMySQLResultsToOffset($result, $rowOffset, $showRows, $displayType, "");
  59. addNewBranch($srwCollection, "srw:numberOfRecords", array(), $rowsFound); // function 'addNewBranch()' is defined in 'webservice.inc.php'
  60. // <srw:resultSetId> not supported
  61. // <srw:resultSetIdleTime> not supported
  62. $srwRecordsBranch = new XMLBranch("srw:records");
  63. if ($showRowsOriginal != 0) // we omit the records list in the response if the SRU query did contain 'maximumRecords=0'
  64. {
  65. $exportArray = array(); // Array for individually exported records
  66. // Generate the export for each record and push them onto an array:
  67. for ($rowCounter=0; (($rowCounter < $showRows) && ($row = @ mysqli_fetch_array($result))); $rowCounter++)
  68. {
  69. if (preg_match("/DC/i", $exportFormat)) // export the current record as DC XML (i.e. simple Dublin Core):
  70. $record = oaidcRecord($row, "srw_dc"); // function 'oaidcRecord()' is defined in 'oaidcxml.inc.php'
  71. else // by default, we export the current record as MODS XML:
  72. $record = modsRecord($row); // function 'modsRecord()' is defined in 'modsxml.inc.php'
  73. // TODO: build 'extraRecordData' for OAI-PMH (see below) using:
  74. // $row['serial'], $row['modified_date'], $row['modified_time']
  75. if (!empty($record)) // unless the record buffer is empty...
  76. array_push($exportArray, $record); // ...add it to an array of exports
  77. }
  78. $i = $rowOffset; // initialize counter
  79. // for each of the DC/MODS records in the result set...
  80. foreach ($exportArray as $record)
  81. {
  82. ++$i; // increment $i by one, then return $i
  83. $srwRecordBranch = new XMLBranch("srw:record");
  84. if (preg_match("/DC/i", $exportFormat))
  85. srwGeneratePackingSchema($srwRecordBranch, "xml", "dc");
  86. else
  87. srwGeneratePackingSchema($srwRecordBranch, "xml", "mods");
  88. $srwRecordDataBranch = new XMLBranch("srw:recordData");
  89. if (preg_match("/MODS/i", $exportFormat))
  90. {
  91. // NOTE: converting the MODS object into a string to perform search & replace actions
  92. // may be very clumsy but I don't know any better... ?:-/
  93. $recordString = $record->getXMLString();
  94. $recordString = preg_replace('/<mods/i','<mods xmlns="http://www.loc.gov/mods/v3"',$recordString);
  95. // alternatively to the above line we could add a 'mods:' identifier to all MODS XML tags:
  96. // $recordString = preg_replace("#<(/)?#","<\\1mods:",$recordString);
  97. $record->removeAllBranches();
  98. $record->parseFromString($recordString);
  99. }
  100. $srwRecordDataBranch->addXMLasBranch($record);
  101. $srwRecordBranch->addXMLBranch($srwRecordDataBranch);
  102. // TODO: add 'extraRecordData' for OAI-PMH as explained in <http://www.dlib.org/dlib/february05/sanderson/02sanderson.html>
  103. // Example:
  104. // <extraRecordData>
  105. // <oai:header xmlns:oai="http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
  106. // <oai:identifier>...</oai:identifier>
  107. // <oai:datestamp>...</oai:datestamp>
  108. // <oai:setSpec>...</oai:setSpec>
  109. // </oai:header>
  110. // </extraRecordData>
  111. //
  112. // Then add to the SRW 'Explain' response:
  113. // 1. an oai.identifier index containing a unique identifier for each record in the database
  114. // 2. an oai.datestamp index containing the date/time the record was added or changed in the database
  115. // 3. an optional oai.set index, browsable via the scan operation, to support selective harvesting of records
  116. addNewBranch($srwRecordBranch, "srw:recordPosition", array(), $i);
  117. $srwRecordsBranch->addXMLBranch($srwRecordBranch);
  118. }
  119. }
  120. $srwCollection->addXMLBranch($srwRecordsBranch);
  121. if (($showRowsOriginal != 0) && ($showMaxRow < $rowsFound)) // show 'nextRecordPosition' if the SRU query did not contain 'maximumRecords=0' and if there are any remaining records to be displayed
  122. addNewBranch($srwCollection, "srw:nextRecordPosition", array(), ($showMaxRow + 1));
  123. $srwCollectionDoc->setXML($srwCollection);
  124. $srwCollectionString = $srwCollectionDoc->getXMLString();
  125. // Add the XML Stylesheet definition:
  126. // Note that this is just a hack (that should get fixed) since I don't know how to do it properly using the ActiveLink PHP XML Package ?:-/
  127. if (!empty($exportStylesheet))
  128. $srwCollectionString = preg_replace("/(?=\<srw:searchRetrieveResponse)/i","<?xml-stylesheet type=\"text/xsl\" href=\"" . $exportStylesheet . "\"?>\n",$srwCollectionString);
  129. return $srwCollectionString;
  130. }
  131. // --------------------------------------------------------------------
  132. // return an SRW 'explainResponse' if the SRW/U client issued either of the following:
  133. // - http://.../refs/sru.php?operation=explain
  134. // - http://.../refs/sru.php?
  135. // - http://.../refs/sru.php
  136. function srwExplainResponse($exportStylesheet)
  137. {
  138. global $contentTypeCharset; // these variables are specified in 'ini.inc.php'
  139. global $databaseBaseURL;
  140. global $officialDatabaseName;
  141. global $hostInstitutionName;
  142. global $feedbackEmail;
  143. global $logoImageURL;
  144. global $defaultLanguage;
  145. global $defaultFeedFormat;
  146. global $loc; // defined in 'locales/core.php'
  147. $srwCollectionDoc = new XMLDocument();
  148. $srwCollectionDoc->setEncoding($contentTypeCharset);
  149. $srwCollection = srwGenerateBaseTags("explainResponse");
  150. $srwRecordBranch = new XMLBranch("srw:record");
  151. srwGeneratePackingSchema($srwRecordBranch, "xml", "zeerex");
  152. $srwRecordDataBranch = new XMLBranch("srw:recordData");
  153. $srwExplainBranch = new XMLBranch("explain");
  154. $srwExplainBranch->setTagAttribute("xmlns", "http://explain.z3950.org/dtd/2.0/");
  155. $srwExplainBranch->setTagAttribute("xmlns:refb", "http://refbase.net/");
  156. // extract the protocol from the base URL:
  157. if (preg_match("#^([^:]+)://.*#",$databaseBaseURL))
  158. $databaseProtocol = preg_replace("#^([^:]+)://.*#","\\1",$databaseBaseURL);
  159. else
  160. $databaseProtocol = "";
  161. // extract the host from the base URL:
  162. if (preg_match("#^[^:]+://(?:www\.)?[^/]+.*#",$databaseBaseURL))
  163. $databaseHost = preg_replace("#^[^:]+://(?:www\.)?([^/]+).*#","\\1",$databaseBaseURL);
  164. else
  165. $databaseHost = $databaseBaseURL;
  166. // extract the path on server from the base URL:
  167. if (preg_match("#^[^:]+://(?:www\.)?[^/]+/.+#",$databaseBaseURL))
  168. $databasePathOnServer = preg_replace("#^[^:]+://(?:www\.)?[^/]+/(.+)#","\\1",$databaseBaseURL);
  169. else
  170. $databasePathOnServer = "";
  171. // get the total number of records in the database:
  172. $recordCount = getTotalNumberOfRecords(); // function 'getTotalNumberOfRecords()' is defined in 'include.inc.php'
  173. // get the default number of records per page preferred by the current user:
  174. $showRows = $_SESSION['userRecordsPerPage'];
  175. // get date/time information when the database was last modified:
  176. $lastModified = getLastModifiedDateTime(); // function 'getLastModifiedDateTime()' is defined in 'include.inc.php'
  177. // --- begin server info ------------------------------------
  178. $srwServerInfoBranch = new XMLBranch("serverInfo");
  179. $srwServerInfoBranch->setTagAttribute("protocol", "SRU");
  180. $srwServerInfoBranch->setTagAttribute("version", "1.1");
  181. if (!empty($databaseProtocol))
  182. $srwServerInfoBranch->setTagAttribute("transport", $databaseProtocol);
  183. $srwServerInfoBranch->setTagContent($databaseHost, "serverInfo/host");
  184. $srwServerInfoBranch->setTagContent("80", "serverInfo/port"); // NOTE: this should really be a variable in 'ini.inc.php' or such
  185. addNewBranch($srwServerInfoBranch, "database", array("numRecs" => $recordCount, "lastUpdate" => $lastModified), $databasePathOnServer . "sru.php"); // function 'addNewBranch()' is defined in 'webservice.inc.php'
  186. // IMPORTANT: if you want to allow remote users who are NOT logged in (userID=0) to query the refbase database
  187. // via 'sru.php' then either the 'Export' or the 'Batch export' user permission needs to be
  188. // enabled at 'user_options.php?userID=0'. This will allow export of XML records via 'sru.php'
  189. // but won't allow a user who isn't logged in to export records via the web interface. However, you
  190. // should be aware that a direct GET query like 'show.php?author=miller&submit=Export&exportFormat=MODS%20XML'
  191. // will be also allowed then!
  192. // As an alternative, you can provide explicit login information within the 'serverInfo/authentication' tag
  193. // below. But, obviously, the provided login information should be only given for an account that has the
  194. // 'Export' permission bit enabled but has otherwise limited access rights!
  195. // If the 'authentication' element is present, but empty, then it implies that authentication is required
  196. // to connect to the server, however there is no publically available login. If it contains a string, then
  197. // this is the token to give in order to authenticate. Otherwise it may contain three elements:
  198. // 1. user: The username to supply.
  199. // 2. group: The group to supply.
  200. // 3. password: The password to supply.
  201. // $srwServerInfoAuthenticationBranch = new XMLBranch("authentication");
  202. // $srwServerInfoAuthenticationBranch->setTagContent("LOGINEMAIL", "authentication/user");
  203. // $srwServerInfoAuthenticationBranch->setTagContent("PASSWORD", "authentication/password");
  204. // $srwServerInfoBranch->addXMLBranch($srwServerInfoAuthenticationBranch);
  205. $srwExplainBranch->addXMLBranch($srwServerInfoBranch);
  206. // --- end server info --------------------------------------
  207. // --- begin database info ----------------------------------
  208. $srwDatabaseInfoBranch = new XMLBranch("databaseInfo");
  209. addNewBranch($srwDatabaseInfoBranch, "title", array("lang" => $defaultLanguage, "primary" => "true"), $officialDatabaseName);
  210. addNewBranch($srwDatabaseInfoBranch, "description", array("lang" => $defaultLanguage, "primary" => "true"), encodeHTMLspecialchars($loc["ThisDatabaseAttempts"]));
  211. $srwDatabaseInfoBranch->setTagContent(encodeHTMLspecialchars($hostInstitutionName), "databaseInfo/author");
  212. $srwDatabaseInfoBranch->setTagContent(encodeHTMLspecialchars($hostInstitutionName) . " (" . $feedbackEmail . ")", "databaseInfo/contact");
  213. $srwDatabaseImplementationBranch = new XMLBranch("implementation");
  214. $srwDatabaseImplementationBranch->setTagAttribute("version", "0.9.6");
  215. $srwDatabaseImplementationBranch->setTagAttribute("identifier", "refbase");
  216. $srwDatabaseImplementationBranch->setTagContent("Web Reference Database (http://refbase.sourceforge.net)", "implementation/title");
  217. $srwDatabaseInfoBranch->addXMLBranch($srwDatabaseImplementationBranch);
  218. $srwDatabaseLinksBranch = new XMLBranch("links");
  219. addNewBranch($srwDatabaseLinksBranch, "link", array("type" => "www"), $databaseBaseURL);
  220. addNewBranch($srwDatabaseLinksBranch, "link", array("type" => "sru"), $databaseBaseURL . "sru.php");
  221. addNewBranch($srwDatabaseLinksBranch, "link", array("type" => "rss"), $databaseBaseURL . generateURL("show.php", $defaultFeedFormat, array("where" => 'serial RLIKE ".+"'), true, $showRows)); // function 'generateURL()' is defined in 'include.inc.php'
  222. addNewBranch($srwDatabaseLinksBranch, "link", array("type" => "icon"), $databaseBaseURL . $logoImageURL);
  223. $srwDatabaseInfoBranch->addXMLBranch($srwDatabaseLinksBranch);
  224. $srwExplainBranch->addXMLBranch($srwDatabaseInfoBranch);
  225. // --- end database info ------------------------------------
  226. // --- begin index info -------------------------------------
  227. $srwIndexInfoBranch = new XMLBranch("indexInfo");
  228. addNewBranch($srwIndexInfoBranch, "set", array("identifier" => "info:srw/cql-context-set/1/cql-v1.1", "name" => "cql"), "");
  229. addNewBranch($srwIndexInfoBranch, "set", array("identifier" => "info:srw/cql-context-set/1/dc-v1.1", "name" => "dc"), "");
  230. addNewBranch($srwIndexInfoBranch, "set", array("identifier" => "http://zing.z3950.org/cql/bath/2.0/", "name" => "bath"), "");
  231. addNewBranch($srwIndexInfoBranch, "set", array("identifier" => "info:srw/cql-context-set/2/rec-1.1", "name" => "rec"), "");
  232. // TODO: The index info of the refbase explain response should also list the original refbase field names,
  233. // similar to how the COPAC SRU gateway does it (<http://tweed.lib.ed.ac.uk:8080/elf/search/copac>).
  234. // Example:
  235. // <index search="true" scan="false" sort="false">
  236. // <title>Author</title>
  237. // <map>
  238. // <name>
  239. // author
  240. // </name>
  241. // </map>
  242. // <map>
  243. // <name set="dc">
  244. // creator
  245. // </name>
  246. // </map>
  247. // </index>
  248. $indexArray = array(); // TODO: '$indexArray' should be an array of arrays so that it can hold multiple mappings
  249. $indexArray["dc.creator"] = array("_set" => "dc",
  250. "_index" => "creator",
  251. "_title" => "author(s) of the resource",
  252. "_refbaseIndex" => "refbase-author");
  253. $indexArray["dc.title"] = array("_set" => "dc",
  254. "_index" => "title",
  255. "_title" => "publication title of the resource",
  256. "_refbaseIndex" => "refbase-title");
  257. $indexArray["dc.date"] = array("_set" => "dc",
  258. "_index" => "date",
  259. "_title" => "year of publication of the resource",
  260. "_refbaseIndex" => "refbase-year");
  261. $indexArray["dc.language"] = array("_set" => "dc",
  262. "_index" => "language",
  263. "_title" => "language of the resource",
  264. "_refbaseIndex" => "refbase-language");
  265. $indexArray["dc.description"] = array("_set" => "dc",
  266. "_index" => "description",
  267. "_title" => "abstract or summary of the resource",
  268. "_refbaseIndex" => "refbase-abstract");
  269. $indexArray["dc.contributor"] = array("_set" => "dc",
  270. "_index" => "contributor",
  271. "_title" => "editor(s) of the resource",
  272. "_refbaseIndex" => "refbase-editor"); // the mapping dc.contributor <-> refbase-editor might be suboptimal, but probably as best as we can do for now
  273. $indexArray["dc.subject"] = array("_set" => "dc",
  274. "_index" => "subject",
  275. "_title" => "topic of the resource",
  276. "_refbaseIndex" => "refbase-keywords");
  277. $indexArray["dc.format"] = array("_set" => "dc",
  278. "_index" => "format",
  279. "_title" => "physical or digital manifestation of the resource",
  280. "_refbaseIndex" => "refbase-medium");
  281. // Note: Currently, we simply expose the contents of the refbase 'type' field as 'dc.type'.
  282. // This may not be ideal since it differs from the approved terms that should be used as values for the 'dc.type' element: <http://dublincore.org/documents/dcmi-type-vocabulary/>.
  283. // However, the document "Using simple Dublin Core to describe eprints" (<http://eprints-uk.rdn.ac.uk/project/docs/simpledc-guidelines/#type>)
  284. // recommends type values that are much closer (but still not identical) to our own type values.
  285. $indexArray["dc.type"] = array("_set" => "dc",
  286. "_index" => "type",
  287. "_title" => "nature or genre of the resource",
  288. "_refbaseIndex" => "refbase-type");
  289. $indexArray["dc.publisher"] = array("_set" => "dc",
  290. "_index" => "publisher",
  291. "_title" => "publisher",
  292. "_refbaseIndex" => "refbase-publisher");
  293. $indexArray["dc.coverage"] = array("_set" => "dc",
  294. "_index" => "coverage",
  295. "_title" => "geographic or topographic area of research",
  296. "_refbaseIndex" => "refbase-area");
  297. // Note: I'm note sure, if 'bath.name' (or maybe better: 'bath.personalName') can be also used to describe the author/creator ('dc.creator') of a publication
  298. // "'Name Search -- Keyword' searches for complete word in headings (or references) for people, corporate bodies, conferences, and geographic names."
  299. // $indexArray["bath.name"] = array("_set" => "bath",
  300. // "_index" => "name",
  301. // "_title" => "author",
  302. // "_refbaseIndex" => "refbase-author");
  303. // Note: Not sure again whether 'bath.topicalSubject' can be offered as synonym for 'dc.subject'
  304. // "'Topical Subject Search -- Keyword' searches for complete word in a topical subject heading or reference."
  305. // $indexArray["bath.topicalSubject"] = array("_set" => "bath",
  306. // "_index" => "topicalSubject",
  307. // "_title" => "keywords",
  308. // "_refbaseIndex" => "refbase-keywords");
  309. // NOTE: I'm not sure if 'isbn' is a valid name for the Bath Context Set? At least, it's not listed at <http://zing.z3950.org/srw/bath/2.0/#2>.
  310. // However, 'bath.isbn' is used e.g. by <http://z3950.loc.gov:7090/voyager?operation=explain&version=1.1> and other SRU servers.
  311. $indexArray["bath.isbn"] = array("_set" => "bath",
  312. "_index" => "isbn",
  313. "_title" => "international standard book number",
  314. "_refbaseIndex" => "refbase-isbn");
  315. $indexArray["bath.issn"] = array("_set" => "bath",
  316. "_index" => "issn",
  317. "_title" => "international standard serial number",
  318. "_refbaseIndex" => "refbase-issn");
  319. $indexArray["bath.corporateName"] = array("_set" => "bath",
  320. "_index" => "corporateName",
  321. "_title" => "corporate author of this publication",
  322. "_refbaseIndex" => "refbase-corporate_author");
  323. $indexArray["bath.conferenceName"] = array("_set" => "bath",
  324. "_index" => "conferenceName",
  325. "_title" => "conference this publication was presented at",
  326. "_refbaseIndex" => "refbase-conference");
  327. // NOTE: I'm not sure if 'notes' is a valid name for the Bath Context Set?
  328. // 'bath.notes' is mentioned at <http://www.loc.gov/z3950/lcserver.html> and <http://zing.z3950.org/srw/bath/2.0/#3>.
  329. $indexArray["bath.notes"] = array("_set" => "bath",
  330. "_index" => "notes",
  331. "_title" => "notes about the resource",
  332. "_refbaseIndex" => "refbase-notes");
  333. $indexArray["rec.identifier"] = array("_set" => "rec",
  334. "_index" => "identifier",
  335. "_title" => "database record number",
  336. "_refbaseIndex" => "refbase-serial");
  337. $indexArray["rec.creationDate"] = array("_set" => "rec",
  338. "_index" => "creationDate",
  339. "_title" => "date/time at which the record was created",
  340. "_refbaseIndex" => "refbase-created_date-created_time"); // 'sru.php': CQL search term should get splitted into date & time information!
  341. $indexArray["rec.creationAgentName"] = array("_set" => "rec",
  342. "_index" => "creationAgentName",
  343. "_title" => "name of the agent responsible for creation of the record",
  344. "_refbaseIndex" => "refbase-created_by");
  345. $indexArray["rec.lastModificationDate"] = array("_set" => "rec",
  346. "_index" => "lastModificationDate",
  347. "_title" => "date/time at which the record was last modified",
  348. "_refbaseIndex" => "refbase-modified_date-modified_time"); // 'sru.php': CQL search term should get splitted into date & time information!
  349. $indexArray["rec.lastModificationAgentName"] = array("_set" => "rec",
  350. "_index" => "lastModificationAgentName",
  351. "_title" => "name of the agent responsible for last modifying the record",
  352. "_refbaseIndex" => "refbase-modified_by");
  353. $indexArray["bib.citekey"] = array("_set" => "bib",
  354. "_index" => "citekey",
  355. "_title" => "user-specific cite key for the record",
  356. "_refbaseIndex" => "refbase-cite_key");
  357. // Not sure how these fields can be mapped:
  358. // "publication" => "Book title or journal name",
  359. // "abbrev_journal" => "Abbreviated journal name",
  360. // "volume" => "Publication volume",
  361. // "issue" => "Publication issue",
  362. // "pages" => "Range or total number of pages",
  363. // "place" => "Place of publication",
  364. // "series_title" => "Series title", // -> could 'bath.seriesTitle' be used? compare with <http://www.loc.gov/z3950/lcserver.html> and <http://copac.ac.uk/interfaces/srw/>
  365. // "abbrev_series_title" => "Abbreviated series title",
  366. // "series_volume" => "Series volume",
  367. // "series_issue" => "Series issue",
  368. // "thesis" => "Thesis",
  369. // "doi" => "Digital object identifier",
  370. // "url" => "Uniform resource locator",
  371. foreach ($indexArray as $indexKey => $index)
  372. {
  373. $srwIndexBranch = new XMLBranch("index");
  374. $srwIndexBranch->setTagAttribute("search", "true");
  375. $srwIndexBranch->setTagAttribute("scan", "false");
  376. $srwIndexBranch->setTagAttribute("sort", "false");
  377. $srwIndexBranch->setTagAttribute("refb:index", $index["_refbaseIndex"]);
  378. addNewBranch($srwIndexBranch, "title", array("lang" => "en"), $index["_title"]);
  379. $srwIndexMapBranch = new XMLBranch("map");
  380. addNewBranch($srwIndexMapBranch, "name", array("set" => $index["_set"]), $index["_index"]);
  381. $srwIndexBranch->addXMLBranch($srwIndexMapBranch);
  382. $srwIndexInfoBranch->addXMLBranch($srwIndexBranch);
  383. }
  384. $srwExplainBranch->addXMLBranch($srwIndexInfoBranch);
  385. // --- end index info ---------------------------------------
  386. // --- begin schema info -------------------------------------
  387. $srwSchemaInfoBranch = new XMLBranch("schemaInfo");
  388. // MODS:
  389. $modsSchemaBranch = new XMLBranch("schema");
  390. $modsSchemaBranch->setTagAttribute("identifier", "http://www.loc.gov/mods/v3"); // or should 'info:srw/schema/1/mods-v3.2' be used?
  391. $modsSchemaBranch->setTagAttribute("location", "http://www.loc.gov/standards/mods/v3/mods-3-0.xsd");
  392. $modsSchemaBranch->setTagAttribute("sort", "false");
  393. $modsSchemaBranch->setTagAttribute("retrieve", "true");
  394. $modsSchemaBranch->setTagAttribute("name", "mods");
  395. addNewBranch($modsSchemaBranch, "title", array("lang" => "en"), "Metadata Object Description Schema (MODS) v3");
  396. $srwSchemaInfoBranch->addXMLBranch($modsSchemaBranch);
  397. // Simple Dublin Core (DC):
  398. $dcSchemaBranch = new XMLBranch("schema");
  399. $dcSchemaBranch->setTagAttribute("identifier", "http://purl.org/dc/elements/1.1/"); // or should 'info:srw/schema/1/dc-v1.1' be used?
  400. $dcSchemaBranch->setTagAttribute("location", "http://dublincore.org/schemas/xmls/simpledc20021212.xsd");
  401. $dcSchemaBranch->setTagAttribute("sort", "false");
  402. $dcSchemaBranch->setTagAttribute("retrieve", "true");
  403. $dcSchemaBranch->setTagAttribute("name", "dc");
  404. addNewBranch($dcSchemaBranch, "title", array("lang" => "en"), "Simple Dublin Core (DC) v1.1");
  405. $srwSchemaInfoBranch->addXMLBranch($dcSchemaBranch);
  406. // Simple Dublin Core (OAI_DC):
  407. // See recommendations for use of simple Dublin Core metadata to describe eprints in eprint archives: <http://eprints-uk.rdn.ac.uk/project/docs/simpledc-guidelines/>
  408. // Example SRW+DC output from LoC: <http://z3950.loc.gov:7090/voyager?query=dc.creator+%3D+%22miller%22&version=1.1&operation=searchRetrieve&recordSchema=dc&startRecord=1&maximumRecords=10>
  409. // $oaidcSchemaBranch = new XMLBranch("schema");
  410. // $oaidcSchemaBranch->setTagAttribute("identifier", "http://www.openarchives.org/OAI/2.0/oai_dc/");
  411. // $oaidcSchemaBranch->setTagAttribute("location", "http://www.openarchives.org/OAI/2.0/oai_dc.xsd");
  412. // $oaidcSchemaBranch->setTagAttribute("sort", "false");
  413. // $oaidcSchemaBranch->setTagAttribute("retrieve", "true");
  414. // $oaidcSchemaBranch->setTagAttribute("name", "oai_dc");
  415. //
  416. // addNewBranch($oaidcSchemaBranch, "title", array("lang" => "en"), "Simple Dublin Core for OAI-PMH (OAI_DC)");
  417. //
  418. // $srwSchemaInfoBranch->addXMLBranch($oaidcSchemaBranch);
  419. $srwExplainBranch->addXMLBranch($srwSchemaInfoBranch);
  420. // --- end schema info ---------------------------------------
  421. // --- begin config info -------------------------------------
  422. $srwConfigInfoBranch = new XMLBranch("configInfo");
  423. // default:
  424. addNewBranch($srwConfigInfoBranch, "default", array("type" => "retrieveSchema"), "mods");
  425. addNewBranch($srwConfigInfoBranch, "default", array("type" => "numberOfRecords"), $showRows);
  426. addNewBranch($srwConfigInfoBranch, "default", array("type" => "stylesheet"), $databaseBaseURL . "srwmods2html.xsl");
  427. addNewBranch($srwConfigInfoBranch, "default", array("type" => "contextSet"), "cql");
  428. addNewBranch($srwConfigInfoBranch, "default", array("type" => "index"), "cql.serverChoice");
  429. addNewBranch($srwConfigInfoBranch, "default", array("type" => "relation"), "all");
  430. // setting:
  431. addNewBranch($srwConfigInfoBranch, "setting", array("type" => "sortSchema"), "identifier");
  432. addNewBranch($srwConfigInfoBranch, "setting", array("type" => "recordPacking"), "xml");
  433. // supports:
  434. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "proximity"), "false");
  435. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "resultSets"), "false");
  436. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "relationModifier"), "false");
  437. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "booleanModifier"), "false"); // TODO: set to 'true' when Rob's CQL-PHP has been implemented successfully
  438. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "sort"), "false");
  439. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "maskingCharacter"), "true");
  440. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "anchoring"), "true");
  441. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "emptyTerm"), "false");
  442. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "recordXPath"), "false");
  443. addNewBranch($srwConfigInfoBranch, "supports", array("type" => "scan"), "false");
  444. $srwExplainBranch->addXMLBranch($srwConfigInfoBranch);
  445. // --- end config info ---------------------------------------
  446. $srwRecordDataBranch->addXMLBranch($srwExplainBranch);
  447. $srwRecordBranch->addXMLBranch($srwRecordDataBranch);
  448. $srwCollection->addXMLBranch($srwRecordBranch);
  449. $srwCollectionDoc->setXML($srwCollection);
  450. $srwCollectionString = $srwCollectionDoc->getXMLString();
  451. // Add the XML Stylesheet definition:
  452. // Note that this is just a hack (that should get fixed) since I don't know how to do it properly using the ActiveLink PHP XML Package ?:-/
  453. if (!empty($exportStylesheet))
  454. $srwCollectionString = preg_replace("/(?=\<srw:explainResponse)/i","<?xml-stylesheet type=\"text/xsl\" href=\"" . $exportStylesheet . "\"?>\n",$srwCollectionString);
  455. return $srwCollectionString;
  456. }
  457. // --------------------------------------------------------------------
  458. // Return SRW diagnostics (i.e. SRW error information) wrapped into SRW XML ('searchRetrieveResponse'):
  459. function srwDiagnostics($diagCode, $diagDetails, $exportStylesheet)
  460. {
  461. global $contentTypeCharset; // defined in 'ini.inc.php'
  462. // Map SRU/W diagnostic numbers to their corresponding messages:
  463. $diagMessages = mapSRWDiagnostics(); // function 'mapSRWDiagnostics()' is defined in 'webservice.inc.php'
  464. if (isset($diagMessages[$diagCode]))
  465. $diagMessage = $diagMessages[$diagCode];
  466. else
  467. $diagMessage = "Unknown error";
  468. $srwCollectionDoc = new XMLDocument();
  469. $srwCollectionDoc->setEncoding($contentTypeCharset);
  470. $srwCollection = srwGenerateBaseTags("searchRetrieveResponse");
  471. $diagnosticsBranch = new XMLBranch("srw:diagnostics");
  472. // since we've defined the 'diag' namespace in the <searchRetrieveResponse> element (see function 'srwGenerateBaseTags()'),
  473. // we can simply use '<diag:diagnostic>' below; otherwise we should use '<diagnostic xmlns="http://www.loc.gov/zing/srw/diagnostic/">':
  474. // addNewBranch($diagnosticsBranch, "diagnostic", array("xmlns" => "http://www.loc.gov/zing/srw/diagnostic/"), "");
  475. $diagnosticsBranch->setTagContent("info:srw/diagnostic/1/" . $diagCode, "srw:diagnostics/diag:diagnostic/uri");
  476. $diagnosticsBranch->setTagContent($diagMessage, "srw:diagnostics/diag:diagnostic/message");
  477. if (!empty($diagDetails))
  478. $diagnosticsBranch->setTagContent(encodeHTMLspecialchars($diagDetails), "srw:diagnostics/diag:diagnostic/details");
  479. $srwCollection->addXMLBranch($diagnosticsBranch);
  480. $srwCollectionDoc->setXML($srwCollection);
  481. $srwCollectionString = $srwCollectionDoc->getXMLString();
  482. // Add the XML Stylesheet definition:
  483. // Note that this is just a hack (that should get fixed) since I don't know how to do it properly using the ActiveLink PHP XML Package ?:-/
  484. if (!empty($exportStylesheet))
  485. $srwCollectionString = preg_replace("/(?=\<srw:searchRetrieveResponse)/i","<?xml-stylesheet type=\"text/xsl\" href=\"" . $exportStylesheet . "\"?>\n",$srwCollectionString);
  486. return $srwCollectionString;
  487. }
  488. // --------------------------------------------------------------------
  489. // Generate the basic SRW XML tree required for a 'searchRetrieveResponse' or 'explainResponse':
  490. function srwGenerateBaseTags($srwOperation)
  491. {
  492. global $exportFormat; // this is needed so that we can distinguish between "SRW_DC XML" and "SRW_MODS XML" record formats
  493. $srwCollection = new XML("srw:" . $srwOperation);
  494. $srwCollection->setTagAttribute("xmlns:srw", "http://www.loc.gov/zing/srw/");
  495. if ($srwOperation == "searchRetrieveResponse")
  496. {
  497. $srwCollection->setTagAttribute("xmlns:diag", "http://www.loc.gov/zing/srw/diagnostic/");
  498. $srwCollection->setTagAttribute("xmlns:xcql", "http://www.loc.gov/zing/cql/xcql/");
  499. if (preg_match("/DC/i", $exportFormat)) // add namespace declarations for "SRW_DC XML":
  500. {
  501. $srwCollection->setTagAttribute("xmlns:srw_dc", "info:srw/schema/1/dc-v1.1");
  502. $srwCollection->setTagAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
  503. $srwCollection->setTagAttribute("xmlns:prism", "http://prismstandard.org/namespaces/1.2/basic/");
  504. }
  505. else // add namespace declarations for "SRW_MODS XML":
  506. $srwCollection->setTagAttribute("xmlns:mods", "http://www.loc.gov/mods/v3");
  507. }
  508. // elseif ($srwOperation == "explainResponse")
  509. // {
  510. // $srwCollection->setTagAttribute("xmlns:zr", "http://explain.z3950.org/dtd/2.0/");
  511. // }
  512. addNewBranch($srwCollection, "srw:version", array(), "1.1"); // function 'addNewBranch()' is defined in 'webservice.inc.php'
  513. return $srwCollection;
  514. }
  515. // --------------------------------------------------------------------
  516. // Generate the basic SRW XML elements 'recordPacking' and 'recordSchema':
  517. function srwGeneratePackingSchema(&$thisObject, $srwPacking, $srwSchema)
  518. {
  519. // available schemas taken from <http://www.loc.gov/z3950/agency/zing/srw/record-schemas.html>
  520. $srwSchemas = array("dc" => "info:srw/schema/1/dc-v1.1", // or should <http://purl.org/dc/elements/1.1/> be used?
  521. // "dcterms" => "http://purl.org/dc/terms/",
  522. "diag" => "info:srw/schema/1/diagnostic-v1.1", // it says 'info:srw/schema/1/diagnostics-v1.1' at <http://www.loc.gov/standards/sru/diagnostics.html> ?:-/
  523. "zeerex" => "http://explain.z3950.org/dtd/2.0/",
  524. "mods" => "info:srw/schema/1/mods-v3.2",
  525. "onix" => "info:srw/schema/1/onix-v2.0",
  526. "marcxml" => "info:srw/schema/1/marcxml-v1.1",
  527. "ead" => "info:srw/schema/1/ead-2002",
  528. "zthes" => "http://zthes.z3950.org/xml/0.5/",
  529. "ccg" => "http://srw.cheshire3.org/schemas/ccg/1.0/",
  530. "rec" => "info:srw/schema/2/rec-1.0",
  531. "server-choice" => "info:srw/schema/1/server-choice",
  532. "xpath" => "info:srw/schema/1/xpath-1.0");
  533. addNewBranch($thisObject, "srw:recordPacking", array(), $srwPacking); // function 'addNewBranch()' is defined in 'webservice.inc.php'
  534. addNewBranch($thisObject, "srw:recordSchema", array(), $srwSchemas[$srwSchema]);
  535. }
  536. // --------------------------------------------------------------------
  537. ?>