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.

714 lines
38 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: ./cite/styles/cite_Vancouver.php
  11. // Repository: $HeadURL$
  12. // Author(s): Matthias Steffens <mailto:refbase@extracts.de>
  13. //
  14. // Created: 04-Aug-08, 12:00
  15. // Modified: $Date: 2012-02-27 20:25:30 +0000 (Mon, 27 Feb 2012) $
  16. // $Author$
  17. // $Revision: 1337 $
  18. // This is a citation style file (which must reside within the 'cite/styles/' sub-directory of your refbase root directory). It contains a
  19. // version of the 'citeRecord()' function that outputs a reference list from selected records according to the citation style used by
  20. // the Vancouver referencing system (also known as "Uniform Requirements for Manuscripts Submitted to Biomedical Journals")
  21. // This Vancouver style was modeled after these resources:
  22. // <http://www.library.uq.edu.au/training/citation/vancouv.pdf>
  23. // <http://library.curtin.edu.au/research_and_information_skills/referencing/vancouver.pdf>
  24. // <http://www.icmje.org/index.html> citing: <http://www.nlm.nih.gov/citingmedicine/>
  25. // <http://www.nlm.nih.gov/bsd/uniform_requirements.html>
  26. // <http://library.sun.ac.za//eng/help/infolit2002/bibvancouver.htm>
  27. // based on 'cite_AMA.php'
  28. // NOTES: - In the Vancouver style, the reference list is arranged numerically in the order in which references are cited in the text.
  29. // This isn't currently handled by this style (it needs to be implemented in the 'cite/formats/cite_*.php' files).
  30. // - For conference proceedings, you'll currently need to add the place & date of the conference in the proceedings title field
  31. // (e.g. "Proceedings of the 5th Germ Cell Tumour Conference; 2001 Sep 13-15; Leeds, UK").
  32. // TODO: - abstracts, newspaper/magazine articles, patents & reports?
  33. // - arrange references numerically
  34. // - for newspaper articles, only the beginning page number of an article should be included (see: <http://www.ncbi.nlm.nih.gov/books/bv.fcgi?rid=citmed.section.41496#41607>)
  35. // - where to put (and how to format) editors of whole books that also have an author?
  36. // - see also inline comments labeled with TODO (and NOTE)
  37. // --------------------------------------------------------------------
  38. // --- BEGIN CITATION STYLE ---
  39. function citeRecord($row, $citeStyle, $citeType, $markupPatternsArray, $encodeHTML)
  40. {
  41. global $alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower, $print, $punct, $space, $upper, $word, $patternModifiers; // defined in 'transtab_unicode_charset.inc.php' and 'transtab_latin1_charset.inc.php'
  42. static $uspsStateAbbreviations;
  43. // Official USPS state abbreviations:
  44. // see <http://www.usps.com/ncsc/lookups/usps_abbreviations.htm>
  45. $uspsStateAbbreviations = "AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|"
  46. . "NE|NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VI|VA|WA|WV|WI|WY";
  47. $record = ""; // make sure that our buffer variable is empty
  48. // --- BEGIN TYPE = JOURNAL ARTICLE / MAGAZINE ARTICLE / NEWSPAPER ARTICLE --------------------------------------------------------------
  49. if (preg_match("/^(Journal Article|Magazine Article|Newspaper Article)$/", $row['type']))
  50. {
  51. if (!empty($row['author'])) // author
  52. {
  53. // Call the 'reArrangeAuthorContents()' function (defined in 'include.inc.php') in order to re-order contents of the author field. Required Parameters:
  54. // 1. input: contents of the author field
  55. // 2. input: boolean value that specifies whether the author's family name comes first (within one author) in the source string
  56. // ('true' means that the family name is followed by the given name (or initials), 'false' if it's the other way around)
  57. //
  58. // 3. input: pattern describing old delimiter that separates different authors
  59. // 4. output: for all authors except the last author: new delimiter that separates different authors
  60. // 5. output: for the last author: new delimiter that separates the last author from all other authors
  61. //
  62. // 6. input: pattern describing old delimiter that separates author name & initials (within one author)
  63. // 7. output: for the first author: new delimiter that separates author name & initials (within one author)
  64. // 8. output: for all authors except the first author: new delimiter that separates author name & initials (within one author)
  65. // 9. output: new delimiter that separates multiple initials (within one author)
  66. // 10. output: for the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  67. // 11. output: for all authors except the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  68. // 12. output: boolean value that specifies whether an author's full given name(s) shall be shortened to initial(s)
  69. //
  70. // 13. output: if the total number of authors is greater than the given number (integer >= 1), only the number of authors given in (14) will be included in the citation along with the string given in (15); keep empty if all authors shall be returned
  71. // 14. output: number of authors (integer >= 1) that is included in the citation if the total number of authors is greater than the number given in (13); keep empty if not applicable
  72. // 15. output: string that's appended to the number of authors given in (14) if the total number of authors is greater than the number given in (13); the actual number of authors can be printed by including '__NUMBER_OF_AUTHORS__' (without quotes) within the string
  73. //
  74. // 16. output: boolean value that specifies whether the re-ordered string shall be returned with higher ASCII chars HTML encoded
  75. $author = reArrangeAuthorContents($row['author'], // 1.
  76. true, // 2.
  77. "/ *; */", // 3.
  78. ", ", // 4.
  79. ", ", // 5.
  80. "/ *, */", // 6.
  81. " ", // 7.
  82. " ", // 8.
  83. "", // 9.
  84. false, // 10.
  85. false, // 11.
  86. true, // 12.
  87. "6", // 13.
  88. "6", // 14.
  89. ", et al.", // 15.
  90. $encodeHTML // 16.
  91. );
  92. if (!preg_match("/\. *$/", $author))
  93. $record .= $author . ".";
  94. else
  95. $record .= $author;
  96. }
  97. if (!empty($row['title'])) // title
  98. {
  99. if (!empty($row['author']))
  100. $record .= " ";
  101. $record .= $row['title'];
  102. }
  103. // From here on we'll assume that at least either the 'author' or the 'title' field did contain some contents
  104. // if this is not the case, the output string will begin with a space. However, any preceding/trailing whitespace will be removed at the cleanup stage (see below)
  105. if (!preg_match("/[?!.] *$/", $record))
  106. $record .= ".";
  107. if (!empty($row['abbrev_journal'])) // abbreviated journal name
  108. $record .= " " . preg_replace("/\./", "", $row['abbrev_journal']); // no punctuation marks are used in the abbreviated journal name, just spaces (TODO: smarten regex pattern)
  109. // if there's no abbreviated journal name, we'll use the full journal name instead:
  110. elseif (!empty($row['publication'])) // publication (= journal) name
  111. $record .= " " . $row['publication'];
  112. if ($row['online_publication'] == "yes") // this record refers to an online publication
  113. $record .= " [Internet]"; // NOTE: some of the above mentioned resources use "[serial online]", "[serial on the Internet]" or just "[online]" instead
  114. // NOTE: the formatting of year/volume/issue is meant for journal articles (TODO: newspaper/magazine articles)
  115. if (!empty($row['year'])) // year
  116. $record .= ". " . $row['year'];
  117. if ($row['online_publication'] == "yes") // append the current date if this record refers to an online publication
  118. $record .= " [cited " . date("Y M j") . "]";
  119. if (!empty($row['volume']) || !empty($row['issue']))
  120. $record .= ";";
  121. if (!empty($row['volume'])) // volume (=month)
  122. $record .= $row['volume'];
  123. if (!empty($row['issue'])) // issue (=day)
  124. $record .= "(" . $row['issue'] . ")";
  125. if (!empty($row['pages'])) // pages
  126. {
  127. if (!empty($row['year']) || !empty($row['volume']) || !empty($row['issue']) || !empty($row['abbrev_journal']) || !empty($row['publication'])) // only add ": " if either year, volume, issue, abbrev_journal or publication isn't empty
  128. $record .= ":";
  129. $record .= formatPageInfo($row['pages'], $markupPatternsArray["endash"], "", "", "", "", "", "", true); // function 'formatPageInfo()' is defined in 'cite.inc.php'
  130. }
  131. if ($row['online_publication'] == "yes") // this record refers to an online publication
  132. {
  133. // append an optional string (given in 'online_citation') plus the DOI (or URL):
  134. if (!empty($row['online_citation'])) // online_citation
  135. {
  136. if (!empty($row['year']) || !empty($row['volume']) || !empty($row['issue']) || !empty($row['abbrev_journal']) || !empty($row['publication'])) // only add ":" or "," if either year, volume, issue, abbrev_journal or publication isn't empty
  137. {
  138. if (empty($row['pages']))
  139. $record .= ":"; // print instead of pages
  140. else
  141. $record .= ";"; // append to pages (TODO: not sure whether this is correct)
  142. }
  143. $record .= $row['online_citation'];
  144. }
  145. if (!empty($row['doi']) || !empty($row['url'])) // doi OR url
  146. {
  147. if (!empty($row['online_citation']) OR (empty($row['online_citation']) AND (!empty($row['year']) || !empty($row['volume']) || !empty($row['issue']) || !empty($row['abbrev_journal']) || !empty($row['publication'])))) // only add "." if online_citation isn't empty, or else if either year, volume, issue, abbrev_journal or publication isn't empty
  148. $record .= ".";
  149. $record .= " Available from: " . $markupPatternsArray["underline-prefix"]; // NOTE: some of the above mentioned resources use "Available from: URL:http://..." instead
  150. if (!empty($row['doi'])) // doi
  151. $uri = "http://dx.doi.org/" . $row['doi'];
  152. else // url
  153. $uri = $row['url'];
  154. if ($encodeHTML)
  155. $record .= encodeHTML($uri);
  156. else
  157. $record .= $uri;
  158. $record .= $markupPatternsArray["underline-suffix"];
  159. }
  160. }
  161. if (!preg_match("/\. *$/", $record) AND ($row['online_publication'] != "yes"))
  162. $record .= "."; // NOTE: the examples in the above mentioned resources differ wildly w.r.t. whether the closing period should be omitted for online publications
  163. }
  164. // --- BEGIN TYPE = ABSTRACT / BOOK CHAPTER / CONFERENCE ARTICLE ------------------------------------------------------------------------
  165. elseif (preg_match("/^(Abstract|Book Chapter|Conference Article)$/", $row['type']))
  166. {
  167. if (!empty($row['author'])) // author
  168. {
  169. // Call the 'reArrangeAuthorContents()' function (defined in 'include.inc.php') in order to re-order contents of the author field. Required Parameters:
  170. // 1. input: contents of the author field
  171. // 2. input: boolean value that specifies whether the author's family name comes first (within one author) in the source string
  172. // ('true' means that the family name is followed by the given name (or initials), 'false' if it's the other way around)
  173. //
  174. // 3. input: pattern describing old delimiter that separates different authors
  175. // 4. output: for all authors except the last author: new delimiter that separates different authors
  176. // 5. output: for the last author: new delimiter that separates the last author from all other authors
  177. //
  178. // 6. input: pattern describing old delimiter that separates author name & initials (within one author)
  179. // 7. output: for the first author: new delimiter that separates author name & initials (within one author)
  180. // 8. output: for all authors except the first author: new delimiter that separates author name & initials (within one author)
  181. // 9. output: new delimiter that separates multiple initials (within one author)
  182. // 10. output: for the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  183. // 11. output: for all authors except the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  184. // 12. output: boolean value that specifies whether an author's full given name(s) shall be shortened to initial(s)
  185. //
  186. // 13. output: if the total number of authors is greater than the given number (integer >= 1), only the number of authors given in (14) will be included in the citation along with the string given in (15); keep empty if all authors shall be returned
  187. // 14. output: number of authors (integer >= 1) that is included in the citation if the total number of authors is greater than the number given in (13); keep empty if not applicable
  188. // 15. output: string that's appended to the number of authors given in (14) if the total number of authors is greater than the number given in (13); the actual number of authors can be printed by including '__NUMBER_OF_AUTHORS__' (without quotes) within the string
  189. //
  190. // 16. output: boolean value that specifies whether the re-ordered string shall be returned with higher ASCII chars HTML encoded
  191. $author = reArrangeAuthorContents($row['author'], // 1.
  192. true, // 2.
  193. "/ *; */", // 3.
  194. ", ", // 4.
  195. ", ", // 5.
  196. "/ *, */", // 6.
  197. " ", // 7.
  198. " ", // 8.
  199. "", // 9.
  200. false, // 10.
  201. false, // 11.
  202. true, // 12.
  203. "6", // 13.
  204. "6", // 14.
  205. ", et al.", // 15.
  206. $encodeHTML // 16.
  207. );
  208. if (!preg_match("/\. *$/", $author))
  209. $record .= $author . ".";
  210. else
  211. $record .= $author;
  212. }
  213. if (!empty($row['title'])) // title
  214. {
  215. if (!empty($row['author']))
  216. $record .= " ";
  217. $record .= $row['title'];
  218. }
  219. if ($row['type'] == "Abstract") // for abstracts, add "[abstract]" label
  220. $record .= " [abstract]";
  221. // From here on we'll assume that at least either the 'author' or the 'title' field did contain some contents
  222. // if this is not the case, the output string will begin with a space. However, any preceding/trailing whitespace will be removed at the cleanup stage (see below)
  223. if (!empty($row['editor'])) // editor
  224. {
  225. // Call the 'reArrangeAuthorContents()' function (defined in 'include.inc.php') in order to re-order contents of the author field. Required Parameters:
  226. // 1. input: contents of the author field
  227. // 2. input: boolean value that specifies whether the author's family name comes first (within one author) in the source string
  228. // ('true' means that the family name is followed by the given name (or initials), 'false' if it's the other way around)
  229. //
  230. // 3. input: pattern describing old delimiter that separates different authors
  231. // 4. output: for all authors except the last author: new delimiter that separates different authors
  232. // 5. output: for the last author: new delimiter that separates the last author from all other authors
  233. //
  234. // 6. input: pattern describing old delimiter that separates author name & initials (within one author)
  235. // 7. output: for the first author: new delimiter that separates author name & initials (within one author)
  236. // 8. output: for all authors except the first author: new delimiter that separates author name & initials (within one author)
  237. // 9. output: new delimiter that separates multiple initials (within one author)
  238. // 10. output: for the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  239. // 11. output: for all authors except the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  240. // 12. output: boolean value that specifies whether an author's full given name(s) shall be shortened to initial(s)
  241. //
  242. // 13. output: if the total number of authors is greater than the given number (integer >= 1), only the number of authors given in (14) will be included in the citation along with the string given in (15); keep empty if all authors shall be returned
  243. // 14. output: number of authors (integer >= 1) that is included in the citation if the total number of authors is greater than the number given in (13); keep empty if not applicable
  244. // 15. output: string that's appended to the number of authors given in (14) if the total number of authors is greater than the number given in (13); the actual number of authors can be printed by including '__NUMBER_OF_AUTHORS__' (without quotes) within the string
  245. //
  246. // 16. output: boolean value that specifies whether the re-ordered string shall be returned with higher ASCII chars HTML encoded
  247. $editor = reArrangeAuthorContents($row['editor'], // 1.
  248. true, // 2.
  249. "/ *; */", // 3.
  250. ", ", // 4.
  251. ", ", // 5.
  252. "/ *, */", // 6.
  253. " ", // 7.
  254. " ", // 8.
  255. "", // 9.
  256. false, // 10.
  257. false, // 11.
  258. true, // 12.
  259. "6", // 13.
  260. "6", // 14.
  261. ", et al.", // 15.
  262. $encodeHTML // 16.
  263. );
  264. if (!preg_match("/[?!.] *$/", $record))
  265. $record .= ".";
  266. $record .= " In: " . $editor . ", ";
  267. if (preg_match("/^[^;\r\n]+(;[^;\r\n]+)+$/", $row['editor'])) // there are at least two editors (separated by ';')
  268. $record .= "editors";
  269. else // there's only one editor (or the editor field is malformed with multiple editors but missing ';' separator[s])
  270. $record .= "editor";
  271. }
  272. $publication = preg_replace("/[ \r\n]*\(Eds?:[^\)\r\n]*\)/i", "", $row['publication']);
  273. if (!empty($publication)) // publication
  274. {
  275. if (!preg_match("/[?!.] *$/", $record))
  276. $record .= ".";
  277. if (empty($row['editor']))
  278. $record .= " In:";
  279. $record .= " " . $publication;
  280. }
  281. if (!empty($row['volume'])) // volume
  282. {
  283. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  284. $record .= ".";
  285. $record .= " Vol " . $row['volume']; // TODO: not sure whether this is correct
  286. }
  287. if (!empty($row['edition']) && !preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $row['edition'])) // edition
  288. {
  289. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  290. $record .= ".";
  291. if (preg_match("/^\d{1,3}$/", $row['edition'])) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
  292. {
  293. if ($row['edition'] == "2")
  294. $editionSuffix = "nd";
  295. elseif ($row['edition'] == "3")
  296. $editionSuffix = "rd";
  297. else
  298. $editionSuffix = "th";
  299. }
  300. else
  301. $editionSuffix = "";
  302. if (!preg_match("/( ed\.?| edition)$/i", $row['edition']))
  303. $editionSuffix .= " ed.";
  304. $record .= " " . $row['edition'] . $editionSuffix;
  305. }
  306. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  307. $record .= ".";
  308. if (!empty($row['place'])) // place
  309. {
  310. // for places in the USA, format any two-letter postal code for the state (i.e. ensure upper case & wrap in parens, eg. "Boca Raton (FL)"):
  311. if (preg_match("/(.+?)[$punct$space]+($uspsStateAbbreviations)[$punct$space]*$/i$patternModifiers", $row['place']))
  312. $record .= " " . preg_replace("/(.+?)[$punct$space]+($uspsStateAbbreviations)[$punct$space]*$/ie$patternModifiers", "'\\1 ('.strtoupper('\\2').')'", $row['place']);
  313. else
  314. $record .= " " . $row['place'];
  315. }
  316. if (!empty($row['publisher'])) // publisher
  317. {
  318. if (!empty($row['place']))
  319. $record .= ":";
  320. $record .= " " . $row['publisher'];
  321. }
  322. if (!empty($row['year'])) // year
  323. $record .= "; " . $row['year'];
  324. if (!empty($row['pages'])) // pages
  325. $record .= ". " . formatPageInfo($row['pages'], $markupPatternsArray["endash"], "p. ", "p. ", "", "", "", "", true); // function 'formatPageInfo()' is defined in 'cite.inc.php'
  326. if (!empty($row['abbrev_series_title']) OR !empty($row['series_title'])) // if there's either a full or an abbreviated series title
  327. {
  328. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  329. $record .= ".";
  330. $record .= " (";
  331. if (!empty($row['abbrev_series_title'])) // abbreviated series title
  332. $record .= preg_replace("/\./", "", $row['abbrev_series_title']); // no punctuation marks are used in the abbreviated series title, just spaces (TODO: smarten regex pattern)
  333. // if there's no abbreviated series title, we'll use the full series title instead:
  334. elseif (!empty($row['series_title'])) // full series title
  335. $record .= $row['series_title'];
  336. if (!empty($row['series_volume'])||!empty($row['series_issue']))
  337. $record .= "; ";
  338. if (!empty($row['series_volume'])) // series volume
  339. $record .= "vol " . $row['series_volume'];
  340. if (!empty($row['series_volume']) && !empty($row['series_issue']))
  341. $record .= "; "; // TODO: not sure whether this is correct
  342. if (!empty($row['series_issue'])) // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
  343. $record .= "no " . $row['series_issue']; // since a series volume should be prefixed with "vol", is it correct to prefix series issues with "no"?
  344. $record .= ")";
  345. }
  346. if (!preg_match("/\. *$/", $record))
  347. $record .= ".";
  348. }
  349. // --- BEGIN TYPE = BOOK WHOLE / CONFERENCE VOLUME / JOURNAL / MANUAL / MANUSCRIPT / MAP / MISCELLANEOUS / PATENT / REPORT / SOFTWARE ---
  350. else // if (preg_match("/Book Whole|Conference Volume|Journal|Manual|Manuscript|Map|Miscellaneous|Patent|Report|Software/", $row['type']))
  351. // note that this also serves as a fallback: unrecognized resource types will be formatted similar to whole books
  352. {
  353. if (!empty($row['author'])) // author
  354. {
  355. $author = preg_replace("/[ \r\n]*\(eds?\)/i", "", $row['author']);
  356. // Call the 'reArrangeAuthorContents()' function (defined in 'include.inc.php') in order to re-order contents of the author field. Required Parameters:
  357. // 1. input: contents of the author field
  358. // 2. input: boolean value that specifies whether the author's family name comes first (within one author) in the source string
  359. // ('true' means that the family name is followed by the given name (or initials), 'false' if it's the other way around)
  360. //
  361. // 3. input: pattern describing old delimiter that separates different authors
  362. // 4. output: for all authors except the last author: new delimiter that separates different authors
  363. // 5. output: for the last author: new delimiter that separates the last author from all other authors
  364. //
  365. // 6. input: pattern describing old delimiter that separates author name & initials (within one author)
  366. // 7. output: for the first author: new delimiter that separates author name & initials (within one author)
  367. // 8. output: for all authors except the first author: new delimiter that separates author name & initials (within one author)
  368. // 9. output: new delimiter that separates multiple initials (within one author)
  369. // 10. output: for the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  370. // 11. output: for all authors except the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  371. // 12. output: boolean value that specifies whether an author's full given name(s) shall be shortened to initial(s)
  372. //
  373. // 13. output: if the total number of authors is greater than the given number (integer >= 1), only the number of authors given in (14) will be included in the citation along with the string given in (15); keep empty if all authors shall be returned
  374. // 14. output: number of authors (integer >= 1) that is included in the citation if the total number of authors is greater than the number given in (13); keep empty if not applicable
  375. // 15. output: string that's appended to the number of authors given in (14) if the total number of authors is greater than the number given in (13); the actual number of authors can be printed by including '__NUMBER_OF_AUTHORS__' (without quotes) within the string
  376. //
  377. // 16. output: boolean value that specifies whether the re-ordered string shall be returned with higher ASCII chars HTML encoded
  378. $author = reArrangeAuthorContents($author, // 1.
  379. true, // 2.
  380. "/ *; */", // 3.
  381. ", ", // 4.
  382. ", ", // 5.
  383. "/ *, */", // 6.
  384. " ", // 7.
  385. " ", // 8.
  386. "", // 9.
  387. false, // 10.
  388. false, // 11.
  389. true, // 12.
  390. "6", // 13.
  391. "6", // 14.
  392. ", et al.", // 15.
  393. $encodeHTML // 16.
  394. );
  395. // if the author is actually the editor of the resource we'll append ', ed' (or ', eds') to the author string:
  396. // [to distinguish editors from authors in the 'author' field, the 'modify.php' script does append ' (ed)' or ' (eds)' if appropriate,
  397. // so we're just checking for these identifier strings here. Alternatively, we could check whether the editor field matches the author field]
  398. if (preg_match("/[ \r\n]*\(ed\)/", $row['author'])) // single editor
  399. $author = $author . ", editor";
  400. elseif (preg_match("/[ \r\n]*\(eds\)/", $row['author'])) // multiple editors
  401. $author = $author . ", editors";
  402. if (!preg_match("/\. *$/", $author))
  403. $record .= $author . ".";
  404. else
  405. $record .= $author;
  406. }
  407. if (!empty($row['title'])) // title
  408. {
  409. if (!empty($row['author']))
  410. $record .= " ";
  411. $record .= $row['title'];
  412. }
  413. if ($row['type'] == "Software") // for software, add software label
  414. $record .= " [computer program]";
  415. if (($row['online_publication'] == "yes") AND empty($row['thesis'])) // this record refers to an online publication (online theses will be handled further down below)
  416. $record .= " [Internet]"; // NOTE: some of the above mentioned resources use "[monograph online]", "[monograph on the Internet]" or just "[online]" instead
  417. if (!empty($row['volume']) AND ($row['type'] != "Software")) // volume
  418. {
  419. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  420. $record .= ".";
  421. $record .= " Vol " . $row['volume']; // TODO: not sure whether this is correct
  422. }
  423. if (!empty($row['edition'])) // edition
  424. {
  425. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  426. $record .= ".";
  427. if ($row['type'] == "Software") // software edition (=version)
  428. {
  429. $record .= " Version " . $row['edition'];
  430. }
  431. elseif (!preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $row['edition'])) // edition
  432. {
  433. if (preg_match("/^\d{1,3}$/", $row['edition'])) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
  434. {
  435. if ($row['edition'] == "2")
  436. $editionSuffix = "nd";
  437. elseif ($row['edition'] == "3")
  438. $editionSuffix = "rd";
  439. else
  440. $editionSuffix = "th";
  441. }
  442. else
  443. $editionSuffix = "";
  444. if (!preg_match("/( ed\.?| edition)$/i", $row['edition']))
  445. $editionSuffix .= " ed.";
  446. $record .= " " . $row['edition'] . $editionSuffix;
  447. }
  448. }
  449. if (!empty($row['editor']) && !preg_match("/[ \r\n]*\(eds?\)/", $row['author'])) // editor (if different from author, see note above regarding the check for ' (ed)' or ' (eds)')
  450. {
  451. // Call the 'reArrangeAuthorContents()' function (defined in 'include.inc.php') in order to re-order contents of the author field. Required Parameters:
  452. // 1. input: contents of the author field
  453. // 2. input: boolean value that specifies whether the author's family name comes first (within one author) in the source string
  454. // ('true' means that the family name is followed by the given name (or initials), 'false' if it's the other way around)
  455. //
  456. // 3. input: pattern describing old delimiter that separates different authors
  457. // 4. output: for all authors except the last author: new delimiter that separates different authors
  458. // 5. output: for the last author: new delimiter that separates the last author from all other authors
  459. //
  460. // 6. input: pattern describing old delimiter that separates author name & initials (within one author)
  461. // 7. output: for the first author: new delimiter that separates author name & initials (within one author)
  462. // 8. output: for all authors except the first author: new delimiter that separates author name & initials (within one author)
  463. // 9. output: new delimiter that separates multiple initials (within one author)
  464. // 10. output: for the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  465. // 11. output: for all authors except the first author: boolean value that specifies if initials go *before* the author's name ['true'], or *after* the author's name ['false'] (which is the default in the db)
  466. // 12. output: boolean value that specifies whether an author's full given name(s) shall be shortened to initial(s)
  467. //
  468. // 13. output: if the total number of authors is greater than the given number (integer >= 1), only the number of authors given in (14) will be included in the citation along with the string given in (15); keep empty if all authors shall be returned
  469. // 14. output: number of authors (integer >= 1) that is included in the citation if the total number of authors is greater than the number given in (13); keep empty if not applicable
  470. // 15. output: string that's appended to the number of authors given in (14) if the total number of authors is greater than the number given in (13); the actual number of authors can be printed by including '__NUMBER_OF_AUTHORS__' (without quotes) within the string
  471. //
  472. // 16. output: boolean value that specifies whether the re-ordered string shall be returned with higher ASCII chars HTML encoded
  473. $editor = reArrangeAuthorContents($row['editor'], // 1.
  474. true, // 2.
  475. "/ *; */", // 3.
  476. ", ", // 4.
  477. ", ", // 5.
  478. "/ *, */", // 6.
  479. " ", // 7.
  480. " ", // 8.
  481. "", // 9.
  482. false, // 10.
  483. false, // 11.
  484. true, // 12.
  485. "6", // 13.
  486. "6", // 14.
  487. ", et al.", // 15.
  488. $encodeHTML // 16.
  489. );
  490. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  491. $record .= ".";
  492. $record .= " " . $editor;
  493. if (preg_match("/^[^;\r\n]+(;[^;\r\n]+)+$/", $row['editor'])) // there are at least two editors (separated by ';')
  494. $record .= ", editors";
  495. else // there's only one editor (or the editor field is malformed with multiple editors but missing ';' separator[s])
  496. $record .= ", editor";
  497. }
  498. if (!empty($row['thesis'])) // thesis
  499. {
  500. // TODO: do we need to use the term "[dissertation]" instead of "[Ph.D. thesis]", etc? What about other thesis types then?
  501. $record .= " [" . $row['thesis'];
  502. if ($row['online_publication'] == "yes") // this record refers to an online thesis
  503. $record .= " on the Internet]";
  504. else
  505. $record .= "]";
  506. }
  507. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  508. $record .= ".";
  509. if (!empty($row['place'])) // place
  510. {
  511. // for places in the USA, format any two-letter postal code for the state (i.e. ensure upper case & wrap in parentheses, eg. "Boca Raton (FL)"):
  512. if (preg_match("/(.+?)[$punct$space]+($uspsStateAbbreviations)[$punct$space]*$/i$patternModifiers", $row['place']))
  513. $record .= " " . preg_replace("/(.+?)[$punct$space]+($uspsStateAbbreviations)[$punct$space]*$/ie$patternModifiers", "'\\1 ('.strtoupper('\\2').')'", $row['place']);
  514. else
  515. $record .= " " . $row['place'];
  516. }
  517. if (!empty($row['publisher'])) // publisher
  518. {
  519. if (!empty($row['place']))
  520. $record .= ":";
  521. $record .= " " . $row['publisher'];
  522. }
  523. $record .= ";";
  524. if (!empty($row['year'])) // year
  525. $record .= " " . $row['year'];
  526. if ($row['type'] == "Software") // for software, volume (=month) and issue (=day) information is printed after the year (TODO: not sure whether this is correct)
  527. {
  528. if (!empty($row['volume'])) // volume (=month)
  529. $record .= " " . $row['volume'];
  530. if (!empty($row['issue'])) // issue (=day)
  531. $record .= " " . $row['issue'];
  532. }
  533. if ($row['online_publication'] == "yes") // append the current date if this record refers to an online publication
  534. $record .= " [cited " . date("Y M j") . "]";
  535. if (!empty($row['abbrev_series_title']) OR !empty($row['series_title'])) // if there's either a full or an abbreviated series title
  536. {
  537. if (!preg_match("@[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$@", $record))
  538. $record .= ".";
  539. $record .= " (";
  540. if (!empty($row['abbrev_series_title'])) // abbreviated series title
  541. $record .= preg_replace("/\./", "", $row['abbrev_series_title']); // no punctuation marks are used in the abbreviated series title, just spaces (TODO: smarten regex pattern)
  542. // if there's no abbreviated series title, we'll use the full series title instead:
  543. elseif (!empty($row['series_title'])) // full series title
  544. $record .= $row['series_title'];
  545. if (!empty($row['series_volume'])||!empty($row['series_issue']))
  546. $record .= "; ";
  547. if (!empty($row['series_volume'])) // series volume
  548. $record .= "vol " . $row['series_volume'];
  549. if (!empty($row['series_volume']) && !empty($row['series_issue']))
  550. $record .= "; "; // TODO: not sure whether this is correct
  551. if (!empty($row['series_issue'])) // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
  552. $record .= "no " . $row['series_issue']; // since a series volume should be prefixed with "vol", is it correct to prefix series issues with "no"?
  553. $record .= ")";
  554. }
  555. if ($row['online_publication'] == "yes" || $row['type'] == "Software") // this record refers to an online publication, or a computer program/software
  556. {
  557. // append an optional string (given in 'online_citation') plus the DOI (or URL):
  558. if (!empty($row['online_citation'])) // online_citation
  559. {
  560. if (!preg_match("/\. *$/", $record))
  561. $record .= ".";
  562. $record .= $row['online_citation'];
  563. }
  564. if (!empty($row['doi']) || !empty($row['url'])) // doi OR url
  565. {
  566. if (!preg_match("/\. *$/", $record))
  567. $record .= ".";
  568. $record .= " Available from: " . $markupPatternsArray["underline-prefix"]; // NOTE: some of the above mentioned resources use "Available from: URL:http://..." instead
  569. if (!empty($row['doi'])) // doi
  570. $uri = "http://dx.doi.org/" . $row['doi'];
  571. else // url
  572. $uri = $row['url'];
  573. if ($encodeHTML)
  574. $record .= encodeHTML($uri);
  575. else
  576. $record .= $uri;
  577. $record .= $markupPatternsArray["underline-suffix"];
  578. }
  579. }
  580. if (!preg_match("/\. *$/", $record) AND ($row['online_publication'] != "yes") AND ($row['type'] != "Software"))
  581. $record .= "."; // NOTE: the examples in the above mentioned resources differ wildly w.r.t. whether the closing period should be omitted for online publications
  582. }
  583. // --- BEGIN POST-PROCESSING -----------------------------------------------------------------------------------------------------------
  584. // do some further cleanup:
  585. $record = trim($record); // remove any preceding or trailing whitespace
  586. return $record;
  587. }
  588. // --- END CITATION STYLE ---
  589. ?>