Overview
Namespaces
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
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 LIBS . '/PhpPath/PhpPath.min.php';
14:
15: use PhpPath\P;
16:
17: /**
18: * Class for control that two files has same content.
19: * For XML, HTML, XHTML etc. do normalize both files before comapring.
20: *
21: * @author Viktor Mašíček <viktor@masicek.net>
22: */
23: class Controlor
24: {
25:
26:
27: /**
28: * Check, if set files have same content.
29: * For XML, HTML, XHTML etc. do normalize both files before comapring.
30: *
31: * @param string $filePath1 Path of the first file
32: * @param string $filePath2 Path of the second file
33: *
34: * @return bool
35: */
36: public function isSame($filePath1, $filePath2)
37: {
38: P::mcf($filePath1);
39: P::mcf($filePath2);
40:
41: $content1 = file_get_contents($filePath1);
42: $content2 = file_get_contents($filePath2);
43:
44: // unify EOL
45: $content1 = str_replace("\r\n", "\n", $content1);
46: $content2 = str_replace("\r\n", "\n", $content2);
47:
48: // normalize
49: $extension1 = strtolower(pathinfo($filePath1, PATHINFO_EXTENSION));
50: if ($extension1 == 'xml' || $extension1 == 'html')
51: {
52: $content1 = $this->normalizeXml($content1, $extension1);
53: }
54: else
55: {
56: // unify possible declaration in "non XML files"
57: $content1 = $this->unifyDeclaration($content1);
58: }
59:
60: $extension2 = strtolower(pathinfo($filePath2, PATHINFO_EXTENSION));
61: if ($extension2 == 'xml' || $extension2 == 'html')
62: {
63: $content2 = $this->normalizeXml($content2, $extension2);
64: }
65: else
66: {
67: // unify possible declaration in "non XML files"
68: $content2 = $this->unifyDeclaration($content2);
69: }
70:
71: return $content1 == $content2;
72: }
73:
74:
75: /**
76: * If content is XML, then return normalized XML input content.
77: * - remove insignificant whitespaces
78: * - sort attributes alphabetical
79: * If content is not XML, return input content.
80: *
81: * @param string $inputContent Normalizing content
82: * @param string $extension Extension of file from withc is content
83: *
84: * @return string
85: */
86: private function normalizeXml($inputContent, $extension)
87: {
88: // add declaration, if not presented for XML
89: if ($extension == 'xml')
90: {
91: // get begin with possible declaration
92: $beginEndIdx = strpos($inputContent, '>');
93: $begin = substr($inputContent, 0, $beginEndIdx + 1);
94: // clean begin (e.g. for UTF-16)
95: $begin = preg_replace('/[^ a-zA-Z0-9?"\'.=<>-]/', '', $begin);
96: if (preg_match('/<\?xml[^?]+\?>/', $begin) === 0)
97: {
98: $inputContent = '<?xml version="1.0" encoding="UTF-8" ?>' . $inputContent;
99: }
100: }
101:
102: // remove insignificant whitespaces
103: // simplier empty elements ('<el></el>' => '<el/>')
104: // simplier attributes ('att = "aaa" att2="bbb"' => 'att="aaa" att2="bbb"')
105: $dom = new \DOMDocument();
106: $dom->preserveWhiteSpace = FALSE;
107: // catch error/warning/notice during reading content as XML or HTML
108: set_error_handler(array($this, 'errorHandler'));
109: try
110: {
111: if ($extension == 'xml')
112: {
113: $dom->loadXml($inputContent);
114: }
115: if ($extension == 'html')
116: {
117: $dom->loadHTML($inputContent);
118: $outputContent = $dom->saveXML();
119: $dom->loadXml($outputContent);
120: }
121: }
122: catch (\Exception $e)
123: {
124: restore_error_handler();
125: // input is not XML or HTML
126: return $inputContent;
127: }
128: restore_error_handler();
129: $outputContent = $dom->saveXML();
130:
131: // normalize empty atribute ('att' => 'att=""')
132: // TODO
133:
134: // sort attributes
135: $outputContent = preg_replace_callback('#<[^/?][^>]*>#', array($this, 'sortAttributes'), $outputContent);
136:
137: $outputContent = $this->unifyDeclaration($outputContent);
138:
139: return $outputContent;
140: }
141:
142:
143: /**
144: * Unify declaration of content. If any declaration are not in content, return unchanged it.
145: *
146: * @param string $content
147: *
148: * @return string
149: */
150: private function unifyDeclaration($content)
151: {
152: $outputContent = $content;
153: $declarationLast = strpos($outputContent, '?>');
154: if ($declarationLast !== FALSE)
155: {
156: $declaration = substr($outputContent, 0, $declarationLast);
157: $declarationUnify = trim($declaration);
158: $declarationUnify = strtolower($declarationUnify);
159: $outputContent = $declarationUnify . substr($outputContent, $declarationLast);
160: }
161:
162: return $outputContent;
163: }
164:
165:
166: /**
167: * Normalize element
168: * - remove insignificant whitespaces
169: * - sort attributes alphabetical
170: *
171: * @param array $matches The first value is parsed element
172: *
173: * @return string
174: */
175: private function sortAttributes($matches)
176: {
177: $input = $matches[0];
178:
179: // begin
180: $beginLast = strpos($input, ' ');
181: $beginLast = $beginLast ?: strpos($input, '/>');
182: $beginLast = $beginLast ?: strpos($input, '>');
183: $begin = substr($input, 0, $beginLast);
184:
185: // end
186: $endFirst = strrpos($input, '/>');
187: $endFirst = $endFirst ?: strrpos($input, '>');
188: $end = substr($input, $endFirst);
189:
190: // attributes
191: $attributes = $input;
192: $attributes = str_replace($begin, '', $attributes);
193: $attributes = str_replace($end, '', $attributes);
194: if ($attributes)
195: {
196: preg_match_all('/[^ ]+="[^"]*"/', $attributes, $matches);
197: $attributes = $matches[0];
198: $attributes = array_filter($attributes);
199: sort($attributes);
200: $attributes = implode(' ', $attributes);
201: }
202:
203: if ($attributes)
204: {
205: $output = $begin . ' ' . $attributes . $end;
206: }
207: else
208: {
209: $output = $begin . $end;
210: }
211:
212: return $output;
213: }
214:
215:
216: /**
217: * Handling of error during reading XML or HTML file.
218: *
219: * @param type $errno
220: * @param type $errstr
221: *
222: * @return void
223: */
224: public function errorHandler($errno, $errstr)
225: {
226: throw new \Exception('Error handler');
227: }
228:
229:
230: }
231: