1 16 package org.outerj.daisy.xmlutil; 17 18 import org.xml.sax.SAXException ; 19 import org.xml.sax.Attributes ; 20 import org.xml.sax.ContentHandler ; 21 import org.xml.sax.Locator ; 22 import org.xml.sax.helpers.AttributesImpl ; 23 24 import javax.xml.transform.sax.SAXTransformerFactory ; 25 import javax.xml.transform.sax.TransformerHandler ; 26 import javax.xml.transform.stream.StreamResult ; 27 import javax.xml.transform.TransformerConfigurationException ; 28 import javax.xml.transform.OutputKeys ; 29 import java.util.List ; 30 import java.util.ArrayList ; 31 import java.util.Map ; 32 import java.util.HashMap ; 33 import java.io.StringWriter ; 34 import java.io.OutputStream ; 35 36 public class XmlSerializer implements ContentHandler { 37 private static boolean needsNamespaceFix = false; 38 private static boolean needsNamespaceFixInitialized = false; 39 private static final String XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace"; 40 41 private ContentHandler nextHandler; 42 43 public XmlSerializer(OutputStream outputStream) throws Exception { 44 if (!needsNamespaceFixInitialized) { 45 synchronized(this) { 46 if (!needsNamespaceFixInitialized) { 50 needsNamespaceFix = needsNamespacesAsAttributes(); 51 needsNamespaceFixInitialized = true; 52 } 53 } 54 } 55 56 TransformerHandler serializer = getTransformerHandler(); 57 serializer.getTransformer().setOutputProperty(OutputKeys.METHOD, "xml"); 58 serializer.setResult(new StreamResult (outputStream)); 59 60 if (needsNamespaceFix) { 61 nextHandler = new NamespaceAsAttributes(serializer); 62 } else { 63 nextHandler = serializer; 64 } 65 } 66 67 private TransformerHandler getTransformerHandler() throws TransformerConfigurationException { 68 SAXTransformerFactory transformerFactory = (SAXTransformerFactory ) SAXTransformerFactory.newInstance(); 69 return transformerFactory.newTransformerHandler(); 70 } 71 72 73 83 private boolean needsNamespacesAsAttributes() throws Exception { 84 85 StringWriter writer = new StringWriter (); 87 88 String uri = "namespaceuri"; 89 String prefix = "nsp"; 90 String check = "xmlns:" + prefix + "='" + uri + "'"; 91 92 TransformerHandler handler = getTransformerHandler(); 93 94 handler.setResult(new StreamResult (writer)); 95 96 handler.startDocument(); 98 handler.startPrefixMapping(prefix, uri); 99 handler.startElement(uri, "element", "", new AttributesImpl ()); 100 handler.endPrefixMapping(prefix); 101 handler.endDocument(); 102 103 String text = writer.toString(); 104 105 boolean needsIt = (text.replace('"', '\'').indexOf(check) == -1); 107 108 111 return needsIt; 112 } 113 114 122 public class NamespaceAsAttributes implements ContentHandler { 123 124 127 private List prefixList = new ArrayList (); 128 129 132 private List uriList = new ArrayList (); 133 134 138 private Map uriToPrefixMap = new HashMap (); 139 private Map prefixToUriMap = new HashMap (); 140 141 144 private boolean hasMappings = false; 145 146 private ContentHandler nextHandler; 147 148 public NamespaceAsAttributes(ContentHandler nextHandler) { 149 this.nextHandler = nextHandler; 150 } 151 152 public void startDocument() throws SAXException { 153 this.uriToPrefixMap.clear(); 155 this.prefixToUriMap.clear(); 156 clearMappings(); 157 nextHandler.startDocument(); 158 } 159 160 164 public void startPrefixMapping(String prefix, String uri) throws SAXException { 165 if (uri != null && !prefix.startsWith("xml") && !this.prefixList.contains(prefix)) { 169 this.hasMappings = true; 170 this.prefixList.add(prefix); 171 this.uriList.add(uri); 172 173 if (prefix.length() > 0) { 176 this.uriToPrefixMap.put(uri, prefix + ":"); 177 } else { 178 this.uriToPrefixMap.put(uri, prefix); 179 } 180 181 this.prefixToUriMap.put(prefix, uri); 182 } 183 nextHandler.startPrefixMapping(prefix, uri); 184 } 185 186 192 public void startElement(String eltUri, String eltLocalName, String eltQName, Attributes attrs) 193 throws SAXException { 194 195 if (null != eltUri && eltUri.length() != 0 && this.uriToPrefixMap.containsKey(eltUri)) { 197 eltQName = this.uriToPrefixMap.get(eltUri) + eltLocalName; 198 } 199 if (this.hasMappings) { 200 202 AttributesImpl newAttrs = null; 204 205 int mappingCount = this.prefixList.size(); 206 int attrCount = attrs.getLength(); 207 208 for (int mapping = 0; mapping < mappingCount; mapping++) { 209 210 String uri = (String ) this.uriList.get(mapping); 212 String prefix = (String ) this.prefixList.get(mapping); 213 String qName = prefix.equals("") ? "xmlns" : ("xmlns:" + prefix); 214 215 boolean found = false; 217 for (int attr = 0; attr < attrCount; attr++) { 218 if (qName.equals(attrs.getQName(attr))) { 219 if (!uri.equals(attrs.getValue(attr))) { 221 System.err.println("XML serializer: URI in prefix mapping and attribute do not match : '" 222 + uri + "' - '" + attrs.getURI(attr) + "'"); 223 throw new SAXException ("URI in prefix mapping and attribute do not match"); 224 } 225 found = true; 226 break; 227 } 228 } 229 230 if (!found) { 231 if (newAttrs == null) { 233 if (attrCount == 0) { 236 newAttrs = new AttributesImpl (); 237 } else { 238 newAttrs = new AttributesImpl (attrs); 239 } 240 } 241 242 if (prefix.equals("")) { 243 newAttrs.addAttribute(XML_NAMESPACE_URI, "xmlns", "xmlns", "CDATA", uri); 244 } else { 245 newAttrs.addAttribute(XML_NAMESPACE_URI, prefix, qName, "CDATA", uri); 246 } 247 } 248 } 250 clearMappings(); 252 253 nextHandler.startElement(eltUri, eltLocalName, eltQName, newAttrs == null ? attrs : newAttrs); 255 } else { 256 nextHandler.startElement(eltUri, eltLocalName, eltQName, attrs); 258 } 259 } 260 261 262 266 public void endElement(String eltUri, String eltLocalName, String eltQName) throws SAXException { 267 if (null != eltUri && eltUri.length() != 0 && this.uriToPrefixMap.containsKey(eltUri)) { 269 eltQName = this.uriToPrefixMap.get(eltUri) + eltLocalName; 270 } 271 nextHandler.endElement(eltUri, eltLocalName, eltQName); 272 } 273 274 278 public void endPrefixMapping(String prefix) throws SAXException { 279 if (this.prefixToUriMap.containsKey(prefix)) { 283 this.uriToPrefixMap.remove(this.prefixToUriMap.get(prefix)); 284 this.prefixToUriMap.remove(prefix); 285 } 286 287 if (hasMappings) { 288 int pos = prefixList.lastIndexOf(prefix); 295 if (pos != -1) { 296 prefixList.remove(pos); 297 uriList.remove(pos); 298 } 299 } 300 301 nextHandler.endPrefixMapping(prefix); 302 } 303 304 307 public void endDocument() throws SAXException { 308 this.uriToPrefixMap.clear(); 310 this.prefixToUriMap.clear(); 311 clearMappings(); 312 nextHandler.endDocument(); 313 } 314 315 private void clearMappings() { 316 this.hasMappings = false; 317 this.prefixList.clear(); 318 this.uriList.clear(); 319 } 320 321 public void characters(char ch[], int start, int length) throws SAXException { 322 nextHandler.characters(ch, start, length); 323 } 324 325 public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { 326 nextHandler.ignorableWhitespace(ch, start, length); 327 } 328 329 public void skippedEntity(String name) throws SAXException { 330 nextHandler.skippedEntity(name); 331 } 332 333 public void setDocumentLocator(Locator locator) { 334 nextHandler.setDocumentLocator(locator); 335 } 336 337 public void processingInstruction(String target, String data) throws SAXException { 338 nextHandler.processingInstruction(target, data); 339 } 340 } 341 342 public void endDocument() throws SAXException { 343 nextHandler.endDocument(); 344 } 345 346 public void startDocument () throws SAXException { 347 nextHandler.startDocument(); 348 } 349 350 public void characters (char ch[], int start, int length) throws SAXException { 351 nextHandler.characters(ch, start, length); 352 } 353 354 public void ignorableWhitespace (char ch[], int start, int length) throws SAXException { 355 nextHandler.ignorableWhitespace(ch, start, length); 356 } 357 358 public void endPrefixMapping (String prefix) throws SAXException { 359 nextHandler.endPrefixMapping(prefix); 360 } 361 362 public void skippedEntity (String name) throws SAXException { 363 nextHandler.skippedEntity(name); 364 } 365 366 public void setDocumentLocator (Locator locator) { 367 nextHandler.setDocumentLocator(locator); 368 } 369 370 public void processingInstruction (String target, String data) throws SAXException { 371 nextHandler.processingInstruction(target, data); 372 } 373 374 public void startPrefixMapping (String prefix, String uri) throws SAXException { 375 nextHandler.startPrefixMapping(prefix, uri); 376 } 377 378 public void endElement (String namespaceURI, String localName, String qName) throws SAXException { 379 nextHandler.endElement(namespaceURI, localName, qName); 380 } 381 382 public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 383 nextHandler.startElement(namespaceURI, localName, qName, atts); 384 } 385 } 386 | Popular Tags |