1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.treetank.service.xml.serialize;
29
30 import static org.treetank.node.IConstants.ATTRIBUTE;
31 import static org.treetank.node.IConstants.ELEMENT;
32 import static org.treetank.node.IConstants.NAMESPACE;
33 import static org.treetank.node.IConstants.ROOT;
34 import static org.treetank.node.IConstants.TEXT;
35
36 import java.io.IOException;
37 import java.util.Iterator;
38 import java.util.Stack;
39
40 import javax.xml.namespace.QName;
41 import javax.xml.stream.XMLEventFactory;
42 import javax.xml.stream.XMLEventReader;
43 import javax.xml.stream.XMLStreamConstants;
44 import javax.xml.stream.XMLStreamException;
45 import javax.xml.stream.events.Attribute;
46 import javax.xml.stream.events.Namespace;
47 import javax.xml.stream.events.XMLEvent;
48
49 import org.treetank.api.INodeReadTrx;
50 import org.treetank.axis.AbsAxis;
51 import org.treetank.axis.DescendantAxis;
52 import org.treetank.axis.FilterAxis;
53 import org.treetank.axis.filter.TextFilter;
54 import org.treetank.exception.TTException;
55 import org.treetank.exception.TTIOException;
56 import org.treetank.node.ElementNode;
57 import org.treetank.node.interfaces.IStructNode;
58
59
60
61
62
63
64
65
66
67
68
69 public final class StAXSerializer implements XMLEventReader {
70
71
72
73
74
75 private transient boolean mCloseElements;
76
77
78 private transient XMLEvent mEvent;
79
80
81 private transient XMLEventFactory mFac = XMLEventFactory.newFactory();
82
83
84 private transient long mKey;
85
86
87 private transient boolean mCloseElementsEmitted;
88
89
90 private transient boolean mNextTag;
91
92
93 private final transient AbsAxis mAxis;
94
95
96 private final transient Stack<Long> mStack;
97
98
99
100
101
102 private transient boolean mGoBack;
103
104
105
106
107
108 private transient boolean mGoUp;
109
110
111
112
113
114 private transient long mLastKey;
115
116
117
118
119 private transient boolean mCloseRtx;
120
121
122
123
124 private final INodeReadTrx mRtx;
125
126
127
128
129
130
131
132
133
134
135 public StAXSerializer(final AbsAxis paramAxis, final INodeReadTrx pRtx) {
136 this(paramAxis, pRtx, true);
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150 public StAXSerializer(final AbsAxis paramAxis, final INodeReadTrx pRtx, final boolean paramCloseRtx) {
151 mNextTag = false;
152 mAxis = paramAxis;
153 mCloseRtx = paramCloseRtx;
154 mStack = new Stack<Long>();
155 mRtx = pRtx;
156 }
157
158
159
160
161
162
163
164
165 private void emitEndTag() throws TTIOException {
166 final long nodeKey = mRtx.getNode().getDataKey();
167 mEvent = mFac.createEndElement(mRtx.getQNameOfCurrentNode(), new NamespaceIterator(mRtx));
168 mRtx.moveTo(nodeKey);
169 }
170
171
172
173
174
175
176
177
178 private void emitNode() throws TTIOException {
179 switch (mRtx.getNode().getKind()) {
180 case ROOT:
181 mEvent = mFac.createStartDocument();
182 break;
183 case ELEMENT:
184 final long key = mRtx.getNode().getDataKey();
185 final QName qName = mRtx.getQNameOfCurrentNode();
186 mEvent = mFac.createStartElement(qName, new AttributeIterator(mRtx), new NamespaceIterator(mRtx));
187 mRtx.moveTo(key);
188 break;
189 case TEXT:
190 mEvent = mFac.createCharacters(mRtx.getValueOfCurrentNode());
191 break;
192 default:
193 throw new IllegalStateException("Kind not known!");
194 }
195 }
196
197
198 @Override
199 public void close() throws XMLStreamException {
200 if (mCloseRtx) {
201 try {
202 mAxis.close();
203 } catch (final TTException exc) {
204 exc.printStackTrace();
205 }
206 }
207 }
208
209
210 @Override
211 public String getElementText() throws XMLStreamException {
212
213 final long nodeKey = mAxis.getNode().getDataKey();
214
215
216
217
218
219
220 if (mCloseElements && (mGoBack || mGoUp)) {
221 if (mGoUp) {
222 mAxis.moveTo(mLastKey);
223 mGoUp = false;
224 } else if (mGoBack) {
225 mAxis.moveTo(mStack.peek());
226 mGoBack = false;
227 }
228 }
229
230 if (mEvent.getEventType() != XMLStreamConstants.START_ELEMENT) {
231 mAxis.moveTo(nodeKey);
232 throw new XMLStreamException("getElementText() only can be called on a start element");
233 }
234 final FilterAxis textFilterAxis =
235 new FilterAxis(new DescendantAxis(mRtx), mRtx, new TextFilter(mRtx));
236 final StringBuilder strBuilder = new StringBuilder();
237
238 while (textFilterAxis.hasNext()) {
239 textFilterAxis.next();
240 strBuilder.append(mRtx.getValueOfCurrentNode());
241 }
242
243 try {
244 mRtx.moveTo(nodeKey);
245 } catch (TTIOException exc) {
246 throw new XMLStreamException(exc);
247 }
248 return strBuilder.toString();
249 }
250
251
252 @Override
253 public Object getProperty(final String mName) {
254 throw new UnsupportedOperationException("Not supported by Treetank!");
255 }
256
257
258 @Override
259 public boolean hasNext() {
260 boolean retVal = false;
261
262 if (!mStack.empty() && (mCloseElements || mCloseElementsEmitted)) {
263
264
265
266
267
268 retVal = true;
269 } else {
270 retVal = mAxis.hasNext();
271 }
272
273 return retVal;
274 }
275
276
277 @Override
278 public XMLEvent nextEvent() throws XMLStreamException {
279 try {
280 if (!mCloseElements && !mCloseElementsEmitted) {
281 mKey = mAxis.next();
282
283 if (mNextTag) {
284 if (mAxis.getNode().getKind() != ELEMENT) {
285 throw new XMLStreamException("The next tag isn't a start- or end-tag!");
286 }
287 mNextTag = false;
288 }
289 }
290 emit();
291 } catch (final TTIOException exc) {
292 throw new XMLStreamException(exc);
293 }
294
295 return mEvent;
296 }
297
298
299 @Override
300 public XMLEvent nextTag() throws XMLStreamException {
301 mNextTag = true;
302 return nextEvent();
303 }
304
305
306 @Override
307 public XMLEvent peek() throws XMLStreamException {
308 final long currNodeKey = mAxis.getNode().getDataKey();
309 try {
310 if (mCloseElements) {
311 mRtx.moveTo(mStack.peek());
312 emitEndTag();
313 } else {
314 final int nodeKind = mRtx.getNode().getKind();
315 if (((IStructNode)mRtx.getNode()).hasFirstChild()) {
316 mRtx.moveTo(((IStructNode)mRtx.getNode()).getFirstChildKey());
317 emitNode();
318 } else if (((IStructNode)mRtx.getNode()).hasRightSibling()) {
319 mRtx.moveTo(((IStructNode)mRtx.getNode()).getRightSiblingKey());
320 processNode(nodeKind);
321 } else if (((IStructNode)mRtx.getNode()).hasParent()) {
322 mRtx.moveTo(mRtx.getNode().getParentKey());
323 emitEndTag();
324 }
325 }
326
327 mRtx.moveTo(currNodeKey);
328 } catch (final TTIOException exc) {
329 throw new XMLStreamException(exc);
330 }
331 return mEvent;
332 }
333
334
335
336
337
338
339 @Override
340 public Object next() {
341 try {
342 mEvent = nextEvent();
343 } catch (final XMLStreamException exc) {
344 exc.printStackTrace();
345 }
346
347 return mEvent;
348 }
349
350
351 @Override
352 public void remove() {
353 throw new UnsupportedOperationException("Not supported!");
354 }
355
356
357
358
359
360
361
362
363
364 private void processNode(final int paramNodeKind) throws TTIOException {
365 switch (paramNodeKind) {
366 case ELEMENT:
367 emitEndTag();
368 break;
369 case TEXT:
370 emitNode();
371 break;
372 default:
373
374 }
375 }
376
377
378
379
380
381
382
383 private void emit() throws TTIOException {
384
385 if (mCloseElements) {
386 if (!mStack.empty() && mStack.peek() != ((IStructNode)mRtx.getNode()).getLeftSiblingKey()) {
387 mRtx.moveTo(mStack.pop());
388 emitEndTag();
389 mRtx.moveTo(mKey);
390 } else if (!mStack.empty()) {
391 mRtx.moveTo(mStack.pop());
392 emitEndTag();
393 mRtx.moveTo(mKey);
394 mCloseElements = false;
395 mCloseElementsEmitted = true;
396 }
397 } else {
398 mCloseElementsEmitted = false;
399
400
401 emitNode();
402
403 final long nodeKey = mRtx.getNode().getDataKey();
404 mLastKey = nodeKey;
405
406
407 if (mRtx.getNode().getKind() == ELEMENT) {
408 mStack.push(nodeKey);
409 }
410
411
412
413 if (!((IStructNode)mRtx.getNode()).hasFirstChild()
414 && !((IStructNode)mRtx.getNode()).hasRightSibling()) {
415 mGoUp = true;
416 moveToNextNode();
417 } else if (mRtx.getNode().getKind() == ELEMENT && !((ElementNode)mRtx.getNode()).hasFirstChild()) {
418
419 mGoBack = true;
420 moveToNextNode();
421 }
422 }
423 }
424
425
426
427
428
429
430 private void moveToNextNode() {
431 mCloseElements = true;
432 if (mAxis.hasNext()) {
433 mKey = mAxis.next();
434 }
435 }
436
437
438
439
440 final class AttributeIterator implements Iterator<Attribute> {
441
442
443
444
445 private final INodeReadTrx mRTX;
446
447
448 private final int mAttCount;
449
450
451 private int mIndex;
452
453
454 private final long mNodeKey;
455
456
457 private final transient XMLEventFactory mFac = XMLEventFactory.newFactory();
458
459
460
461
462
463
464
465 public AttributeIterator(final INodeReadTrx rtx) {
466 mRTX = rtx;
467 mNodeKey = mRTX.getNode().getDataKey();
468 mIndex = 0;
469
470 if (mRTX.getNode().getKind() == ELEMENT) {
471 mAttCount = ((ElementNode)mRTX.getNode()).getAttributeCount();
472 } else {
473 mAttCount = 0;
474 }
475 }
476
477 @Override
478 public boolean hasNext() {
479 boolean retVal = false;
480
481 if (mIndex < mAttCount) {
482 retVal = true;
483 }
484
485 return retVal;
486 }
487
488 @Override
489 public Attribute next() {
490 try {
491 mRTX.moveTo(mNodeKey);
492 mRTX.moveToAttribute(mIndex++);
493 assert mRTX.getNode().getKind() == ATTRIBUTE;
494 final QName qName = mRTX.getQNameOfCurrentNode();
495 final String value = mRTX.getValueOfCurrentNode();
496 mRTX.moveTo(mNodeKey);
497 return mFac.createAttribute(qName, value);
498 } catch (TTIOException exc) {
499 throw new RuntimeException(exc);
500 }
501 }
502
503 @Override
504 public void remove() {
505 throw new UnsupportedOperationException("Not supported!");
506 }
507 }
508
509
510
511
512
513
514
515
516 final class NamespaceIterator implements Iterator<Namespace> {
517
518
519
520
521 private final INodeReadTrx mRTX;
522
523
524 private final int mNamespCount;
525
526
527 private int mIndex;
528
529
530 private final long mNodeKey;
531
532
533 private final transient XMLEventFactory mFac = XMLEventFactory.newInstance();
534
535
536
537
538
539
540
541 public NamespaceIterator(final INodeReadTrx rtx) {
542 mRTX = rtx;
543 mNodeKey = mRTX.getNode().getDataKey();
544 mIndex = 0;
545
546 if (mRTX.getNode().getKind() == ELEMENT) {
547 mNamespCount = ((ElementNode)mRTX.getNode()).getNamespaceCount();
548 } else {
549 mNamespCount = 0;
550 }
551 }
552
553 @Override
554 public boolean hasNext() {
555 boolean retVal = false;
556
557 if (mIndex < mNamespCount) {
558 retVal = true;
559 }
560
561 return retVal;
562 }
563
564 @Override
565 public Namespace next() {
566 try {
567 mRTX.moveTo(mNodeKey);
568 mRTX.moveToNamespace(mIndex++);
569 assert mRTX.getNode().getKind() == NAMESPACE;
570 final QName qName = mRTX.getQNameOfCurrentNode();
571 mRTX.moveTo(mNodeKey);
572 return mFac.createNamespace(qName.getLocalPart(), qName.getNamespaceURI());
573 } catch (TTIOException exc) {
574 throw new RuntimeException(exc);
575 }
576 }
577
578 @Override
579 public void remove() {
580 throw new UnsupportedOperationException("Not supported!");
581 }
582 }
583 }