Overview
Namespaces
Classes
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\Reports;
11:
12: require_once ROOT . '/Exceptions.php';
13: require_once LIBS . '/PhpPath/PhpPath.min.php';
14:
15: use PhpPath\P;
16:
17: /**
18: * Merging of more reported tests into one XML file.
19: *
20: * @author Viktor Mašíček <viktor@masicek.net>
21: */
22: class Merger
23: {
24:
25:
26: /**
27: * List of reports for generating
28: *
29: * @var arry of \SimpleXML
30: */
31: private $reports;
32:
33:
34: /**
35: * Make merge of all added reports, save result into file and
36: * return path of generated file
37: *
38: * @param string $outputDirPath Path of directory for generating mergered report
39: *
40: * @return string
41: */
42: public function merge($outputDirPath)
43: {
44: // make name of output
45: P::cd($outputDirPath);
46: $outputPath = P::m($outputDirPath, date('Y-m-d-H-i-s'). '-merge' . '.xml');
47:
48: $mergeredReports = $this->getMergeredReport();
49: $this->saveMegeredReports($outputPath, $mergeredReports);
50:
51: return $outputPath;
52: }
53:
54:
55: /**
56: * Add report into list of mergered reports
57: *
58: * @param string $path Path of XML file with reports
59: *
60: * @throws \XSLTBenchmarking\InvalidArgumentException Wrong format of file with params
61: * @return void
62: */
63: public function addReportFile($path)
64: {
65: $path = P::mcf($path);
66:
67: // validate
68: $dom = new \DOMDocument();
69: $dom->load($path);
70: try {
71: $dom->schemaValidate(P::m(__DIR__, 'Report.xsd'));
72: } catch (\Exception $e) {
73: $error = libxml_get_last_error();
74: throw new \XSLTBenchmarking\InvalidArgumentException(
75: 'File "' . $path . '" has wrong format: ' . $error->message
76: );
77: }
78:
79: // make SimpleXML
80: $report = new \SimpleXMLElement($path, 0, TRUE);
81:
82: $this->reports[] = $report;
83: }
84:
85:
86: /**
87: * Merge reports into one SimpleXML object.
88: *
89: * @return \SimpleXMLElement
90: */
91: private function getMergeredReport()
92: {
93: $mergeEl = new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><reports></reports>');
94:
95: // skeleton
96: $globalEl = $mergeEl->addChild('global');
97: $processorsListEl = $globalEl->addChild('processors');
98: $testsListEl = $mergeEl->addChild('tests');
99:
100: foreach ($this->reports as $report)
101: {
102: // processors
103: $processors = $report->xpath('//global/processors');
104: $this->copyChilds($processors[0], $processorsListEl, array('processor|name'));
105:
106: // tests
107: $tests = $report->xpath('//tests');
108: $this->copyChilds($tests[0], $testsListEl, array('test|name', 'processor|name', 'input|input|expectedOutput'));
109: }
110:
111: return $mergeEl;
112: }
113:
114:
115: /**
116: * Copy children elements from source element into destination element.
117: * Runction is called recursively if $childrenInfos have more than one value.
118: *
119: * @param \SimpleXMLElement $sourceElement Source XML element
120: * @param \SimpleXMLElement $destinationElement Destionation XML element
121: * @param array $childrenInfos Information for copy.
122: * Each value is name of copied element and atributes for comapring (separated by '|').
123: *
124: * @return void
125: */
126: private function copyChilds(
127: \SimpleXMLElement $sourceElement,
128: \SimpleXMLElement $destinationElement,
129: array $childrenInfos = array()
130: )
131: {
132: $childInfo = array_shift($childrenInfos);
133: $infos = explode('|', $childInfo);
134: $childName = array_shift($infos);
135:
136: $childrenElements = $sourceElement->xpath($childName);
137: foreach ($childrenElements as $childElement)
138: {
139: $checkRule = array();
140: foreach ($infos as $info)
141: {
142: $checkRule[] = '@' . $info . '="' . (string)$childElement[$info] . '"';
143: }
144: if ($checkRule)
145: {
146: $checkRule = '[' . implode(' and ', $checkRule) . ']';
147: }
148:
149: $destionationChildElements = $destinationElement->xpath($childName . $checkRule);
150: if (count($destionationChildElements) == 0)
151: {
152: $addedElement = $destinationElement->addChild($childName);
153: }
154: else
155: {
156: $addedElement = $destionationChildElements[0];
157: }
158:
159: // copy attribute - newer values are preferred
160: $this->copyOrReplaceAttributes($childElement, $addedElement);
161:
162: // copy children
163: if (count($childrenInfos) > 0)
164: {
165: $this->copyChilds($childElement, $addedElement, $childrenInfos);
166: }
167: }
168: }
169:
170:
171: /**
172: * Copy element from source element into destination element.
173: * If attribute existed in destination element, than its value is replaced by newer.
174: *
175: * @param \SimpleXMLElement $sourceElement Source XML element
176: * @param \SimpleXMLElement $destinationElement Destionation XML element
177: *
178: * @return void
179: */
180: private function copyOrReplaceAttributes(\SimpleXMLElement $sourceElement, \SimpleXMLElement $destinationElement)
181: {
182: foreach ($sourceElement->attributes() as $name => $value)
183: {
184: $destinationElement[$name] = $value;
185: }
186: }
187:
188:
189: /**
190: * Save mergered reports into file. XML is indented.
191: *
192: * @param sring $outputPath Path of file
193: * @param \SimpleXMLElement $mergeredReports Report for saving
194: *
195: * @return void
196: */
197: private function saveMegeredReports($outputPath, \SimpleXMLElement $mergeredReports)
198: {
199: // save + make indent
200: $dom = dom_import_simplexml($mergeredReports)->ownerDocument;
201: $dom->formatOutput = TRUE;
202: $dom->save($outputPath);
203: }
204:
205:
206: }
207: