Omit include of boost/regex.hpp
[metaproxy-moved-to-github.git] / src / filter_query_rewrite.cpp
1 /* $Id: filter_query_rewrite.cpp,v 1.5 2006-03-16 09:38:33 adam Exp $
2    Copyright (c) 2005, Index Data.
3
4 %LICENSE%
5  */
6
7
8 #include "config.hpp"
9 #include "filter.hpp"
10 #include "package.hpp"
11
12 #include "util.hpp"
13 #include "filter_query_rewrite.hpp"
14
15 #include <yaz/zgdu.h>
16 #include <yaz/xmlquery.h>
17 #include <yaz/diagbib1.h>
18
19 #include <libxslt/xsltutils.h>
20 #include <libxslt/transform.h>
21
22 namespace yf = yp2::filter;
23
24 namespace yp2 {
25     namespace filter {
26         class QueryRewrite::Rep {
27         public:
28             Rep();
29             ~Rep();
30             void process(yp2::Package &package) const;
31             void configure(const xmlNode * ptr);
32         private:
33             xsltStylesheetPtr m_stylesheet;
34         };
35     }
36 }
37
38 yf::QueryRewrite::Rep::Rep()
39 {
40     m_stylesheet = 0;
41 }
42
43 yf::QueryRewrite::Rep::~Rep()
44 {
45     if (m_stylesheet)
46         xsltFreeStylesheet(m_stylesheet);
47 }
48
49 yf::QueryRewrite::QueryRewrite() : m_p(new Rep)
50 {
51 }
52
53 yf::QueryRewrite::~QueryRewrite()
54 {  // must have a destructor because of boost::scoped_ptr
55 }
56
57 void yf::QueryRewrite::process(yp2::Package &package) const
58 {
59     m_p->process(package);
60 }
61
62 void yp2::filter::QueryRewrite::configure(const xmlNode *ptr)
63 {
64     m_p->configure(ptr);
65 }
66
67 void yf::QueryRewrite::Rep::process(yp2::Package &package) const
68 {
69     Z_GDU *gdu = package.request().get();
70     
71     if (gdu && gdu->which == Z_GDU_Z3950)
72     {
73         Z_APDU *apdu_req = gdu->u.z3950;
74         if (apdu_req->which == Z_APDU_searchRequest)
75         {
76             int error_code = 0;
77             const char *addinfo = 0;
78             yp2::odr odr;
79             Z_SearchRequest *req = apdu_req->u.searchRequest;
80             
81             xmlDocPtr doc_input = 0;
82             yaz_query2xml(req->query, &doc_input);
83             
84             if (!doc_input)
85             {
86                 error_code = YAZ_BIB1_MALFORMED_QUERY;
87                 addinfo = "converion from Query to XML failed";
88             }
89             else
90             {
91                 if (m_stylesheet)
92                 {
93                     xmlDocPtr doc_res = xsltApplyStylesheet(m_stylesheet,
94                                                             doc_input, 0);
95                     if (!doc_res)
96                     {
97                         error_code = YAZ_BIB1_MALFORMED_QUERY;
98                         addinfo = "XSLT transform failed for query";
99                     }
100                     else
101                     {
102                         const xmlNode *root_element = xmlDocGetRootElement(doc_res);
103                         yaz_xml2query(root_element, &req->query, odr,
104                                       &error_code, &addinfo);
105                         xmlFreeDoc(doc_res);
106                     }
107                 }
108                 xmlFreeDoc(doc_input);
109             }
110             package.request() = gdu;
111             if (error_code)
112             {
113                 Z_APDU *f_apdu = 
114                     odr.create_searchResponse(apdu_req, error_code, addinfo);
115                 package.response() = f_apdu;
116                 return;
117             }
118         } 
119     }
120     package.move();
121 }
122
123 void yp2::filter::QueryRewrite::Rep::configure(const xmlNode *ptr)
124 {
125     for (ptr = ptr->children; ptr; ptr = ptr->next)
126     {
127         if (ptr->type != XML_ELEMENT_NODE)
128             continue;
129         if (!strcmp((const char *) ptr->name, "xslt"))
130         {
131             if (m_stylesheet)
132             {
133                 throw yp2::filter::FilterException
134                     ("Only one xslt element allowed in query_rewrite filter");
135             }
136
137             std::string fname = yp2::xml::get_text(ptr);
138             m_stylesheet = xsltParseStylesheetFile(BAD_CAST fname.c_str());
139             if (!m_stylesheet)
140             {
141                 throw yp2::filter::FilterException
142                     ("Failed to read stylesheet " 
143                      + fname
144                      + " in query_rewrite filter");
145             }
146         }
147         else
148         {
149             throw yp2::filter::FilterException
150                 ("Bad element " 
151                  + std::string((const char *) ptr->name)
152                  + " in query_rewrite filter");
153         }
154     }
155 }
156
157 static yp2::filter::Base* filter_creator()
158 {
159     return new yp2::filter::QueryRewrite;
160 }
161
162 extern "C" {
163     struct yp2_filter_struct yp2_filter_query_rewrite = {
164         0,
165         "query-rewrite",
166         filter_creator
167     };
168 }
169
170 /*
171  * Local variables:
172  * c-basic-offset: 4
173  * indent-tabs-mode: nil
174  * c-file-style: "stroustrup"
175  * End:
176  * vim: shiftwidth=4 tabstop=8 expandtab
177  */