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