1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.feedparser;
18
19 import java.util.Iterator;
20 import java.util.List;
21
22 import org.apache.commons.feedparser.locate.EntityDecoder;
23 import org.jaxen.jdom.JDOMXPath;
24 import org.jdom.Attribute;
25 import org.jdom.CDATA;
26 import org.jdom.Comment;
27 import org.jdom.Element;
28 import org.jdom.Text;
29 import org.jdom.output.XMLOutputter;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class AtomFeedParser extends BaseParser {
48
49
50
51
52
53
54 public static void parse( FeedParserListener listener,
55 org.jdom.Document doc ) throws Exception {
56
57 FeedParserState state = new FeedParserState( listener );
58
59 FeedVersion v = new FeedVersion();
60 v.isAtom = true;
61 listener.onFeedVersion( v );
62
63 listener.init();
64
65 Element root = doc.getRootElement();
66
67 doLocale( state, listener, root );
68
69 doChannel( state, listener, doc );
70 doEntry( state, listener, doc );
71
72 doLocaleEnd( state, listener, root );
73
74 listener.finished();
75
76 }
77
78 private static void doChannel( FeedParserState state,
79 FeedParserListener listener,
80 org.jdom.Document doc ) throws Exception {
81
82 Element root = doc.getRootElement();
83
84
85 String title = selectText( "/atom:feed/atom:title", root );
86
87
88
89
90 String link = selectSingleAttribute( "/atom:feed/atom:link[@rel='alternate'][@type='text/html']/@href", root );
91
92
93
94 String tagline = selectText( "/atom:feed/atom:tagline", root );
95
96
97 listener.onChannel( state, title, link, tagline );
98
99 listener.onChannelEnd();
100
101 }
102
103 private static void doEntry( FeedParserState state,
104 FeedParserListener listener,
105 org.jdom.Document doc ) throws Exception {
106
107 JDOMXPath xpath = new JDOMXPath( "/atom:feed/atom:entry" );
108 xpath.setNamespaceContext( NS.context );
109
110 List items = xpath.selectNodes( doc );
111
112 Iterator i = items.iterator();
113
114
115 while ( i.hasNext() ) {
116
117 Element child = (Element)i.next();
118
119 doLocale( state, listener, child );
120
121 String title = selectText( "atom:title", child );
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 String link = selectSingleAttribute( "atom:link[@rel='alternate'][@type='text/html']/@href",
138 child );
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 String description = null;
154
155 Element summary = child.getChild( "summary", NS.ATOM );
156
157 if ( summary != null ) {
158
159 String type = summary.getAttributeValue( "type", NS.ATOM );
160
161 if ( type == null || "text/plain".equals( type ) )
162 description = summary.getText();
163
164 }
165
166 state.current = child;
167
168 listener.onItem( state, title, link, description, link );
169
170 doLink( state, listener, child );
171
172 doMeta( state, listener, child );
173
174 doContent( state, listener, child );
175
176 MetaFeedParser.parse( listener, state );
177 TagFeedParser.parse( listener, state );
178
179 listener.onItemEnd();
180 doLocale( state, listener, child );
181
182 }
183
184 }
185
186 private static void doLink( FeedParserState state,
187 FeedParserListener listener,
188 Element current ) throws Exception {
189
190 if ( listener instanceof LinkFeedParserListener == false )
191 return;
192
193 LinkFeedParserListener lfpl = (LinkFeedParserListener)listener;
194
195 JDOMXPath xpath = new JDOMXPath( "atom:link" );
196 xpath.setNamespaceContext( NS.context );
197
198 List items = xpath.selectNodes( current );
199
200 Iterator it = items.iterator();
201
202
203 while ( it.hasNext() ) {
204
205 Element link = (Element)it.next();
206
207 String href = link.getAttributeValue( "href" );
208 String rel = link.getAttributeValue( "rel" );
209 String type = link.getAttributeValue( "type" );
210
211 String title = null;
212 long length = -1;
213
214 lfpl.onLink( state, rel, type, href, title, length );
215
216 }
217
218 }
219
220 private static void doContent( FeedParserState state,
221 FeedParserListener listener,
222 Element current ) throws Exception {
223
224 if ( ! (listener instanceof ContentFeedParserListener) )
225 return;
226
227 ContentFeedParserListener clistener = (ContentFeedParserListener)listener;
228
229 JDOMXPath xpath = new JDOMXPath( "atom:content" );
230 xpath.setNamespaceContext( NS.context );
231
232 List items = xpath.selectNodes( current );
233
234 Iterator i = items.iterator();
235
236
237 while ( i.hasNext() ) {
238
239 Element content = (Element)i.next();
240
241 doLocale( state, listener, content );
242
243 String type = content.getAttributeValue( "type", "text/plain" );
244 String mode = content.getAttributeValue( "mode" );
245
246 String format = null;
247 String encoding = null;
248
249 String value = null;
250
251
252 if ( "xml".equals( mode ) ) {
253 value = content.getText();
254 } else if ( "escaped".equals( mode ) ) {
255
256
257 value = getXMLOfContent( content.getContent() );
258 value = EntityDecoder.decode( value );
259 } else {
260 mode = "xml";
261 value = getXMLOfContent( content.getContent() );
262 }
263
264 boolean isSummary = false;
265
266 clistener.onContent( state, type, format, encoding, mode, value, isSummary );
267
268 doLocaleEnd( state, listener, content );
269
270 }
271
272 xpath = new JDOMXPath( "atom:summary[@type='application/xhtml+xml']" );
273 xpath.setNamespaceContext( NS.context );
274 Element e = (Element)xpath.selectSingleNode( current );
275
276 if ( e != null ) {
277
278 String type = "text/html";
279 String format = "application/xhtml+xml";
280 String encoding = null;
281 String mode = "xml";
282
283
284
285 String value = getXMLOfContent( e );
286 boolean isSummary = true;
287
288 clistener.onContent( state, type, format, encoding, mode, value, isSummary );
289
290 }
291
292 }
293
294 private static String getXMLOfContent( Element element ) {
295 return getXMLOfContent( element.getContent() );
296 }
297
298
299
300
301
302
303 private static String getXMLOfContent( List content ) {
304
305
306
307
308
309 StringBuffer buff = new StringBuffer( 10000 );
310
311
312
313 XMLOutputter outputter = new XMLOutputter();
314
315 Iterator it = content.iterator();
316
317 while ( it.hasNext() ) {
318
319 Object next = it.next();
320
321 if ( next instanceof String ) {
322 buff.append( (String)next );
323 } else if ( next instanceof Element ) {
324 buff.append( outputter.outputString( (Element)next ) );
325 } else if ( next instanceof CDATA ) {
326 buff.append( ((CDATA)next).getText() );
327 } else if ( next instanceof Comment ) {
328 buff.append( outputter.outputString( (Comment)next ) );
329 } else if ( next instanceof Text ) {
330 buff.append( outputter.outputString( (Text)next ) );
331 }
332
333 }
334
335 return buff.toString();
336
337 }
338
339 private static void doMeta( FeedParserState state,
340 FeedParserListener listener,
341 Element element ) throws Exception {
342
343
344
345 if ( ! (listener instanceof MetaFeedParserListener) )
346 return;
347
348 MetaFeedParserListener mlistener = (MetaFeedParserListener)listener;
349
350
351 String subject = selectText( "dc:subject", element);
352
353 if ( subject != null ) {
354 mlistener.onSubject( state, subject );
355 mlistener.onSubjectEnd();
356 }
357
358 }
359
360 private static Element selectSingleElement( String query, org.jdom.Document doc ) throws Exception {
361
362 JDOMXPath xpath = new JDOMXPath( query );
363 xpath.setNamespaceContext( NS.context );
364
365
366 return (Element)xpath.selectSingleNode( doc );
367
368 }
369
370 private static String selectSingleAttribute( String query, Element element ) throws Exception {
371
372 JDOMXPath xpath = new JDOMXPath( query );
373 xpath.setNamespaceContext( NS.context );
374
375
376 Attribute a = (Attribute)xpath.selectSingleNode( element );
377 if ( a == null )
378 return null;
379
380 return a.getValue();
381
382 }
383
384 }
385