1 <?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
23 class SWyEdConverterDOM
24 {
25 26 27 28
29 private $_mapper = array(
30
31 'w-intial-node-id' => "/ns:graphml/ns:key[@for='graph'][@attr.name='Initial-node-id']/@id",
32
33
34 'n-constraint' => "/ns:graphml/ns:key[@for='node'][@attr.name='Constraint']/@id",
35 'n-label' => "/ns:graphml/ns:key[@for='node'][@attr.name='Label']/@id",
36 'n-graphics' => "/ns:graphml/ns:key[@for='node'][@yfiles.type='nodegraphics']/@id",
37
38
39 'e-task' => "/ns:graphml/ns:key[@for='edge'][@attr.name='Task']/@id",
40 );
41 42 43
44 private $_dom;
45 46 47
48 private $_xp;
49 50 51 52
53 private $_yedProperties = array();
54 55 56 57 58
59 public function convert($graphmlFile)
60 {
61 $this->_dom = new DOMDocument();
62 $this->_dom->load($graphmlFile);
63
64 $this->_xp = new DOMXPath($this->_dom);
65 $this->_xp->registerNamespace('ns','http://graphml.graphdrawing.org/xmlns');
66 $this->_xp->registerNamespace('y','http://www.yworks.com/xml/graphml');
67
68 $this->_extractYedProperties();
69
70 $workflow = $this->_collectWorkflow();
71
72
73 $nodes = $this->_collectNodes();
74
75
76 $edges = $this->_collectEdges();
77
78
79
80 $result = $this->_createSwWorkflow($workflow, $nodes, $edges);
81
82 return $result;
83
84 }
85 86 87 88 89 90 91 92
93 private function _createSwWorkflow($w,$n,$e)
94 {
95 $nodes=array();
96
97 foreach ($n as $key => $node) {
98
99 $newNode = array(
100 'id' => $node['id'],
101 'label' => $node['label'],
102 'constraint' => $node['constraint'],
103 'metadata' => array(
104 'background-color' => $node['background-color'],
105 'color' => $node['color']
106 )
107 );
108 if(isset($e[$key])){
109 foreach ($e[$key] as $trgKey => $edge) {
110 $newNode['transition'][$n[$trgKey]['id']] = $edge;
111 }
112 }
113
114
115
116 if(isset($newNode['transition'])){
117 foreach($newNode['transition'] as $targetId => $edge){
118 if(count($edge) == 0){
119 unset($newNode['transition'][$targetId]);
120 $newNode['transition'][] = $targetId;
121 }elseif(isset($edge['task'])){
122 $newNode['transition'][$targetId] = $edge['task'];
123 }
124 }
125 }
126 $nodes[] = $newNode;
127 }
128 return array(
129 'initial' => $w['initial'],
130 'node' => $nodes
131 );
132 }
133 134 135 136
137 private function ()
138 {
139 foreach ($this->_mapper as $attrName => $xp) {
140
141 $nodeList = $this->_xp->query($xp);
142 if( $nodeList->length != 1){
143 throw new CException("failed to extract id for attribute $attrName");
144 }
145
146 $this->_yedProperties[$attrName] = $nodeList->item(0)->value;
147 }
148 }
149 150 151 152
153 private function _collectWorkflow()
154 {
155 $nlGraph = $this->_xp->query('//ns:graph');
156 if($nlGraph->length == 0)
157 throw new CException("no workflow definition found");
158
159 if($nlGraph->length > 1)
160 throw new CException("more than one workflow found");
161
162
163
164
165 $nl2 = $this->_xp->query('/ns:graphml/ns:graph/ns:data[@key="'.$this->_yedProperties['w-intial-node-id'].'"]');
166 if($nl2->length!=1 || $this->_isBlank($nl2->item(0)->nodeValue) )
167 throw new CException("failed to extract initial node id for this workflow");
168
169 $result=array(
170 'initial' => trim($nl2->item(0)->nodeValue)
171 );
172
173 return $result;
174 }
175 176 177 178 179
180 private function _collectEdges()
181 {
182 $nlEdges = $this->_xp->query('//ns:edge');
183 if($nlEdges->length == 0)
184 throw new CException("no edge could be found in this workflow");
185
186 $result=array();
187 for($i=0; $i < $nlEdges->length; $i++)
188 {
189 $currentNode= $nlEdges->item($i);
190
191 $source = trim($this->_xp->query("@source",$currentNode)->item(0)->value);
192 $target = trim($this->_xp->query("@target",$currentNode)->item(0)->value);
193
194 if(!isset($result[$source]) || !isset($result[$source][$target])){
195 $result[$source][$target] = array();
196 }
197
198
199
200
201 $nl2 = $this->_xp->query('ns:data[@key="'.$this->_yedProperties['e-task'].'"]',$currentNode);
202 if($nl2->length==1 && ! $this->_isBlank($nl2->item(0)->nodeValue))
203 $result[$source][$target]['task'] = trim($nl2->item(0)->nodeValue);
204 }
205 return $result;
206 }
207 208 209 210 211 212 213 214
215 private function _collectNodes()
216 {
217 $nlNodes = $this->_xp->query('//ns:node');
218 if($nlNodes->length == 0)
219 throw new CException("no node could be found in this workflow");
220
221 $result=array();
222 for($i=0; $i < $nlNodes->length; $i++)
223 {
224 $currentNode = $nlNodes->item($i);
225
226 $nl2 = $this->_xp->query("@id",$currentNode);
227
228 if($nl2->length != 1)
229 throw new CException("failed to extract yed node id");
230
231
232 $yNodeId = trim($nl2->item(0)->value);
233
234
235
236 $nl2 = $this->_xp->query('ns:data[@key="'.$this->_yedProperties['n-graphics'].'"]/y:ShapeNode/y:NodeLabel',$currentNode);
237 if($nl2->length !=1)
238 continue;
239
240 $result[$yNodeId] = array();
241 $result[$yNodeId]['id'] = trim($nl2->item(0)->nodeValue);
242
243
244
245 $nl2 = $this->_xp->query('ns:data[@key="'.$this->_yedProperties['n-constraint'].'"]',$currentNode);
246 if($nl2->length==1)
247 $result[$yNodeId]['constraint'] = trim($nl2->item(0)->nodeValue);
248
249 $nl2 = $this->_xp->query('ns:data[@key="'.$this->_yedProperties['n-label'].'"]',$currentNode);
250 if($nl2->length==1)
251 $result[$yNodeId]['label'] = trim($nl2->item(0)->nodeValue);
252
253 $nl2 = $this->_xp->query('ns:data[@key="'.$this->_yedProperties['n-graphics'].'"]/y:ShapeNode/y:Fill/@color',$currentNode);
254 if($nl2->length ==1)
255 $result[$yNodeId]['background-color'] = trim($nl2->item(0)->nodeValue);
256
257 $nl2 = $this->_xp->query('ns:data[@key="'.$this->_yedProperties['n-graphics'].'"]/y:ShapeNode/y:NodeLabel/@textColor',$currentNode);
258 if($nl2->length ==1)
259 $result[$yNodeId]['color'] = trim($nl2->item(0)->nodeValue);
260 }
261 return $result;
262 }
263 264 265 266
267 private function _isBlank($str)
268 {
269 return !isset($str) || strlen(trim($str)) == 0;
270 }
271 }