001 /*
002 * Copyright 1999,2004 The Apache Software Foundation.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.apache.commons.feedparser;
018
019 import java.util.Date;
020
021 import org.apache.commons.feedparser.tools.ISO8601DateParser;
022 import org.apache.commons.feedparser.tools.RFC822DateParser;
023 import org.jdom.Element;
024 import org.jdom.Namespace;
025
026 /**
027 * Handles parsing RSS metadata including dates
028 *
029 * @author <a href="mailto:burton@apache.org">Kevin A. Burton (burtonator)</a>
030 * @version $Id: MetaFeedParser.java 373879 2006-01-31 17:23:15Z mvdb $
031 */
032 public class MetaFeedParser extends BaseParser {
033
034 /**
035 *
036 */
037 public static void parse( FeedParserListener listener,
038 FeedParserState state ) throws FeedParserException {
039
040 //FIXME: this should be refactored into a new class called
041 //MetaFeedParser to be used by both Atom and RSS. Also the date
042 //handling below needs to be generic.
043
044 if ( listener instanceof MetaFeedParserListener == false )
045 return;
046
047 MetaFeedParserListener mfp = (MetaFeedParserListener)listener;
048
049 parseDate( state, mfp );
050
051 //FIXME: make sure RSS .9 is working and 0.91. I just need to confirm
052 //but I think they are working correctly
053 parseGUID( state, mfp );
054
055 parseAuthor( state, mfp );
056
057 parseComments( state, mfp );
058
059 parseCommentsFeed( state, mfp );
060
061 }
062
063 private static void parseComments( FeedParserState state,
064 MetaFeedParserListener listener )
065 throws FeedParserException {
066
067 Element element = state.current.getChild( "comments" );
068
069 if ( element != null ) {
070
071 String resource = element.getText();
072 listener.onComments( state, resource );
073 listener.onCommentsEnd();
074
075 }
076
077 }
078
079 private static void parseCommentsFeed( FeedParserState state,
080 MetaFeedParserListener listener )
081 throws FeedParserException {
082
083 Element element = state.current.getChild( "commentRSS", NS.WFW );
084
085 if ( element != null ) {
086
087 String resource = element.getText();
088 listener.onCommentsFeed( state, resource );
089 listener.onCommentsFeedEnd();
090
091 }
092
093 }
094
095 private static void parseAuthor( FeedParserState state,
096 MetaFeedParserListener listener )
097 throws FeedParserException {
098
099 Element element = null;
100
101 String name = null;
102 String email = null;
103 String resource = null;
104
105 try {
106
107 //atom:author
108
109 element = state.current.getChild( "author", NS.ATOM );
110
111 if ( element != null ) {
112 name = selectText( "atom:name", element );
113 email = selectText( "atom:email", element );
114 resource = selectText( "atom:uri", element );
115 }
116
117 //dc:creator (RSS 1.0)
118 element = state.current.getChild( "creator", NS.DC );
119
120 if ( element != null )
121 name = element.getText();
122
123 //author (RSS 2.0)
124 element = state.current.getChild( "author" );
125
126 if ( element != null )
127 name = element.getText();
128
129 if ( name != null && ! "".equals( name ) ) {
130
131 listener.onAuthor( state,
132 name,
133 email,
134 resource );
135
136 listener.onAuthorEnd();
137
138 }
139
140 } catch ( Exception e ) {
141 throw new FeedParserException( e );
142 }
143
144 }
145
146 private static void parseGUID( FeedParserState state,
147 MetaFeedParserListener listener )
148 throws FeedParserException {
149
150 Element id = null;
151
152 String guid = null;
153 boolean isPermalink = false;
154
155 id = state.current.getChild( "id", NS.ATOM );
156
157 if ( id != null ) {
158 guid = id.getText();
159 }
160
161 id = state.current.getChild( "guid" );
162
163 if ( id != null ) {
164
165 guid = id.getText();
166 isPermalink = "true".equals( id.getAttributeValue( "isPermalink" ) );
167
168 }
169
170 if ( guid != null ) {
171
172 listener.onGUID( state,
173 guid,
174 isPermalink );
175
176 listener.onGUIDEnd();
177
178 }
179
180 }
181
182 private static void parseDate( FeedParserState state,
183 MetaFeedParserListener listener )
184 throws FeedParserException {
185
186 if ( parseDate( "date", NS.DC, listener, state ) )
187 return;
188
189 // http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html#rfc.section.4.13.8
190 //
191 // The "atom:created" element is a Date construct that indicates the
192 // time that the entry was created. atom:entry elements MAY contain
193 // an atom:created element, but MUST NOT contain more than one.
194
195 // The content of an atom:created element MUST have a time zone
196 // whose value SHOULD be "UTC".
197
198 if ( parseDate( "created", NS.ATOM, listener, state ) )
199 return;
200
201 // http://www.mnot.net/drafts/draft-nottingham-atom-format-02.html#rfc.section.4.13.8
202 //
203 // If atom:created is not present, its content MUST considered to be
204 // the same as that of atom:modified.
205
206 if ( parseDate( "modified", NS.ATOM, listener, state ) )
207 return;
208
209 //support RSS 2.0 and RSS 0.9x dates.
210
211 if ( parseDate( "pubDate", null, listener, state, false ) )
212 return;
213
214 }
215
216 private static boolean parseDate( String name,
217 Namespace ns,
218 MetaFeedParserListener listener,
219 FeedParserState state ) {
220
221 return parseDate( name, ns, listener, state, true );
222
223 }
224
225 private static boolean parseDate( String name,
226 Namespace ns,
227 MetaFeedParserListener listener,
228 FeedParserState state,
229 boolean ISO8601 ) {
230 try {
231 //ok. Support dc:date
232 String v = state.current.getChildText( name, ns );
233
234 if ( v != null ) {
235
236 Date d = null;
237 if ( ISO8601 ) {
238 d = ISO8601DateParser.parse( v );
239 } else {
240 d = RFC822DateParser.parse( v );
241 }
242
243 listener.onCreated( state, d );
244 listener.onCreatedEnd();
245
246 return true;
247 }
248 } catch ( Throwable t ) {
249 // ignore the exception, so we can just move on
250 }
251
252 return false;
253
254 }
255
256 }