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 */