Overview

Namespaces

  • PHP
  • XSLTBenchmarking
    • Reports
    • RunnerConsole
    • TestsGenerator
    • TestsRunner

Classes

  • AMemoryUsageDriver
  • AProcessorDriver
  • Controlor
  • Libxslt1123phpProcessorDriver
  • Libxslt1126phpProcessorDriver
  • LinuxMemoryUsageDriver
  • MemoryUsage
  • MSXML30ProcessorDriver
  • MSXML60ProcessorDriver
  • Params
  • Processor
  • Runner
  • Sablotron103cmdProcessorDriver
  • Saxon655ProcessorDriver
  • SaxonHE9402ProcessorDriver
  • Test
  • TestRunner
  • WindowsMemoryUsageDriver
  • Xalan271ProcessorDriver
  • XmlParamsDriver
  • Xsltproc1123ProcessorDriver
  • Xsltproc1126ProcessorDriver
  • XT20051206ProcessorDriver

Interfaces

  • IParamsDriver
  • Overview
  • Namespace
  • Class
  • Tree
  • Todo
  1: <?php
  2: 
  3: /**
  4:  * XSLT Benchmarking
  5:  * @link https://github.com/masicek/XSLT-Benchmarking
  6:  * @author Viktor Mašíček <viktor@masicek.net>
  7:  * @license "New" BSD License
  8:  */
  9: 
 10: namespace XSLTBenchmarking\TestsRunner;
 11: 
 12: require_once ROOT . '/Exceptions.php';
 13: require_once ROOT . '/Microtime.php';
 14: require_once LIBS . '/PhpPath/PhpPath.min.php';
 15: 
 16: use XSLTBenchmarking\Microtime;
 17: use PhpPath\P;
 18: 
 19: 
 20: /**
 21:  * Class for parse one template in one processor
 22:  *
 23:  * @author Viktor Mašíček <viktor@masicek.net>
 24:  */
 25: class Processor
 26: {
 27: 
 28: 
 29:     /**
 30:      * Path of dirctory containing processors drivers
 31:      *
 32:      * @var string
 33:      */
 34:     private $driversDir;
 35: 
 36:     /**
 37:      * Namespace of processors drivers
 38:      *
 39:      * @var string
 40:      */
 41:     private $driversNamespace;
 42: 
 43:     /**
 44:      * Path of temporary directory
 45:      *
 46:      * @var string
 47:      */
 48:     private $tmpDir;
 49: 
 50:     /**
 51:      * Class for measure memory usage of run command
 52:      *
 53:      * @var MemoryUsage
 54:      */
 55:     private $memoryUsage;
 56: 
 57:     /**
 58:      * List of available names of processors
 59:      *
 60:      * @var array
 61:      */
 62:     private $available = NULL;
 63: 
 64:     /**
 65:      * List of informations about processors
 66:      *
 67:      * @var array
 68:      */
 69:     private $informations = NULL;
 70: 
 71: 
 72:     /**
 73:      * Configure object
 74:      *
 75:      * @param string $tmpDir Path of temporary directory
 76:      * @param MemoryUsage $memoryUsage Class for measure memory usage of run command
 77:      * @param string $driversDir Path of dirctory containing processor drivers
 78:      * @param string $driversNamespace Namespace of processors drivers
 79:      */
 80:     public function __construct(
 81:         $tmpDir,
 82:         MemoryUsage $memoryUsage,
 83:         $driversDir = NULL,
 84:         $driversNamespace = '\XSLTBenchmarking\TestsRunner\\'
 85:     )
 86:     {
 87:         if (is_null($driversDir))
 88:         {
 89:             $driversDir = P::m(__DIR__, 'Drivers');
 90:         }
 91: 
 92:         $this->tmpDir = P::mcd($tmpDir);
 93:         $this->memoryUsage = $memoryUsage;
 94:         $this->driversDir = P::mcd($driversDir);
 95:         $this->driversNamespace = $driversNamespace;
 96:     }
 97: 
 98: 
 99:     /**
100:      * Return list of available names of processors
101:      *
102:      * @return array ([name] => AProcessorDriver)
103:      */
104:     public function getAvailable()
105:     {
106:         if (!$this->available)
107:         {
108:             $this->available = $this->detectAvailable();
109:         }
110:         return $this->available;
111:     }
112: 
113: 
114:     /**
115:      * Return information about processors
116:      *
117:      * @return array
118:      */
119:     public function getInformations()
120:     {
121:         if (!$this->informations)
122:         {
123:             $this->informations = $this->readInformations();
124:         }
125:         return $this->informations;
126:     }
127: 
128: 
129:     /**
130:      * Run one XSLT transformation in the processor
131:      *
132:      * @param string $processorName Name of used processor
133:      * @param string $templatePath Path of XSLT template
134:      * @param string $xmlInputPath Path of XML input file
135:      * @param string $outputPath Path of generated output file
136:      *
137:      * @return array|string List of spend times on transformation|Error message
138:      */
139:     public function run($processorName, $templatePath, $xmlInputPath, $outputPath, $repeating)
140:     {
141:         $processors = $this->getAvailable();
142:         if (!isset($processors[$processorName]))
143:         {
144:             throw new \XSLTBenchmarking\InvalidArgumentException('Unknown processor "' . $processorName . '"');
145:         }
146: 
147:         $processor = $processors[$processorName];
148: 
149:         P::mcf($templatePath);
150:         P::mcf($xmlInputPath);
151: 
152:         // stylesheet for transformation have to be set in input XML file
153:         if ($processor->isTemplateSetInInput())
154:         {
155:             $xmlInputPath = $this->makeInputWithTemplatePath($xmlInputPath, $templatePath);
156:         }
157: 
158:         $errorPath = P::m($this->tmpDir, 'transformation.err');
159: 
160:         $beforeCommand = $this->getCommand($processor->getBeforeCommandTemplate(), $templatePath, $xmlInputPath, $outputPath, $errorPath);
161:         $commandBase = $this->getCommand($processor->getCommandTemplate(), $templatePath, $xmlInputPath, $outputPath, $errorPath);
162:         $afterCommand = $this->getCommand($processor->getAfterCommandTemplate(), $templatePath, $xmlInputPath, $outputPath, $errorPath);
163: 
164:         $times = array();
165:         $memoryList = array();
166:         for ($repeatingIdx = 0; $repeatingIdx < $repeating; $repeatingIdx++)
167:         {
168:             if (is_file($errorPath))
169:             {
170:                 throw new \XSLTBenchmarking\InvalidStateException('Error tmp file should not exist "' . $errorPath . '"');
171:             }
172: 
173:             $command = $commandBase;
174: 
175:             // each transformation generate into separate file
176:             if ($repeatingIdx != 0)
177:             {
178:                 $outputPathNew = preg_replace('/[.]([^.]*)$/', '-' . $repeatingIdx . '.$1', $outputPath);
179:                 $command = str_replace($outputPath, $outputPathNew, $command);
180:             }
181: 
182:             // preparing command
183:             if ($beforeCommand)
184:             {
185:                 exec($beforeCommand);
186:             }
187: 
188:             // memore usage - run
189:             $command = $this->memoryUsage->run($command);
190: 
191:             // transformation command
192:             $timeStart = Microtime::now();
193:             exec($command);
194:             $timeEnd = Microtime::now();
195: 
196:             // memore usage - get
197:             $memoryList[] = (string)$this->memoryUsage->get();
198: 
199:             // concluding comand
200:             if ($afterCommand)
201:             {
202:                 exec($afterCommand);
203:             }
204: 
205:             // check exitence of generated file
206:             if ($repeatingIdx == 0 && !is_file($outputPath))
207:             {
208:                 $error = 'Output file was not be generated (' . $outputPath . ')';
209:                 // detect generated error
210:                 if (is_file($errorPath))
211:                 {
212:                     $error .= '; ' . file_get_contents($errorPath);
213:                     unlink($errorPath);
214:                 }
215: 
216:                 break;
217:             }
218:             if ($repeatingIdx != 0 && !is_file($outputPathNew))
219:             {
220:                 $error = 'Output file (repeated) was not be generated (' . $outputPathNew . ')';
221:                 // detect generated error
222:                 if (is_file($errorPath))
223:                 {
224:                     $error .= '; ' . file_get_contents($errorPath);
225:                     unlink($errorPath);
226:                 }
227: 
228:                 break;
229:             }
230: 
231:             // difference between two same transformation
232:             if ($repeatingIdx != 0)
233:             {
234:                 if (file_get_contents($outputPath) == file_get_contents($outputPathNew))
235:                 {
236:                     unlink($outputPathNew);
237:                 }
238:                 else
239:                 {
240:                     $error = 'Difference between two same transformation: (' . $outputPath . ') != (' . $outputPathNew . ')';
241:                     break;
242:                 }
243:             }
244: 
245:             // detect error
246:             if (is_file($errorPath))
247:             {
248:                 $error = file_get_contents($errorPath);
249:                 unlink($errorPath);
250:             }
251:             else
252:             {
253:                 $error = '';
254:             }
255: 
256:             if ($error)
257:             {
258:                 break;
259:             }
260: 
261:             // spend time
262:             $times[] = Microtime::substract($timeEnd, $timeStart);
263:         }
264: 
265:         if ($error)
266:         {
267:             return $error;
268:         }
269:         else
270:         {
271:             return array(
272:                 'times' => $times,
273:                 'memory' => $memoryList
274:             );
275:         }
276:     }
277: 
278: 
279:     // --- PRIVATE FUNCTIONS ---
280: 
281: 
282:     /**
283:      * Detect list of available names of processors
284:      *
285:      * @return array ([name] => AProcessorDriver)
286:      */
287:     private function detectAvailable()
288:     {
289:         $driversFiles = scandir($this->driversDir);
290: 
291:         $drivers = array();
292:         foreach ($driversFiles as $driverFile)
293:         {
294:             if (in_array($driverFile, array('AProcessorDriver.php', '.', '..')))
295:             {
296:                 continue;
297:             }
298: 
299:             // driver have to be php file
300:             if (substr($driverFile, -4) !== '.php')
301:             {
302:                 continue;
303:             }
304: 
305:             require_once P::m($this->driversDir, $driverFile);
306:             $className = $this->driversNamespace . substr($driverFile, 0, -4);
307:             $driver = new $className;
308: 
309:             // driver have to be instance of AProcessorDriver
310:             if (($driver instanceof AProcessorDriver) && ($driver->isAvailable()))
311:             {
312:                 $drivers[$driver->getName()] = $driver;
313:             }
314:         }
315: 
316:         return $drivers;
317:     }
318: 
319: 
320:     /**
321:      * Read information about processors
322:      *
323:      * @return array
324:      */
325:     private function readInformations()
326:     {
327:         $informations = array();
328:         foreach ($this->getAvailable() as $name => $processorDriver)
329:         {
330:             $informations[$name] = $processorDriver->getInformations();
331:         }
332: 
333:         return $informations;
334:     }
335: 
336: 
337:     /**
338:      * Make command from template
339:      *
340:      * Templates substitutions:
341:      * [XSLT] = path of XSLT template for transformation
342:      * [INPUT] = path of input XML file
343:      * [OUTPUT] = path of generated output XML file
344:      * [ERROR] = path of file for eventual generated error message
345:      * [PROCESSORS] = path of directory containing XSLT processors (libraries, command-line program etc.)
346:      * [LIBS] = path of Libs directory
347:      *
348:      * @param string $commandTemplate Template of command
349:      * @param string $templatePath Path of XSLT template for transformation
350:      * @param string $xmlInputPath Path of input XML file
351:      * @param string $outputPath Path of generated output XML file
352:      * @param string $errorPath Path of file for eventual generated error message
353:      *
354:      * @return string
355:      */
356:     private function getCommand($commandTemplate, $templatePath, $xmlInputPath, $outputPath, $errorPath)
357:     {
358:         $command = $commandTemplate;
359: 
360:         // replace substitutions
361:         $command = str_replace('[XSLT]', $templatePath, $command);
362:         $command = str_replace('[INPUT]', $xmlInputPath, $command);
363:         $command = str_replace('[OUTPUT]', $outputPath, $command);
364:         $command = str_replace('[ERROR]', $errorPath, $command);
365:         $command = str_replace('[PROCESSORS]', P::m(LIBS, 'Processors'), $command);
366:         $command = str_replace('[LIBS]', P::m(LIBS), $command);
367: 
368:         return $command;
369:     }
370: 
371: 
372:     /**
373:      * Add into input XML path of template by directive "<?xml-stylesheet href="[XSLT]" type="text/xml" ..."
374:      * and return path of generated file (in temporary directory).
375:      *
376:      * @param string $xmlInputPath Path of input XML
377:      * @param string $templatePath Path of template
378:      *
379:      * @return string
380:      */
381:     private function makeInputWithTemplatePath($xmlInputPath, $templatePath)
382:     {
383:         $content = file_get_contents($xmlInputPath);
384: 
385:         // add template path
386:         $content = str_replace(
387:             '<?xml version="1.0" encoding="UTF-8"?>',
388:             '<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="' . $templatePath . '" ?>',
389:             $content
390:         );
391: 
392:         $xmlInputPath = P::m($this->tmpDir, basename($xmlInputPath));
393:         file_put_contents($xmlInputPath, $content);
394: 
395:         return $xmlInputPath;
396:     }
397: 
398: 
399: }
400: 
XSTL Benchmarking API documentation generated by ApiGen.
Generated using the TokenReflection library.