001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.soap.util.stax;
018
019 /*
020 * This implementation comes from the XFire project
021 * https://svn.codehaus.org/xfire/trunk/xfire/xfire-core/src/main/org/codehaus/xfire/util/stax/
022 */
023
024 import java.util.ArrayList;
025 import java.util.HashMap;
026 import java.util.Iterator;
027 import java.util.List;
028 import java.util.Map;
029
030 import javax.xml.namespace.NamespaceContext;
031 import javax.xml.namespace.QName;
032 import javax.xml.stream.Location;
033 import javax.xml.stream.XMLStreamConstants;
034 import javax.xml.stream.XMLStreamException;
035 import javax.xml.stream.XMLStreamReader;
036
037 import org.w3c.dom.Attr;
038 import org.w3c.dom.CDATASection;
039 import org.w3c.dom.Comment;
040 import org.w3c.dom.Document;
041 import org.w3c.dom.Element;
042 import org.w3c.dom.EntityReference;
043 import org.w3c.dom.NamedNodeMap;
044 import org.w3c.dom.Node;
045 import org.w3c.dom.Text;
046
047 /**
048 * Abstract logic for creating XMLStreamReader from DOM documents.
049 * Its works using adapters for Element, Node and Attribute ( @see ElementAdapter }
050 *
051 * @author <a href="mailto:tsztelak@gmail.com">Tomasz Sztelak</a>
052 */
053 public class DOMStreamReader implements XMLStreamReader {
054 public Map properties = new HashMap();
055
056 private ArrayList<ElementFrame> frames = new ArrayList<ElementFrame>();
057
058 private ElementFrame frame;
059
060 private int currentEvent = XMLStreamConstants.START_DOCUMENT;
061
062 private Node content;
063
064 private Document document;
065
066 private DOMNamespaceContext context;
067
068 /**
069 * @param element
070 */
071 public DOMStreamReader(Element element) {
072 this.frame = new ElementFrame(element, null);
073 frames.add(this.frame);
074 newFrame(frame);
075 this.document = element.getOwnerDocument();
076 }
077
078 protected ElementFrame getCurrentFrame() {
079 return frame;
080 }
081
082 /* (non-Javadoc)
083 * @see javax.xml.stream.XMLStreamReader#getProperty(java.lang.String)
084 */
085 public Object getProperty(String key) throws IllegalArgumentException {
086 return properties.get(key);
087 }
088
089 /* (non-Javadoc)
090 * @see javax.xml.stream.XMLStreamReader#next()
091 */
092 public int next() throws XMLStreamException {
093 if (frame.ended) {
094 frames.remove(frames.size() - 1);
095 if (!frames.isEmpty()) {
096 frame = (ElementFrame) frames.get(frames.size() - 1);
097 } else {
098 currentEvent = END_DOCUMENT;
099 return currentEvent;
100 }
101 }
102
103 if (!frame.started) {
104 frame.started = true;
105 currentEvent = START_ELEMENT;
106 } else if (frame.currentAttribute < getAttributeCount() - 1) {
107 frame.currentAttribute++;
108 currentEvent = ATTRIBUTE;
109 } else if (frame.currentNamespace < getNamespaceCount() - 1) {
110 frame.currentNamespace++;
111 currentEvent = NAMESPACE;
112 } else if (frame.currentChild < getChildCount() - 1) {
113 frame.currentChild++;
114
115 currentEvent = moveToChild(frame.currentChild);
116
117 if (currentEvent == START_ELEMENT) {
118 ElementFrame newFrame = getChildFrame(frame.currentChild);
119 newFrame.started = true;
120 frame = newFrame;
121 frames.add(this.frame);
122 currentEvent = START_ELEMENT;
123
124 newFrame(newFrame);
125 }
126 } else {
127 frame.ended = true;
128 currentEvent = END_ELEMENT;
129 endElement();
130 }
131 return currentEvent;
132 }
133
134 protected void skipFrame() {
135 frame.ended = true;
136 currentEvent = END_ELEMENT;
137 }
138
139 /* (non-Javadoc)
140 * @see javax.xml.stream.XMLStreamReader#require(int, java.lang.String, java.lang.String)
141 */
142 public void require(int arg0, String arg1, String arg2) throws XMLStreamException {
143 throw new UnsupportedOperationException();
144 }
145
146 /* (non-Javadoc)
147 * @see javax.xml.stream.XMLStreamReader#nextTag()
148 */
149 public int nextTag() throws XMLStreamException {
150 while (hasNext()) {
151 int e = next();
152 if (e == START_ELEMENT || e == END_ELEMENT)
153 return e;
154 }
155
156 return currentEvent;
157 }
158
159 /* (non-Javadoc)
160 * @see javax.xml.stream.XMLStreamReader#hasNext()
161 */
162 public boolean hasNext() throws XMLStreamException {
163 return !(frames.size() == 0 && frame.ended);
164
165 }
166
167 /* (non-Javadoc)
168 * @see javax.xml.stream.XMLStreamReader#close()
169 */
170 public void close() throws XMLStreamException {
171 }
172
173 /* (non-Javadoc)
174 * @see javax.xml.stream.XMLStreamReader#isStartElement()
175 */
176 public boolean isStartElement() {
177 return (currentEvent == START_ELEMENT);
178 }
179
180 /* (non-Javadoc)
181 * @see javax.xml.stream.XMLStreamReader#isEndElement()
182 */
183 public boolean isEndElement() {
184 return (currentEvent == END_ELEMENT);
185 }
186
187 /* (non-Javadoc)
188 * @see javax.xml.stream.XMLStreamReader#isCharacters()
189 */
190 public boolean isCharacters() {
191 return (currentEvent == CHARACTERS);
192 }
193
194 /* (non-Javadoc)
195 * @see javax.xml.stream.XMLStreamReader#isWhiteSpace()
196 */
197 public boolean isWhiteSpace() {
198 return (currentEvent == SPACE);
199 }
200
201 public int getEventType() {
202 return currentEvent;
203 }
204
205 public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
206 char[] src = getText().toCharArray();
207
208 if (sourceStart + length >= src.length)
209 length = src.length - sourceStart;
210
211 for (int i = 0; i < length; i++) {
212 target[targetStart + i] = src[i + sourceStart];
213 }
214
215 return length;
216 }
217
218 public boolean hasText() {
219 return (currentEvent == CHARACTERS || currentEvent == DTD || currentEvent == ENTITY_REFERENCE
220 || currentEvent == COMMENT || currentEvent == SPACE);
221 }
222
223 public Location getLocation() {
224 return new Location() {
225
226 public int getCharacterOffset() {
227 return 0;
228 }
229
230 public int getColumnNumber() {
231 return 0;
232 }
233
234 public int getLineNumber() {
235 return 0;
236 }
237
238 public String getPublicId() {
239 return null;
240 }
241
242 public String getSystemId() {
243 return null;
244 }
245
246 };
247 }
248
249 public boolean hasName() {
250 return (currentEvent == START_ELEMENT || currentEvent == END_ELEMENT);
251 }
252
253 public String getVersion() {
254 return null;
255 }
256
257 public boolean isStandalone() {
258 return false;
259 }
260
261 public boolean standaloneSet() {
262 // TODO Auto-generated method stub
263 return false;
264 }
265
266 public String getCharacterEncodingScheme() {
267 // TODO Auto-generated method stub
268 return null;
269 }
270
271 /**
272 * Get the document associated with this stream.
273 *
274 * @return
275 */
276 public Document getDocument() {
277 return document;
278 }
279
280 /**
281 * Find name spaces declaration in attributes and move them to separate
282 * collection.
283 */
284 protected void newFrame(ElementFrame frame) {
285 Element element = getCurrentElement();
286 frame.uris = new ArrayList<String>();
287 frame.prefixes = new ArrayList<String>();
288 frame.attributes = new ArrayList<Node>();
289
290 if (context == null)
291 context = new DOMNamespaceContext();
292
293 context.setElement(element);
294
295 NamedNodeMap nodes = element.getAttributes();
296
297 String ePrefix = element.getPrefix();
298 if (ePrefix == null) {
299 ePrefix = "";
300 }
301
302 for (int i = 0; i < nodes.getLength(); i++) {
303 Node node = nodes.item(i);
304 String prefix = node.getPrefix();
305 String localName = node.getLocalName();
306 String value = node.getNodeValue();
307 String name = node.getNodeName();
308
309 if (prefix == null)
310 prefix = "";
311
312 if (name != null && name.equals("xmlns")) {
313 frame.uris.add(value);
314 frame.prefixes.add("");
315 } else if (prefix.length() > 0 && prefix.equals("xmlns")) {
316 frame.uris.add(value);
317 frame.prefixes.add(localName);
318 } else if (name.startsWith("xmlns:")) {
319 prefix = name.substring(6);
320 frame.uris.add(value);
321 frame.prefixes.add(prefix);
322 } else {
323 frame.attributes.add(node);
324 }
325 }
326 }
327
328 protected void endElement() {
329 }
330
331 protected Element getCurrentElement() {
332 return (Element) getCurrentFrame().element;
333 }
334
335 public Element skipElement() {
336 Element e = (Element) getCurrentFrame().element;
337 skipFrame();
338 return e;
339 }
340
341 protected ElementFrame getChildFrame(int currentChild) {
342 return new ElementFrame(getCurrentElement().getChildNodes().item(currentChild), getCurrentFrame());
343 }
344
345 protected int getChildCount() {
346 return getCurrentElement().getChildNodes().getLength();
347 }
348
349 protected int moveToChild(int currentChild) {
350 this.content = getCurrentElement().getChildNodes().item(currentChild);
351
352 if (content instanceof Text)
353 return CHARACTERS;
354 else if (content instanceof Element)
355 return START_ELEMENT;
356 else if (content instanceof CDATASection)
357 return CDATA;
358 else if (content instanceof Comment)
359 return CHARACTERS;
360 else if (content instanceof EntityReference)
361 return ENTITY_REFERENCE;
362
363 throw new IllegalStateException();
364 }
365
366 public String getElementText() throws XMLStreamException {
367 return getText();
368 }
369
370 public String getNamespaceURI(String prefix) {
371 ElementFrame frame = getCurrentFrame();
372
373 while (null != frame) {
374 int index = frame.prefixes.indexOf(prefix);
375 if (index != -1) {
376 return (String) frame.uris.get(index);
377 }
378
379 frame = frame.parent;
380 }
381
382 return null;
383 }
384
385 public String getAttributeValue(String ns, String local) {
386 if (ns == null || ns.equals(""))
387 return getCurrentElement().getAttribute(local);
388 else
389 return getCurrentElement().getAttributeNS(ns, local);
390 }
391
392 public int getAttributeCount() {
393 return getCurrentFrame().attributes.size();
394 }
395
396 Attr getAttribute(int i) {
397 return (Attr) getCurrentFrame().attributes.get(i);
398 }
399
400 private String getLocalName(Attr attr) {
401
402 String name = attr.getLocalName();
403 if (name == null) {
404 name = attr.getNodeName();
405 }
406 return name;
407 }
408
409 public QName getAttributeName(int i) {
410 Attr at = getAttribute(i);
411
412 String prefix = at.getPrefix();
413 String ln = getLocalName(at);
414 // at.getNodeName();
415 String ns = at.getNamespaceURI();
416
417 if (prefix == null) {
418 return new QName(ns, ln);
419 } else {
420 return new QName(ns, ln, prefix);
421 }
422 }
423
424 public String getAttributeNamespace(int i) {
425 return getAttribute(i).getNamespaceURI();
426 }
427
428 public String getAttributeLocalName(int i) {
429 Attr attr = getAttribute(i);
430 String name = getLocalName(attr);
431 return name;
432 }
433
434 public String getAttributePrefix(int i) {
435 return getAttribute(i).getPrefix();
436 }
437
438 public String getAttributeType(int i) {
439 return toStaxType(getAttribute(i).getNodeType());
440 }
441
442 public static String toStaxType(short jdom) {
443 switch (jdom) {
444 default:
445 return null;
446 }
447 }
448
449 public String getAttributeValue(int i) {
450 return getAttribute(i).getValue();
451 }
452
453 public boolean isAttributeSpecified(int i) {
454 return getAttribute(i).getValue() != null;
455 }
456
457 public int getNamespaceCount() {
458 return getCurrentFrame().prefixes.size();
459 }
460
461 public String getNamespacePrefix(int i) {
462 return (String) getCurrentFrame().prefixes.get(i);
463 }
464
465 public String getNamespaceURI(int i) {
466 return (String) getCurrentFrame().uris.get(i);
467 }
468
469 public NamespaceContext getNamespaceContext() {
470 return context;
471 }
472
473 public String getText() {
474 Node node = getCurrentElement().getChildNodes().item(getCurrentFrame().currentChild);
475 return node.getNodeValue();
476 }
477
478 public char[] getTextCharacters() {
479 return getText().toCharArray();
480 }
481
482 public int getTextStart() {
483 return 0;
484 }
485
486 public int getTextLength() {
487 return getText().length();
488 }
489
490 public String getEncoding() {
491 return null;
492 }
493
494 public QName getName() {
495 Element el = getCurrentElement();
496
497 String prefix = getPrefix();
498 String ln = getLocalName();
499
500 if (prefix == null) {
501 return new QName(el.getNamespaceURI(), ln);
502 } else {
503 return new QName(el.getNamespaceURI(), ln, prefix);
504 }
505 }
506
507 public String getLocalName() {
508 String name = getCurrentElement().getLocalName();
509 // When the element has no namespaces, null is returned
510 if (name == null) {
511 name = getCurrentElement().getNodeName();
512 }
513 return name;
514 }
515
516 public String getNamespaceURI() {
517 return getCurrentElement().getNamespaceURI();
518 }
519
520 public String getPrefix() {
521 String prefix = getCurrentElement().getPrefix();
522 if (prefix == null) {
523 prefix = "";
524 }
525 return prefix;
526 }
527
528 public String getPITarget() {
529 throw new UnsupportedOperationException();
530 }
531
532 public String getPIData() {
533 throw new UnsupportedOperationException();
534 }
535
536 public class DOMNamespaceContext implements NamespaceContext {
537 private Element currentNode;
538
539 public String getNamespaceURI(String prefix) {
540 String name = prefix;
541 if (name.length() == 0)
542 name = "xmlns";
543 else
544 name = "xmlns:" + prefix;
545
546 return getNamespaceURI(currentNode, name);
547 }
548
549 private String getNamespaceURI(Element e, String name) {
550 Attr attr = e.getAttributeNode(name);
551 if (attr == null) {
552 Node n = e.getParentNode();
553 if (n instanceof Element && n != e) {
554 return getNamespaceURI((Element) n, name);
555 }
556 } else {
557 return attr.getValue();
558 }
559
560 return null;
561 }
562
563 public String getPrefix(String uri) {
564 return getPrefix(currentNode, uri);
565 }
566
567 private String getPrefix(Element e, String uri) {
568 NamedNodeMap attributes = e.getAttributes();
569 for (int i = 0; i < attributes.getLength(); i++) {
570 Attr a = (Attr) attributes.item(i);
571
572 String val = a.getValue();
573 if (val != null && val.equals(uri)) {
574 String name = a.getNodeName();
575 if (name.equals("xmlns"))
576 return "";
577 else
578 return name.substring(6);
579 }
580 }
581
582 Node n = e.getParentNode();
583 if (n instanceof Element && n != e) {
584 return getPrefix((Element) n, uri);
585 }
586
587 return null;
588 }
589
590 public Iterator<String> getPrefixes(String uri) {
591 List<String> prefixes = new ArrayList<String>();
592
593 String prefix = getPrefix(uri);
594 if (prefix != null)
595 prefixes.add(prefix);
596
597 return prefixes.iterator();
598 }
599
600 public Element getElement() {
601 return currentNode;
602 }
603
604 public void setElement(Element currentNode) {
605 this.currentNode = currentNode;
606 }
607 }
608
609 public static class ElementFrame {
610 public ElementFrame(Object element, ElementFrame parent) {
611 this.element = element;
612 this.parent = parent;
613 }
614
615 final Object element;
616 final ElementFrame parent;
617 boolean started = false;
618 boolean ended = false;
619 int currentChild = -1;
620 int currentAttribute = -1;
621 int currentNamespace = -1;
622 int currentElement = -1;
623 List<String> uris;
624 List<String> prefixes;
625 List<Node> attributes;
626 List allAttributes;
627 }
628
629 }