1/* 2 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 * 25 * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC. 26 */ 27 28package com.sun.xml.internal.fastinfoset.tools; 29 30import java.io.IOException; 31import java.io.OutputStream; 32import java.io.OutputStreamWriter; 33import java.io.Writer; 34import java.util.ArrayList; 35import java.util.List; 36import java.util.Stack; 37 38import org.xml.sax.Attributes; 39import org.xml.sax.SAXException; 40import org.xml.sax.ext.LexicalHandler; 41import org.xml.sax.helpers.DefaultHandler; 42import com.sun.xml.internal.fastinfoset.CommonResourceBundle; 43 44public class SAXEventSerializer extends DefaultHandler 45 implements LexicalHandler { 46 47 private Writer _writer; 48 private boolean _charactersAreCDATA; 49 private StringBuffer _characters; 50 51 private Stack _namespaceStack = new Stack(); 52 protected List _namespaceAttributes; 53 54 public SAXEventSerializer(OutputStream s) throws IOException { 55 _writer = new OutputStreamWriter(s); 56 _charactersAreCDATA = false; 57 } 58 59 // -- ContentHandler interface --------------------------------------- 60 61 public void startDocument() throws SAXException { 62 try { 63 _writer.write("<sax xmlns=\"http://www.sun.com/xml/sax-events\">\n"); 64 _writer.write("<startDocument/>\n"); 65 _writer.flush(); 66 } 67 catch (IOException e) { 68 throw new SAXException(e); 69 } 70 } 71 72 public void endDocument() throws SAXException { 73 try { 74 _writer.write("<endDocument/>\n"); 75 _writer.write("</sax>"); 76 _writer.flush(); 77 _writer.close(); 78 } 79 catch (IOException e) { 80 throw new SAXException(e); 81 } 82 } 83 84 85 public void startPrefixMapping(String prefix, String uri) 86 throws SAXException 87 { 88 if (_namespaceAttributes == null) { 89 _namespaceAttributes = new ArrayList(); 90 } 91 92 String qName = (prefix.length() == 0) ? "xmlns" : "xmlns" + prefix; 93 AttributeValueHolder attribute = new AttributeValueHolder( 94 qName, 95 prefix, 96 uri, 97 null, 98 null); 99 _namespaceAttributes.add(attribute); 100 } 101 102 public void endPrefixMapping(String prefix) 103 throws SAXException 104 { 105 /* 106 try { 107 outputCharacters(); 108 109 _writer.write("<endPrefixMapping prefix=\"" + 110 prefix + "\"/>\n"); 111 _writer.flush(); 112 } 113 catch (IOException e) { 114 throw new SAXException(e); 115 } 116 */ 117 } 118 119 public void startElement(String uri, String localName, 120 String qName, Attributes attributes) 121 throws SAXException 122 { 123 try { 124 outputCharacters(); 125 126 if (_namespaceAttributes != null) { 127 128 AttributeValueHolder[] attrsHolder = new AttributeValueHolder[0]; 129 attrsHolder = (AttributeValueHolder[])_namespaceAttributes.toArray(attrsHolder); 130 131 // Sort attributes 132 quicksort(attrsHolder, 0, attrsHolder.length - 1); 133 134 for (int i = 0; i < attrsHolder.length; i++) { 135 _writer.write("<startPrefixMapping prefix=\"" + 136 attrsHolder[i].localName + "\" uri=\"" + attrsHolder[i].uri + "\"/>\n"); 137 _writer.flush(); 138 } 139 140 _namespaceStack.push(attrsHolder); 141 _namespaceAttributes = null; 142 } else { 143 _namespaceStack.push(null); 144 } 145 146 AttributeValueHolder[] attrsHolder = 147 new AttributeValueHolder[attributes.getLength()]; 148 for (int i = 0; i < attributes.getLength(); i++) { 149 attrsHolder[i] = new AttributeValueHolder( 150 attributes.getQName(i), 151 attributes.getLocalName(i), 152 attributes.getURI(i), 153 attributes.getType(i), 154 attributes.getValue(i)); 155 } 156 157 // Sort attributes 158 quicksort(attrsHolder, 0, attrsHolder.length - 1); 159 160 int attributeCount = 0; 161 for (int i = 0; i < attrsHolder.length; i++) { 162 if (attrsHolder[i].uri.equals("http://www.w3.org/2000/xmlns/")) { 163 // Ignore XMLNS attributes 164 continue; 165 } 166 attributeCount++; 167 } 168 169 if (attributeCount == 0) { 170 _writer.write("<startElement uri=\"" + uri 171 + "\" localName=\"" + localName + "\" qName=\"" 172 + qName + "\"/>\n"); 173 return; 174 } 175 176 _writer.write("<startElement uri=\"" + uri 177 + "\" localName=\"" + localName + "\" qName=\"" 178 + qName + "\">\n"); 179 180 // Serialize attributes as children 181 for (int i = 0; i < attrsHolder.length; i++) { 182 if (attrsHolder[i].uri.equals("http://www.w3.org/2000/xmlns/")) { 183 // Ignore XMLNS attributes 184 continue; 185 } 186 _writer.write( 187 " <attribute qName=\"" + attrsHolder[i].qName + 188 "\" localName=\"" + attrsHolder[i].localName + 189 "\" uri=\"" + attrsHolder[i].uri + 190 // "\" type=\"" + attrsHolder[i].type + 191 "\" value=\"" + attrsHolder[i].value + 192 "\"/>\n"); 193 } 194 195 _writer.write("</startElement>\n"); 196 _writer.flush(); 197 } 198 catch (IOException e) { 199 throw new SAXException(e); 200 } 201 } 202 203 public void endElement(String uri, String localName, String qName) 204 throws SAXException 205 { 206 try { 207 outputCharacters(); 208 209 _writer.write("<endElement uri=\"" + uri 210 + "\" localName=\"" + localName + "\" qName=\"" 211 + qName + "\"/>\n"); 212 _writer.flush(); 213 214 // Write out the end prefix here rather than waiting 215 // for the explicit events 216 AttributeValueHolder[] attrsHolder = (AttributeValueHolder[])_namespaceStack.pop(); 217 if (attrsHolder != null) { 218 for (int i = 0; i < attrsHolder.length; i++) { 219 _writer.write("<endPrefixMapping prefix=\"" + 220 attrsHolder[i].localName + "\"/>\n"); 221 _writer.flush(); 222 } 223 } 224 225 } 226 catch (IOException e) { 227 throw new SAXException(e); 228 } 229 } 230 231 public void characters(char[] ch, int start, int length) 232 throws SAXException 233 { 234 if (length == 0) { 235 return; 236 } 237 238 if (_characters == null) { 239 _characters = new StringBuffer(); 240 } 241 242 // Coalesce multiple character events 243 _characters.append(ch, start, length); 244 245 /* 246 try { 247 _writer.write("<characters>" + 248 (_charactersAreCDATA ? "<![CDATA[" : "") + 249 new String(ch, start, length) + 250 (_charactersAreCDATA ? "]]>" : "") + 251 "</characters>\n"); 252 _writer.flush(); 253 } 254 catch (IOException e) { 255 throw new SAXException(e); 256 } 257 */ 258 } 259 260 private void outputCharacters() throws SAXException { 261 if (_characters == null) { 262 return; 263 } 264 265 try { 266 _writer.write("<characters>" + 267 (_charactersAreCDATA ? "<![CDATA[" : "") + 268 _characters + 269 (_charactersAreCDATA ? "]]>" : "") + 270 "</characters>\n"); 271 _writer.flush(); 272 273 _characters = null; 274 } catch (IOException e) { 275 throw new SAXException(e); 276 } 277 } 278 279 public void ignorableWhitespace(char[] ch, int start, int length) 280 throws SAXException 281 { 282 // Report ignorable ws as characters (assumes validation off) 283 characters(ch, start, length); 284 } 285 286 public void processingInstruction(String target, String data) 287 throws SAXException 288 { 289 try { 290 outputCharacters(); 291 292 _writer.write("<processingInstruction target=\"" + target 293 + "\" data=\"" + data + "\"/>\n"); 294 _writer.flush(); 295 } 296 catch (IOException e) { 297 throw new SAXException(e); 298 } 299 } 300 301 // -- LexicalHandler interface --------------------------------------- 302 303 public void startDTD(String name, String publicId, String systemId) 304 throws SAXException { 305 // Not implemented 306 } 307 308 public void endDTD() 309 throws SAXException { 310 // Not implemented 311 } 312 313 public void startEntity(String name) 314 throws SAXException { 315 // Not implemented 316 } 317 318 public void endEntity(String name) 319 throws SAXException { 320 // Not implemented 321 } 322 323 public void startCDATA() 324 throws SAXException { 325 _charactersAreCDATA = true; 326 } 327 328 public void endCDATA() 329 throws SAXException { 330 _charactersAreCDATA = false; 331 } 332 333 public void comment(char[] ch, int start, int length) 334 throws SAXException 335 { 336 try { 337 outputCharacters(); 338 339 _writer.write("<comment>" + 340 new String(ch, start, length) + 341 "</comment>\n"); 342 _writer.flush(); 343 } 344 catch (IOException e) { 345 throw new SAXException(e); 346 } 347 } 348 349 // -- Utility methods ------------------------------------------------ 350 351 private void quicksort(AttributeValueHolder[] attrs, int p, int r) { 352 while (p < r) { 353 final int q = partition(attrs, p, r); 354 quicksort(attrs, p, q); 355 p = q + 1; 356 } 357 } 358 359 private int partition(AttributeValueHolder[] attrs, int p, int r) { 360 AttributeValueHolder x = attrs[(p + r) >>> 1]; 361 int i = p - 1; 362 int j = r + 1; 363 while (true) { 364 while (x.compareTo(attrs[--j]) < 0); 365 while (x.compareTo(attrs[++i]) > 0); 366 if (i < j) { 367 final AttributeValueHolder t = attrs[i]; 368 attrs[i] = attrs[j]; 369 attrs[j] = t; 370 } 371 else { 372 return j; 373 } 374 } 375 } 376 377 public static class AttributeValueHolder implements Comparable { 378 public final String qName; 379 public final String localName; 380 public final String uri; 381 public final String type; 382 public final String value; 383 384 public AttributeValueHolder(String qName, 385 String localName, 386 String uri, 387 String type, 388 String value) 389 { 390 this.qName = qName; 391 this.localName = localName; 392 this.uri = uri; 393 this.type = type; 394 this.value = value; 395 } 396 397 public int compareTo(Object o) { 398 try { 399 return qName.compareTo(((AttributeValueHolder) o).qName); 400 } catch (Exception e) { 401 throw new RuntimeException(CommonResourceBundle.getInstance().getString("message.AttributeValueHolderExpected")); 402 } 403 } 404 405 @Override 406 public boolean equals(Object o) { 407 try { 408 return (o instanceof AttributeValueHolder) && 409 qName.equals(((AttributeValueHolder) o).qName); 410 } catch (Exception e) { 411 throw new RuntimeException(CommonResourceBundle.getInstance().getString("message.AttributeValueHolderExpected")); 412 } 413 } 414 415 @Override 416 public int hashCode() { 417 int hash = 7; 418 hash = 97 * hash + (this.qName != null ? this.qName.hashCode() : 0); 419 return hash; 420 } 421 } 422 423} 424