Refactor yaz_match-routines to separate source
[yaz-moved-to-github.git] / src / xml_match.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file xml_match.c
7  * \brief XML node inspection utilities
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdlib.h>
14
15 #include <yaz/srw.h>
16 #include <yaz/wrbuf.h>
17 #if YAZ_HAVE_XML2
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
20 #include "sru-p.h"
21
22 int yaz_match_xsd_element(xmlNodePtr ptr, const char *elem)
23 {
24     if (ptr->type == XML_ELEMENT_NODE && !xmlStrcmp(ptr->name, BAD_CAST elem))
25     {
26         return 1;
27     }
28     return 0;
29 }
30
31 #define CHECK_TYPE 0
32
33 int yaz_match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
34                            char **val, int *len)
35 {
36 #if CHECK_TYPE
37     struct _xmlAttr *attr;
38 #endif
39     if (!yaz_match_xsd_element(ptr, elem))
40         return 0;
41 #if CHECK_TYPE
42     for (attr = ptr->properties; attr; attr = attr->next)
43         if (!strcmp(attr->name, "type") &&
44             attr->children && attr->children->type == XML_TEXT_NODE)
45         {
46             const char *t = strchr(attr->children->content, ':');
47             if (t)
48                 t = t + 1;
49             else
50                 t = attr->children->content;
51             if (!strcmp(t, "string"))
52                 break;
53         }
54     if (!attr)
55         return 0;
56 #endif
57     ptr = ptr->children;
58     if (!ptr || ptr->type != XML_TEXT_NODE)
59     {
60         *val = "";
61         return 1;
62     }
63     *val = odr_strdup(o, (const char *) ptr->content);
64     if (len)
65         *len = xmlStrlen(ptr->content);
66     return 1;
67 }
68
69
70 int yaz_match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o, char **val)
71 {
72     return yaz_match_xsd_string_n(ptr, elem, o, val, 0);
73 }
74
75 int yaz_match_xsd_XML_n2(xmlNodePtr ptr, const char *elem, ODR o,
76                          char **val, int *len, int fixup_root)
77 {
78     xmlBufferPtr buf;
79     int no_root_nodes = 0;
80
81     if (!yaz_match_xsd_element(ptr, elem))
82         return 0;
83
84     buf = xmlBufferCreate();
85
86     /* Copy each element nodes at top.
87        In most cases there is only one root node.. At least one server
88        http://www.theeuropeanlibrary.org/sru/sru.pl
89        has multiple root nodes in recordData.
90     */
91     for (ptr = ptr->children; ptr; ptr = ptr->next)
92     {
93         if (ptr->type == XML_ELEMENT_NODE)
94         {
95             /* copy node to get NS right (bug #740). */
96             xmlNode *tmp = xmlCopyNode(ptr, 1);
97
98             xmlNodeDump(buf, tmp->doc, tmp, 0, 0);
99
100             xmlFreeNode(tmp);
101             no_root_nodes++;
102         }
103     }
104     if (no_root_nodes != 1 && fixup_root)
105     {
106         /* does not appear to be an XML document. Make it so */
107         xmlBufferAddHead(buf, (const xmlChar *) "<yaz_record>", -1);
108         xmlBufferAdd(buf, (const xmlChar *) "</yaz_record>", -1);
109     }
110     *val = (char *) odr_malloc(o, buf->use + 1);
111     memcpy(*val, buf->content, buf->use);
112     (*val)[buf->use] = '\0';
113
114     if (len)
115         *len = buf->use;
116
117     xmlBufferFree(buf);
118
119     return 1;
120 }
121
122 int yaz_match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
123                         char **val, int *len)
124 {
125     return yaz_match_xsd_XML_n2(ptr, elem, o, val, len, 0);
126 }
127
128 int yaz_match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o,
129                           Odr_int **val)
130 {
131 #if CHECK_TYPE
132     struct _xmlAttr *attr;
133 #endif
134     if (!yaz_match_xsd_element(ptr, elem))
135         return 0;
136 #if CHECK_TYPE
137     for (attr = ptr->properties; attr; attr = attr->next)
138         if (!strcmp(attr->name, "type") &&
139             attr->children && attr->children->type == XML_TEXT_NODE)
140         {
141             const char *t = strchr(attr->children->content, ':');
142             if (t)
143                 t = t + 1;
144             else
145                 t = attr->children->content;
146             if (!strcmp(t, "integer"))
147                 break;
148         }
149     if (!attr)
150         return 0;
151 #endif
152     ptr = ptr->children;
153     if (!ptr || ptr->type != XML_TEXT_NODE)
154         return 0;
155     *val = odr_intdup(o, odr_atoi((const char *) ptr->content));
156     return 1;
157 }
158
159
160 #endif
161
162
163 /*
164  * Local variables:
165  * c-basic-offset: 4
166  * c-file-style: "Stroustrup"
167  * indent-tabs-mode: nil
168  * End:
169  * vim: shiftwidth=4 tabstop=8 expandtab
170  */
171