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