1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2 * vim: ts=4 sw=4 noet ai cindent syntax=c
4 * Copyright (c) 2007 Mikko Sysikaski <mikko.sysikaski@gmail.com>
5 * Toni Spets <toni.spets@gmail.com>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
28 #define PARSE_OPTIONS 0
31 void prss_parse_doc(PRSS *result, xmlDocPtr doc);
33 void prss_parse_data(void *result, const char *xml_data)
35 PRSS *data = (PRSS*)result;
37 xmlDocPtr doc = xmlReadMemory(xml_data, strlen(xml_data), "", NULL,
44 prss_parse_doc(data, doc);
48 void free_rss_items(PRSS *data)
52 for (i = 0; i < data->item_count; i++) {
53 #define CLEAR(a) if (data->items[i].a) { free(data->items[i].a); data->items[i].a = 0; }
67 void prss_free(PRSS *data)
81 #define CLEAR(a) if (data->a) { free(data->a); data->a = 0; }
90 CLEAR(managingEditor);
97 static inline void prss_null_item(PRSS_Item *i)
99 memset(i, 0, sizeof(PRSS_Item));
102 static inline void read_item(PRSS_Item *res, xmlNodePtr data)
106 for (; data; data = data->next) {
109 if (data->type != XML_ELEMENT_NODE) {
112 child = data->children;
118 #define ASSIGN(a) if (strcasecmp((const char*)data->name, #a) == EQUAL) { \
119 if (res->a) free(res->a); \
120 res->a = strdup((const char*)child->content); \
132 static inline void read_element(PRSS *res, xmlNodePtr n)
136 if (n->type != XML_ELEMENT_NODE) {
145 #define ASSIGN(a) if (strcasecmp((const char*)n->name, #a) == EQUAL) { \
146 if (res->a) free(res->a); \
147 res->a = strdup((const char*)child->content); \
155 ASSIGN(lastBuildDate);
158 ASSIGN(managingEditor);
163 if (!strcasecmp((const char*)n->name, "item")) {
164 read_item(&res->items[res->item_count++], n->children);
168 static inline int parse_rss_2_0(PRSS *res, xmlNodePtr root)
170 xmlNodePtr channel = root->children;
174 DBGP("parsing rss 2.0 or <1 doc");
176 while (channel && (channel->type != XML_ELEMENT_NODE
177 || strcmp((const char *) channel->name, "channel"))) {
178 channel = channel->next;
184 for (n = channel->children; n; n = n->next) {
185 if (n->type == XML_ELEMENT_NODE &&
186 !strcmp((const char *) n->name, "item")) {
191 if (res->version) free(res->version);
192 res->version = strndup("2.0", text_buffer_size);
193 if (res->items) free_rss_items(res);
194 res->items = malloc(items * sizeof(PRSS_Item));
197 for (n = channel->children; n; n = n->next) {
198 read_element(res, n);
203 static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root)
208 DBGP("parsing rss 1.0 doc");
210 for (n = root->children; n; n = n->next) {
211 if (n->type == XML_ELEMENT_NODE) {
212 if (!strcmp((const char *) n->name, "item")) {
214 } else if (!strcmp((const char *) n->name, "channel")) {
217 for (i = n->children; i; i = i->next) {
218 read_element(res, i);
224 if (res->version) free(res->version);
225 res->version = strndup("1.0", text_buffer_size);
226 if (res->items) free_rss_items(res);
227 res->items = malloc(items * sizeof(PRSS_Item));
230 for (n = root->children; n; n = n->next) {
231 if (n->type == XML_ELEMENT_NODE &&
232 !strcmp((const char *) n->name, "item")) {
233 read_item(&res->items[res->item_count++], n->children);
240 void prss_parse_doc(PRSS *result, xmlDocPtr doc)
242 xmlNodePtr root = xmlDocGetRootElement(doc);
245 if (root->type == XML_ELEMENT_NODE) {
246 if (!strcmp((const char *) root->name, "RDF")) {
248 parse_rss_1_0(result, root);
250 } else if (!strcmp((const char *) root->name, "rss")) {
251 // RSS 2.0 or <1.0 document
252 parse_rss_2_0(result, root);