1 package xdoclet.sdk.xgg.binding;
2
3 import java.util.Collection;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Iterator;
7 import java.util.Map;
8 import java.util.Set;
9 import java.util.Stack;
10
11 import org.relaxng.datatype.Datatype;
12
13 import com.sun.msv.grammar.AttributeExp;
14 import com.sun.msv.grammar.ChoiceExp;
15 import com.sun.msv.grammar.ConcurExp;
16 import com.sun.msv.grammar.DataExp;
17 import com.sun.msv.grammar.ElementExp;
18 import com.sun.msv.grammar.Expression;
19 import com.sun.msv.grammar.ExpressionPool;
20 import com.sun.msv.grammar.ExpressionVisitor;
21 import com.sun.msv.grammar.InterleaveExp;
22 import com.sun.msv.grammar.ListExp;
23 import com.sun.msv.grammar.MixedExp;
24 import com.sun.msv.grammar.NameClass;
25 import com.sun.msv.grammar.OneOrMoreExp;
26 import com.sun.msv.grammar.OtherExp;
27 import com.sun.msv.grammar.ReferenceExp;
28 import com.sun.msv.grammar.SequenceExp;
29 import com.sun.msv.grammar.ValueExp;
30
31 /***
32 * This visitor visits a RNG grammar model and constructs an XGG model from it.
33 * The XGG model is simpler than the RNG model, and will be used to
34 * generate java beans representing the elements in the grammar.
35 *
36 * @author <a href="mailto:aslak.hellesoy at bekk.no">Aslak Hellesøy</a>
37 * @author <a href="mailto:christian at inx-soft.com">Christian Kvalheim</a>
38 * @author <a href="mailto:letiemble at users.sourceforge.net">Laurent Etiemble</a>
39 * @version $Revision: 1.7 $
40 */
41 class XGGVisitor implements ExpressionVisitor {
42 private final Stack _bindings = new Stack();
43 private final HashMap _cardinalities = new HashMap();
44 private final Map _elementMap = new HashMap();
45 private final Stack _elements = new Stack();
46 private final ExpressionPool _expressionPool;
47
48 /*** The current version */
49 private final String _version;
50 /*** We're keeping track of already visited ElementExp to avoid infinite recursion. */
51 private final Set _visitedElementExps = new HashSet();
52
53 /***
54 * Constructor for the XGGVisitor object
55 *
56 * @param expressionPool Description of the Parameter
57 * @param version Description of the Parameter
58 */
59 public XGGVisitor(ExpressionPool expressionPool, String version) {
60 _expressionPool = expressionPool;
61 _version = version;
62 }
63
64
65 /***
66 * Gets the elements attribute of the XGGVisitor object
67 *
68 * @return The elements value
69 */
70 public Collection getElements() {
71 return _elementMap.values();
72 }
73
74
75 /***
76 * Description of the Method
77 *
78 * @return Description of the Return Value
79 */
80 public Object onAnyString() {
81 // If a current binding is defined, set it up
82 if (!_bindings.isEmpty()) {
83 Binding binding = (Binding) _bindings.peek();
84 binding.setRegexp(".*");
85 }
86
87 return null;
88 }
89
90
91 /***
92 * Description of the Method
93 *
94 * @param attributeExp Description of the Parameter
95 * @return Description of the Return Value
96 */
97 public Object onAttribute(AttributeExp attributeExp) {
98 // Add the attribute to the current element
99 Element element = (Element) _elements.peek();
100
101 // Create the Attribute binding
102 Attribute attribute = new Attribute(attributeExp.getNameClass().toString(), element);
103 element.addChild(attribute);
104
105 // Set the current binding
106 _bindings.push(attribute);
107
108 // Visit the content
109 Expression contentModel = attributeExp.getContentModel();
110 contentModel.visit(this);
111
112 // Unset the current binding
113 _bindings.pop();
114
115 // Set the cardinality
116 Cardinality card = (Cardinality) _cardinalities.get(element);
117 if (card != null) {
118 // If there is a cardinality context, set the minimum
119 attribute.getCardinality().setMin(card.getMin());
120 }
121
122 return attribute;
123 }
124
125
126 /***
127 * Description of the Method
128 *
129 * @param choiceExp Description of the Parameter
130 * @return Description of the Return Value
131 */
132 public Object onChoice(ChoiceExp choiceExp) {
133 // Check if there is an element
134 Element element = null;
135 if (!_elements.isEmpty()) {
136 element = (Element) _elements.peek();
137 }
138
139 // Check if there is a related cardinality
140 Cardinality card = (Cardinality) _cardinalities.get(element);
141 boolean started = (card == null);
142 if (started) {
143 card = new Cardinality(Cardinality.ZERO, Cardinality.ONE);
144 _cardinalities.put(element, card);
145 }
146
147 // Visit the children
148 for (Iterator children = choiceExp.children(); children.hasNext(); ) {
149 Expression child = (Expression) children.next();
150 child.visit(this);
151 }
152
153 // If the cardinality was created here, then dispose it
154 if (started) {
155 _cardinalities.remove(element);
156 }
157
158 return null;
159 }
160
161
162 /***
163 * Description of the Method
164 *
165 * @param concurExp Description of the Parameter
166 * @return Description of the Return Value
167 */
168 public Object onConcur(ConcurExp concurExp) {
169 return null;
170 }
171
172
173 /***
174 * Description of the Method
175 *
176 * @param dataExp Description of the Parameter
177 * @return Description of the Return Value
178 */
179 public Object onData(DataExp dataExp) {
180 // Get the Data Type
181 Datatype dt = dataExp.getType();
182
183 // If a current binding is defined, set it up
184 if (!_bindings.isEmpty()) {
185 Binding binding = (Binding) _bindings.peek();
186 binding.setRegexp(DataTypeUtils.getRegexp(dt));
187 }
188
189 return null;
190 }
191
192
193 /***
194 * Description of the Method
195 *
196 * @param elementExp Description of the Parameter
197 * @return Description of the Return Value
198 */
199 public Object onElement(ElementExp elementExp) {
200 // Create a new XGG Element
201 Element newElement = getElement(elementExp);
202
203 // Add the new element to the current one.
204 if (!_elements.isEmpty()) {
205 Element parent = (Element) _elements.peek();
206
207 // Grab the cardinality associated to the parent
208 Cardinality card = (Cardinality) _cardinalities.get(parent);
209
210 // Seek if SubElement has already been registered
211 SubElement subElement = parent.getSubElement(newElement.getXmlName());
212 boolean create = (subElement == null);
213 if (create) {
214 subElement = new SubElement(newElement, parent);
215 parent.addChild(subElement);
216
217 // If a cardinality exists, set the values
218 if (card != null) {
219 subElement.getCardinality().setMin(card.getMin());
220 subElement.getCardinality().setMax(card.getMax());
221 }
222 } else {
223 // If a cardinality dosen't exists, use the element one
224 if (card == null) {
225 subElement.getCardinality().setMin(subElement.getCardinality().getMin() + 1);
226 } else {
227 // If a cardinality exists...
228 if (card.getMax() != Cardinality.UNBOUNDED) {
229 // ... alter value
230 subElement.getCardinality().setMax(subElement.getCardinality().getMax() + card.getMax());
231 } else {
232 // ... set value
233 subElement.getCardinality().setMax(Cardinality.UNBOUNDED);
234 }
235 }
236 }
237 // Normalize the cardinality
238 subElement.getCardinality().normalize();
239
240 // Set and augment the index.
241
242 }
243
244 if (_visitedElementExps.add(elementExp)) {
245 _elements.push(newElement);
246
247 // Set the current binding
248 _bindings.push(newElement);
249
250 // Visit the content
251 Expression contentModel = elementExp.getContentModel();
252 contentModel.visit(this);
253
254 // Unset the current binding
255 _bindings.pop();
256
257 _elements.pop();
258 }
259
260 return newElement;
261 }
262
263
264 /***
265 * Description of the Method
266 *
267 * @return Description of the Return Value
268 */
269 public Object onEpsilon() {
270 return null;
271 }
272
273
274 /***
275 * Description of the Method
276 *
277 * @param interleaveExp Description of the Parameter
278 * @return Description of the Return Value
279 */
280 public Object onInterleave(InterleaveExp interleaveExp) {
281 for (Iterator children = interleaveExp.children(); children.hasNext(); ) {
282 Expression child = (Expression) children.next();
283 child.visit(this);
284 }
285
286 return null;
287 }
288
289
290 /***
291 * Description of the Method
292 *
293 * @param listExp Description of the Parameter
294 * @return Description of the Return Value
295 */
296 public Object onList(ListExp listExp) {
297 listExp.exp.visit(this);
298
299 return null;
300 }
301
302
303 /***
304 * Description of the Method
305 *
306 * @param mixedExp Description of the Parameter
307 * @return Description of the Return Value
308 */
309 public Object onMixed(MixedExp mixedExp) {
310 mixedExp.exp.visit(this);
311
312 return null;
313 }
314
315
316 /***
317 * Description of the Method
318 *
319 * @return Description of the Return Value
320 */
321 public Object onNullSet() {
322 return null;
323 }
324
325
326 /***
327 * Description of the Method
328 *
329 * @param oneOrMoreExp Description of the Parameter
330 * @return Description of the Return Value
331 */
332 public Object onOneOrMore(OneOrMoreExp oneOrMoreExp) {
333 // Check if there is an element
334 Element element = null;
335 if (!_elements.isEmpty()) {
336 element = (Element) _elements.peek();
337 }
338
339 // Check if there is a related cardinality
340 Cardinality card = (Cardinality) _cardinalities.get(element);
341 boolean started = (card == null);
342 if (started) {
343 card = new Cardinality(Cardinality.ONE, Cardinality.UNBOUNDED);
344 _cardinalities.put(element, card);
345 }
346 card.setMax(Cardinality.UNBOUNDED);
347
348 // Visit the expression
349 oneOrMoreExp.exp.visit(this);
350
351 // If the cardinality was created here, then dispose it
352 if (started) {
353 _cardinalities.remove(element);
354 }
355
356 return null;
357 }
358
359
360 /***
361 * Description of the Method
362 *
363 * @param otherExp Description of the Parameter
364 * @return Description of the Return Value
365 */
366 public Object onOther(OtherExp otherExp) {
367 otherExp.exp.visit(this);
368
369 return null;
370 }
371
372
373 /***
374 * Description of the Method
375 *
376 * @param referenceExp Description of the Parameter
377 * @return Description of the Return Value
378 */
379 public Object onRef(ReferenceExp referenceExp) {
380 Expression expanded = referenceExp.getExpandedExp(_expressionPool);
381 expanded.visit(this);
382
383 return null;
384 }
385
386
387 /***
388 * Description of the Method
389 *
390 * @param sequenceExp Description of the Parameter
391 * @return Description of the Return Value
392 */
393 public Object onSequence(SequenceExp sequenceExp) {
394 for (Iterator children = sequenceExp.children(); children.hasNext(); ) {
395 Expression child = (Expression) children.next();
396 child.visit(this);
397 }
398
399 return null;
400 }
401
402
403 /***
404 * Description of the Method
405 *
406 * @param valueExp Description of the Parameter
407 * @return Description of the Return Value
408 */
409 public Object onValue(ValueExp valueExp) {
410 // Get the Data Type
411 Datatype dt = valueExp.getType();
412
413 // If a current binding is defined, set it up
414 if (!_bindings.isEmpty()) {
415 Binding binding = (Binding) _bindings.peek();
416 binding.setRegexp(DataTypeUtils.getRegexp(dt));
417 }
418
419 return null;
420 }
421
422
423 /***
424 * Gets the element attribute of the XGGVisitor object
425 *
426 * @param elementExp Description of the Parameter
427 * @return The element value
428 */
429 private Element getElement(ElementExp elementExp) {
430 // The xmlName is the same as in the DTD
431 NameClass nameClass = elementExp.getNameClass();
432 String xmlName = nameClass.toString();
433
434 Element result = (Element) _elementMap.get(xmlName);
435 if (result == null) {
436 result = new Element(xmlName, _version);
437 _elementMap.put(xmlName, result);
438 }
439
440 return result;
441 }
442 }
This page was automatically generated by Maven