001    /** 
002     * 
003     * Copyright 2004 Protique Ltd
004     * 
005     * Licensed under the Apache License, Version 2.0 (the "License"); 
006     * you may not use this file except in compliance with the License. 
007     * 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     **/
018    package org.codehaus.activesoap.util;
019    
020    import org.xml.sax.ContentHandler;
021    import org.xml.sax.Attributes;
022    import org.xml.sax.SAXException;
023    import org.xml.sax.helpers.AttributesImpl;
024    
025    import javax.xml.namespace.NamespaceContext;
026    import javax.xml.namespace.QName;
027    import javax.xml.stream.XMLStreamConstants;
028    import javax.xml.stream.XMLStreamException;
029    import javax.xml.stream.XMLStreamReader;
030    import javax.xml.stream.XMLStreamWriter;
031    
032    import javanet.staxutils.XMLStreamUtils;
033    import javanet.staxutils.XMLStreamReaderToContentHandler;
034    
035    /**
036     * Utility methods for working with an XMLStreamWriter.
037     * Maybe push this back into stax-utils project.
038     *
039     * @version $Revision: 1.14 $
040     */
041    public class XMLStreamHelper implements XMLStreamConstants {
042        private static Attributes emptyAttributes = new AttributesImpl();
043    
044    
045        /**
046         * Returns true if currently at the start of an element, otherwise move forwards to the next
047         * element start and return true, otherwise false is returned if the end of the stream is reached.
048         */
049        public static boolean skipToStartOfElement(XMLStreamReader in) throws XMLStreamException {
050            for (int code = in.getEventType(); code != END_DOCUMENT; code = in.next()) {
051                if (code == START_ELEMENT) {
052                    return true;
053                }
054            }
055            return false;
056        }
057    
058        public static void writeStartElement(QName qname, ContentHandler handler) throws SAXException {
059            handler.startElement(qname.getNamespaceURI(), qname.getLocalPart(), QNameHelper.getQualifiedName(qname), emptyAttributes);
060        }
061    
062        public static void writeEndElement(QName qname, ContentHandler handler) throws SAXException {
063            handler.endElement(qname.getNamespaceURI(), qname.getLocalPart(), QNameHelper.getQualifiedName(qname));
064        }
065    
066    
067        /**
068         * Copies the current element and its conetnt to the output
069         */
070        public static void copy(XMLStreamReader in, XMLStreamWriter out, boolean repairing) throws XMLStreamException {
071            int elementCount = 0;
072            for (int code = in.getEventType(); in.hasNext(); code = in.next()) {
073                switch (code) {
074                    case START_ELEMENT:
075                        elementCount++;
076                        writeStartElementAndAttributes(out, in, repairing);
077                        break;
078    
079                    case END_ELEMENT:
080                        if (--elementCount < 0) {
081                            return;
082                        }
083                        out.writeEndElement();
084                        break;
085    
086                    case CDATA:
087                        out.writeCData(in.getText());
088                        break;
089    
090                    case CHARACTERS:
091                        out.writeCharacters(in.getText());
092                        break;
093                }
094            }
095            while (elementCount-- > 0) {
096                out.writeEndElement();
097            }
098        }
099    
100        public static void writeStartElement(XMLStreamWriter out, String prefix, String uri, String localName, boolean repairing) throws XMLStreamException {
101            boolean map = isPrefixNotMappedToUri(out, prefix, uri);
102            if (prefix != null && prefix.length() > 0) {
103                if (map) {
104                    out.setPrefix(prefix, uri);
105                }
106                out.writeStartElement(prefix, localName, uri);
107                if (map && !repairing) {
108                    out.writeNamespace(prefix, uri);
109                }
110            }
111            else {
112                boolean hasURI = uri != null && uri.length() > 0;
113                if (map && hasURI) {
114                    out.setDefaultNamespace(uri);
115                }
116                out.writeStartElement(uri, localName);
117                if (map && !repairing && hasURI) {
118                    out.writeDefaultNamespace(uri);
119                }
120            }
121        }
122    
123        public static void writeStartElement(XMLStreamWriter out, QName envelopeName, boolean repairing) throws XMLStreamException {
124            writeStartElement(out, envelopeName.getPrefix(), envelopeName.getNamespaceURI(), envelopeName.getLocalPart(), repairing);
125        }
126    
127        public static void writeStartElement(XMLStreamWriter out, XMLStreamReader in, boolean repairing) throws XMLStreamException {
128            String prefix = in.getPrefix();
129    
130            // we can avoid this step if in repairing mode
131            int count = in.getNamespaceCount();
132            for (int i = 0; i < count; i++) {
133                String aPrefix = in.getNamespacePrefix(i);
134                if (prefix == aPrefix || (prefix != null && prefix.equals(aPrefix))) {
135                    continue;
136                }
137                String uri = in.getNamespaceURI(i);
138                if (isPrefixNotMappedToUri(out, aPrefix, uri)) {
139                    if (aPrefix != null && aPrefix.length() > 0) {
140                        out.setPrefix(aPrefix, uri);
141                    }
142                    else {
143                        out.setDefaultNamespace(uri);
144                    }
145                }
146            }
147            String localName = in.getLocalName();
148            String uri = in.getNamespaceURI();
149            writeStartElement(out, prefix, uri, localName, repairing);
150        }
151    
152    
153        public static void writeStartElementAndAttributes(XMLStreamWriter out, XMLStreamReader in, boolean repairing) throws XMLStreamException {
154            writeStartElement(out, in, repairing);
155            if (!repairing) {
156                writeNamespaces(out, in, in.getPrefix());
157            }
158            writeAttributes(out, in);
159        }
160    
161        public static void writeAttributes(XMLStreamWriter out, XMLStreamReader in) throws XMLStreamException {
162            int count = in.getAttributeCount();
163            for (int i = 0; i < count; i++) {
164                out.writeAttribute(in.getAttributePrefix(i),
165                        in.getAttributeNamespace(i),
166                        in.getAttributeLocalName(i),
167                        in.getAttributeValue(i));
168            }
169        }
170    
171        public static void writeNamespaces(XMLStreamWriter out, XMLStreamReader in, String prefixOfCurrentElement) throws XMLStreamException {
172            int count = in.getNamespaceCount();
173            for (int i = 0; i < count; i++) {
174                String prefix = in.getNamespacePrefix(i);
175                String uri = in.getNamespaceURI(i);
176                if (prefixOfCurrentElement != null && prefixOfCurrentElement.equals(prefix)) {
177                    continue;
178                }
179                if (isPrefixNotMappedToUri(out, prefix, uri)) {
180                    out.writeNamespace(prefix, uri);
181                }
182            }
183        }
184    
185    
186        public static void writeNamespacesExcludingPrefixAndNamespace(XMLStreamWriter out, XMLStreamReader in, String ignorePrefix, String ignoreNamespace) throws XMLStreamException {
187            int count = in.getNamespaceCount();
188            for (int i = 0; i < count; i++) {
189                String prefix = in.getNamespacePrefix(i);
190                if (!ignorePrefix.equals(prefix)) {
191                    String uri = in.getNamespaceURI(i);
192                    if (!ignoreNamespace.equals(uri)) {
193                        out.writeNamespace(prefix, uri);
194                    }
195                }
196            }
197        }
198    
199        public static void writeAttribute(XMLStreamWriter out, QName name, String attributeValue) throws XMLStreamException {
200            writeAttribute(out, name.getPrefix(), name.getNamespaceURI(), name.getLocalPart(), attributeValue);
201        }
202    
203        public static void writeAttribute(XMLStreamWriter out, String prefix, String namespaceURI, String localPart, String attributeValue) throws XMLStreamException {
204            out.writeAttribute(prefix, namespaceURI, localPart, attributeValue);
205        }
206    
207        protected static boolean isPrefixNotMappedToUri(XMLStreamWriter out, String prefix, String uri) {
208            if (prefix == null) {
209                prefix = "";
210            }
211            NamespaceContext context = out.getNamespaceContext();
212            if (context == null) {
213                return false;
214            }
215            String mappedUri = context.getPrefix(prefix);
216            boolean map = (mappedUri == null || !mappedUri.equals(uri));
217            return map;
218        }
219    
220        /**
221         * Copies the content to the SAX stream
222         */
223        public static void copy(XMLStreamReader in, ContentHandler contentHandler) throws XMLStreamException {
224            XMLStreamReaderToContentHandler converter = new XMLStreamReaderToContentHandler(in, contentHandler);
225            converter.bridge();
226        }
227    
228        /**
229         * Copies the element and its content to the SAX stream
230         */
231        public static void copyElement(XMLStreamReader in, ContentHandler contentHandler) throws XMLStreamException {
232            copy(new DocumentFilterXMLStreamReader(in.getName(), in), contentHandler);
233        }
234    
235    }