1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
3 * Copyright (c) 2007 Mikko Sysikaski <mikko.sysikaski@gmail.com>
4 * Toni Spets <toni.spets@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * vim: ts=4 sw=4 noet ai cindent syntax=c
25 #include <libxml/parser.h>
26 #include <libxml/tree.h>
29 #define PARSE_OPTIONS 0
32 void prss_parse_doc(PRSS *result, xmlDocPtr doc);
34 void prss_parse_data(void *result, const char *xml_data)
36 PRSS *data = (PRSS*)result;
38 xmlDocPtr doc = xmlReadMemory(xml_data, strlen(xml_data), "", NULL,
45 prss_parse_doc(data, doc);
49 void free_rss_items(PRSS *data)
53 for (i = 0; i < data->item_count; i++) {
54 #define CLEAR(a) if (data->items[i].a) { free(data->items[i].a); data->items[i].a = 0; }
68 void prss_free(PRSS *data)
82 #define CLEAR(a) if (data->a) { free(data->a); data->a = 0; }
91 CLEAR(managingEditor);
98 static inline void prss_null_item(PRSS_Item *i)
100 memset(i, 0, sizeof(PRSS_Item));
103 static inline void read_item(PRSS_Item *res, xmlNodePtr data)
107 for (; data; data = data->next) {
110 if (data->type != XML_ELEMENT_NODE) {
113 child = data->children;
119 #define ASSIGN(a) if (strcasecmp((const char*)data->name, #a) == EQUAL) { \
120 if (res->a) free(res->a); \
121 res->a = strdup((const char*)child->content); \
133 static inline void read_element(PRSS *res, xmlNodePtr n)
137 if (n->type != XML_ELEMENT_NODE) {
146 #define ASSIGN(a) if (strcasecmp((const char*)n->name, #a) == EQUAL) { \
147 if (res->a) free(res->a); \
148 res->a = strdup((const char*)child->content); \
156 ASSIGN(lastBuildDate);
159 ASSIGN(managingEditor);
164 if (!strcasecmp((const char*)n->name, "item")) {
165 read_item(&res->items[res->item_count++], n->children);
169 static inline int parse_rss_2_0(PRSS *res, xmlNodePtr root)
171 xmlNodePtr channel = root->children;
175 DBGP("parsing rss 2.0 or <1 doc");
177 while (channel && (channel->type != XML_ELEMENT_NODE
178 || strcmp((const char *) channel->name, "channel"))) {
179 channel = channel->next;
185 for (n = channel->children; n; n = n->next) {
186 if (n->type == XML_ELEMENT_NODE &&
187 !strcmp((const char *) n->name, "item")) {
192 if (res->version) free(res->version);
193 res->version = strndup("2.0", text_buffer_size);
194 if (res->items) free_rss_items(res);
195 res->items = malloc(items * sizeof(PRSS_Item));
198 for (n = channel->children; n; n = n->next) {
199 read_element(res, n);
204 static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root)
209 DBGP("parsing rss 1.0 doc");
211 for (n = root->children; n; n = n->next) {
212 if (n->type == XML_ELEMENT_NODE) {
213 if (!strcmp((const char *) n->name, "item")) {
215 } else if (!strcmp((const char *) n->name, "channel")) {
218 for (i = n->children; i; i = i->next) {
219 read_element(res, i);
225 if (res->version) free(res->version);
226 res->version = strndup("1.0", text_buffer_size);
227 if (res->items) free_rss_items(res);
228 res->items = malloc(items * sizeof(PRSS_Item));
231 for (n = root->children; n; n = n->next) {
232 if (n->type == XML_ELEMENT_NODE &&
233 !strcmp((const char *) n->name, "item")) {
234 read_item(&res->items[res->item_count++], n->children);
241 void prss_parse_doc(PRSS *result, xmlDocPtr doc)
243 xmlNodePtr root = xmlDocGetRootElement(doc);
246 if (root->type == XML_ELEMENT_NODE) {
247 if (!strcmp((const char *) root->name, "RDF")) {
249 parse_rss_1_0(result, root);
251 } else if (!strcmp((const char *) root->name, "rss")) {
252 // RSS 2.0 or <1.0 document
253 parse_rss_2_0(result, root);