Initial commit
This commit is contained in:
commit
b2df740514
19 changed files with 1640 additions and 0 deletions
134
rss.c
Normal file
134
rss.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
|
||||
#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;
|
||||
}
|
||||
Reference in a new issue