PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Xerxes/Citation.php

http://xerxes-portal.googlecode.com/
PHP | 665 lines | 325 code | 149 blank | 191 comment | 60 complexity | f8dd3f46833cdae45a089d2beef1ddcb MD5 | raw file
  1. <?php
  2. /**
  3. * Citation Style Language Engine
  4. *
  5. * TODO: look at this http://xbiblio.svn.sourceforge.net/viewvc/xbiblio/csl/schema/trunk/csl-terms.rnc?view=markup
  6. *
  7. * @author David Walker
  8. * @copyright 2009 California State University
  9. * @version $Id: Citation.php 1030 2010-01-05 18:42:09Z dwalker@calstate.edu $
  10. * @package Xerxes
  11. * @link http://xerxes.calstate.edu
  12. * @license http://www.gnu.org/licenses/
  13. */
  14. class Xerxes_Citation
  15. {
  16. private $data; // the supplied data object to be formatted, yo!
  17. private $csl; // simple-xml object csl file
  18. private $formatted = ""; // final formatted citation
  19. private $bibliography_options = array(); // bibliography options
  20. private $citation_options = array(); // citation options
  21. public function loadStyle($file)
  22. {
  23. $this->csl = new SimpleXMLElement($file, null, true);
  24. $this->csl->registerXPathNamespace("csl", "http://purl.org/net/xbiblio/csl");
  25. }
  26. public function process($record)
  27. {
  28. if ( $record instanceof Xerxes_Record )
  29. {
  30. $record = $this->convertXerxesRecord($record);
  31. }
  32. // check to make sure a csl file has been loaded first
  33. if ( ! $this->csl instanceof SimpleXMLElement )
  34. {
  35. throw new Exception( "must load a csl file via loadStyle() before processing" );
  36. }
  37. // blank the previously processed citation
  38. $this->formatted = "";
  39. // set the new data object as a property
  40. $this->data = $record;
  41. // bibliography
  42. $this->recursive($this->csl->bibliography);
  43. echo $this->formatted;
  44. }
  45. private function convertXerxesRecord(Xerxes_Record $xerxes)
  46. {
  47. $citation = new Xerxes_Citation_Data();
  48. $map = array (
  49. "type" => "format",
  50. "issued" => "year",
  51. // "accessed" => "",
  52. "number" => "",
  53. "number_of_volumes" => "",
  54. // "container_title" => "",
  55. // "collection_title" => "",
  56. "publisher_place" => "place",
  57. "event" => "",
  58. "event_place" => "",
  59. "page" => "startPage",
  60. "locator" => "",
  61. "genre" => "format"
  62. // "url" => "",
  63. );
  64. foreach ( $citation as $key => $value )
  65. {
  66. if ( $key == "names")
  67. {
  68. foreach ( $xerxes->getAuthors() as $author )
  69. {
  70. $name = new Xerxes_Citation_Name();
  71. foreach ( $author as $key => $value )
  72. {
  73. $name->$key = $value;
  74. }
  75. array_push($citation->names, $name);
  76. }
  77. }
  78. $target = $key;
  79. if ( array_key_exists($key, $map) )
  80. {
  81. $target = $map[$key];
  82. }
  83. $method = Xerxes_Framework_Parser::strtoupper(substr($target, 0, 1));
  84. $method .= substr($target, 1);
  85. $method = "get$method";
  86. if ( method_exists($xerxes, $method) )
  87. {
  88. $citation->$key = $xerxes->$method();
  89. }
  90. }
  91. print_r($citation);
  92. }
  93. private function choose($choose)
  94. {
  95. foreach ( $choose->children() as $condition )
  96. {
  97. if ( $condition->getName() == "if" || $condition->getName() == "else-if" )
  98. {
  99. $match = (string) $condition["match"];
  100. // check the data type
  101. if ( $condition["type"] )
  102. {
  103. $done = false;
  104. $arrTypes = explode(" ", (string) $condition["type"]);
  105. foreach ( $arrTypes as $type )
  106. {
  107. if ( $this->data->type == $type )
  108. {
  109. if ( $match == "any")
  110. {
  111. $done = true;
  112. break;
  113. }
  114. elseif ( $match == "none")
  115. {
  116. $done = false;
  117. break;
  118. }
  119. else // all or default?
  120. {
  121. $done = true;
  122. }
  123. }
  124. else
  125. {
  126. if ( $match == "all")
  127. {
  128. $done = false;
  129. break;
  130. }
  131. if ( $match == "none")
  132. {
  133. $done = true;
  134. }
  135. }
  136. }
  137. if ( $done == true )
  138. {
  139. return $condition;
  140. }
  141. }
  142. // checking to see if a property of the data object exists
  143. elseif ( $condition["variable"] )
  144. {
  145. $variable = (string) $condition["variable"];
  146. if ( isset($this->data->$variable) )
  147. {
  148. return $condition;
  149. }
  150. }
  151. elseif ( $condition["is-numeric"] )
  152. {
  153. $variable = (string) $condition["is-numeric"];
  154. if ( isset($this->data->$variable) )
  155. {
  156. if ( (int) $this->data->$variable != 0 )
  157. {
  158. return $condition;
  159. }
  160. }
  161. }
  162. elseif ( $condition["is-date"] )
  163. {
  164. $variable = (string) $condition["is-date"];
  165. if ( isset($this->data->$variable) )
  166. {
  167. if ( $this->data->$variable instanceof Xerxes_Citation_Date )
  168. {
  169. return $condition;
  170. }
  171. }
  172. }
  173. // position { "first" | "subsequent" | "ibid" | "ibid-with-locator" }
  174. // disambiguate
  175. // locator
  176. }
  177. elseif ( $condition->getName() == "else")
  178. {
  179. return $condition;
  180. }
  181. else
  182. {
  183. throw new Exception("child of choose must be 'if', 'else-if' or 'else'");
  184. }
  185. }
  186. }
  187. private function text($text)
  188. {
  189. // get the text from the bib data
  190. if ( $text["variable"] )
  191. {
  192. $variable = (string) $text["variable"];
  193. if ( isset($this->data->$variable) )
  194. {
  195. $data = $this->data->$variable;
  196. }
  197. }
  198. // get the text from a macro
  199. if ( $text["macro"] )
  200. {
  201. $macro_name = (string) $text["macro"];
  202. $macros = $this->csl->xpath("//csl:macro[@name ='$macro_name']");
  203. if ( count($macros) == 1 )
  204. {
  205. $this->recursive($macros[0]);
  206. }
  207. else
  208. {
  209. throw new Exception("no macro defined for '$macro_name'");
  210. }
  211. }
  212. }
  213. private function formatting($data, $node)
  214. {
  215. $style = ""; // stylistic rendering
  216. // stylistic elements
  217. foreach ( $node->attributes as $attribute )
  218. {
  219. if ( $attribute->getName() == "font-family" ||
  220. $attribute->getName() == "font-style" ||
  221. $attribute->getName() == "font-variant" ||
  222. $attribute->getName() == "font-weight" ||
  223. $attribute->getName() == "text-decoration" ||
  224. $attribute->getName() == "vertical-align" ||
  225. $attribute->getName() == "display")
  226. {
  227. $style .= " " . $attribute->getName() . ": " . (string) $attribute;
  228. }
  229. }
  230. // capitalization
  231. if ( $node["text-case"] )
  232. {
  233. switch ( (string) $node["text-case"] )
  234. {
  235. case "lowercase":
  236. $data = Xerxes_Framework_Parser::strtolower($data);
  237. break;
  238. case "uppercase":
  239. $data = Xerxes_Framework_Parser::strtoupper($data);
  240. break;
  241. case "capitalize-first":
  242. case "sentence":
  243. $data = Xerxes_Framework_Parser::strtoupper(substr($data, 0, 1)) . substr($data, 1);
  244. break;
  245. case "capitalize-all":
  246. //TODO: add this to parser?
  247. break;
  248. case "title":
  249. //TODO: make reference to parser?
  250. break;
  251. }
  252. }
  253. // stylistic rendering
  254. if ( $style != "" )
  255. {
  256. $data = "<span style=\"$style\">$data</span>";
  257. }
  258. // add quotes
  259. if ( $node["quotes"] )
  260. {
  261. $data = "\"" . $data . "\"";
  262. }
  263. return $node["prefix"] . $data . $node["suffix"];
  264. }
  265. private function recursive($element)
  266. {
  267. $name = $element->getName();
  268. if ($name == "choose")
  269. {
  270. $fork = $this->choose($element);
  271. if ( $fork != null )
  272. {
  273. $this->recursive($fork);
  274. }
  275. }
  276. else
  277. {
  278. if ( method_exists($this, $name) )
  279. {
  280. return $this->{$name}($element);
  281. }
  282. foreach ( $element->children() as $element_child )
  283. {
  284. $this->recursive($element_child);
  285. }
  286. }
  287. }
  288. private function load_options()
  289. {
  290. // citation: et-al | et-al-subsequent | disambiguate | collapse
  291. // bibliography: et-al | hanging-indent | second-field-align | subsequent-author-substitute | line-formatting
  292. foreach ( $this->csl->bibliography->option as $option )
  293. {
  294. $name = (string) $option["name"];
  295. $value = (string) $option["value"];
  296. $this->bibliography_options[$name] = $value;
  297. }
  298. }
  299. }
  300. class Xerxes_Citation_Data
  301. {
  302. /**
  303. * article
  304. * article-magazine
  305. * article-newspaper
  306. * article-journal
  307. * bill
  308. * book
  309. * broadcast
  310. * chapter
  311. * entry
  312. * entry-dictionary
  313. * entry-encyclopedia
  314. * figure
  315. * graphic
  316. * interview
  317. * legislation
  318. * legal_case
  319. * manuscript
  320. * map
  321. * motion_picture
  322. * musical_score
  323. * pamphlet
  324. * paper-conference
  325. * patent
  326. * post
  327. * post-weblog
  328. * personal_communication
  329. * report
  330. * review
  331. * review-book
  332. * song
  333. * speech
  334. * thesis
  335. * treaty
  336. * webpage
  337. */
  338. public $type;
  339. // names
  340. public $names = array();
  341. /**
  342. * the primary title for the cited item
  343. */
  344. public $title;
  345. /**
  346. * the secondary title for the cited item; for a book chapter, this
  347. * would be a book title, for an article the journal title, etc.
  348. */
  349. public $container_title;
  350. /**
  351. * the tertiary title for the cited item; for example, a series title
  352. */
  353. public $collection_title;
  354. /**
  355. * collection number; for example, series number
  356. */
  357. public $collection_number;
  358. /**
  359. * title of a related original version; often useful in cases of translation
  360. */
  361. public $original_title;
  362. /**
  363. * the name of the publisher
  364. */
  365. public $publisher;
  366. /**
  367. * the location of the publisher
  368. */
  369. public $publisher_place;
  370. /**
  371. * the name of the archive
  372. */
  373. public $archive;
  374. /**
  375. * the location of the archive
  376. */
  377. public $archive_place;
  378. /**
  379. * issuing authority (for patents) or judicial authority (such as court
  380. * for legal cases)
  381. */
  382. public $authority;
  383. /**
  384. * the location within an archival collection (for example, box and folder)
  385. */
  386. public $archive_location;
  387. /**
  388. * the name or title of a related event such as a conference or hearing
  389. */
  390. public $event;
  391. /**
  392. * the location or place for the related event
  393. */
  394. public $event_place;
  395. /**
  396. * the range of pages an item covers in a containing item
  397. */
  398. public $page;
  399. /**
  400. * the first page of an item within a containing item
  401. */
  402. public $page_first;
  403. /**
  404. * a description to locate an item within some larger container or
  405. * collection; a volume or issue number is a kind of locator, for example.
  406. */
  407. public $locator;
  408. /**
  409. * version description
  410. */
  411. public $version;
  412. /**
  413. * volume number for the container periodical
  414. */
  415. public $volume;
  416. /**
  417. * refers to the number of items in multi-volume books and such
  418. */
  419. public $number_of_volumes;
  420. /**
  421. * refers to the number of items in multi-volume books and such
  422. */
  423. public $number_of_pages;
  424. /**
  425. * the issue number for the container publication
  426. */
  427. public $issue;
  428. public $chapter_number;
  429. /**
  430. * medium description (DVD, CD, etc.)
  431. */
  432. public $medium;
  433. /**
  434. * the (typically publication) status of an item; for example "forthcoming"
  435. */
  436. public $status;
  437. /**
  438. * an edition description
  439. */
  440. public $edition;
  441. /**
  442. * a section description (for newspapers, etc.)
  443. */
  444. public $section;
  445. public $genre;
  446. /**
  447. * a short inline note, often used to refer to additional details of the resource
  448. */
  449. public $note;
  450. /**
  451. * notes made by a reader about the content of the resource
  452. */
  453. public $annote;
  454. public $abstract;
  455. public $keyword;
  456. /**
  457. * a document number; useful for reports and such
  458. */
  459. public $number;
  460. /**
  461. * for related referenced resources; this is here for legal case
  462. * histories, but may be relevant for other contexts.
  463. */
  464. public $references;
  465. public $URL;
  466. public $DOI;
  467. public $ISBN;
  468. public $call_number;
  469. /**
  470. * the number used for the in-text citation mark in numeric styles
  471. */
  472. public $citation_number;
  473. /**
  474. * the label used for the in-text citation mark in label styles
  475. */
  476. public $citation_label;
  477. /**
  478. * The number of a preceding note containing the first reference to
  479. * this item. Relevant only for note-based styles, and null for first references.
  480. */
  481. public $first_reference_note_number;
  482. /**
  483. * The year suffix for author-date styles; e.g. the 'a' in 'a'.
  484. */
  485. public $year_suffix;
  486. }
  487. class Xerxes_Citation_Date
  488. {
  489. public $year;
  490. public $month;
  491. public $day;
  492. }
  493. class Xerxes_Citation_Name
  494. {
  495. public $first;
  496. public $last;
  497. public $init;
  498. public $name;
  499. /**
  500. * the person or entitiy's role, valid values include:
  501. *
  502. * author
  503. * editor
  504. * translator
  505. * recipient
  506. * interviewer
  507. * publisher
  508. * composer
  509. * original-publisher
  510. * original-author
  511. * container-author
  512. * collection-editor
  513. */
  514. public $role;
  515. }
  516. ?>