1<?php 2/** 3 * XML_GRDDL 4 * 5 * PHP version 5 6 * 7 * Copyright (c) 2008, Daniel O'Connor <daniel.oconnor@gmail.com>. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * * Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * * Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * * Neither the name of Daniel O'Connor nor the names of his 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 30 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 * 39 * @category Semantic_Web 40 * @package XML_GRDDL 41 * @author Daniel O'Connor <daniel.oconnor@gmail.com> 42 * @copyright 2008 Daniel O'Connor 43 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 44 * @version SVN: $Id: Xsl.php 261528 2008-06-23 11:20:59Z clockwerx $ 45 * @link http://code.google.com/p/xmlgrddl/ 46 */ 47 48require_once 'XML/GRDDL/Driver.php'; 49 50/** 51 * A driver for PHP 5's XSL extension. 52 * 53 * Requires PHP 5.2.6, XSL extension 54 * 55 * @category Semantic_Web 56 * @package XML_GRDDL 57 * @author Daniel O'Connor <daniel.oconnor@gmail.com> 58 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 59 * @version Release: @package_version@ 60 * @link http://code.google.com/p/xmlgrddl/ 61 */ 62class XML_GRDDL_Driver_Xsl extends XML_GRDDL_Driver 63{ 64 /** 65 * Make a new instance of XML_GRRDL_Driver_XSL directly 66 * 67 * @param mixed[] $options An array of driver specific options 68 * 69 * @todo Document driver specific options! 70 * 71 * @see XML_GRDDL::factory() 72 * 73 * @return void 74 */ 75 public function __construct($options = array()) 76 { 77 if (!extension_loaded('xsl')) { 78 throw new XML_GRDDL_Exception("Don't forget to enable the xsl 79 extension"); 80 } 81 82 parent::__construct($options); 83 } 84 85 /** 86 * Transform the given XML with the provided XSLT. 87 * 88 * @param string $stylesheet URL or file location of an XSLT transformation 89 * @param string $xml String of XML 90 * 91 * @bug fails http://www.w3.org/TR/grddl-tests/#grddlProfileBase1 because 92 * when we DOMDocument::loadXML(), it's from a string, and worse, that string 93 * is HTML. We can't work out the DOMDocument->documentElement->baseURI 94 * correctly. 95 * 96 * @return string Transformed document contents. 97 */ 98 public function transform($stylesheet, $xml) 99 { 100 if (empty($stylesheet) || empty($xml)) { 101 $this->logger->log("Given empty stylesheet or xml"); 102 return $xml; 103 } 104 105 $oldCwd = getcwd(); 106 107 $paths = array(); 108 109 $paths[] = '@data_dir@/@package_name@/data/grddl-library/'; 110 $paths[] = dirname(__FILE__) . '/../../../data/grddl-library/'; 111 112 foreach ($paths as $path) { 113 if (file_exists($path)) { 114 chdir($path); 115 break; 116 } 117 } 118 119 if (getcwd() == $oldCwd) { 120 $this->logger->log("Could not access standard transform library"); 121 } 122 123 try { 124 $this->logger->log("Attempting to transform with " . $stylesheet); 125 126 $dom = new DOMDocument('1.0'); 127 $dom->loadXML($xml); 128 129 130 $xslt = $this->fetch($stylesheet, 'xsl'); 131 132 $xsl = new DOMDocument(); 133 $xsl->loadXML($xslt, LIBXML_NOCDATA | LIBXML_NOENT); 134 135 $this->checkStylesheetOutputType($xsl); 136 137 set_error_handler(array($this, 'handleTransformationErrorMessage')); 138 139 $proc = new XSLTProcessor(); 140 $proc->importStyleSheet($xsl); 141 142 $result = $proc->transformToXML($dom); 143 restore_error_handler(); 144 145 $this->logger->log("Transformed successfully with " . $stylesheet); 146 147 return $result; 148 } catch (XML_GRDDL_Exception $e) { 149 restore_error_handler(); 150 chdir($oldCwd); 151 152 throw $e; 153 } 154 } 155 156 /** 157 * A driver specific method to check if a given stylesheet will output 158 * an understandable format. 159 * 160 * This driver only understands application/rdf+xml 161 * 162 * @param DOMDocument $stylesheet A given stylesheet to inspect 163 * 164 * @see http://code.google.com/p/xmlgrddl/issues/detail?id=24#makechanges 165 * 166 * @throws XML_GRDDL_Exception 167 * 168 * @return bool 169 */ 170 protected function checkStylesheetOutputType(DOMDocument $stylesheet) 171 { 172 $this->logger->log("Checking stylesheet for odd output types"); 173 174 $sxe = simplexml_import_dom($stylesheet); 175 176 177 $sxe->registerXPathNamespace('xsl', 'http://www.w3.org/1999/XSL/Transform'); 178 179 $nodes = $sxe->xpath('//xsl:output[@media-type]'); 180 181 if (empty($nodes)) { 182 $this->logger->log("No xsl:output media-type found / not a stylesheet," 183 . " assuming application/rdf+xml"); 184 return true; 185 } 186 187 list($output) = $nodes; 188 189 $this->logger->log("This transformation produces " . $output['media-type']); 190 191 if ($output['media-type'] != 'application/rdf+xml') { 192 throw new XML_GRDDL_Exception("Cannot use this transform, I don't " 193 . "understand " . $output['media-type']); 194 } 195 196 return true; 197 } 198 199 /** 200 * Handle generated error messages 201 * 202 * @param string $errno Error number 203 * @param string $errstr Error message 204 * @param string $errfile Error file 205 * @param string $errline Error line 206 * @param string[] $errcontext Error context 207 * 208 * @throws XML_GRDDL_Exception 209 * @return void 210 */ 211 public function handleTransformationErrorMessage($errno, $errstr, $errfile, 212 $errline, $errcontext = array()) 213 { 214 throw new XML_GRDDL_Exception($errstr); 215 } 216} 217