001: /*
002: * Copyright 2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.xml.stream;
018:
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.List;
022: import javax.xml.XMLConstants;
023: import javax.xml.namespace.QName;
024: import javax.xml.stream.Location;
025: import javax.xml.stream.XMLEventFactory;
026: import javax.xml.stream.XMLStreamException;
027: import javax.xml.stream.events.XMLEvent;
028: import javax.xml.stream.util.XMLEventConsumer;
029:
030: import org.springframework.util.StringUtils;
031: import org.springframework.xml.namespace.QNameUtils;
032: import org.springframework.xml.namespace.SimpleNamespaceContext;
033: import org.xml.sax.Attributes;
034: import org.xml.sax.Locator;
035:
036: /**
037: * SAX <code>ContentHandler</code> that transforms callback calls to <code>XMLEvent</code>s and writes them to a
038: * <code>XMLEventConsumer</code>.
039: *
040: * @author Arjen Poutsma
041: * @see XMLEvent
042: * @see XMLEventConsumer
043: * @since 1.0.0
044: */
045: public class StaxEventContentHandler extends AbstractStaxContentHandler {
046:
047: private final XMLEventFactory eventFactory;
048:
049: private final XMLEventConsumer eventConsumer;
050:
051: private Locator locator;
052:
053: /**
054: * Constructs a new instance of the <code>StaxEventContentHandler</code> that writes to the given
055: * <code>XMLEventConsumer</code>. A default <code>XMLEventFactory</code> will be created.
056: *
057: * @param consumer the consumer to write events to
058: */
059: public StaxEventContentHandler(XMLEventConsumer consumer) {
060: eventFactory = XMLEventFactory.newInstance();
061: eventConsumer = consumer;
062: }
063:
064: /**
065: * Constructs a new instance of the <code>StaxEventContentHandler</code> that uses the given event factory to create
066: * events and writes to the given <code>XMLEventConsumer</code>.
067: *
068: * @param consumer the consumer to write events to
069: * @param factory the factory used to create events
070: */
071: public StaxEventContentHandler(XMLEventConsumer consumer,
072: XMLEventFactory factory) {
073: eventFactory = factory;
074: eventConsumer = consumer;
075: }
076:
077: public void setDocumentLocator(Locator locator) {
078: this .locator = locator;
079: }
080:
081: protected void startDocumentInternal() throws XMLStreamException {
082: consumeEvent(eventFactory.createStartDocument());
083: }
084:
085: protected void endDocumentInternal() throws XMLStreamException {
086: consumeEvent(eventFactory.createEndDocument());
087: }
088:
089: protected void startElementInternal(QName name, Attributes atts,
090: SimpleNamespaceContext namespaceContext)
091: throws XMLStreamException {
092: List attributes = getAttributes(atts);
093: List namespaces = createNamespaces(namespaceContext);
094: consumeEvent(eventFactory.createStartElement(name, attributes
095: .iterator(), namespaces.iterator()));
096: }
097:
098: protected void endElementInternal(QName name,
099: SimpleNamespaceContext namespaceContext)
100: throws XMLStreamException {
101: List namespaces = createNamespaces(namespaceContext);
102: consumeEvent(eventFactory.createEndElement(name, namespaces
103: .iterator()));
104: }
105:
106: protected void charactersInternal(char[] ch, int start, int length)
107: throws XMLStreamException {
108: consumeEvent(eventFactory.createCharacters(new String(ch,
109: start, length)));
110: }
111:
112: protected void ignorableWhitespaceInternal(char[] ch, int start,
113: int length) throws XMLStreamException {
114: consumeEvent(eventFactory.createIgnorableSpace(new String(ch,
115: start, length)));
116: }
117:
118: protected void processingInstructionInternal(String target,
119: String data) throws XMLStreamException {
120: consumeEvent(eventFactory.createProcessingInstruction(target,
121: data));
122: }
123:
124: private void consumeEvent(XMLEvent event) throws XMLStreamException {
125: if (locator != null) {
126: eventFactory.setLocation(new SaxLocation(locator));
127: }
128: eventConsumer.add(event);
129: }
130:
131: /** Creates and returns a list of <code>NameSpace</code> objects from the <code>NamespaceContext</code>. */
132: private List createNamespaces(
133: SimpleNamespaceContext namespaceContext) {
134: List namespaces = new ArrayList();
135: String defaultNamespaceUri = namespaceContext
136: .getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX);
137: if (StringUtils.hasLength(defaultNamespaceUri)) {
138: namespaces.add(eventFactory
139: .createNamespace(defaultNamespaceUri));
140: }
141: for (Iterator iterator = namespaceContext.getBoundPrefixes(); iterator
142: .hasNext();) {
143: String prefix = (String) iterator.next();
144: String namespaceUri = namespaceContext
145: .getNamespaceURI(prefix);
146: namespaces.add(eventFactory.createNamespace(prefix,
147: namespaceUri));
148: }
149: return namespaces;
150: }
151:
152: private List getAttributes(Attributes attributes) {
153: List list = new ArrayList();
154: for (int i = 0; i < attributes.getLength(); i++) {
155: QName name = QNameUtils.toQName(attributes.getURI(i),
156: attributes.getQName(i));
157: if (!("xmlns".equals(name.getLocalPart()) || "xmlns"
158: .equals(QNameUtils.getPrefix(name)))) {
159: list.add(eventFactory.createAttribute(name, attributes
160: .getValue(i)));
161: }
162: }
163: return list;
164: }
165:
166: //
167: // No operation
168: //
169:
170: protected void skippedEntityInternal(String name)
171: throws XMLStreamException {
172: }
173:
174: private static class SaxLocation implements Location {
175:
176: private Locator locator;
177:
178: public SaxLocation(Locator locator) {
179: this .locator = locator;
180: }
181:
182: public int getLineNumber() {
183: return locator.getLineNumber();
184: }
185:
186: public int getColumnNumber() {
187: return locator.getColumnNumber();
188: }
189:
190: public int getCharacterOffset() {
191: return -1;
192: }
193:
194: public String getPublicId() {
195: return locator.getPublicId();
196: }
197:
198: public String getSystemId() {
199: return locator.getSystemId();
200: }
201: }
202: }
|