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:
018: package org.apache.commons.digester.rss;
019:
020: import java.io.File;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.net.URL;
024:
025: import org.apache.commons.digester.Digester;
026: import org.apache.commons.logging.LogFactory;
027: import org.xml.sax.InputSource;
028: import org.xml.sax.SAXException;
029:
030: /**
031: * <p>Implementation of <strong>org.apache.commons.digester.Digester</strong>
032: * designed to process input streams that conform to the <em>Rich Site
033: * Summary</em> DTD, version 0.91. For more information about this format,
034: * see the <a href="http://my.netscape.com/publish/">My Netscape</a> site.</p>
035: *
036: * <p>The default implementation object returned by calling
037: * <code>parse()</code> (an instance of
038: * <code>org.apache.commons.digester.rss.Channel</code>)
039: * knows how to render itself in XML format via the <code>render()</code>
040: * method. See the test <code>main()</code> method below for an
041: * example of using these classes.</p>
042: */
043:
044: public class RSSDigester extends Digester {
045:
046: // ----------------------------------------------------------- Constructors
047:
048: // ----------------------------------------------------- Instance Variables
049:
050: /**
051: * Have we been configured yet?
052: */
053: protected boolean configured = false;
054:
055: /**
056: * The set of public identifiers, and corresponding resource names,
057: * for the versions of the DTDs that we know about.
058: */
059: protected static final String registrations[] = {
060: "-//Netscape Communications//DTD RSS 0.9//EN",
061: "/org/apache/commons/digester/rss/rss-0.9.dtd",
062: "-//Netscape Communications//DTD RSS 0.91//EN",
063: "/org/apache/commons/digester/rss/rss-0.91.dtd", };
064:
065: // ------------------------------------------------------------- Properties
066:
067: /**
068: * The fully qualified class name of the <code>Channel</code>
069: * implementation class.
070: */
071: protected String channelClass = "org.apache.commons.digester.rss.Channel";
072:
073: public String getChannelClass() {
074: return (this .channelClass);
075: }
076:
077: public void setChannelClass(String channelClass) {
078: this .channelClass = channelClass;
079: }
080:
081: /**
082: * The fully qualified class name of the <code>Image</code>
083: * implementation class.
084: */
085: protected String imageClass = "org.apache.commons.digester.rss.Image";
086:
087: public String getImageClass() {
088: return (this .imageClass);
089: }
090:
091: public void setImageClass(String imageClass) {
092: this .imageClass = imageClass;
093: }
094:
095: /**
096: * The fully qualified class name of the <code>Item</code>
097: * implementation class.
098: */
099: protected String itemClass = "org.apache.commons.digester.rss.Item";
100:
101: public String getItemClass() {
102: return (this .itemClass);
103: }
104:
105: public void setItemClass(String itemClass) {
106: this .itemClass = itemClass;
107: }
108:
109: /**
110: * The fully qualified class name of the <code>TextInput</code>
111: * implementation class.
112: */
113: protected String textInputClass = "org.apache.commons.digester.rss.TextInput";
114:
115: public String getTextInputClass() {
116: return (this .textInputClass);
117: }
118:
119: public void setTextInputClass(String textInputClass) {
120: this .textInputClass = textInputClass;
121: }
122:
123: // --------------------------------------------------------- Public Methods
124:
125: /**
126: * Parse the content of the specified file using this Digester. Returns
127: * the root element from the object stack (which will be the Channel).
128: *
129: * @param file File containing the XML data to be parsed
130: *
131: * @exception IOException if an input/output error occurs
132: * @exception SAXException if a parsing exception occurs
133: */
134: public Object parse(File file) throws IOException, SAXException {
135:
136: configure();
137: return (super .parse(file));
138:
139: }
140:
141: /**
142: * Parse the content of the specified input source using this Digester.
143: * Returns the root element from the object stack (which will be the
144: * Channel).
145: *
146: * @param input Input source containing the XML data to be parsed
147: *
148: * @exception IOException if an input/output error occurs
149: * @exception SAXException if a parsing exception occurs
150: */
151: public Object parse(InputSource input) throws IOException,
152: SAXException {
153:
154: configure();
155: return (super .parse(input));
156:
157: }
158:
159: /**
160: * Parse the content of the specified input stream using this Digester.
161: * Returns the root element from the object stack (which will be
162: * the Channel).
163: *
164: * @param input Input stream containing the XML data to be parsed
165: *
166: * @exception IOException if an input/output error occurs
167: * @exception SAXException if a parsing exception occurs
168: */
169: public Object parse(InputStream input) throws IOException,
170: SAXException {
171:
172: configure();
173: return (super .parse(input));
174:
175: }
176:
177: /**
178: * Parse the content of the specified URI using this Digester.
179: * Returns the root element from the object stack (which will be
180: * the Channel).
181: *
182: * @param uri URI containing the XML data to be parsed
183: *
184: * @exception IOException if an input/output error occurs
185: * @exception SAXException if a parsing exception occurs
186: */
187: public Object parse(String uri) throws IOException, SAXException {
188:
189: configure();
190: return (super .parse(uri));
191:
192: }
193:
194: // -------------------------------------------------------- Package Methods
195:
196: // ------------------------------------------------------ Protected Methods
197:
198: /**
199: * Configure the parsing rules that will be used to process RSS input.
200: */
201: protected void configure() {
202:
203: if (configured) {
204: return;
205: }
206:
207: // Register local copies of the DTDs we understand
208: for (int i = 0; i < registrations.length; i += 2) {
209: URL url = this .getClass().getResource(registrations[i + 1]);
210: if (url != null) {
211: register(registrations[i], url.toString());
212: }
213: }
214:
215: // FIXME - validate the "version" attribute of the rss element?
216:
217: // Add the rules for the Channel object
218: addObjectCreate("rss/channel", channelClass);
219: addCallMethod("rss/channel/copyright", "setCopyright", 0);
220: addCallMethod("rss/channel/description", "setDescription", 0);
221: addCallMethod("rss/channel/docs", "setDocs", 0);
222: addCallMethod("rss/channel/language", "setLanguage", 0);
223: addCallMethod("rss/channel/lastBuildDate", "setLastBuildDate",
224: 0);
225: addCallMethod("rss/channel/link", "setLink", 0);
226: addCallMethod("rss/channel/managingEditor",
227: "setManagingEditor", 0);
228: addCallMethod("rss/channel/pubDate", "setPubDate", 0);
229: addCallMethod("rss/channel/rating", "setRating", 0);
230: addCallMethod("rss/channel/skipDays/day", "addSkipDay", 0);
231: addCallMethod("rss/channel/skipHours/hour", "addSkipHour", 0);
232: addCallMethod("rss/channel/title", "setTitle", 0);
233: addCallMethod("rss/channel/webMaster", "setWebMaster", 0);
234:
235: // Add the rules for the Image object
236: addObjectCreate("rss/channel/image", imageClass);
237: addSetNext("rss/channel/image", "setImage",
238: "org.apache.commons.digester.rss.Image");
239: addCallMethod("rss/channel/image/description",
240: "setDescription", 0);
241: addCallMethod("rss/channel/image/height", "setHeight", 0,
242: new Class[] { Integer.TYPE });
243: addCallMethod("rss/channel/image/link", "setLink", 0);
244: addCallMethod("rss/channel/image/title", "setTitle", 0);
245: addCallMethod("rss/channel/image/url", "setURL", 0);
246: addCallMethod("rss/channel/image/width", "setWidth", 0,
247: new Class[] { Integer.TYPE });
248:
249: // Add the rules for the Item object
250: addObjectCreate("rss/channel/item", itemClass);
251: addSetNext("rss/channel/item", "addItem",
252: "org.apache.commons.digester.rss.Item");
253: addCallMethod("rss/channel/item/description", "setDescription",
254: 0);
255: addCallMethod("rss/channel/item/link", "setLink", 0);
256: addCallMethod("rss/channel/item/title", "setTitle", 0);
257:
258: // Add the rules for the TextInput object
259: addObjectCreate("rss/channel/textinput", textInputClass);
260: addSetNext("rss/channel/textinput", "setTextInput",
261: "org.apache.commons.digester.rss.TextInput");
262: addCallMethod("rss/channel/textinput/description",
263: "setDescription", 0);
264: addCallMethod("rss/channel/textinput/link", "setLink", 0);
265: addCallMethod("rss/channel/textinput/name", "setName", 0);
266: addCallMethod("rss/channel/textinput/title", "setTitle", 0);
267:
268: // Mark this digester as having been configured
269: configured = true;
270:
271: }
272:
273: // ------------------------------------------------------ Test Main Program
274:
275: /**
276: * Test main program that parses the channel description included in this
277: * package as a static resource.
278: *
279: * @param args The command line arguments (ignored)
280: */
281: public static void main(String args[]) {
282:
283: try {
284: System.out.println("RSSDigester Test Program");
285: System.out.println("Opening input stream ...");
286: InputStream is = RSSDigester.class
287: .getResourceAsStream("/org/apache/commons/digester/rss/rss-example.xml");
288: System.out.println("Creating new digester ...");
289: RSSDigester digester = new RSSDigester();
290: if ((args.length > 0) && (args[0].equals("-debug"))) {
291: digester.setLogger(LogFactory.getLog("RSSDigester"));
292: }
293: System.out.println("Parsing input stream ...");
294: Channel channel = (Channel) digester.parse(is);
295: System.out.println("Closing input stream ...");
296: is.close();
297: System.out.println("Dumping channel info ...");
298: channel.render(System.out);
299: } catch (Exception e) {
300: System.out.println("-->Exception");
301: e.printStackTrace(System.out);
302: }
303:
304: }
305:
306: }
|