001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.xml;
018:
019: import javax.xml.transform.Transformer;
020: import javax.xml.transform.TransformerFactory;
021: import javax.xml.transform.TransformerException;
022: import javax.xml.transform.TransformerConfigurationException;
023: import javax.xml.transform.dom.DOMSource;
024: import javax.xml.transform.sax.SAXResult;
025: import org.xml.sax.Attributes;
026: import org.xml.sax.ContentHandler;
027: import org.xml.sax.Locator;
028: import org.xml.sax.SAXException;
029: import org.xml.sax.ext.LexicalHandler;
030: import org.w3c.dom.Node;
031:
032: /**
033: * A special purpose <code>XMLConsumer</code> which can:
034: * <ul>
035: * <li>Trim empty characters if
036: * {@link #setIgnoreEmptyCharacters(boolean) ignoreEmptyCharacters} is set.
037: * <li>Ignore root element if
038: * {@link #setIgnoreRootElement(boolean) ignoreRootElement} is set.
039: * <li>Ignore startDocument, endDocument events.
040: * <li>Ignore startDTD, endDTD, and all comments within DTD.
041: * </ul>
042: *
043: * <p>It is more complicated version of {@link EmbeddedXMLPipe} which, except
044: * being used to include other files into the SAX events stream, can perform
045: * optional operations described above.</p>
046: *
047: * @see EmbeddedXMLPipe
048: * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
049: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
050: * @version CVS $Id: IncludeXMLConsumer.java 433543 2006-08-22 06:22:54Z crossley $
051: */
052: public class IncludeXMLConsumer implements XMLConsumer {
053:
054: /** The TrAX factory for serializing xml */
055: private static final TransformerFactory FACTORY = TransformerFactory
056: .newInstance();
057:
058: private final ContentHandler contentHandler;
059: private final LexicalHandler lexicalHandler;
060:
061: private boolean ignoreEmptyCharacters;
062: private boolean ignoreRootElement;
063: private int ignoreRootElementCount;
064: private boolean inDTD;
065:
066: /**
067: * Constructor
068: */
069: public IncludeXMLConsumer(XMLConsumer consumer) {
070: this .contentHandler = consumer;
071: this .lexicalHandler = consumer;
072: }
073:
074: /**
075: * Constructor
076: */
077: public IncludeXMLConsumer(ContentHandler contentHandler,
078: LexicalHandler lexicalHandler) {
079: this .contentHandler = contentHandler;
080: this .lexicalHandler = lexicalHandler;
081: }
082:
083: /**
084: * Constructor
085: */
086: public IncludeXMLConsumer(ContentHandler contentHandler) {
087: this .contentHandler = contentHandler;
088: this .lexicalHandler = contentHandler instanceof LexicalHandler ? (LexicalHandler) contentHandler
089: : null;
090: }
091:
092: /**
093: * Utility method to stream a DOM node into the provided content handler,
094: * lexical handler.
095: *
096: * @param node The DOM Node to be included
097: * @param contentHandler The SAX ContentHandler receiving the information
098: * @param lexicalHandler The SAX LexicalHandler receiving the information (optional)
099: */
100: public static void includeNode(Node node,
101: ContentHandler contentHandler, LexicalHandler lexicalHandler)
102: throws SAXException {
103: if (node != null) {
104: if (node.getNodeType() == Node.TEXT_NODE) {
105: String value = node.getNodeValue();
106: contentHandler.characters(value.toCharArray(), 0, value
107: .length());
108: } else {
109: try {
110: IncludeXMLConsumer filter = new IncludeXMLConsumer(
111: contentHandler, lexicalHandler);
112: Transformer transformer = FACTORY.newTransformer();
113: DOMSource source = new DOMSource(node);
114: SAXResult result = new SAXResult(filter);
115: result.setLexicalHandler(filter);
116: transformer.transform(source, result);
117: } catch (TransformerConfigurationException e) {
118: throw new SAXException(
119: "TransformerConfigurationException", e);
120: } catch (TransformerException e) {
121: throw new SAXException("TransformerException", e);
122: }
123: }
124: }
125: }
126:
127: /**
128: * Control SAX event handling.
129: * If set to <code>true</code> all empty characters events are ignored.
130: * The default is <code>false</code>.
131: */
132: public void setIgnoreEmptyCharacters(boolean value) {
133: this .ignoreEmptyCharacters = value;
134: }
135:
136: /**
137: * Control SAX event handling.
138: * If set to <code>true</code> the root element is ignored.
139: * The default is <code>false</code>.
140: */
141: public void setIgnoreRootElement(boolean value) {
142: this .ignoreRootElement = value;
143: this .ignoreRootElementCount = 0;
144: }
145:
146: //
147: // ContentHandler interface
148: //
149:
150: public void setDocumentLocator(Locator loc) {
151: this .contentHandler.setDocumentLocator(loc);
152: }
153:
154: public void startDocument() throws SAXException {
155: // Ignored
156: }
157:
158: public void endDocument() throws SAXException {
159: // Ignored
160: }
161:
162: public void startPrefixMapping(String prefix, String uri)
163: throws SAXException {
164: this .contentHandler.startPrefixMapping(prefix, uri);
165: }
166:
167: public void endPrefixMapping(String prefix) throws SAXException {
168: this .contentHandler.endPrefixMapping(prefix);
169: }
170:
171: public void startElement(String uri, String local, String qName,
172: Attributes attr) throws SAXException {
173: if (this .ignoreRootElement == false
174: || this .ignoreRootElementCount > 0) {
175: this .contentHandler.startElement(uri, local, qName, attr);
176: }
177: this .ignoreRootElementCount++;
178: }
179:
180: public void endElement(String uri, String local, String qName)
181: throws SAXException {
182: this .ignoreRootElementCount--;
183: if (!this .ignoreRootElement || this .ignoreRootElementCount > 0) {
184: this .contentHandler.endElement(uri, local, qName);
185: }
186: }
187:
188: public void characters(char[] ch, int start, int end)
189: throws SAXException {
190: if (this .ignoreEmptyCharacters) {
191: String text = new String(ch, start, end).trim();
192: if (text.length() > 0) {
193: this .contentHandler.characters(text.toCharArray(), 0,
194: text.length());
195: }
196: } else {
197: this .contentHandler.characters(ch, start, end);
198: }
199: }
200:
201: public void ignorableWhitespace(char[] ch, int start, int end)
202: throws SAXException {
203: if (!this .ignoreEmptyCharacters) {
204: this .contentHandler.ignorableWhitespace(ch, start, end);
205: }
206: }
207:
208: public void processingInstruction(String name, String value)
209: throws SAXException {
210: this .contentHandler.processingInstruction(name, value);
211: }
212:
213: public void skippedEntity(String ent) throws SAXException {
214: this .contentHandler.skippedEntity(ent);
215: }
216:
217: //
218: // LexicalHandler interface
219: //
220:
221: public void startDTD(String name, String public_id, String system_id)
222: throws SAXException {
223: // Ignored
224: this .inDTD = true;
225: }
226:
227: public void endDTD() throws SAXException {
228: // Ignored
229: this .inDTD = false;
230: }
231:
232: public void startEntity(String name) throws SAXException {
233: if (lexicalHandler != null) {
234: lexicalHandler.startEntity(name);
235: }
236: }
237:
238: public void endEntity(String name) throws SAXException {
239: if (lexicalHandler != null) {
240: lexicalHandler.endEntity(name);
241: }
242: }
243:
244: public void startCDATA() throws SAXException {
245: if (lexicalHandler != null) {
246: lexicalHandler.startCDATA();
247: }
248: }
249:
250: public void endCDATA() throws SAXException {
251: if (lexicalHandler != null) {
252: lexicalHandler.endCDATA();
253: }
254: }
255:
256: public void comment(char ary[], int start, int length)
257: throws SAXException {
258: if (!inDTD && lexicalHandler != null) {
259: lexicalHandler.comment(ary, start, length);
260: }
261: }
262: }
|