Extra root tag node for data1
[yaz-moved-to-github.git] / retrieval / d1_expat.c
1 /*
2  * Copyright (c) 2002, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: d1_expat.c,v 1.3 2002-07-03 10:04:04 adam Exp $
6  */
7
8 #if HAVE_EXPAT_H
9
10 #include <assert.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include <yaz/xmalloc.h>
15 #include <yaz/log.h>
16 #include <yaz/data1.h>
17
18 #include <expat.h>
19
20 struct user_info {
21     data1_node *d1_stack[256];
22     int level;
23     data1_handle dh;
24     NMEM nmem;
25 };
26
27 static void cb_start (void *user, const char *el, const char **attr)
28 {
29     struct user_info *ui = (struct user_info*) user;
30     if (ui->level == 1)
31         data1_set_root (ui->dh, ui->d1_stack[0], ui->nmem, el);
32     ui->d1_stack[ui->level] = data1_mk_tag (ui->dh, ui->nmem, el, attr,
33                                                 ui->d1_stack[ui->level-1]);
34     ui->level++;
35     yaz_log (LOG_DEBUG, "cb_start %s", el);
36 }
37
38 static void cb_end (void *user, const char *el)
39 {
40     struct user_info *ui = (struct user_info*) user;
41
42     ui->level--;
43     yaz_log (LOG_DEBUG, "cb_end %s", el);
44 }
45
46 static void cb_chardata (void *user, const char *s, int len)
47 {
48     struct user_info *ui = (struct user_info*) user;
49     int i;
50
51     for (i = 0; i<len; i++)
52         if (!strchr ("\n\n ", s[i]))
53             break;
54     if (i != len)
55     {
56         ui->d1_stack[ui->level] = data1_mk_text_n (ui->dh, ui->nmem, s, len,
57                                                    ui->d1_stack[ui->level -1]);
58     }
59 }
60
61 static void cb_decl (void *user, const char *version, const char*encoding,
62                      int standalone)
63 {
64     struct user_info *ui = (struct user_info*) user;
65     const char *attr_list[7];
66
67     attr_list[0] = "version";
68     attr_list[1] = version;
69
70     attr_list[2] = "encoding";
71     attr_list[3] = encoding;
72
73     attr_list[4] = "standalone";
74     attr_list[5] = standalone  ? "yes" : "no";
75
76     attr_list[6] = 0;
77     
78     data1_mk_preprocess (ui->dh, ui->nmem, "xml", attr_list,
79                              ui->d1_stack[ui->level-1]);
80     yaz_log (LOG_DEBUG, "decl version=%s encoding=%s",
81              version ? version : "null",
82              encoding ? encoding : "null");
83 }
84     
85 static void cb_processing (void *user, const char *target,
86                            const char *data)
87 {
88     struct user_info *ui = (struct user_info*) user;
89     data1_node *res =
90         data1_mk_preprocess (ui->dh, ui->nmem, target, 0,
91                              ui->d1_stack[ui->level-1]);
92     data1_mk_text_nf (ui->dh, ui->nmem, data, strlen(data), res);
93     
94     yaz_log (LOG_DEBUG, "decl processing target=%s data=%s",
95              target ? target : "null",
96              data ? data : "null");
97     
98     
99 }
100
101 static void cb_comment (void *user, const char *data)
102 {
103     struct user_info *ui = (struct user_info*) user;
104     yaz_log (LOG_DEBUG, "decl comment data=%s", data ? data : "null");
105     data1_mk_comment (ui->dh, ui->nmem, data, ui->d1_stack[ui->level-1]);
106 }
107
108 static void cb_doctype_start (void *userData, const char *doctypeName,
109                               const char *sysid, const char *pubid,
110                               int has_internal_subset)
111 {
112     yaz_log (LOG_DEBUG, "doctype start doctype=%s sysid=%s pubid=%s",
113              doctypeName, sysid, pubid);
114 }
115
116 static void cb_doctype_end (void *userData)
117 {
118     yaz_log (LOG_DEBUG, "doctype end");
119 }
120
121
122 static void cb_entity_decl (void *userData, const char *entityName,
123                             int is_parameter_entity,
124                             const char *value, int value_length,
125                             const char *base, const char *systemId,
126                             const char *publicId, const char *notationName)
127 {
128     yaz_log (LOG_DEBUG,
129              "entity %s is_para_entry=%d value=%.*s base=%s systemId=%s"
130              " publicId=%s notationName=%s",
131              entityName, is_parameter_entity, value_length, value,
132              base, systemId, publicId, notationName);
133     
134 }
135
136 #define XML_CHUNK 1024
137
138 data1_node *data1_read_xml (data1_handle dh,
139                             int (*rf)(void *, char *, size_t), void *fh,
140                             NMEM m)
141 {
142     XML_Parser parser;
143     struct user_info uinfo;
144     int done = 0;
145
146     uinfo.level = 1;
147     uinfo.dh = dh;
148     uinfo.nmem = m;
149     uinfo.d1_stack[0] = data1_mk_node2 (dh, m, DATA1N_root, 0);
150     uinfo.d1_stack[1] = 0; /* indicate no children (see end of routine) */
151     
152     parser = XML_ParserCreate (0 /* encoding */);
153     
154     XML_SetElementHandler (parser, cb_start, cb_end);
155     XML_SetCharacterDataHandler (parser, cb_chardata);
156     XML_SetXmlDeclHandler (parser, cb_decl);
157     XML_SetProcessingInstructionHandler (parser, cb_processing);
158     XML_SetUserData (parser, &uinfo);
159     XML_SetCommentHandler (parser, cb_comment);
160     XML_SetDoctypeDeclHandler (parser, cb_doctype_start, cb_doctype_end);
161     XML_SetEntityDeclHandler (parser, cb_entity_decl);
162
163     while (!done)
164     {
165         int r;
166         void *buf = XML_GetBuffer (parser, XML_CHUNK);
167         if (!buf)
168         {
169             /* error */
170             return 0;
171         }
172         r = (*rf)(fh, buf, XML_CHUNK);
173         if (r < 0)
174         {
175             /* error */
176             return 0;
177         }
178         else if (r == 0)
179             done = 1;
180         XML_ParseBuffer (parser, r, done);
181     }
182     XML_ParserFree (parser);
183     if (!uinfo.d1_stack[1])
184         return 0;
185     return uinfo.d1_stack[0];
186 }
187
188 #endif