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