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 #include <libxml/parser.h>
19 #include <libxml/tree.h>
27 #define PARSE_OPTIONS 0
30 PRSS *prss_parse_doc(xmlDocPtr doc);
32 PRSS *prss_parse_data(const char *xml_data)
34 xmlDocPtr doc = xmlReadMemory(xml_data, strlen(xml_data), "", NULL,
41 return prss_parse_doc(doc);
44 PRSS *prss_parse_file(const char *xml_file)
46 xmlDocPtr doc = xmlReadFile(xml_file, NULL, PARSE_OPTIONS);
52 return prss_parse_doc(doc);
55 void prss_free(PRSS *data)
60 xmlFreeDoc(data->_data);
66 static inline void prss_null(PRSS *p)
68 memset(p, 0, sizeof(PRSS));
70 static inline void prss_null_item(PRSS_Item *i)
72 memset(i, 0, sizeof(PRSS_Item));
75 static inline void read_item(PRSS_Item *res, xmlNodePtr data)
79 res->title = res->link = res->description = NULL;
80 for (; data; data = data->next) {
81 if (data->type != XML_ELEMENT_NODE) {
84 xmlNodePtr child = data->children;
90 if (!strcasecmp((char *) data->name, "title")) {
91 res->title = (char *) child->content;
92 } else if (!strcasecmp((char *) data->name, "link")) {
93 res->link = (char *) child->content;
94 } else if (!strcasecmp((char *) data->name, "description")) {
95 res->description = (char *) child->content;
96 } else if (!strcasecmp((char *) data->name, "category")) {
97 res->category = (char *) child->content;
98 } else if (!strcasecmp((char *) data->name, "pubDate")) {
99 res->pubdate = (char *) child->content;
100 } else if (!strcasecmp((char *) data->name, "guid")) {
101 res->guid = (char *) child->content;
105 static inline void read_element(PRSS *res, xmlNodePtr n)
107 if (n->type != XML_ELEMENT_NODE) {
110 xmlNodePtr child = n->children;
116 if (!strcasecmp((char *) n->name, "title")) {
117 res->title = (char *) child->content;
118 } else if (!strcasecmp((char *) n->name, "link")) {
119 res->link = (char *) child->content;
120 } else if (!strcasecmp((char *) n->name, "description")) {
121 res->description = (char *) child->content;
122 } else if (!strcasecmp((char *) n->name, "language")) {
123 res->language = (char *) child->content;
124 } else if (!strcasecmp((char *) n->name, "pubDate")) {
125 res->pubdate = (char *) child->content;
126 } else if (!strcasecmp((char *) n->name, "lastBuildDate")) {
127 res->lastbuilddate = (char *) child->content;
128 } else if (!strcasecmp((char *) n->name, "generator")) {
129 res->generator = (char *) child->content;
130 } else if (!strcasecmp((char *) n->name, "docs")) {
131 res->docs = (char *) child->content;
132 } else if (!strcasecmp((char *) n->name, "managingEditor")) {
133 res->managingeditor = (char *) child->content;
134 } else if (!strcasecmp((char *) n->name, "webMaster")) {
135 res->webmaster = (char *) child->content;
136 } else if (!strcasecmp((char *) n->name, "copyright")) {
137 res->copyright = (char *) child->content;
138 } else if (!strcasecmp((char *) n->name, "ttl")) {
139 res->ttl = (char *) child->content;
140 } else if (!strcasecmp((char *) n->name, "item")) {
141 read_item(&res->items[res->item_count++], n->children);
145 static inline int parse_rss_2_0(PRSS *res, xmlNodePtr root)
147 xmlNodePtr channel = root->children;
149 while (channel && (channel->type != XML_ELEMENT_NODE
150 || strcmp((char *) channel->name, "channel"))) {
151 channel = channel->next;
160 for (n = channel->children; n; n = n->next) {
161 if (n->type == XML_ELEMENT_NODE && !strcmp((char *) n->name, "item")) {
166 res->version = strdup("2.0");
167 res->items = malloc(items * sizeof(PRSS_Item));
170 for (n = channel->children; n; n = n->next) {
171 read_element(res, n);
176 static inline int parse_rss_1_0(PRSS *res, xmlNodePtr root)
181 for (n = root->children; n; n = n->next) {
182 if (n->type == XML_ELEMENT_NODE) {
183 if (!strcmp((char *) n->name, "item")) {
185 } else if (!strcmp((char *) n->name, "channel")) {
188 for (i = n->children; i; i = i->next) {
189 read_element(res, i);
195 res->version = strdup("1.0");
196 res->items = malloc(items * sizeof(PRSS_Item));
199 for (n = root->children; n; n = n->next) {
200 if (n->type == XML_ELEMENT_NODE && !strcmp((char *) n->name, "item")) {
201 read_item(&res->items[res->item_count++], n->children);
207 static inline int parse_rss_0_9x(PRSS *res, xmlNodePtr root)
210 return parse_rss_2_0(res, root);
213 PRSS *prss_parse_doc(xmlDocPtr doc)
215 /* FIXME: doc shouldn't be freed after failure when called explicitly from
218 xmlNodePtr root = xmlDocGetRootElement(doc);
219 PRSS *result = malloc(sizeof(PRSS));
224 if (root->type == XML_ELEMENT_NODE) {
225 if (!strcmp((char *) root->name, "RDF")) {
227 if (!parse_rss_1_0(result, root)) {
233 } else if (!strcmp((char *) root->name, "rss")) {
234 // RSS 2.0 or <1.0 document
235 if (!parse_rss_2_0(result, root)) {