1 /* 2 * Copyright (c) 1997, 2012, 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.xml.internal.bind.v2.runtime.output; 27 28 import java.io.IOException; 29 30 import javax.xml.stream.XMLStreamException; 31 32 import com.sun.xml.internal.bind.util.AttributesImpl; 33 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; 34 35 import org.xml.sax.ContentHandler; 36 import org.xml.sax.SAXException; 37 import org.xml.sax.helpers.LocatorImpl; 38 39 /** 40 * {@link XmlOutput} implementation that writes to SAX {@link ContentHandler}. 41 * 42 * @author Kohsuke Kawaguchi 43 */ 44 public class SAXOutput extends XmlOutputAbstractImpl { 45 protected final ContentHandler out; 46 47 public SAXOutput(ContentHandler out) { 48 this.out = out; 49 out.setDocumentLocator(new LocatorImpl()); 50 } 51 52 private String elementNsUri,elementLocalName,elementQName; 53 54 private char[] buf = new char[256]; 55 56 private final AttributesImpl atts = new AttributesImpl(); 57 58 59 // not called if we are generating fragments 60 @Override 61 public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws SAXException, IOException, XMLStreamException { 62 super.startDocument(serializer, fragment,nsUriIndex2prefixIndex,nsContext); 63 if(!fragment) 64 out.startDocument(); 65 } 66 67 public void endDocument(boolean fragment) throws SAXException, IOException, XMLStreamException { 68 if(!fragment) 69 out.endDocument(); 70 super.endDocument(fragment); 71 } 72 73 public void beginStartTag(int prefix, String localName) { 74 elementNsUri = nsContext.getNamespaceURI(prefix); 75 elementLocalName = localName; 76 elementQName = getQName(prefix,localName); 77 atts.clear(); 78 } 79 80 public void attribute(int prefix, String localName, String value) { 81 String qname; 82 String nsUri; 83 if(prefix==-1) { 84 nsUri = ""; 85 qname = localName; 86 } else { 87 nsUri = nsContext.getNamespaceURI(prefix); 88 String p = nsContext.getPrefix(prefix); 89 if(p.length()==0) 90 // this is more likely a bug in the application code (NamespacePrefixMapper implementation) 91 // this only happens when it tries to assign "" prefix to a non-"" URI, 92 // which is by itself violation of namespace rec. But let's just be safe. 93 // See http://forums.java.net/jive/thread.jspa?messageID=212598#212598 94 qname = localName; 95 else 96 qname = p +':'+localName; 97 } 98 atts.addAttribute( nsUri, localName, qname, "CDATA", value ); 99 } 100 101 public void endStartTag() throws SAXException { 102 NamespaceContextImpl.Element ns = nsContext.getCurrent(); 103 if(ns!=null) { 104 int sz = ns.count(); 105 for( int i=0; i<sz; i++ ) { 106 String p = ns.getPrefix(i); 107 String uri = ns.getNsUri(i); 108 if(uri.length()==0 && ns.getBase()==1) 109 continue; // no point in defining xmlns='' on the root 110 out.startPrefixMapping(p,uri); 111 } 112 } 113 out.startElement(elementNsUri,elementLocalName,elementQName,atts); 114 } 115 116 public void endTag(int prefix, String localName) throws SAXException { 117 out.endElement( 118 nsContext.getNamespaceURI(prefix), 119 localName, 120 getQName(prefix, localName) 121 ); 122 123 NamespaceContextImpl.Element ns = nsContext.getCurrent(); 124 if(ns!=null) { 125 int sz = ns.count(); 126 for( int i=sz-1; i>=0; i-- ) { 127 String p = ns.getPrefix(i); 128 String uri = ns.getNsUri(i); 129 if(uri.length()==0 && ns.getBase()==1) 130 continue; // no point in definint xmlns='' on the root 131 out.endPrefixMapping(p); 132 } 133 } 134 } 135 136 private String getQName(int prefix, String localName) { 137 String qname; 138 String p = nsContext.getPrefix(prefix); 139 if(p.length()==0) 140 qname = localName; 141 else 142 qname = p+':'+localName; 143 return qname; 144 } 145 146 public void text(String value, boolean needsSP) throws IOException, SAXException, XMLStreamException { 147 int vlen = value.length(); 148 if(buf.length<=vlen) { 149 buf = new char[Math.max(buf.length*2,vlen+1)]; 150 } 151 if(needsSP) { 152 value.getChars(0,vlen,buf,1); 153 buf[0] = ' '; 154 } else { 155 value.getChars(0,vlen,buf,0); 156 } 157 out.characters(buf,0,vlen+(needsSP?1:0)); 158 } 159 160 public void text(Pcdata value, boolean needsSP) throws IOException, SAXException, XMLStreamException { 161 int vlen = value.length(); 162 if(buf.length<=vlen) { 163 buf = new char[Math.max(buf.length*2,vlen+1)]; 164 } 165 if(needsSP) { 166 value.writeTo(buf,1); 167 buf[0] = ' '; 168 } else { 169 value.writeTo(buf,0); 170 } 171 out.characters(buf,0,vlen+(needsSP?1:0)); 172 } 173 }