1/* 2 * Copyright (c) 2005, 2006, 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 26package com.sun.org.apache.xalan.internal.xsltc.trax; 27 28import java.util.ArrayList; 29import java.util.Collection; 30import java.util.Collections; 31import java.util.HashMap; 32import java.util.Iterator; 33import java.util.List; 34import java.util.Map; 35 36import javax.xml.stream.XMLEventFactory; 37import javax.xml.stream.XMLStreamException; 38import javax.xml.stream.events.*; 39import javax.xml.stream.XMLEventWriter; 40 41import org.xml.sax.Attributes; 42import org.xml.sax.SAXException; 43import org.xml.sax.ext.Locator2; 44 45/** 46 * @author Sunitha Reddy 47 */ 48public class SAX2StAXEventWriter extends SAX2StAXBaseWriter { 49 50 51 private XMLEventWriter writer; 52 53 54 private XMLEventFactory eventFactory; 55 56 57 private List namespaceStack = new ArrayList(); 58 59 60 private boolean needToCallStartDocument = false; 61 62 63 public SAX2StAXEventWriter() { 64 65 eventFactory = XMLEventFactory.newInstance(); 66 67 } 68 69 70 public SAX2StAXEventWriter(XMLEventWriter writer) { 71 72 this.writer = writer; 73 eventFactory = XMLEventFactory.newInstance(); 74 75 } 76 77 public SAX2StAXEventWriter(XMLEventWriter writer, 78 XMLEventFactory factory) { 79 80 this.writer = writer; 81 if (factory != null) { 82 83 this.eventFactory = factory; 84 85 } else { 86 87 eventFactory = XMLEventFactory.newInstance(); 88 89 } 90 91 } 92 93 public XMLEventWriter getEventWriter() { 94 95 return writer; 96 97 } 98 99 100 public void setEventWriter(XMLEventWriter writer) { 101 102 this.writer = writer; 103 104 } 105 106 107 public XMLEventFactory getEventFactory() { 108 109 return eventFactory; 110 111 } 112 113 114 public void setEventFactory(XMLEventFactory factory) { 115 116 this.eventFactory = factory; 117 118 } 119 120 public void startDocument() throws SAXException { 121 122 super.startDocument(); 123 124 namespaceStack.clear(); 125 126 eventFactory.setLocation(getCurrentLocation()); 127 128 // Encoding and version info will be available only after startElement 129 // is called for first time. So, defer START_DOCUMENT event of StAX till 130 // that point of time. 131 needToCallStartDocument = true; 132 } 133 134 private void writeStartDocument() throws SAXException { 135 try { 136 if (docLocator == null) 137 writer.add(eventFactory.createStartDocument()); 138 else { 139 try{ 140 writer.add(eventFactory.createStartDocument(((Locator2)docLocator).getEncoding(),((Locator2)docLocator).getXMLVersion())); 141 } catch(ClassCastException e){ 142 writer.add(eventFactory.createStartDocument()); 143 } 144 } 145 } catch (XMLStreamException e) { 146 throw new SAXException(e); 147 } 148 needToCallStartDocument = false; 149 } 150 151 public void endDocument() throws SAXException { 152 153 eventFactory.setLocation(getCurrentLocation()); 154 155 try { 156 157 writer.add(eventFactory.createEndDocument()); 158 159 } catch (XMLStreamException e) { 160 161 throw new SAXException(e); 162 163 } 164 165 super.endDocument(); 166 167 // clear the namespaces 168 namespaceStack.clear(); 169 170 } 171 172 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 173 174 if (needToCallStartDocument) { 175 writeStartDocument(); 176 } 177 178 // set document location 179 eventFactory.setLocation(getCurrentLocation()); 180 181 // create attribute and namespace events 182 Collection[] events = {null, null}; 183 createStartEvents(attributes, events); 184 185 namespaceStack.add(events[0]); 186 187 try { 188 189 String[] qname = {null, null}; 190 parseQName(qName, qname); 191 192 writer.add(eventFactory.createStartElement(qname[0], uri, 193 qname[1], events[1].iterator(), events[0].iterator())); 194 195 } catch (XMLStreamException e) { 196 197 throw new SAXException(e); 198 199 } finally { 200 201 super.startElement(uri, localName, qName, attributes); 202 203 } 204 205 } 206 207 public void endElement(String uri, String localName, String qName) 208 throws SAXException { 209 210 super.endElement(uri, localName, qName); 211 212 eventFactory.setLocation(getCurrentLocation()); 213 214 // parse name 215 String[] qname = {null, null}; 216 parseQName(qName, qname); 217 218 // get namespaces 219 Collection nsList = (Collection) namespaceStack.remove(namespaceStack.size() - 1); 220 Iterator nsIter = nsList.iterator(); 221 222 try { 223 224 writer.add(eventFactory.createEndElement(qname[0], uri, qname[1], 225 nsIter)); 226 227 } catch (XMLStreamException e) { 228 229 throw new SAXException(e); 230 231 } 232 233 } 234 235 public void comment(char[] ch, int start, int length) throws SAXException { 236 if (needToCallStartDocument) { 237 // Drat. We were trying to postpone this until the first element so that we could get 238 // the locator, but we can't output a comment before the start document, so we're just 239 // going to have to do without the locator if it hasn't been set yet. 240 writeStartDocument(); 241 } 242 243 super.comment(ch, start, length); 244 245 eventFactory.setLocation(getCurrentLocation()); 246 try { 247 248 writer.add(eventFactory.createComment(new String(ch, start, 249 length))); 250 251 } catch (XMLStreamException e) { 252 253 throw new SAXException(e); 254 255 } 256 257 } 258 259 public void characters(char[] ch, int start, int length) 260 throws SAXException { 261 262 super.characters(ch, start, length); 263 264 try { 265 266 if (!isCDATA) { 267 268 eventFactory.setLocation(getCurrentLocation()); 269 writer.add(eventFactory.createCharacters(new String(ch, 270 start, length))); 271 272 } 273 274 } catch (XMLStreamException e) { 275 276 throw new SAXException(e); 277 278 } 279 280 } 281 282 public void ignorableWhitespace(char[] ch, int start, int length) 283 throws SAXException { 284 285 super.ignorableWhitespace(ch, start, length); 286 characters(ch, start, length); 287 288 } 289 290 public void processingInstruction(String target, String data) 291 throws SAXException { 292 293 if (needToCallStartDocument) { 294 // Drat. We were trying to postpone this until the first element so that we could get 295 // the locator, but we can't output a PI before the start document, so we're just 296 // going to have to do without the locator if it hasn't been set yet. 297 writeStartDocument(); 298 } 299 300 super.processingInstruction(target, data); 301 try { 302 303 writer.add(eventFactory.createProcessingInstruction(target, data)); 304 305 } catch (XMLStreamException e) { 306 307 throw new SAXException(e); 308 309 } 310 311 } 312 313 public void endCDATA() throws SAXException { 314 315 eventFactory.setLocation(getCurrentLocation()); 316 try { 317 318 writer.add(eventFactory.createCData(CDATABuffer.toString())); 319 320 } catch (XMLStreamException e) { 321 322 throw new SAXException(e); 323 324 } 325 326 super.endCDATA(); 327 328 } 329 330 331 protected void createStartEvents(Attributes attributes, Collection[] events) { 332 333 Map nsMap = null; 334 List attrs = null; 335 336 // create namespaces 337 if (namespaces != null) { 338 final int nDecls = namespaces.size(); 339 for (int i = 0; i < nDecls; i++) { 340 final String prefix = (String) namespaces.elementAt(i++); 341 String uri = (String) namespaces.elementAt(i); 342 Namespace ns = createNamespace(prefix, uri); 343 if (nsMap == null) { 344 nsMap = new HashMap(); 345 } 346 nsMap.put(prefix, ns); 347 } 348 } 349 350 // create attributes 351 String[] qname = {null, null}; 352 for (int i = 0, s = attributes.getLength(); i < s; i++) { 353 354 parseQName(attributes.getQName(i), qname); 355 356 String attrPrefix = qname[0]; 357 String attrLocal = qname[1]; 358 359 String attrQName = attributes.getQName(i); 360 String attrValue = attributes.getValue(i); 361 String attrURI = attributes.getURI(i); 362 363 if ("xmlns".equals(attrQName) || "xmlns".equals(attrPrefix)) { 364 // namespace declaration disguised as an attribute. If the 365 // namespace has already been declared, skip it, otherwise 366 // write it as an namespace 367 if (nsMap == null) { 368 nsMap = new HashMap(); 369 } 370 371 if (!nsMap.containsKey(attrLocal)) { 372 Namespace ns = createNamespace(attrLocal, attrValue); 373 nsMap.put(attrLocal, ns); 374 } 375 376 } else { 377 378 Attribute attribute; 379 if (attrPrefix.length() > 0) { 380 381 attribute = eventFactory.createAttribute(attrPrefix, 382 attrURI, attrLocal, attrValue); 383 384 } else { 385 386 attribute = eventFactory.createAttribute(attrLocal, 387 attrValue); 388 389 } 390 391 if (attrs == null) { 392 393 attrs = new ArrayList(); 394 395 } 396 attrs.add(attribute); 397 398 } 399 } 400 401 events[0] = (nsMap == null ? Collections.EMPTY_LIST : nsMap.values()); 402 events[1] = (attrs == null ? Collections.EMPTY_LIST : attrs); 403 404 } 405 406 protected Namespace createNamespace(String prefix, String uri) { 407 408 if (prefix == null || prefix.length() == 0) { 409 410 return eventFactory.createNamespace(uri); 411 412 } else { 413 414 return eventFactory.createNamespace(prefix, uri); 415 416 } 417 418 } 419 420} 421