2 * Copyright (c) 2007 Mikko Sysikaski <mikko.sysikaski@gmail.com>
3 * Toni Spets <toni.spets@gmail.com>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <libxml/parser.h>
21 #include <libxml/tree.h>
28 #define PARSE_OPTIONS 0
31 PRSS* prss_parse_doc(xmlDocPtr doc);
33 PRSS* prss_parse_data(const char* xml_data)
35 xmlDocPtr doc = xmlReadMemory(xml_data, strlen(xml_data), "", NULL, PARSE_OPTIONS);
39 return prss_parse_doc(doc);
41 PRSS* prss_parse_file(const char* xml_file)
43 xmlDocPtr doc = xmlReadFile(xml_file, NULL, PARSE_OPTIONS);
47 return prss_parse_doc(doc);
49 void prss_free(PRSS* data)
53 xmlFreeDoc(data->_data);
58 static inline void prss_null(PRSS* p)
60 memset(p, 0, sizeof(PRSS));
62 static inline void prss_null_item(PRSS_Item* i)
64 memset(i, 0, sizeof(PRSS_Item));
67 static inline void read_item(PRSS_Item* res, xmlNodePtr data)
71 res->title = res->link = res->description = NULL;
72 for(; data; data = data->next) {
73 if (data->type != XML_ELEMENT_NODE)
75 xmlNodePtr child = data->children;
79 if (!strcmp((char*)data->name, "title")) {
80 res->title = (char*)child->content;
81 } else if (!strcmp((char*)data->name, "link")) {
82 res->link = (char*)child->content;
83 } else if (!strcmp((char*)data->name, "description")) {
84 res->description = (char*)child->content;
85 } else if (!strcmp((char*)data->name, "category")) {
86 res->category = (char*)child->content;
87 } else if (!strcmp((char*)data->name, "pubDate")) {
88 res->pubdate = (char*)child->content;
89 } else if (!strcmp((char*)data->name, "guid")) {
90 res->guid = (char*)child->content;
94 static inline void read_element(PRSS* res, xmlNodePtr n)
96 if (n->type != XML_ELEMENT_NODE)
98 xmlNodePtr child = n->children;
102 if (!strcmp((char*)n->name, "title")) {
103 res->title = (char*)child->content;
104 } else if (!strcmp((char*)n->name, "link")) {
105 res->link = (char*)child->content;
106 } else if (!strcmp((char*)n->name, "description")) {
107 res->description = (char*)child->content;
108 } else if (!strcmp((char*)n->name, "language")) {
109 res->language = (char*)child->content;
110 } else if (!strcmp((char*)n->name, "pubDate")) {
111 res->pubdate = (char*)child->content;
112 } else if (!strcmp((char*)n->name, "lastBuildDate")) {
113 res->lastbuilddate = (char*)child->content;
114 } else if (!strcmp((char*)n->name, "generator")) {
115 res->generator = (char*)child->content;
116 } else if (!strcmp((char*)n->name, "docs")) {
117 res->docs = (char*)child->content;
118 } else if (!strcmp((char*)n->name, "managingEditor")) {
119 res->managingeditor = (char*)child->content;
120 } else if (!strcmp((char*)n->name, "webMaster")) {
121 res->webmaster = (char*)child->content;
122 } else if (!strcmp((char*)n->name, "item")) {
123 read_item(&res->items[res->item_count++], n->children);
127 static inline int parse_rss_2_0(PRSS* res, xmlNodePtr root)
129 xmlNodePtr channel = root->children;
131 && (channel->type!=XML_ELEMENT_NODE
132 || strcmp((char*)channel->name, "channel")))
133 channel = channel->next;
139 for(n = channel->children; n; n = n->next)
140 if (n->type==XML_ELEMENT_NODE && !strcmp((char*)n->name, "item"))
143 res->items = malloc(items*sizeof(PRSS_Item));
146 for(n = channel->children; n; n = n->next) {
147 read_element(res, n);
152 static inline int parse_rss_1_0(PRSS* res, xmlNodePtr root)
156 for(n = root->children; n; n = n->next) {
157 if (n->type==XML_ELEMENT_NODE) {
158 if (!strcmp((char*)n->name, "item"))
160 else if (!strcmp((char*)n->name, "channel")) {
162 for(i = n->children; i; i = i->next) {
163 read_element(res, i);
169 res->items = malloc(items*sizeof(PRSS_Item));
172 for(n = root->children; n; n = n->next) {
173 if (n->type==XML_ELEMENT_NODE && !strcmp((char*)n->name, "item"))
174 read_item(&res->items[res->item_count++], n->children);
179 static inline int parse_rss_0_9x(PRSS* res, xmlNodePtr root)
182 return parse_rss_2_0(res, root);
185 PRSS* prss_parse_doc(xmlDocPtr doc)
187 // FIXME: doc shouldn't be freed after failure when called explicitly from program!
189 xmlNodePtr root = xmlDocGetRootElement(doc);
190 PRSS* result = malloc(sizeof(PRSS));
194 if (root->type == XML_ELEMENT_NODE) {
195 if (!strcmp((char*)root->name, "RDF")) {
197 if (!parse_rss_1_0(result, root)) {
203 } else if (!strcmp((char*)root->name, "rss")) {
204 // RSS 2.0 or <1.0 document
205 if (!parse_rss_2_0(result, root)) {