001: package org.jibx.runtime.impl;
002:
003: import javax.xml.stream.Location;
004: import javax.xml.stream.XMLStreamConstants;
005: import javax.xml.stream.XMLStreamException;
006: import javax.xml.stream.XMLStreamReader;
007:
008: import org.jibx.runtime.IXMLReader;
009: import org.jibx.runtime.IntStack;
010: import org.jibx.runtime.JiBXException;
011:
012: /**
013: * Wrapper for a StAX parser implementation. This delegates most calls
014: * more or less directly, only adding the required namespace functionality
015: * on top of the StAX API.
016: */
017: public class StAXReaderWrapper implements IXMLReader {
018: /** Event type code translation array. Indexed by the StAX event code, it
019: returns the corresponding XML reader event code. */
020: static final byte[] s_eventTranslations = new byte[256];
021: static {
022: s_eventTranslations[XMLStreamConstants.CDATA] = IXMLReader.CDSECT;
023: s_eventTranslations[XMLStreamConstants.CHARACTERS] = IXMLReader.TEXT;
024: s_eventTranslations[XMLStreamConstants.COMMENT] = IXMLReader.COMMENT;
025: s_eventTranslations[XMLStreamConstants.DTD] = IXMLReader.DOCDECL;
026: s_eventTranslations[XMLStreamConstants.END_DOCUMENT] = IXMLReader.END_DOCUMENT;
027: s_eventTranslations[XMLStreamConstants.END_ELEMENT] = IXMLReader.END_TAG;
028: s_eventTranslations[XMLStreamConstants.ENTITY_REFERENCE] = IXMLReader.ENTITY_REF;
029: s_eventTranslations[XMLStreamConstants.PROCESSING_INSTRUCTION] = IXMLReader.PROCESSING_INSTRUCTION;
030: s_eventTranslations[XMLStreamConstants.SPACE] = IXMLReader.IGNORABLE_WHITESPACE;
031: s_eventTranslations[XMLStreamConstants.START_DOCUMENT] = IXMLReader.START_DOCUMENT;
032: s_eventTranslations[XMLStreamConstants.START_ELEMENT] = IXMLReader.START_TAG;
033: }
034:
035: /** Actual parser. */
036: private final XMLStreamReader m_parser;
037:
038: /** Parser processing namespaces flag. */
039: final boolean m_isNamespaceAware;
040:
041: /** Document name. */
042: private final String m_docName;
043:
044: /** Current element nesting depth. */
045: int m_nestingDepth;
046:
047: /** Namespace definitions in scope at each nesting depth. */
048: private IntStack m_inScopeCounts;
049:
050: /** Namespace URIs in scope. */
051: private StringArray m_inScopeUris;
052:
053: /** Namespace prefixes in scope. */
054: private StringArray m_inScopePrefixes;
055:
056: /** Accumulated text for return. */
057: private String m_accumulatedText;
058:
059: /** Accumulated text is processing instruction flag (otherwise content) */
060: private boolean m_isProcessingInstruction;
061:
062: /** Document encoding (apparently cannot be read after parse done). */
063: private String m_encoding;
064:
065: /**
066: * Constructor used by factory.
067: *
068: * @param rdr event reader
069: * @param nsa namespace aware flag
070: */
071: public StAXReaderWrapper(XMLStreamReader rdr, String name,
072: boolean nsa) {
073: m_parser = rdr;
074: m_docName = name;
075: m_isNamespaceAware = nsa;
076: m_inScopeCounts = new IntStack();
077: m_inScopeCounts.push(0);
078: m_inScopeUris = new StringArray();
079: m_inScopePrefixes = new StringArray();
080: }
081:
082: /**
083: * Build current parse input position description.
084: *
085: * @return text description of current parse position
086: */
087: public String buildPositionString() {
088: Location location = m_parser.getLocation();
089: String base = "(line " + location.getLineNumber() + ", col "
090: + location.getColumnNumber();
091: if (m_docName != null) {
092: base += ", in " + m_docName;
093: }
094: return base + ')';
095: }
096:
097: /**
098: * Handle start tag. This increments the nesting count, and records all
099: * namespaces associated with the start tag.
100: */
101: private void startTag() {
102: if (m_nestingDepth == 0) {
103: m_encoding = m_parser.getEncoding();
104: if (m_encoding == null) {
105: m_encoding = m_parser.getCharacterEncodingScheme();
106: if (m_encoding == null) {
107: m_encoding = "UTF-8";
108: }
109: }
110: }
111: m_nestingDepth++;
112: int count = m_parser.getNamespaceCount();
113: for (int i = 0; i < count; i++) {
114: m_inScopeUris.add(m_parser.getNamespaceURI(i));
115: m_inScopePrefixes.add(m_parser.getNamespacePrefix(i));
116: }
117: m_inScopeCounts.push(m_inScopeUris.size());
118: }
119:
120: /**
121: * Handle end tag. This decrements the nesting count, and deletes all
122: * namespaces associated with the start tag.
123: */
124: private void endTag() {
125: m_nestingDepth--;
126: int count = m_inScopeCounts.pop() - m_inScopeCounts.peek();
127: if (count > 0) {
128: m_inScopeUris.remove(count);
129: m_inScopePrefixes.remove(count);
130: }
131: }
132:
133: /* (non-Javadoc)
134: * @see org.jibx.runtime.IXMLReader#nextToken()
135: */
136: public int nextToken() throws JiBXException {
137: if (m_accumulatedText == null) {
138: try {
139: int code;
140: loop: while (true) {
141: code = s_eventTranslations[m_parser.next()];
142: switch (code) {
143:
144: case START_TAG:
145: startTag();
146: break loop;
147:
148: case END_TAG:
149: endTag();
150: break loop;
151:
152: case PROCESSING_INSTRUCTION:
153: m_accumulatedText = m_parser.getPITarget()
154: + ' ' + m_parser.getPIData();
155: m_isProcessingInstruction = true;
156: while (s_eventTranslations[m_parser.next()] == 0)
157: ;
158: break loop;
159:
160: case 0:
161: break;
162:
163: default:
164: break loop;
165: }
166: }
167: return code;
168:
169: } catch (XMLStreamException e) {
170: throw new JiBXException("Error parsing document "
171: + buildPositionString(), e);
172: }
173: } else {
174: m_accumulatedText = null;
175: m_isProcessingInstruction = false;
176: int code = s_eventTranslations[m_parser.getEventType()];
177: if (code == START_TAG) {
178: startTag();
179: } else if (code == END_TAG) {
180: endTag();
181: }
182: return code;
183: }
184: }
185:
186: /* (non-Javadoc)
187: * @see org.jibx.runtime.IXMLReader#next()
188: */
189: public int next() throws JiBXException {
190: String text = null;
191: StringBuffer buff = null;
192: try {
193: int type;
194: if (m_accumulatedText == null) {
195: m_parser.next();
196: } else {
197: m_accumulatedText = null;
198: m_isProcessingInstruction = false;
199: }
200: loop: while (true) {
201: type = s_eventTranslations[m_parser.getEventType()];
202: switch (type) {
203:
204: case ENTITY_REF:
205: if (m_parser.getText() == null) {
206: throw new JiBXException(
207: "Unexpanded entity reference in text at "
208: + buildPositionString());
209: }
210: // fall through into text accumulation
211:
212: case CDSECT:
213: case TEXT:
214: if (text == null) {
215: text = m_parser.getText();
216: } else {
217: if (buff == null) {
218: buff = new StringBuffer(text);
219: }
220: buff.append(m_parser.getTextCharacters());
221: }
222: break;
223:
224: case END_TAG:
225: if (text == null) {
226: endTag();
227: return type;
228: }
229: break loop;
230:
231: case START_TAG:
232: if (text == null) {
233: startTag();
234: return type;
235: }
236: break loop;
237:
238: case END_DOCUMENT:
239: if (text == null) {
240: return type;
241: }
242: break loop;
243:
244: default:
245: break;
246:
247: }
248: m_parser.next();
249: }
250: if (buff == null) {
251: m_accumulatedText = text;
252: } else {
253: m_accumulatedText = buff.toString();
254: }
255: return TEXT;
256: } catch (XMLStreamException e) {
257: throw new JiBXException("Error parsing document "
258: + buildPositionString(), e);
259: }
260: }
261:
262: /* (non-Javadoc)
263: * @see org.jibx.runtime.IXMLReader#getEventType()
264: */
265: public int getEventType() throws JiBXException {
266: if (m_accumulatedText == null) {
267: return s_eventTranslations[m_parser.getEventType()];
268: } else if (m_isProcessingInstruction) {
269: return PROCESSING_INSTRUCTION;
270: } else {
271: return TEXT;
272: }
273: }
274:
275: /* (non-Javadoc)
276: * @see org.jibx.runtime.IXMLReader#getName()
277: */
278: public String getName() {
279: return m_parser.getLocalName();
280: }
281:
282: /* (non-Javadoc)
283: * @see org.jibx.runtime.IXMLReader#getNamespace()
284: */
285: public String getNamespace() {
286: String uri = m_parser.getNamespaceURI();
287: if (uri == null) {
288: return "";
289: } else {
290: return uri;
291: }
292: }
293:
294: /* (non-Javadoc)
295: * @see org.jibx.runtime.IXMLReader#getPrefix()
296: */
297: public String getPrefix() {
298: String prefix = m_parser.getPrefix();
299: if (prefix != null && prefix.length() == 0) {
300: return null;
301: } else {
302: return prefix;
303: }
304: }
305:
306: /* (non-Javadoc)
307: * @see org.jibx.runtime.IXMLReader#getAttributeCount()
308: */
309: public int getAttributeCount() {
310: return m_parser.getAttributeCount();
311: }
312:
313: /* (non-Javadoc)
314: * @see org.jibx.runtime.IXMLReader#getAttributeName(int)
315: */
316: public String getAttributeName(int index) {
317: try {
318: return m_parser.getAttributeLocalName(index);
319: } catch (ArrayIndexOutOfBoundsException e) {
320: throw new IllegalStateException(e.getMessage());
321: }
322: }
323:
324: /* (non-Javadoc)
325: * @see org.jibx.runtime.IXMLReader#getAttributeNamespace(int)
326: */
327: public String getAttributeNamespace(int index) {
328: try {
329: String uri = m_parser.getAttributeNamespace(index);
330: if (uri == null) {
331: return "";
332: } else {
333: return uri;
334: }
335: } catch (ArrayIndexOutOfBoundsException e) {
336: throw new IllegalStateException(e.getMessage());
337: }
338: }
339:
340: /* (non-Javadoc)
341: * @see org.jibx.runtime.IXMLReader#getAttributePrefix(int)
342: */
343: public String getAttributePrefix(int index) {
344: try {
345: String prefix = m_parser.getAttributePrefix(index);
346: if (prefix != null && prefix.length() == 0) {
347: return null;
348: } else {
349: return prefix;
350: }
351: } catch (ArrayIndexOutOfBoundsException e) {
352: throw new IllegalStateException(e.getMessage());
353: }
354: }
355:
356: /* (non-Javadoc)
357: * @see org.jibx.runtime.IXMLReader#getAttributeValue(int)
358: */
359: public String getAttributeValue(int index) {
360: try {
361: return m_parser.getAttributeValue(index);
362: } catch (ArrayIndexOutOfBoundsException e) {
363: throw new IllegalStateException(e.getMessage());
364: }
365: }
366:
367: /* (non-Javadoc)
368: * @see org.jibx.runtime.IXMLReader#getAttributeValue(java.lang.String, java.lang.String)
369: */
370: public String getAttributeValue(String ns, String name) {
371: try {
372: return m_parser.getAttributeValue(ns, name);
373: } catch (ArrayIndexOutOfBoundsException e) {
374: throw new IllegalStateException(e.getMessage());
375: }
376: }
377:
378: /* (non-Javadoc)
379: * @see org.jibx.runtime.IXMLReader#getText()
380: */
381: public String getText() {
382: if (m_accumulatedText == null) {
383: return m_parser.getText();
384: } else {
385: return m_accumulatedText;
386: }
387: }
388:
389: /* (non-Javadoc)
390: * @see org.jibx.runtime.IXMLReader#getNestingDepth()
391: */
392: public int getNestingDepth() {
393: return m_nestingDepth;
394: }
395:
396: /* (non-Javadoc)
397: * @see org.jibx.runtime.IXMLReader#getNamespaceCount(int)
398: */
399: public int getNamespaceCount(int depth) {
400: return m_inScopeCounts.peek(m_nestingDepth - depth);
401: }
402:
403: /* (non-Javadoc)
404: * @see org.jibx.runtime.IXMLReader#getNamespaceUri(int)
405: */
406: public String getNamespaceUri(int index) {
407: return m_inScopeUris.get(index);
408: }
409:
410: /* (non-Javadoc)
411: * @see org.jibx.runtime.IXMLReader#getNamespacePrefix(int)
412: */
413: public String getNamespacePrefix(int index) {
414: String prefix = m_inScopePrefixes.get(index);
415: if (prefix != null && prefix.length() == 0) {
416: return null;
417: } else {
418: return prefix;
419: }
420: }
421:
422: /* (non-Javadoc)
423: * @see org.jibx.runtime.IXMLReader#getDocumentName()
424: */
425: public String getDocumentName() {
426: return m_docName;
427: }
428:
429: /* (non-Javadoc)
430: * @see org.jibx.runtime.IXMLReader#getLineNumber()
431: */
432: public int getLineNumber() {
433: return m_parser.getLocation().getLineNumber();
434: }
435:
436: /* (non-Javadoc)
437: * @see org.jibx.runtime.IXMLReader#getColumnNumber()
438: */
439: public int getColumnNumber() {
440: return m_parser.getLocation().getColumnNumber();
441: }
442:
443: /* (non-Javadoc)
444: * @see org.jibx.runtime.IXMLReader#getNamespace(java.lang.String)
445: */
446: public String getNamespace(String prefix) {
447: int index = m_inScopePrefixes.size();
448: while (--index >= 0) {
449: String comp = m_inScopePrefixes.get(index);
450: if ((prefix == null && comp == null)
451: || (prefix != null && prefix.equals(comp))) {
452: return m_inScopeUris.get(index);
453: }
454: }
455: return null;
456: }
457:
458: /* (non-Javadoc)
459: * @see org.jibx.runtime.IXMLReader#getInputEncoding()
460: */
461: public String getInputEncoding() {
462: return m_encoding;
463: }
464:
465: /* (non-Javadoc)
466: * @see org.jibx.runtime.IXMLReader#isNamespaceAware()
467: */
468: public boolean isNamespaceAware() {
469: return m_isNamespaceAware;
470: }
471: }
|