001    /*
002     * (c) Copyright 2009 University of Bristol
003     * All rights reserved.
004     * [See end of file]
005     */
006    package net.rootdev.javardfa;
007    
008    import java.util.Iterator;
009    import java.util.SortedMap;
010    import java.util.TreeMap;
011    import javax.xml.namespace.NamespaceContext;
012    import javax.xml.namespace.QName;
013    import javax.xml.stream.XMLEventReader;
014    import javax.xml.stream.XMLEventWriter;
015    import javax.xml.stream.XMLStreamException;
016    import javax.xml.stream.XMLStreamWriter;
017    import javax.xml.stream.events.Attribute;
018    import javax.xml.stream.events.ProcessingInstruction;
019    import javax.xml.stream.events.StartElement;
020    import javax.xml.stream.events.XMLEvent;
021    
022    /**
023     * All this class does currently is ensure the order of attributes, but
024     * (By using a stream writer) it is more controllable than the event writer.
025     *
026     * @author pldms
027     */
028    public class CanonicalXMLEventWriter
029            implements XMLEventWriter {
030    
031        private final XMLStreamWriter swriter;
032        private StartElement last;
033    
034        public CanonicalXMLEventWriter(XMLStreamWriter swriter) {
035            this.swriter = swriter;
036        }
037    
038        public void flush() throws XMLStreamException {
039            swriter.flush();
040        }
041    
042        public void close() throws XMLStreamException {
043            swriter.close();
044        }
045    
046        public void add(XMLEvent event) throws XMLStreamException {
047            if (event.isEndElement()) {
048                swriter.writeEndElement();
049            } else if (event.isCharacters()) {
050                swriter.writeCharacters(event.asCharacters().getData());
051            } else if (event.isProcessingInstruction()) {
052                swriter.writeProcessingInstruction(((ProcessingInstruction) event).getData(),
053                        ((ProcessingInstruction) event).getTarget());
054            } else if (event.isStartElement()) {
055                StartElement se = event.asStartElement();
056                swriter.writeStartElement(se.getName().getPrefix(),
057                        se.getName().getLocalPart(),
058                        se.getName().getNamespaceURI());
059                writeAttributes(se);
060                swriter.writeCharacters(""); // Force close of start element
061            } else {
062                System.err.printf("Gah! Missed one <%s>, '%s'\n", event.getClass(), event);
063            }
064        }
065    
066        public void add(XMLEventReader reader) throws XMLStreamException {
067            while (reader.hasNext()) {
068                this.add(reader.nextEvent());
069            }
070        }
071    
072        public String getPrefix(String uri) throws XMLStreamException {
073            return swriter.getPrefix(uri);
074        }
075    
076        public void setPrefix(String prefix, String uri) throws XMLStreamException {
077            swriter.setPrefix(prefix, uri);
078        }
079    
080        public void setDefaultNamespace(String uri) throws XMLStreamException {
081            swriter.setDefaultNamespace(uri);
082        }
083    
084        public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
085            swriter.setNamespaceContext(context);
086        }
087    
088        public NamespaceContext getNamespaceContext() {
089            return swriter.getNamespaceContext();
090        }
091    
092        private void writeAttributes(StartElement se) throws XMLStreamException {
093            SortedMap<String, Attribute> atts = new TreeMap<String, Attribute>();
094            for (Iterator i = se.getAttributes(); i.hasNext();) {
095                Attribute a = (Attribute) i.next();
096                atts.put(getName(a), a);
097            }
098            for (Attribute a : atts.values()) {
099                swriter.writeAttribute(
100                        a.getName().getPrefix(),
101                        a.getName().getNamespaceURI(),
102                        a.getName().getLocalPart(),
103                        a.getValue());
104            }
105        }
106    
107        private String getName(Attribute a) {
108            QName name = a.getName();
109            String toReturn = (name.getPrefix() == null) ? name.getLocalPart() : name.getPrefix() + ":" + name.getLocalPart();
110            if (toReturn.startsWith("xml:")) {
111                return "_" + toReturn;
112            } else {
113                return toReturn;
114            }
115        }
116    }
117    
118    /*
119     * (c) Copyright 2009 University of Bristol
120     * All rights reserved.
121     *
122     * Redistribution and use in source and binary forms, with or without
123     * modification, are permitted provided that the following conditions
124     * are met:
125     * 1. Redistributions of source code must retain the above copyright
126     *    notice, this list of conditions and the following disclaimer.
127     * 2. Redistributions in binary form must reproduce the above copyright
128     *    notice, this list of conditions and the following disclaimer in the
129     *    documentation and/or other materials provided with the distribution.
130     * 3. The name of the author may not be used to endorse or promote products
131     *    derived from this software without specific prior written permission.
132     *
133     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
134     * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
135     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
136     * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
137     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
138     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
139     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
140     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
141     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
142     * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
143     */