PageRenderTime 178ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/bin/doc2rst.php

https://bitbucket.org/aboozar/zf2
PHP | 369 lines | 332 code | 8 blank | 29 comment | 6 complexity | 27971a9c004a01d02bff4b393fde1987 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #!/usr/bin/env php
  2. <?php
  3. /**
  4. * Zend Framework
  5. *
  6. * LICENSE
  7. *
  8. * This source file is subject to the new BSD license that is bundled
  9. * with this package in the file LICENSE.txt.
  10. * It is also available through the world-wide-web at this URL:
  11. * http://framework.zend.com/license/new-bsd
  12. * If you did not receive a copy of the license and are unable to
  13. * obtain it through the world-wide-web, please send an email
  14. * to license@zend.com so we can send you a copy immediately.
  15. *
  16. * @category Zend
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. namespace ZendBin;
  21. use Zend\Console;
  22. use Zend\File\ClassFileLocator;
  23. use Zend\Loader\StandardAutoloader;
  24. use Zend\Text\Table;
  25. /*
  26. * Convert the ZF documentation from DocBook to reStructuredText format
  27. *
  28. * Usage:
  29. * --help|-h Get usage message
  30. * --docbook|-d Docbook file to convert
  31. * --output|-o File output in reStructuredText format; By default,
  32. * assumes <docbook>.rst
  33. */
  34. echo "DocBook to reStructuredText conversion for ZF documentation\n";
  35. echo "-----------------------------------------------------------\n";
  36. $libPath = getenv('LIB_PATH') ? getenv('LIB_PATH') : __DIR__ . '/../library';
  37. if (!is_dir($libPath)) {
  38. // Try to load StandardAutoloader from include_path
  39. if (false === include('Zend/Loader/StandardAutoloader.php')) {
  40. echo "Unable to locate autoloader via include_path; aborting" . PHP_EOL;
  41. exit(2);
  42. }
  43. } elseif (false === include($libPath . '/Zend/Loader/StandardAutoloader.php')) {
  44. echo "Unable to locate autoloader via library; aborting" . PHP_EOL;
  45. exit(2);
  46. }
  47. // Setup autoloading
  48. $loader = new StandardAutoloader(array('autoregister_zf' => true));
  49. $loader->register();
  50. $rules = array(
  51. 'help|h' => 'Get usage message',
  52. 'docbook|d-s' => 'Docbook file to convert',
  53. 'output|o-s' => 'Output file; if not provided, assumes <docbook>.rst"',
  54. );
  55. try {
  56. $opts = new Console\Getopt($rules);
  57. $opts->parse();
  58. } catch (Console\Exception\RuntimeException $e) {
  59. echo $e->getUsageMessage();
  60. exit(2);
  61. }
  62. if (!$opts->getOptions() || $opts->getOption('h')) {
  63. echo $opts->getUsageMessage();
  64. exit(0);
  65. }
  66. $docbook = $opts->getOption('d');
  67. if (!file_exists($docbook)) {
  68. echo "Error: the docbook file $docbook doesn't exist.\n";
  69. exit(2);
  70. }
  71. $rstFile = $opts->getOption('o');
  72. if (empty($rstFile)) {
  73. if (substr($docbook,-4) === '.xml') {
  74. $rstFile = substr($docbook, 0, strlen($docbook)-4) . '.rst';
  75. } else {
  76. $rstFile = $docbook . '.rst';
  77. }
  78. }
  79. // Load the docbook file (input)
  80. $xml = new \DOMDocument;
  81. $xml->load($docbook);
  82. $xsltFile = __DIR__ . '/doc2rst.xsl';
  83. // Load the XSLT file
  84. $xsl = new \DOMDocument;
  85. if (!file_exists($xsltFile)) {
  86. echo "The $xsltFile is missing, I cannot procede with the conversion.\n";
  87. exit(2);
  88. }
  89. $xsl->load($xsltFile);
  90. $proc = new \XSLTProcessor;
  91. $proc->registerPHPFunctions();
  92. $proc->importStyleSheet($xsl);
  93. echo "Writing to $rstFile\n";
  94. $output = $proc->transformToXml($xml);
  95. if (false === $output) {
  96. echo "Error during the conversion\n";
  97. exit(2);
  98. }
  99. // remove single spaces in the beginning of new lines
  100. $lines = explode("\n", $output);
  101. $output = '';
  102. foreach ($lines as $line) {
  103. if (empty($line)) {
  104. $output .= "\n";
  105. } elseif (($line[0] === ' ') && ($line[1] !== ' ')) {
  106. $output .= substr($line, 1) . "\n";
  107. } else {
  108. $output .= "$line\n";
  109. }
  110. }
  111. // Add the list of the external links at the end of the document
  112. $output .= "\n" . RstConvert::getLinks();
  113. file_put_contents($rstFile, $output);
  114. echo "Conversion done.\n";
  115. exit(0);
  116. /**
  117. * XSLT php:function()
  118. */
  119. class RstConvert
  120. {
  121. public static $links = array();
  122. /**
  123. * Convert the programlisting tag
  124. *
  125. * @param string $text
  126. * @return string
  127. */
  128. public static function programlisting($text)
  129. {
  130. $rows = explode("\n", $text);
  131. $output = "\n.. code-block:: php\n :linenos:\n";
  132. foreach ($rows as $row) {
  133. $output .= " $row\n";
  134. }
  135. return $output;
  136. }
  137. /**
  138. * Convert the note tag
  139. *
  140. * @param string $text
  141. * @return string
  142. */
  143. public static function note($text)
  144. {
  145. $rows = explode("\n", $text);
  146. $tot = count($rows);
  147. if ('' !== trim($rows[0])) {
  148. $output = " **" . trim($rows[0]) . "**\n";
  149. } else {
  150. $output = '';
  151. }
  152. for ($i=1; $i < $tot; $i++) {
  153. if ('' !== trim($rows[$i])) {
  154. $output .= " {$rows[$i]}\n";
  155. }
  156. }
  157. return $output;
  158. }
  159. /**
  160. * Convert the listitem tag
  161. *
  162. * @param string $text
  163. * @return string
  164. */
  165. public static function listitem($text)
  166. {
  167. $rows = explode("\n", $text);
  168. $output = "\n";
  169. foreach ($rows as $row) {
  170. if ('' !== trim($row)) {
  171. $output .= " - ". trim($row) . "\n";
  172. }
  173. }
  174. $output .= "\n";
  175. return $output;
  176. }
  177. /**
  178. * Convert the first section/title tag (maintitle)
  179. *
  180. * @param string $text
  181. * @return string
  182. */
  183. public static function maintitle($text)
  184. {
  185. $text = str_replace('\\', '\\\\', trim($text));
  186. $count = strlen($text);
  187. $output = $text . "\n";
  188. $output .= str_repeat('=', $count) . "\n";
  189. return $output;
  190. }
  191. /**
  192. * Convert all the section/title, except for the first
  193. *
  194. * @param string $text
  195. * @return string
  196. */
  197. public static function title($text)
  198. {
  199. $text = str_replace('\\', '\\\\', trim($text));
  200. $count = strlen($text);
  201. $output = "\n" . $text . "\n";
  202. $output .= str_repeat('-', $count) . "\n";
  203. return $output;
  204. }
  205. /**
  206. * Format the string removing \n, multiple white spaces and \ in \\
  207. *
  208. * @param string $text
  209. * @return string
  210. */
  211. public static function formatText($text)
  212. {
  213. return str_replace('\\', '\\\\', trim(preg_replace('/\s+/', ' ', str_replace("\n", '', $text))));
  214. }
  215. /**
  216. * Conver the link tag
  217. *
  218. * @param DOMElement $node
  219. * @return string
  220. */
  221. public static function link($node)
  222. {
  223. $value = self::formatText($node[0]->nodeValue);
  224. if ($node[0]->getAttribute('linkend')) {
  225. return " :ref:`$value <" . $node[0]->getAttribute('linkend') . ">` ";
  226. } else {
  227. self::$links[$value] = $node[0]->getAttribute('xlink:href');
  228. return " `$value`_ ";
  229. }
  230. }
  231. /**
  232. * Get all the external links of the document
  233. *
  234. * @return string
  235. */
  236. public static function getLinks()
  237. {
  238. $output = '';
  239. foreach (self::$links as $key => $value) {
  240. $output .= ".. _`$key`: $value\n";
  241. }
  242. return $output;
  243. }
  244. /**
  245. * Convert the table tag
  246. *
  247. * @param DOMElement $node
  248. * @return string
  249. */
  250. public static function table($node)
  251. {
  252. // check if thead exists
  253. if (0 !== $node[0]->getElementsByTagName('thead')->length) {
  254. $head = true;
  255. } else {
  256. $head = false;
  257. }
  258. $rows = $node[0]->getElementsByTagName('row');
  259. $table = array();
  260. $totRow = $rows->length;
  261. $j = 0;
  262. foreach ($rows as $row) {
  263. $cols = $row->getElementsByTagName('entry');
  264. $totCol = $cols->length;
  265. if (!isset($widthCol)) {
  266. $widthCol = array_fill(0, $totCol, 0);
  267. }
  268. $i = 0;
  269. foreach ($cols as $col) {
  270. $table[$j][$i] = self::formatText($col->nodeValue);
  271. $length = strlen($table[$j][$i]);
  272. if ($length > $widthCol[$i]) {
  273. $widthCol[$i] = $length;
  274. }
  275. $i++;
  276. }
  277. $j++;
  278. }
  279. $tableText = new Table\Table(array(
  280. 'columnWidths' => $widthCol,
  281. 'decorator' => 'ascii'
  282. ));
  283. for ($j=0; $j < $totRow; $j++) {
  284. $row = new Table\Row();
  285. for ($i=0; $i < $totCol; $i++) {
  286. $row->appendColumn(new Table\Column($table[$j][$i]));
  287. }
  288. $tableText->appendRow($row);
  289. }
  290. $output = $tableText->render();
  291. // if thead exists change the table style with head (= instead of -)
  292. if ($head) {
  293. $table = explode("\n", $output);
  294. $newOutput = '';
  295. $i = 0;
  296. foreach ($table as $row) {
  297. if ('+-' === substr($row, 0, 2)) {
  298. $i++;
  299. }
  300. if (2 === $i) {
  301. $row = str_replace('-', '=', $row);
  302. }
  303. $newOutput .= "$row\n";
  304. }
  305. return $newOutput;
  306. }
  307. return $output;
  308. }
  309. /**
  310. * Convert an XML file name to the RST ZF2 standard naming convention
  311. * For instance, Zend_Config-XmlIntro.xml become zend.config.xml-intro.rst
  312. *
  313. * @param string $name
  314. * @return string
  315. */
  316. public static function XmlFileNameToRst($name)
  317. {
  318. if ('.xml' === strtolower(substr($name, -4))) {
  319. $name = substr($name, 0, strlen($name)-4);
  320. }
  321. $tot = strlen($name);
  322. $output = '';
  323. $word = false;
  324. for ($i=0; $i < $tot; $i++) {
  325. if (preg_match('/[A-Z]/', $name[$i])) {
  326. if ($word) {
  327. $output .= '-';
  328. }
  329. $output .= strtolower($name[$i]);
  330. } elseif ('_' === $name[$i] || '-' === $name[$i]) {
  331. $output .= '.';
  332. $word = false;
  333. } else {
  334. $output .= $name[$i];
  335. $word = true;
  336. }
  337. }
  338. return $output.'.rst';
  339. }
  340. }