001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.aegis.xml.stax;
019:
020: import java.io.InputStream;
021: import java.util.regex.Matcher;
022: import java.util.regex.Pattern;
023:
024: import javax.xml.namespace.NamespaceContext;
025: import javax.xml.namespace.QName;
026: import javax.xml.stream.XMLStreamException;
027: import javax.xml.stream.XMLStreamReader;
028:
029: import org.apache.cxf.aegis.DatabindingException;
030: import org.apache.cxf.aegis.util.XmlConstants;
031: import org.apache.cxf.aegis.xml.AbstractMessageReader;
032: import org.apache.cxf.aegis.xml.MessageReader;
033: import org.apache.cxf.staxutils.DepthXMLStreamReader;
034: import org.apache.cxf.staxutils.StaxUtils;
035:
036: /**
037: * Reads literal encoded messages.
038: *
039: * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
040: */
041: public class ElementReader extends AbstractMessageReader implements
042: MessageReader {
043: private static final Pattern QNAME_PATTERN = Pattern
044: .compile("([^:]+):([^:]+)");
045:
046: private DepthXMLStreamReader root;
047:
048: private String value;
049:
050: private String localName;
051:
052: private QName name;
053:
054: private QName xsiType;
055:
056: private boolean hasCheckedChildren;
057:
058: private boolean hasChildren;
059:
060: private String namespace;
061:
062: private int depth;
063:
064: private int currentAttribute;
065:
066: /**
067: * @param root
068: */
069: public ElementReader(DepthXMLStreamReader root) {
070: this .root = root;
071: this .localName = root.getLocalName();
072: this .name = root.getName();
073: this .namespace = root.getNamespaceURI();
074:
075: extractXsiType();
076:
077: depth = root.getDepth();
078: }
079:
080: public ElementReader(XMLStreamReader reader) {
081: this (
082: reader instanceof DepthXMLStreamReader ? (DepthXMLStreamReader) reader
083: : new DepthXMLStreamReader(reader));
084: }
085:
086: /**
087: * @param is
088: * @throws XMLStreamException
089: */
090: public ElementReader(InputStream is) throws XMLStreamException {
091: // XMLInputFactory factory = XMLInputFactory.newInstance();
092: // XMLStreamReader xmlReader = factory.createXMLStreamReader(is);
093: XMLStreamReader xmlReader = StaxUtils.createXMLStreamReader(is,
094: null);
095:
096: xmlReader.nextTag();
097:
098: this .root = new DepthXMLStreamReader(xmlReader);
099: this .localName = root.getLocalName();
100: this .name = root.getName();
101: this .namespace = root.getNamespaceURI();
102:
103: extractXsiType();
104:
105: depth = root.getDepth();
106: }
107:
108: private void extractXsiType() {
109: /*
110: * We're making a conscious choice here -- garbage in == garbate out.
111: */
112: String xsiTypeQname = root.getAttributeValue(
113: XmlConstants.XSI_NS, "type");
114: if (xsiTypeQname != null) {
115: Matcher m = QNAME_PATTERN.matcher(xsiTypeQname);
116: if (m.matches()) {
117: NamespaceContext nc = root.getNamespaceContext();
118: this .xsiType = new QName(
119: nc.getNamespaceURI(m.group(1)), m.group(2), m
120: .group(1));
121: } else {
122: this .xsiType = new QName(this .namespace, xsiTypeQname,
123: "");
124: }
125: }
126: }
127:
128: /**
129: * @see org.codehaus.xfire.aegis.MessageReader#getValue()
130: */
131: public String getValue() {
132: if (value == null) {
133: try {
134: value = root.getElementText();
135:
136: hasCheckedChildren = true;
137: hasChildren = false;
138: if (root.hasNext()) {
139: root.next();
140: }
141: } catch (XMLStreamException e) {
142: throw new DatabindingException(
143: "Could not read XML stream.", e);
144: }
145:
146: if (value == null) {
147: value = "";
148: } else {
149: value = value.trim();
150: }
151: }
152: return value;
153: }
154:
155: public String getValue(String ns, String attr) {
156: return root.getAttributeValue(ns, attr);
157: }
158:
159: public boolean hasMoreElementReaders() {
160: // Check to see if we checked before,
161: // so we don't mess up the stream position.
162: if (!hasCheckedChildren) {
163: checkHasMoreChildReaders();
164: }
165:
166: return hasChildren;
167: }
168:
169: private boolean checkHasMoreChildReaders() {
170: try {
171: int event = root.getEventType();
172: while (root.hasNext()) {
173: switch (event) {
174: case XMLStreamReader.START_ELEMENT:
175: if (root.getDepth() > depth) {
176: hasCheckedChildren = true;
177: hasChildren = true;
178:
179: return true;
180: }
181: break;
182: case XMLStreamReader.END_ELEMENT:
183: if (root.getDepth() < depth) {
184: hasCheckedChildren = true;
185: hasChildren = false;
186:
187: if (root.hasNext()) {
188: root.next();
189: }
190: return false;
191: }
192: break;
193: case XMLStreamReader.END_DOCUMENT:
194: // We should never get here...
195: hasCheckedChildren = true;
196: hasChildren = false;
197: return false;
198: default:
199: break;
200: }
201:
202: if (root.hasNext()) {
203: event = root.next();
204: }
205: }
206:
207: hasCheckedChildren = true;
208: hasChildren = false;
209: return false;
210: } catch (XMLStreamException e) {
211: throw new DatabindingException("Error parsing document.", e);
212: }
213: }
214:
215: public MessageReader getNextElementReader() {
216: if (!hasCheckedChildren) {
217: checkHasMoreChildReaders();
218: }
219:
220: if (!hasChildren) {
221: return null;
222: }
223:
224: hasCheckedChildren = false;
225:
226: return new ElementReader(root);
227: }
228:
229: public QName getName() {
230: return name;
231: }
232:
233: public String getLocalName() {
234: return localName;
235: }
236:
237: public String getNamespace() {
238: return namespace;
239: }
240:
241: public QName getXsiType() {
242: return xsiType;
243: }
244:
245: public XMLStreamReader getXMLStreamReader() {
246: return root;
247: }
248:
249: public boolean hasMoreAttributeReaders() {
250: if (!root.isStartElement()) {
251: return false;
252: }
253:
254: return currentAttribute < root.getAttributeCount();
255: }
256:
257: public MessageReader getAttributeReader(QName qName) {
258: return new AttributeReader(qName, root.getAttributeValue(qName
259: .getNamespaceURI(), qName.getLocalPart()));
260: }
261:
262: public MessageReader getNextAttributeReader() {
263: MessageReader reader = new AttributeReader(root
264: .getAttributeName(currentAttribute), root
265: .getAttributeValue(currentAttribute));
266: currentAttribute++;
267:
268: return reader;
269: }
270:
271: public String getNamespaceForPrefix(String prefix) {
272: return root.getNamespaceURI(prefix);
273: }
274: }
|