001: /*--
002:
003: $Id: JDOMSource.java,v 1.1 2005/04/27 09:32:43 wittek Exp $
004:
005: Copyright (C) 2001-2004 Jason Hunter & Brett McLaughlin.
006: All rights reserved.
007:
008: Redistribution and use in source and binary forms, with or without
009: modification, are permitted provided that the following conditions
010: are met:
011:
012: 1. Redistributions of source code must retain the above copyright
013: notice, this list of conditions, and the following disclaimer.
014:
015: 2. Redistributions in binary form must reproduce the above copyright
016: notice, this list of conditions, and the disclaimer that follows
017: these conditions in the documentation and/or other materials
018: provided with the distribution.
019:
020: 3. The name "JDOM" must not be used to endorse or promote products
021: derived from this software without prior written permission. For
022: written permission, please contact <request_AT_jdom_DOT_org>.
023:
024: 4. Products derived from this software may not be called "JDOM", nor
025: may "JDOM" appear in their name, without prior written permission
026: from the JDOM Project Management <request_AT_jdom_DOT_org>.
027:
028: In addition, we request (but do not require) that you include in the
029: end-user documentation provided with the redistribution and/or in the
030: software itself an acknowledgement equivalent to the following:
031: "This product includes software developed by the
032: JDOM Project (http://www.jdom.org/)."
033: Alternatively, the acknowledgment may be graphical using the logos
034: available at http://www.jdom.org/images/logos.
035:
036: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
040: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: SUCH DAMAGE.
048:
049: This software consists of voluntary contributions made by many
050: individuals on behalf of the JDOM Project and was originally
051: created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
052: Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
053: on the JDOM Project, please see <http://www.jdom.org/>.
054:
055: */
056:
057: package org.jdom.transform;
058:
059: import java.io.*;
060: import java.util.*;
061:
062: import javax.xml.transform.sax.*;
063:
064: import org.jdom.*;
065: import org.jdom.output.*;
066: import org.xml.sax.*;
067:
068: /**
069: * A holder for an XML Transformation source: a Document, Element, or list of
070: * nodes.
071: * <p>
072: * The is provides input to a
073: * {@link javax.xml.transform.Transformer JAXP TrAX Transformer}.
074: * <p>
075: * The following example shows how to apply an XSL Transformation
076: * to a JDOM document and get the transformation result in the form
077: * of a list of JDOM nodes:
078: * <pre><code>
079: * public static List transform(Document doc, String stylesheet)
080: * throws JDOMException {
081: * try {
082: * Transformer transformer = TransformerFactory.newInstance()
083: * .newTransformer(new StreamSource(stylesheet));
084: * JDOMSource in = new JDOMSource(doc);
085: * JDOMResult out = new JDOMResult();
086: * transformer.transform(in, out);
087: * return out.getResult();
088: * }
089: * catch (TransformerException e) {
090: * throw new JDOMException("XSLT Transformation failed", e);
091: * }
092: * }
093: * </code></pre>
094: *
095: * @see org.jdom.transform.JDOMResult
096: *
097: * @version $Revision: 1.1 $, $Date: 2005/04/27 09:32:43 $
098: * @author Laurent Bihanic
099: * @author Jason Hunter
100: */
101: public class JDOMSource extends SAXSource {
102:
103: private static final String CVS_ID = "@(#) $RCSfile: JDOMSource.java,v $ $Revision: 1.1 $ $Date: 2005/04/27 09:32:43 $ $Name: $";
104:
105: /**
106: * If {@link javax.xml.transform.TransformerFactory#getFeature}
107: * returns <code>true</code> when passed this value as an
108: * argument, the Transformer natively supports JDOM.
109: * <p>
110: * <strong>Note</strong>: This implementation does not override
111: * the {@link SAXSource#FEATURE} value defined by its superclass
112: * to be considered as a SAXSource by Transformer implementations
113: * not natively supporting JDOM.
114: * </p>
115: */
116: public final static String JDOM_FEATURE = "http://org.jdom.transform.JDOMSource/feature";
117:
118: /**
119: * The XMLReader object associated to this source or
120: * <code>null</code> if no XMLReader has yet been requested.
121: *
122: * @see #getXMLReader
123: */
124: private XMLReader xmlReader = null;
125:
126: /**
127: * Creates a JDOM TrAX source wrapping a JDOM document.
128: *
129: * @param source the JDOM document to use as source for the
130: * transformations
131: *
132: * @throws IllegalArgumentException if <code>source</code> is
133: * <code>null</code>.
134: */
135: public JDOMSource(Document source) {
136: setDocument(source);
137: }
138:
139: /**
140: * Creates a JDOM TrAX source wrapping a list of JDOM nodes.
141: *
142: * @param source the JDOM nodes to use as source for the
143: * transformations
144: *
145: * @throws IllegalArgumentException if <code>source</code> is
146: * <code>null</code>.
147: */
148: public JDOMSource(List source) {
149: setNodes(source);
150: }
151:
152: /**
153: * Creates a JDOM TrAX source wrapping a JDOM element.
154: *
155: * @param source the JDOM element to use as source for the
156: * transformations
157: *
158: * @throws IllegalArgumentException if <code>source</code> is
159: * <code>null</code>.
160: */
161: public JDOMSource(Element source) {
162: List nodes = new ArrayList();
163: nodes.add(source);
164:
165: setNodes(nodes);
166: }
167:
168: /**
169: * Sets the source document used by this TrAX source.
170: *
171: * @param source the JDOM document to use as source for the
172: * transformations
173: *
174: * @throws IllegalArgumentException if <code>source</code> is
175: * <code>null</code>.
176: *
177: * @see #getDocument
178: */
179: public void setDocument(Document source) {
180: super .setInputSource(new JDOMInputSource(source));
181: }
182:
183: /**
184: * Returns the source document used by this TrAX source.
185: *
186: * @return the source document used by this TrAX source or
187: * <code>null</code> if the source is a node list.
188: *
189: * @see #setDocument
190: */
191: public Document getDocument() {
192: Object src = ((JDOMInputSource) getInputSource()).getSource();
193: Document doc = null;
194:
195: if (src instanceof Document) {
196: doc = (Document) src;
197: }
198: return doc;
199: }
200:
201: /**
202: * Sets the source node list used by this TrAX source.
203: *
204: * @param source the JDOM nodes to use as source for the
205: * transformations
206: *
207: * @throws IllegalArgumentException if <code>source</code> is
208: * <code>null</code>.
209: *
210: * @see #getNodes
211: */
212: public void setNodes(List source) {
213: super .setInputSource(new JDOMInputSource(source));
214: }
215:
216: /**
217: * Returns the source node list used by this TrAX source.
218: *
219: * @return the source node list used by this TrAX source or
220: * <code>null</code> if the source is a JDOM document.
221: *
222: * @see #setDocument
223: */
224: public List getNodes() {
225: Object src = ((JDOMInputSource) getInputSource()).getSource();
226: List nodes = null;
227:
228: if (src instanceof List) {
229: nodes = (List) src;
230: }
231: return nodes;
232: }
233:
234: //-------------------------------------------------------------------------
235: // SAXSource overwritten methods
236: //-------------------------------------------------------------------------
237:
238: /**
239: * Sets the SAX InputSource to be used for the Source.
240: * <p>
241: * As this implementation only supports JDOM document as data
242: * source, this method always throws an
243: * {@link UnsupportedOperationException}.
244: * </p>
245: *
246: * @param inputSource a valid InputSource reference.
247: *
248: * @throws UnsupportedOperationException always!
249: */
250: public void setInputSource(InputSource inputSource)
251: throws UnsupportedOperationException {
252: throw new UnsupportedOperationException();
253: }
254:
255: /**
256: * Set the XMLReader to be used for the Source.
257: * <p>
258: * As this implementation only supports JDOM document as data
259: * source, this method throws an
260: * {@link UnsupportedOperationException} if the provided reader
261: * object does not implement the SAX {@link XMLFilter}
262: * interface. Otherwise, the JDOM document reader will be
263: * attached as parent of the filter chain.</p>
264: *
265: * @param reader a valid XMLReader or XMLFilter reference.
266: *
267: * @throws UnsupportedOperationException if <code>reader</code>
268: * is not a SAX
269: * {@link XMLFilter}.
270: * @see #getXMLReader
271: */
272: public void setXMLReader(XMLReader reader)
273: throws UnsupportedOperationException {
274: if (reader instanceof XMLFilter) {
275: // Connect the filter chain to a document reader.
276: XMLFilter filter = (XMLFilter) reader;
277: while (filter.getParent() instanceof XMLFilter) {
278: filter = (XMLFilter) (filter.getParent());
279: }
280: filter.setParent(new DocumentReader());
281:
282: // Read XML data from filter chain.
283: this .xmlReader = reader;
284: } else {
285: throw new UnsupportedOperationException();
286: }
287: }
288:
289: /**
290: * Returns the XMLReader to be used for the Source.
291: * <p>
292: * This implementation returns a specific XMLReader reading
293: * the XML data from the source JDOM document.
294: * </p>
295: *
296: * @return an XMLReader reading the XML data from the source
297: * JDOM document.
298: */
299: public XMLReader getXMLReader() {
300: if (this .xmlReader == null) {
301: this .xmlReader = new DocumentReader();
302: }
303: return this .xmlReader;
304: }
305:
306: //=========================================================================
307: // JDOMInputSource nested class
308: //=========================================================================
309:
310: /**
311: * A subclass of the SAX InputSource interface that wraps a JDOM
312: * Document.
313: * <p>
314: * This class is nested in JDOMSource as it is not intented to
315: * be used independently of its friend: DocumentReader.
316: * </p>
317: *
318: * @see org.jdom.Document
319: */
320: private static class JDOMInputSource extends InputSource {
321: /**
322: * The source as a JDOM document or a list of JDOM nodes.
323: */
324: private Object source = null;
325:
326: /**
327: * Builds a InputSource wrapping the specified JDOM Document.
328: *
329: * @param document the source document.
330: */
331: public JDOMInputSource(Document document) {
332: this .source = document;
333: }
334:
335: /**
336: * Builds a InputSource wrapping a list of JDOM nodes.
337: *
338: * @param nodes the source JDOM nodes.
339: */
340: public JDOMInputSource(List nodes) {
341: this .source = nodes;
342: }
343:
344: /**
345: * Returns the source.
346: *
347: * @return the source as a JDOM document or a list of JDOM nodes.
348: */
349: public Object getSource() {
350: return source;
351: }
352:
353: //-------------------------------------------------------------------------
354: // InputSource overwritten methods
355: //-------------------------------------------------------------------------
356:
357: /**
358: * Sets the character stream for this input source.
359: * <p>
360: * This implementation always throws an
361: * {@link UnsupportedOperationException} as the only source
362: * stream supported is the source JDOM document.
363: * </p>
364: *
365: * @param characterStream a character stream containing
366: * an XML document.
367: *
368: * @throws UnsupportedOperationException always!
369: */
370: public void setCharacterStream(Reader characterStream)
371: throws UnsupportedOperationException {
372: throw new UnsupportedOperationException();
373: }
374:
375: /**
376: * Gets the character stream for this input source.
377: * <p>
378: * Note that this method is only provided to make this
379: * InputSource implementation acceptable by any XML
380: * parser. As it generates an in-memory string representation
381: * of the JDOM document, it is quite inefficient from both
382: * speed and memory consumption points of view.
383: * </p>
384: *
385: * @return a Reader to a string representation of the
386: * source JDOM document.
387: */
388: public Reader getCharacterStream() {
389: Object src = this .getSource();
390: Reader reader = null;
391:
392: if (src instanceof Document) {
393: // Get an in-memory string representation of the document
394: // and return a reader on it.
395: reader = new StringReader(new XMLOutputter()
396: .outputString((Document) src));
397: } else {
398: if (src instanceof List) {
399: reader = new StringReader(new XMLOutputter()
400: .outputString((List) src));
401: }
402: // Else: No source, no reader!
403: }
404: return reader;
405: }
406: }
407:
408: //=========================================================================
409: // DocumentReader nested class
410: //=========================================================================
411:
412: /**
413: * An implementation of the SAX2 XMLReader interface that presents
414: * a SAX view of a JDOM Document. The actual generation of the
415: * SAX events is delegated to JDOM's SAXOutputter.
416: *
417: * @see org.jdom.Document
418: * @see org.jdom.output.SAXOutputter
419: */
420: private static class DocumentReader extends SAXOutputter implements
421: XMLReader {
422: /**
423: * Public default constructor.
424: */
425: public DocumentReader() {
426: super ();
427: }
428:
429: //----------------------------------------------------------------------
430: // SAX XMLReader interface support
431: //----------------------------------------------------------------------
432:
433: /**
434: * Parses an XML document from a system identifier (URI).
435: * <p>
436: * This implementation does not support reading XML data from
437: * system identifiers, only from JDOM documents. Hence,
438: * this method always throws a {@link SAXNotSupportedException}.
439: * </p>
440: *
441: * @param systemId the system identifier (URI).
442: *
443: * @throws SAXNotSupportedException always!
444: */
445: public void parse(String systemId)
446: throws SAXNotSupportedException {
447: throw new SAXNotSupportedException(
448: "Only JDOM Documents are supported as input");
449: }
450:
451: /**
452: * Parses an XML document.
453: * <p>
454: * The methods accepts only <code>JDOMInputSource</code>s
455: * instances as input sources.
456: * </p>
457: *
458: * @param input the input source for the top-level of the
459: * XML document.
460: *
461: * @throws SAXException any SAX exception,
462: * possibly wrapping
463: * another exception.
464: * @throws SAXNotSupportedException if the input source does
465: * not wrap a JDOM document.
466: */
467: public void parse(InputSource input) throws SAXException {
468: if (input instanceof JDOMInputSource) {
469: try {
470: Object source = ((JDOMInputSource) input)
471: .getSource();
472: if (source instanceof Document) {
473: this .output((Document) source);
474: } else {
475: this .output((List) source);
476: }
477: } catch (JDOMException e) {
478: throw new SAXException(e.getMessage(), e);
479: }
480: } else {
481: throw new SAXNotSupportedException(
482: "Only JDOM Documents are supported as input");
483: }
484: }
485: }
486: }
|