PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/common/libraries/plugin/pear/phing/filters/XsltFilter.php

https://bitbucket.org/chamilo/chamilo-dev/
PHP | 453 lines | 209 code | 55 blank | 189 comment | 14 complexity | c6f7649fb8e837a318c20480a4d7a5eb MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT
  1. <?php
  2. /*
  3. * $Id: XsltFilter.php 557 2009-08-29 13:54:38Z mrook $
  4. *
  5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  6. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  7. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  8. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  9. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. *
  17. * This software consists of voluntary contributions made by many individuals
  18. * and is licensed under the LGPL. For more information please see
  19. * <http://phing.info>.
  20. */
  21. include_once 'phing/filters/BaseParamFilterReader.php';
  22. include_once 'phing/filters/ChainableReader.php';
  23. /**
  24. * Applies XSL stylesheet to incoming text.
  25. *
  26. * Uses PHP XSLT support (libxslt).
  27. *
  28. * @author Hans Lellelid <hans@velum.net>
  29. * @author Yannick Lecaillez <yl@seasonfive.com>
  30. * @author Andreas Aderhold <andi@binarycloud.com>
  31. * @version $Id: XsltFilter.php 557 2009-08-29 13:54:38Z mrook $
  32. * @see FilterReader
  33. * @package phing.filters
  34. */
  35. class XsltFilter extends BaseParamFilterReader implements ChainableReader
  36. {
  37. /**
  38. * Path to XSL stylesheet.
  39. * @var string
  40. */
  41. private $xslFile = null;
  42. /**
  43. * Whether XML file has been transformed.
  44. * @var boolean
  45. */
  46. private $processed = false;
  47. /**
  48. * XSLT Params.
  49. * @var array
  50. */
  51. private $xsltParams = array();
  52. /**
  53. * Whether to use loadHTML() to parse the input XML file.
  54. */
  55. private $html = false;
  56. /**
  57. * Whether to resolve entities in the XML document (see
  58. * {@link http://www.php.net/manual/en/class.domdocument.php#domdocument.props.resolveexternals}
  59. * for more details).
  60. *
  61. * @var bool
  62. *
  63. * @since 2.4
  64. */
  65. private $resolveDocumentExternals = false;
  66. /**
  67. * Whether to resolve entities in the stylesheet.
  68. *
  69. * @var bool
  70. *
  71. * @since 2.4
  72. */
  73. private $resolveStylesheetExternals = false;
  74. /**
  75. * Create new XSLT Param object, to handle the <param/> nested element.
  76. * @return XSLTParam
  77. */
  78. function createParam()
  79. {
  80. $num = array_push($this->xsltParams, new XSLTParam());
  81. return $this->xsltParams[$num - 1];
  82. }
  83. /**
  84. * Sets the XSLT params for this class.
  85. * This is used to "clone" this class, in the chain() method.
  86. * @param array $params
  87. */
  88. function setParams($params)
  89. {
  90. $this->xsltParams = $params;
  91. }
  92. /**
  93. * Returns the XSLT params set for this class.
  94. * This is used to "clone" this class, in the chain() method.
  95. * @return array
  96. */
  97. function getParams()
  98. {
  99. return $this->xsltParams;
  100. }
  101. /**
  102. * Set the XSLT stylesheet.
  103. * @param mixed $file PhingFile object or path.
  104. */
  105. function setStyle(PhingFile $file)
  106. {
  107. $this->xslFile = $file;
  108. }
  109. /**
  110. * Whether to use HTML parser for the XML.
  111. * This is supported in libxml2 -- Yay!
  112. * @return boolean
  113. */
  114. function getHtml()
  115. {
  116. return $this->html;
  117. }
  118. /**
  119. * Whether to use HTML parser for XML.
  120. * @param boolean $b
  121. */
  122. function setHtml($b)
  123. {
  124. $this->html = (boolean) $b;
  125. }
  126. /**
  127. * Get the path to XSLT stylesheet.
  128. * @return mixed XSLT stylesheet path.
  129. */
  130. function getStyle()
  131. {
  132. return $this->xslFile;
  133. }
  134. /**
  135. * Whether to resolve entities in document.
  136. *
  137. * @param bool $resolveExternals
  138. *
  139. * @since 2.4
  140. */
  141. function setResolveDocumentExternals($resolveExternals)
  142. {
  143. $this->resolveDocumentExternals = (bool) $resolveExternals;
  144. }
  145. /**
  146. * @return bool
  147. *
  148. * @since 2.4
  149. */
  150. function getResolveDocumentExternals()
  151. {
  152. return $this->resolveDocumentExternals;
  153. }
  154. /**
  155. * Whether to resolve entities in stylesheet.
  156. *
  157. * @param bool $resolveExternals
  158. *
  159. * @since 2.4
  160. */
  161. function setResolveStylesheetExternals($resolveExternals)
  162. {
  163. $this->resolveStylesheetExternals = (bool) $resolveExternals;
  164. }
  165. /**
  166. * @return bool
  167. *
  168. * @since 2.4
  169. */
  170. function getResolveStylesheetExternals()
  171. {
  172. return $this->resolveStylesheetExternals;
  173. }
  174. /**
  175. * Reads stream, applies XSLT and returns resulting stream.
  176. * @return string transformed buffer.
  177. * @throws BuildException - if XSLT support missing, if error in xslt processing
  178. */
  179. function read($len = null)
  180. {
  181. if (! class_exists('XSLTProcessor'))
  182. {
  183. throw new BuildException("Could not find the XSLTProcessor class. Make sure PHP has been compiled/configured to support XSLT.");
  184. }
  185. if ($this->processed === true)
  186. {
  187. return - 1; // EOF
  188. }
  189. if (! $this->getInitialized())
  190. {
  191. $this->_initialize();
  192. $this->setInitialized(true);
  193. }
  194. // Read XML
  195. $_xml = null;
  196. while (($data = $this->in->read($len)) !== - 1)
  197. $_xml .= $data;
  198. if ($_xml === null)
  199. { // EOF?
  200. return - 1;
  201. }
  202. if (empty($_xml))
  203. {
  204. $this->log("XML file is empty!", Project :: MSG_WARN);
  205. return ''; // return empty string, don't attempt to apply XSLT
  206. }
  207. // Read XSLT
  208. $_xsl = null;
  209. $xslFr = new FileReader($this->xslFile);
  210. $xslFr->readInto($_xsl);
  211. $this->log("Tranforming XML " . $this->in->getResource() . " using style " . $this->xslFile->getPath(), Project :: MSG_VERBOSE);
  212. $out = '';
  213. try
  214. {
  215. $out = $this->process($_xml, $_xsl);
  216. $this->processed = true;
  217. }
  218. catch (IOException $e)
  219. {
  220. throw new BuildException($e);
  221. }
  222. return $out;
  223. }
  224. // {{{ method _ProcessXsltTransformation($xml, $xslt) throws BuildException
  225. /**
  226. * Try to process the XSLT transformation
  227. *
  228. * @param string XML to process.
  229. * @param string XSLT sheet to use for the processing.
  230. *
  231. * @throws BuildException On XSLT errors
  232. */
  233. protected function process($xml, $xsl)
  234. {
  235. $processor = new XSLTProcessor();
  236. // Create and setup document.
  237. $xmlDom = new DOMDocument();
  238. $xmlDom->resolveExternals = $this->resolveDocumentExternals;
  239. // Create and setup stylesheet.
  240. $xslDom = new DOMDocument();
  241. $xslDom->resolveExternals = $this->resolveStylesheetExternals;
  242. if ($this->html)
  243. {
  244. $xmlDom->loadHTML($xml);
  245. }
  246. else
  247. {
  248. $xmlDom->loadXML($xml);
  249. }
  250. $xslDom->loadxml($xsl);
  251. $processor->importStylesheet($xslDom);
  252. // ignoring param "type" attrib, because
  253. // we're only supporting direct XSL params right now
  254. foreach ($this->xsltParams as $param)
  255. {
  256. $this->log("Setting XSLT param: " . $param->getName() . "=>" . $param->getExpression(), Project :: MSG_DEBUG);
  257. $processor->setParameter(null, $param->getName(), $param->getExpression());
  258. }
  259. $errorlevel = error_reporting();
  260. error_reporting($errorlevel & ~ E_WARNING);
  261. @$result = $processor->transformToXML($xmlDom);
  262. error_reporting($errorlevel);
  263. if (false === $result)
  264. {
  265. //$errno = xslt_errno($processor);
  266. //$err = xslt_error($processor);
  267. throw new BuildException("XSLT Error");
  268. }
  269. else
  270. {
  271. return $result;
  272. }
  273. }
  274. /**
  275. * Creates a new XsltFilter using the passed in
  276. * Reader for instantiation.
  277. *
  278. * @param Reader A Reader object providing the underlying stream.
  279. * Must not be <code>null</code>.
  280. *
  281. * @return Reader A new filter based on this configuration, but filtering
  282. * the specified reader
  283. */
  284. function chain(Reader $reader)
  285. {
  286. $newFilter = new XsltFilter($reader);
  287. $newFilter->setProject($this->getProject());
  288. $newFilter->setStyle($this->getStyle());
  289. $newFilter->setInitialized(true);
  290. $newFilter->setParams($this->getParams());
  291. $newFilter->setHtml($this->getHtml());
  292. return $newFilter;
  293. }
  294. /**
  295. * Parses the parameters to get stylesheet path.
  296. */
  297. private function _initialize()
  298. {
  299. $params = $this->getParameters();
  300. if ($params !== null)
  301. {
  302. for($i = 0, $_i = count($params); $i < $_i; $i ++)
  303. {
  304. if ($params[$i]->getType() === null)
  305. {
  306. if ($params[$i]->getName() === "style")
  307. {
  308. $this->setStyle($params[$i]->getValue());
  309. }
  310. }
  311. elseif ($params[$i]->getType() == "param")
  312. {
  313. $xp = new XSLTParam();
  314. $xp->setName($params[$i]->getName());
  315. $xp->setExpression($params[$i]->getValue());
  316. $this->xsltParams[] = $xp;
  317. }
  318. }
  319. }
  320. }
  321. }
  322. /**
  323. * Class that holds an XSLT parameter.
  324. *
  325. * @package phing.filters
  326. */
  327. class XSLTParam
  328. {
  329. private $name;
  330. private $expr;
  331. /**
  332. * Sets param name.
  333. * @param string $name
  334. */
  335. public function setName($name)
  336. {
  337. $this->name = $name;
  338. }
  339. /**
  340. * Get param name.
  341. * @return string
  342. */
  343. public function getName()
  344. {
  345. return $this->name;
  346. }
  347. /**
  348. * Sets expression value (alias to the setExpression()) method.
  349. *
  350. * @param string $v
  351. * @see setExpression()
  352. */
  353. public function setValue($v)
  354. {
  355. $this->setExpression($v);
  356. }
  357. /**
  358. * Gets expression value (alias to the getExpression()) method.
  359. *
  360. * @param string $v
  361. * @see getExpression()
  362. */
  363. public function getValue()
  364. {
  365. return $this->getExpression();
  366. }
  367. /**
  368. * Sets expression value.
  369. * @param string $expr
  370. */
  371. public function setExpression($expr)
  372. {
  373. $this->expr = $expr;
  374. }
  375. /**
  376. * Sets expression to dynamic register slot.
  377. * @param RegisterSlot $expr
  378. */
  379. public function setListeningExpression(RegisterSlot $expr)
  380. {
  381. $this->expr = $expr;
  382. }
  383. /**
  384. * Returns expression value -- performs lookup if expr is registerslot.
  385. * @return string
  386. */
  387. public function getExpression()
  388. {
  389. if ($this->expr instanceof RegisterSlot)
  390. {
  391. return $this->expr->getValue();
  392. }
  393. else
  394. {
  395. return $this->expr;
  396. }
  397. }
  398. }