4ceb023ee7b77c045947f6a53bd13165da4375d9
[yaz-moved-to-github.git] / src / record_conv.c
1 /*
2  * Copyright (C) 2005-2006, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: record_conv.c,v 1.1 2006-05-02 20:47:45 adam Exp $
6  */
7 /**
8  * \file record_conv.c
9  * \brief Record Conversions utility
10  */
11
12 #if HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #if HAVE_XML2
17 #include <libxml/parser.h>
18 #include <libxml/tree.h>
19 #endif
20
21 #include <string.h>
22
23 #include <yaz/record_conv.h>
24 #include <yaz/wrbuf.h>
25 #include <yaz/xmalloc.h>
26 #include <yaz/nmem.h>
27
28 /** \brief The internal structure for yaz_record_conv_t */
29 struct yaz_record_conv_struct {
30     /** memory for configuration */
31     NMEM nmem;
32
33     /** conversion rules (allocated using NMEM) */
34     struct yaz_record_conv_rule *rules;
35
36     /** pointer to last conversion rule pointer in chain */
37     struct yaz_record_conv_rule **rules_p;
38
39     /** string buffer for error messages */
40     WRBUF wr_error;
41 };
42
43 /** \brief tranformation types (rule types) */
44 enum YAZ_RECORD_CONV_RULE 
45 {
46     YAZ_RECORD_CONV_RULE_XSLT,
47     YAZ_RECORD_CONV_RULE_MARC_TO_XML,
48     YAZ_RECORD_CONV_RULE_XML_TO_MARC
49 };
50
51 /** \brief tranformation info (rule info) */
52 struct yaz_record_conv_rule {
53     enum YAZ_RECORD_CONV_RULE which;
54     union {
55         struct {
56             const char *stylesheet;
57         } xslt;
58         struct {
59             const char *charset;
60         } marc_to_xml;
61         struct {
62             const char *charset;
63         } xml_to_marc;
64     } u;
65     struct yaz_record_conv_rule *next;
66 };
67
68 yaz_record_conv_t yaz_record_conv_create()
69 {
70     yaz_record_conv_t p = xmalloc(sizeof(*p));
71     p->nmem = nmem_create();
72     p->wr_error = wrbuf_alloc();
73     return p;
74 }
75
76 void yaz_record_conv_destroy(yaz_record_conv_t p)
77 {
78     if (p)
79     {
80         nmem_destroy(p->nmem);
81         wrbuf_free(p->wr_error, 1);
82         xfree(p);
83     }
84 }
85
86 #if HAVE_XML2
87 static struct yaz_record_conv_rule *add_rule(yaz_record_conv_t p,
88                                              enum YAZ_RECORD_CONV_RULE type)
89 {
90     struct yaz_record_conv_rule *r = nmem_malloc(p->nmem, sizeof(*r));
91     r->which = type;
92     r->next = 0;
93     *p->rules_p = r;
94     p->rules_p = &r->next;
95     return r;
96 }
97
98 static void yaz_record_conv_reset(yaz_record_conv_t p)
99 {
100     wrbuf_rewind(p->wr_error);
101     nmem_reset(p->nmem);
102     p->rules = 0;
103     p->rules_p = &p->rules;
104 }
105
106 static int conv_xslt(yaz_record_conv_t p, const xmlNode *ptr)
107 {
108     struct _xmlAttr *attr;
109     const char *stylesheet = 0;
110
111     for (attr = ptr->properties; attr; attr = attr->next)
112     {
113         if (!xmlStrcmp(attr->name, BAD_CAST "stylesheet") &&
114             attr->children && attr->children->type == XML_TEXT_NODE)
115             stylesheet = (const char *) attr->children->content;
116         else
117         {
118             wrbuf_printf(p->wr_error, "Bad attribute '%s'."
119                          "Expected stylesheet.", attr->name);
120             return -1;
121         }
122     }
123     if (stylesheet)
124     {
125         struct yaz_record_conv_rule *r =
126             add_rule(p, YAZ_RECORD_CONV_RULE_XSLT);
127         r->u.xslt.stylesheet = nmem_strdup(p->nmem, stylesheet);
128         return 0;
129     }
130     wrbuf_printf(p->wr_error, "Missing attribute 'stylesheet'");
131     return -1;
132 }
133
134 static int conv_marc_to_xml(yaz_record_conv_t p, const xmlNode *ptr)
135 {
136     struct _xmlAttr *attr;
137     const char *charset = 0;
138     struct yaz_record_conv_rule *r;
139
140     for (attr = ptr->properties; attr; attr = attr->next)
141     {
142         if (!xmlStrcmp(attr->name, BAD_CAST "charset") &&
143             attr->children && attr->children->type == XML_TEXT_NODE)
144             charset = (const char *) attr->children->content;
145         else
146         {
147             wrbuf_printf(p->wr_error, "Bad attribute '%s'."
148                          "Expected charset.", attr->name);
149             return -1;
150         }
151     }
152     r = add_rule(p, YAZ_RECORD_CONV_RULE_MARC_TO_XML);
153     if (charset)
154         r->u.marc_to_xml.charset = nmem_strdup(p->nmem, charset);
155     else
156         r->u.marc_to_xml.charset = 0;
157     return 0;
158 }
159
160 static int conv_xml_to_marc(yaz_record_conv_t p, const xmlNode *ptr)
161 {
162     struct _xmlAttr *attr;
163     const char *charset = 0;
164     struct yaz_record_conv_rule *r;
165
166     for (attr = ptr->properties; attr; attr = attr->next)
167     {
168         if (!xmlStrcmp(attr->name, BAD_CAST "charset") &&
169             attr->children && attr->children->type == XML_TEXT_NODE)
170             charset = (const char *) attr->children->content;
171         else
172         {
173             wrbuf_printf(p->wr_error, "Bad attribute '%s'."
174                          "Expected charset.", attr->name);
175             return -1;
176         }
177     }
178     r = add_rule(p, YAZ_RECORD_CONV_RULE_XML_TO_MARC);
179     if (charset)
180         r->u.xml_to_marc.charset = nmem_strdup(p->nmem, charset);
181     else
182         r->u.xml_to_marc.charset = 0;
183     return 0;
184 }
185
186
187 int yaz_record_conv_configure(yaz_record_conv_t p, const void *ptr_v)
188 {
189     const xmlNode *ptr = ptr_v; 
190
191     yaz_record_conv_reset(p);
192
193     if (ptr && ptr->type == XML_ELEMENT_NODE &&
194         !strcmp((const char *) ptr->name, "convert"))
195     {
196         for (ptr = ptr->children; ptr; ptr = ptr->next)
197         {
198             if (ptr->type != XML_ELEMENT_NODE)
199                 continue;
200             if (!strcmp((const char *) ptr->name, "xslt"))
201             {
202                 if (conv_xslt(p, ptr))
203                     return -1;
204             }
205             else if (!strcmp((const char *) ptr->name, "marc_to_xml"))
206             {
207                 if (conv_marc_to_xml(p, ptr))
208                     return -1;
209             }
210             else if (!strcmp((const char *) ptr->name, "xml_to_marc"))
211             {
212                 if (conv_xml_to_marc(p, ptr))
213                     return -1;
214             }
215             else
216             {
217                 wrbuf_printf(p->wr_error, "Bad element '%s'."
218                              "Expected xslt, marc_to_xml,...", ptr->name);
219                 return -1;
220             }
221         }
222     }
223     else
224     {
225         wrbuf_printf(p->wr_error, "Missing 'convert' element");
226         return -1;
227     }
228     return 0;
229 }
230
231 #else
232 /* HAVE_XML2 */
233 int yaz_record_conv_configure(yaz_record_conv_t p, const void *ptr_v)
234 {
235     wrbuf_rewind(p->wr_error);
236     wrbuf_printf(p->wr_error, "No XML support for yaz_record_conv");
237     return -1;
238 }
239
240 #endif
241
242 const char *yaz_record_conv_get_error(yaz_record_conv_t p)
243 {
244     return wrbuf_buf(p->wr_error);
245 }
246
247 /*
248  * Local variables:
249  * c-basic-offset: 4
250  * indent-tabs-mode: nil
251  * End:
252  * vim: shiftwidth=4 tabstop=8 expandtab
253  */
254