001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the "License"). You may not use this file except
005: * in compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://jwsdp.dev.java.net/CDDLv1.0.html
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * HEADER in each file and include the License file at
014: * https://jwsdp.dev.java.net/CDDLv1.0.html If applicable,
015: * add the following below this CDDL HEADER, with the
016: * fields enclosed by brackets "[]" replaced with your
017: * own identifying information: Portions Copyright [yyyy]
018: * [name of copyright owner]
019: */
020:
021: package com.sun.xml.txw2.output;
022:
023: import com.sun.xml.txw2.TxwException;
024: import org.xml.sax.ContentHandler;
025: import org.xml.sax.SAXException;
026: import org.xml.sax.ext.LexicalHandler;
027: import org.xml.sax.helpers.AttributesImpl;
028:
029: import javax.xml.transform.sax.SAXResult;
030: import java.util.Stack;
031:
032: /**
033: * {@link XmlSerializer} for {@link SAXResult} and {@link ContentHandler}.
034: *
035: * @author Ryan.Shoemaker@Sun.COM
036: */
037: public class SaxSerializer implements XmlSerializer {
038:
039: private final ContentHandler writer;
040: private final LexicalHandler lexical;
041:
042: public SaxSerializer(ContentHandler handler) {
043: this (handler, null, true);
044: }
045:
046: /**
047: * Creates an {@link XmlSerializer} that writes SAX events.
048: *
049: * <p>
050: * Sepcifying a non-null {@link LexicalHandler} allows applications
051: * to write comments and CDATA sections.
052: */
053: public SaxSerializer(ContentHandler handler, LexicalHandler lex) {
054: this (handler, lex, true);
055: }
056:
057: public SaxSerializer(ContentHandler handler, LexicalHandler lex,
058: boolean indenting) {
059: if (!indenting) {
060: writer = handler;
061: lexical = lex;
062: } else {
063: IndentingXMLFilter indenter = new IndentingXMLFilter(
064: handler, lex);
065: writer = indenter;
066: lexical = indenter;
067: }
068: }
069:
070: public SaxSerializer(SAXResult result) {
071: this (result.getHandler(), result.getLexicalHandler());
072: }
073:
074: // XmlSerializer implementation
075:
076: public void startDocument() {
077: try {
078: writer.startDocument();
079: } catch (SAXException e) {
080: throw new TxwException(e);
081: }
082: }
083:
084: // namespace prefix bindings
085: // add in #writeXmlns and fired in #endStartTag
086: private final Stack<String> prefixBindings = new Stack<String>();
087:
088: public void writeXmlns(String prefix, String uri) {
089: // defend against parsers that pass null in for "xmlns" prefix
090: if (prefix == null) {
091: prefix = "";
092: }
093:
094: if (prefix.equals("xml")) {
095: return;
096: }
097:
098: prefixBindings.add(uri);
099: prefixBindings.add(prefix);
100: }
101:
102: // element stack
103: private final Stack<String> elementBindings = new Stack<String>();
104:
105: public void beginStartTag(String uri, String localName,
106: String prefix) {
107: // save element bindings for #endTag
108: elementBindings.add(getQName(prefix, localName));
109: elementBindings.add(localName);
110: elementBindings.add(uri);
111: }
112:
113: // attribute storage
114: // attrs are buffered in #writeAttribute and sent to the content
115: // handler in #endStartTag
116: private final AttributesImpl attrs = new AttributesImpl();
117:
118: public void writeAttribute(String uri, String localName,
119: String prefix, StringBuilder value) {
120: attrs.addAttribute(uri, localName, getQName(prefix, localName),
121: "CDATA", value.toString());
122: }
123:
124: public void endStartTag(String uri, String localName, String prefix) {
125: try {
126: while (prefixBindings.size() != 0) {
127: writer.startPrefixMapping(prefixBindings.pop(), // prefix
128: prefixBindings.pop() // uri
129: );
130: }
131:
132: writer.startElement(uri, localName, getQName(prefix,
133: localName), attrs);
134:
135: attrs.clear();
136: } catch (SAXException e) {
137: throw new TxwException(e);
138: }
139: }
140:
141: public void endTag() {
142: try {
143: writer.endElement(elementBindings.pop(), // uri
144: elementBindings.pop(), // localName
145: elementBindings.pop() // qname
146: );
147: } catch (SAXException e) {
148: throw new TxwException(e);
149: }
150: }
151:
152: public void text(StringBuilder text) {
153: try {
154: writer.characters(text.toString().toCharArray(), 0, text
155: .length());
156: } catch (SAXException e) {
157: throw new TxwException(e);
158: }
159: }
160:
161: public void cdata(StringBuilder text) {
162: if (lexical == null)
163: throw new UnsupportedOperationException(
164: "LexicalHandler is needed to write PCDATA");
165:
166: try {
167: lexical.startCDATA();
168: text(text);
169: lexical.endCDATA();
170: } catch (SAXException e) {
171: throw new TxwException(e);
172: }
173: }
174:
175: public void comment(StringBuilder comment) {
176: try {
177: if (lexical == null)
178: throw new UnsupportedOperationException(
179: "LexicalHandler is needed to write comments");
180: else
181: lexical.comment(comment.toString().toCharArray(), 0,
182: comment.length());
183: } catch (SAXException e) {
184: throw new TxwException(e);
185: }
186: }
187:
188: public void endDocument() {
189: try {
190: writer.endDocument();
191: } catch (SAXException e) {
192: throw new TxwException(e);
193: }
194: }
195:
196: public void flush() {
197: // noop
198: }
199:
200: // other methods
201: private static String getQName(String prefix, String localName) {
202: final String qName;
203: if (prefix == null || prefix.length() == 0)
204: qName = localName;
205: else
206: qName = prefix + ':' + localName;
207:
208: return qName;
209: }
210: }
|