1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.xolite.impl;
17
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import javax.xml.namespace.NamespaceContext;
28
29 import net.sf.xolite.NamespacedName;
30 import net.sf.xolite.XMLEventParser;
31 import net.sf.xolite.XMLObjectFactory;
32 import net.sf.xolite.XMLParseException;
33 import net.sf.xolite.XMLSerializable;
34
35
36
37
38
39
40
41 public abstract class BaseXMLEventParser implements XMLEventParser {
42
43
44
45 private XMLSerializable currentHandler;
46
47 private XMLSerializable lastParsed;
48
49 private List<LevelInfo> levels;
50
51 private int currentLevel = -1;
52
53 private boolean currentlyInTagEnd;
54
55 private boolean currentlyInFirstOrLast;
56
57 private XMLObjectFactory factory;
58
59 private Map<Object, Object> customObjects;
60
61
62 public BaseXMLEventParser() {
63 levels = new ArrayList<LevelInfo>();
64 }
65
66
67
68
69
70
71
72
73 public void setFactory(XMLObjectFactory newFactory) {
74 factory = newFactory;
75 }
76
77
78
79
80
81
82
83
84 public String getNamespaceURI(String prefix) {
85 for (int i = currentLevel; i >= 0; i--) {
86 String uri = levels.get(i).getPrefixMappings().getNamespaceURI(prefix);
87 if (uri != null) return uri;
88 }
89 return null;
90 }
91
92
93
94
95
96
97
98 public String getPrefix(String namespaceURI) {
99 for (int i = currentLevel; i >= 0; i--) {
100 String prefix = levels.get(i).getPrefixMappings().getPrefix(namespaceURI);
101 if (prefix != null) return prefix;
102 }
103 return null;
104 }
105
106
107
108
109
110
111
112 public Iterator<String> getPrefixes(String namespaceURI) {
113 Set<String> prefixes = new HashSet<String>();
114 for (int i = currentLevel; i >= 0; i--) {
115 MapPrefixResolver prefixMappings = levels.get(i).getPrefixMappings();
116 for (Iterator<String> levelPrefixes = prefixMappings.getPrefixes(namespaceURI); levelPrefixes.hasNext();) {
117 prefixes.add(levelPrefixes.next());
118 }
119 }
120 return prefixes.iterator();
121 }
122
123
124
125
126
127 public NamespacedName getCurrentElementName() {
128 LevelInfo level = getCurrentLevel();
129 return new NamespacedName(level.getCurrentURI(), level.getCurrentElementName());
130 }
131
132
133 public NamespaceContext getCurrentDefinedNamespaces() {
134 MapPrefixResolver context = new MapPrefixResolver();
135 for (int i = 0; i <= currentLevel; i++) {
136 MapPrefixResolver prefixMappings = levels.get(i).getPrefixMappings();
137 context.addAll(prefixMappings);
138 }
139 return context;
140 }
141
142
143 public void delegateParsingTo(XMLSerializable handlerOfSubElements) throws XMLParseException {
144 if (currentHandler == null) throw new IllegalStateException("The currentHandler is null");
145 LevelInfo level = getCurrentLevel();
146 if (level == null)
147 throw new IllegalStateException("The delegateParsingTo(..) method can only be called from startElement(..)");
148 if (currentlyInTagEnd)
149 throw new IllegalStateException("The delegateParsingTo(..) method can only be called from startElement(..)");
150 level.addHandler(handlerOfSubElements);
151 currentHandler = handlerOfSubElements;
152 currentlyInFirstOrLast = true;
153 handlerOfSubElements.startElement(level.getCurrentURI(), level.getCurrentElementName(), this);
154 currentlyInFirstOrLast = false;
155 }
156
157
158 public XMLSerializable parseElement(String uri, String localName) throws XMLParseException {
159 XMLSerializable child = getFactory().createObject(uri, localName, this);
160 delegateParsingTo(child);
161 return child;
162 }
163
164
165 public boolean isFirstEvent() {
166 return currentlyInFirstOrLast && !currentlyInTagEnd;
167 }
168
169
170 public boolean isLastEvent() {
171 return currentlyInFirstOrLast && currentlyInTagEnd;
172 }
173
174
175 public XMLSerializable getLastParsedObject() throws XMLParseException {
176 return lastParsed;
177 }
178
179
180 public NamespacedName getQualifiedName(String qName) throws XMLParseException {
181 int colonIndex = qName.indexOf(':');
182 String prefix = (colonIndex < 0) ? "" : qName.substring(0, colonIndex);
183 String uri = getNamespaceURI(prefix);
184 if ((uri == null) && !prefix.equals("")) throwParseException("Unbound prefix for '" + qName + "'", null);
185 String name = (colonIndex < 0) ? qName : qName.substring(colonIndex + 1);
186 NamespacedName qualified = new NamespacedName(uri, name);
187 return qualified;
188 }
189
190
191 public XMLObjectFactory getFactory() throws XMLParseException {
192 if (factory == null) throw new XMLParseException("XmlObjectFactory is not defined");
193 return factory;
194 }
195
196
197 public Object getCustomObject(Object key) {
198 return (customObjects == null) ? null : customObjects.get(key);
199 }
200
201
202 public void putCustomObject(Object key, Object value) {
203 if (customObjects == null) customObjects = new HashMap<Object, Object>();
204 customObjects.put(key, value);
205 }
206
207
208
209
210
211 public void throwUnexpectedNamespaceException(String expected) throws XMLParseException {
212 StringBuffer sb = new StringBuffer("Unexpected namespace: ");
213 LevelInfo level = getCurrentLevel();
214 if (level != null) {
215 sb.append("'");
216 sb.append(level.getCurrentURI());
217 if (expected != null) {
218 sb.append("', expected: '");
219 sb.append(expected);
220 sb.append("'");
221 }
222 }
223 throwParseException(sb.toString(), null, true);
224 }
225
226
227 public void throwUnexpectedElementException(String expectedTags) throws XMLParseException {
228 StringBuilder sb = new StringBuilder("Unexpected element ");
229 appendCurrentElement(sb);
230 if (expectedTags != null) {
231 sb.append(" (expected= ");
232 sb.append(expectedTags);
233 sb.append(")");
234 }
235 throwParseException(sb.toString(), null, false);
236 }
237
238
239 public void throwParseException(String message, Throwable cause) throws XMLParseException {
240 throwParseException(message, cause, true);
241 }
242
243
244 private void throwParseException(String message, Throwable cause, boolean addLocation) throws XMLParseException {
245 StringBuilder sb = new StringBuilder(message);
246 if (addLocation) {
247 sb.append(" in element ");
248 appendCurrentElement(sb);
249 }
250 XMLParseException pe = new XMLParseException(sb.toString());
251 if (cause != null) pe.initCause(cause);
252 addLocationInfo(pe);
253 throw pe;
254 }
255
256
257 private void appendCurrentElement(StringBuilder sb) {
258 sb.append("<");
259 if (currentlyInTagEnd) sb.append("/");
260 LevelInfo level = getCurrentLevel();
261 if (level != null) {
262 if ((level.getCurrentURI() != null) && !level.getCurrentURI().equals("")) {
263 sb.append(level.getCurrentURI());
264 sb.append(":");
265 }
266 sb.append(level.getCurrentElementName());
267 } else {
268 sb.append("???");
269 }
270 sb.append(">");
271 }
272
273
274 protected void transformAndThrowException(Exception source) throws XMLParseException {
275 if (source instanceof XMLParseException) {
276 throw (XMLParseException) source;
277 } else {
278 XMLParseException xpe = new XMLParseException(source.getMessage(), source);
279 addLocationInfo(xpe);
280 throw xpe;
281 }
282 }
283
284
285 protected abstract void addLocationInfo(XMLParseException xpe);
286
287
288
289
290
291 protected void setup(XMLSerializable rootHandler) {
292 clearState();
293 setupRootHandler(rootHandler);
294 currentlyInFirstOrLast = true;
295 }
296
297
298 protected void tearDown() {
299 clearState();
300 }
301
302
303
304
305
306 private void clearState() {
307 for (LevelInfo level : levels) {
308 level.clear();
309 }
310 currentHandler = null;
311 lastParsed = null;
312 currentLevel = -1;
313 }
314
315
316 LevelInfo getCurrentLevel() {
317 if (currentLevel < 0) return null;
318 return levels.get(currentLevel);
319 }
320
321
322 void increaseLevel(String uri, String localName) {
323 currentLevel++;
324 LevelInfo newLevel;
325 if (currentLevel < levels.size()) {
326 newLevel = levels.get(currentLevel);
327 } else if (currentLevel == levels.size()) {
328 newLevel = new LevelInfo();
329 levels.add(newLevel);
330 } else {
331
332 throw new IllegalStateException("Level mismatch");
333 }
334 newLevel.init(uri, localName);
335 }
336
337
338 void decreaseLevel(String uri, String localName) throws XMLParseException {
339 assert (currentLevel >= 0);
340 LevelInfo level = getCurrentLevel();
341 int handlerCount = level.getHandlerCount();
342 if (handlerCount > 0) {
343 for (int i = handlerCount - 1; i >= 0; i--) {
344 XMLSerializable nextHandler = null;
345 if (i > 0) nextHandler = level.getHandlers().get(i - 1);
346 else nextHandler = getNextHandler(currentLevel - 1);
347
348 lastParsed = currentHandler;
349 currentHandler = nextHandler;
350 currentlyInFirstOrLast = (i > 0);
351 if (currentHandler != null) {
352 currentHandler.endElement(level.getCurrentURI(), level.getCurrentElementName(), this);
353 }
354 }
355 }
356 level.clear();
357 currentLevel--;
358 }
359
360
361 private void setupRootHandler(XMLSerializable root) {
362 assert (currentLevel == -1);
363 increaseLevel(null, null);
364 levels.get(0).addHandler(root);
365 currentLevel--;
366 currentHandler = root;
367 }
368
369
370 protected void pushPrefixMappingInNextLevel(String prefix, String namespaceURI) {
371 increaseLevel(null, null);
372 levels.get(currentLevel).getPrefixMappings().addPrefixMapping(prefix, namespaceURI);
373 currentLevel--;
374 }
375
376
377 private XMLSerializable getNextHandler(int fromLevel) {
378 for (int i = fromLevel; i >= 0; i--) {
379 LevelInfo level = levels.get(i);
380 int handlerCount = level.getHandlerCount();
381 if (handlerCount > 0) {
382 return level.getHandlers().get(handlerCount - 1);
383 }
384 }
385 return null;
386 }
387
388
389 protected void startElementImpl(String uri, String localName) throws Exception {
390 increaseLevel(uri, localName);
391 currentlyInTagEnd = false;
392 currentHandler.startElement(uri, localName, BaseXMLEventParser.this);
393 currentlyInFirstOrLast = false;
394 }
395
396
397 protected void endElementImpl(String uri, String localName) throws Exception {
398 currentlyInTagEnd = true;
399 currentlyInFirstOrLast = getCurrentLevel().getHandlerCount() > 0;
400 currentHandler.endElement(uri, localName, BaseXMLEventParser.this);
401 decreaseLevel(uri, localName);
402 }
403
404
405
406
407
408
409
410
411 static class LevelInfo {
412
413
414 private List<XMLSerializable> handlers;
415
416 private MapPrefixResolver prefixMappings;
417
418 private String currentElementURI;
419
420 private String currentElementName;
421
422
423 LevelInfo() {
424 handlers = new ArrayList<XMLSerializable>();
425 prefixMappings = new MapPrefixResolver();
426 }
427
428
429 public int getHandlerCount() {
430 return handlers.size();
431 }
432
433
434 void addHandler(XMLSerializable handler) {
435 handlers.add(handler);
436 }
437
438
439 List<XMLSerializable> getHandlers() {
440 return handlers;
441 }
442
443
444 void init(String uri, String localName) {
445 currentElementURI = uri;
446 currentElementName = localName;
447 }
448
449
450 void clear() {
451 handlers.clear();
452 prefixMappings.clear();
453 currentElementURI = null;
454 currentElementName = null;
455 }
456
457
458 String getCurrentURI() {
459 return currentElementURI;
460 }
461
462
463 String getCurrentElementName() {
464 return currentElementName;
465 }
466
467
468 MapPrefixResolver getPrefixMappings() {
469 return prefixMappings;
470 }
471
472 }
473
474
475 }