Archived
1
0
Fork 0
This repository has been archived on 2026-05-10. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
dlight/rss.c
Henrik Hautakoski b2df740514 Initial commit
2011-09-21 17:13:28 +02:00

134 lines
2.3 KiB
C

#include <libxml/parser.h>
#include <libxml/tree.h>
#include "rss.h"
/* Sidestep warnings about signedness (xmlChar = unsigned char) */
#define xmlStrcmp(a, b) xmlStrcmp((xmlChar *)a, (xmlChar *)b)
#define xmlGetProp(n, p) xmlGetProp(n, (xmlChar *) p)
struct __walk_info {
xmlNodePtr current;
};
struct __rssdoc {
xmlDocPtr xmldoc;
xmlNodePtr channel;
xmlNodePtr firstitem;
};
struct __rss {
struct __rssdoc doc;
struct __walk_info info;
};
static xmlNodePtr getchild(xmlNodePtr node, const char *name) {
if (node) {
xmlNodePtr it;
for(it = node->children; it; it = it->next) {
if (!xmlStrcmp(it->name, name))
return it;
}
}
return NULL;
}
static const char* getnodetext(xmlNodePtr node) {
if (node) {
if (node->type == XML_ELEMENT_NODE)
node = node->children;
if (node->type == XML_TEXT_NODE)
return (const char *) node->content;
}
return "";
}
static int validate(struct __rssdoc *doc) {
xmlChar *attr;
xmlNodePtr node;
if (!doc->xmldoc)
return -1;
node = doc->xmldoc->children;
if (xmlStrcmp(node->name, "rss"))
return -1;
attr = xmlGetProp(node, "version");
if (!attr)
return -1;
/* get channel node */
node = xmlFirstElementChild(node);
if (!node || xmlStrcmp(node->name, "channel"))
return -1;
doc->channel = node;
/* get first item */
node = getchild(node, "item");
if (!node)
return -1;
doc->firstitem = node;
while(node) {
if (xmlStrcmp(node->name, "item"))
return -1;
node = xmlNextElementSibling(node);
}
return 0;
}
rss_t rss_parse(void *buf, size_t size) {
rss_t rss = malloc(sizeof(struct __rss));
rss->doc.xmldoc = xmlReadMemory(buf, size, "noname.xml", NULL, 0);
if (validate(&rss->doc) < 0) {
rss_free(rss);
return NULL;
}
rss->info.current = rss->doc.firstitem;
return rss;
}
void rss_free(rss_t r) {
if (!r)
return;
if (r->doc.xmldoc)
xmlFreeDoc(r->doc.xmldoc);
free(r);
}
int rss_walk_next(rss_t rss, struct rss_item *item) {
if (rss && rss->info.current) {
/* fill item */
xmlNodePtr cur = rss->info.current;
item->title = getnodetext(getchild(cur, "title"));
item->link = getnodetext(getchild(cur, "link"));
rss->info.current = xmlNextElementSibling(rss->info.current);
return 1;
}
return 0;
}
int rss_walk_reset(rss_t rss) {
if (rss) {
rss->info.current = rss->doc.firstitem;
return 1;
}
return 0;
}