From 31babd0a7a0d4ee7091cfb740205ab6fe1c89ae5 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Thu, 27 Oct 2011 13:44:17 +0200 Subject: [PATCH] Embedded XSLT stylesheets for service New service definition element, xslt, that allows an embedded stylesheet to be defined. This can be referred to from pz:xslt as an alternative to external files. --- NEWS | 4 + doc/pazpar2_conf.xml | 26 ++++- src/Makefile.am | 1 + src/normalize_cache.c | 4 +- src/normalize_cache.h | 2 +- src/normalize_record.c | 19 ++-- src/normalize_record.h | 4 +- src/pazpar2_config.c | 15 +++ src/pazpar2_config.h | 2 + src/service_xslt.c | 123 +++++++++++++++++++++++ src/service_xslt.h | 45 +++++++++ src/session.c | 2 +- test/gils_service.xml | 257 +++++++++++++++++++++++++++++++++++++++++++++++- win/makefile | 1 + 14 files changed, 489 insertions(+), 16 deletions(-) create mode 100644 src/service_xslt.c create mode 100644 src/service_xslt.h diff --git a/NEWS b/NEWS index 083d60a..794094b 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,8 @@ +New service definition element, xslt, that allows an embedded stylesheet +to be defined. This can be referred to from pz:xslt as an alternative to +external files. + New pz:sortmap:field setting for specifying hints on how to make a target natively sort on a field. This is used for command=show in conjunction with sort. diff --git a/doc/pazpar2_conf.xml b/doc/pazpar2_conf.xml index e558c65..dcc1fdf 100644 --- a/doc/pazpar2_conf.xml +++ b/doc/pazpar2_conf.xml @@ -369,6 +369,20 @@ + xslt + + + Defines a XSLT stylesheet. The xslt + element takes exactly one attribute id + which names the stylesheet. This can be referred to in target + settings . + + + The content of the xslt element is the embedded stylesheet XML + + + + icu_chain @@ -991,13 +1005,21 @@ - pz:xslt + pz:xslt - Is a comma separated list of of files that specifies + Is a comma separated list of of stylesheet names that specifies how to convert incoming records to the internal representation. + For each name, the embedded stylesheets (XSL) that comes with the + service definition are consulted first and takes precedence over + external files; see + of service definition). + If the name does not match an embedded stylesheet it is + considered a filename. + + The suffix of each file specifies the kind of tranformation. Suffix ".xsl" makes an XSL transform. Suffix ".mmap" will use the MMAP transform (described below). diff --git a/src/Makefile.am b/src/Makefile.am index 2f3643d..55d3ed5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,6 +38,7 @@ libpazpar2_a_SOURCES = \ record.c record.h \ relevance.c relevance.h \ sel_thread.c sel_thread.h \ + service_xslt.c service_xslt.h \ session.c session.h \ settings.c settings.h \ termlists.c termlists.h diff --git a/src/normalize_cache.c b/src/normalize_cache.c index 862a258..21b1f8a 100644 --- a/src/normalize_cache.c +++ b/src/normalize_cache.c @@ -56,7 +56,7 @@ normalize_cache_t normalize_cache_create(void) } normalize_record_t normalize_cache_get(normalize_cache_t nc, - struct conf_config *conf, + struct conf_service *service, const char *spec) { normalize_record_t nt; @@ -70,7 +70,7 @@ normalize_record_t normalize_cache_get(normalize_cache_t nc, nt = ci->nt; else { - nt = normalize_record_create(conf, spec); + nt = normalize_record_create(service, spec); if (nt) { ci = nmem_malloc(nc->nmem, sizeof(*ci)); diff --git a/src/normalize_cache.h b/src/normalize_cache.h index 46b55ad..fab116e 100644 --- a/src/normalize_cache.h +++ b/src/normalize_cache.h @@ -26,7 +26,7 @@ typedef struct normalize_cache_s *normalize_cache_t; normalize_cache_t normalize_cache_create(void); normalize_record_t normalize_cache_get(normalize_cache_t nc, - struct conf_config *conf, + struct conf_service *service, const char *spec); void normalize_cache_destroy(normalize_cache_t nc); diff --git a/src/normalize_record.c b/src/normalize_record.c index e2c28cf..f75a0ee 100644 --- a/src/normalize_record.c +++ b/src/normalize_record.c @@ -29,14 +29,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "normalize_record.h" #include "pazpar2_config.h" - +#include "service_xslt.h" #include "marcmap.h" #include #include struct normalize_step { struct normalize_step *next; - xsltStylesheet *stylesheet; + xsltStylesheet *stylesheet; /* created by normalize_record */ + xsltStylesheet *stylesheet2; /* external stylesheet (service) */ struct marcmap *marcmap; }; @@ -45,7 +46,7 @@ struct normalize_record_s { NMEM nmem; }; -normalize_record_t normalize_record_create(struct conf_config *conf, +normalize_record_t normalize_record_create(struct conf_service *service, const char *spec) { NMEM nmem = nmem_create(); @@ -54,6 +55,7 @@ normalize_record_t normalize_record_create(struct conf_config *conf, int i, num; int no_errors = 0; char **stylesheets; + struct conf_config *conf = service->server->config; nt->nmem = nmem; @@ -65,9 +67,11 @@ normalize_record_t normalize_record_create(struct conf_config *conf, *m = nmem_malloc(nt->nmem, sizeof(**m)); (*m)->marcmap = NULL; (*m)->stylesheet = NULL; - - // XSLT - if (!strcmp(&stylesheets[i][strlen(stylesheets[i])-4], ".xsl")) + + (*m)->stylesheet2 = service_xslt_get(service, stylesheets[i]); + if ((*m)->stylesheet2) + ; + else if (!strcmp(&stylesheets[i][strlen(stylesheets[i])-4], ".xsl")) { if (!((*m)->stylesheet = xsltParseStylesheetFile((xmlChar *) wrbuf_cstr(fname)))) @@ -77,7 +81,6 @@ normalize_record_t normalize_record_create(struct conf_config *conf, no_errors++; } } - // marcmap else if (!strcmp(&stylesheets[i][strlen(stylesheets[i])-5], ".mmap")) { if (!((*m)->marcmap = marcmap_load(wrbuf_cstr(fname), nt->nmem))) @@ -132,6 +135,8 @@ int normalize_record_transform(normalize_record_t nt, xmlDoc **doc, xmlDoc *ndoc; if (m->stylesheet) ndoc = xsltApplyStylesheet(m->stylesheet, *doc, parms); + else if (m->stylesheet2) + ndoc = xsltApplyStylesheet(m->stylesheet2, *doc, parms); else if (m->marcmap) ndoc = marcmap_apply(m->marcmap, *doc); else diff --git a/src/normalize_record.h b/src/normalize_record.h index 06c953c..25155af 100644 --- a/src/normalize_record.h +++ b/src/normalize_record.h @@ -21,9 +21,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define NORMALIZE_RECORD_H typedef struct normalize_record_s *normalize_record_t; -struct conf_config; +struct conf_service; -normalize_record_t normalize_record_create(struct conf_config *conf, +normalize_record_t normalize_record_create(struct conf_service *service, const char *spec); void normalize_record_destroy(normalize_record_t nt); diff --git a/src/pazpar2_config.c b/src/pazpar2_config.c index c6567bd..dd1c570 100644 --- a/src/pazpar2_config.c +++ b/src/pazpar2_config.c @@ -41,6 +41,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "ppmutex.h" #include "incref.h" #include "pazpar2_config.h" +#include "service_xslt.h" #include "settings.h" #include "eventl.h" #include "http.h" @@ -56,6 +57,13 @@ struct conf_config database_hosts_t database_hosts; }; +struct service_xslt +{ + char *id; + xsltStylesheetPtr xsp; + struct service_xslt *next; +}; + static void conf_metadata_assign(NMEM nmem, struct conf_metadata * metadata, const char *name, @@ -115,6 +123,7 @@ static struct conf_service *service_init(struct conf_server *server, service->nmem = nmem; service->next = 0; service->databases = 0; + service->xslt_list = 0; service->server = server; service->session_timeout = 60; /* default session timeout */ service->z3950_session_timeout = 180; @@ -230,6 +239,7 @@ void service_destroy(struct conf_service *service) { if (!pazpar2_decref(&service->ref_count, service->mutex)) { + service_xslt_destroy(service); pp2_charset_fact_destroy(service->charsets); yaz_mutex_destroy(&service->mutex); nmem_destroy(service->nmem); @@ -542,6 +552,11 @@ static struct conf_service *service_create_static(struct conf_server *server, if (parse_metadata(service, n, &md_node, &sk_node)) return 0; } + else if (!strcmp((const char *) n->name, (const char *) "xslt")) + { + if (service_xslt_config(service, n)) + return 0; + } else { yaz_log(YLOG_FATAL, "Bad element: %s", n->name); diff --git a/src/pazpar2_config.h b/src/pazpar2_config.h index f3c346b..403ec16 100644 --- a/src/pazpar2_config.h +++ b/src/pazpar2_config.h @@ -118,6 +118,8 @@ struct conf_service /* duplicated from conf_server */ pp2_charset_fact_t charsets; + struct service_xslt *xslt_list; + struct database *databases; struct conf_server *server; }; diff --git a/src/service_xslt.c b/src/service_xslt.c new file mode 100644 index 0000000..bd4b580 --- /dev/null +++ b/src/service_xslt.c @@ -0,0 +1,123 @@ +/* This file is part of Pazpar2. + Copyright (C) 2006-2011 Index Data + +Pazpar2 is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "service_xslt.h" +#include "pazpar2_config.h" + +struct service_xslt +{ + char *id; + xsltStylesheetPtr xsp; + struct service_xslt *next; +}; + +xsltStylesheetPtr service_xslt_get(struct conf_service *service, + const char *id) +{ + struct service_xslt *sx; + for (sx = service->xslt_list; sx; sx = sx->next) + if (!strcmp(id, sx->id)) + return sx->xsp; + return 0; +} + +void service_xslt_destroy(struct conf_service *service) +{ + struct service_xslt *sx = service->xslt_list; + for (; sx; sx = sx->next) + xsltFreeStylesheet(sx->xsp); +} + +int service_xslt_config(struct conf_service *service, xmlNode *n) +{ + xmlDoc *xsp_doc; + xmlNode *root = n->children; + struct service_xslt *sx; + const char *id = 0; + struct _xmlAttr *attr; + for (attr = n->properties; attr; attr = attr->next) + if (!strcmp((const char *) attr->name, "id")) + id = (const char *) attr->children->content; + else + { + yaz_log(YLOG_FATAL, "Invalid attribute %s for xslt element", + (const char *) n->name); + return -1; + } + if (!id) + { + yaz_log(YLOG_FATAL, "Missing attribute id for xslt element"); + return 0; + } + while (root && root->type != XML_ELEMENT_NODE) + root = root->next; + if (!root) + { + yaz_log(YLOG_FATAL, "Missing content for xslt element"); + return -1; + } + for (sx = service->xslt_list; sx; sx = sx->next) + if (!strcmp(sx->id, id)) + { + yaz_log(YLOG_FATAL, "Multiple xslt with id=%s", id); + return -1; + } + + sx = nmem_malloc(service->nmem, sizeof(*sx)); + sx->id = nmem_strdup(service->nmem, id); + sx->next = service->xslt_list; + service->xslt_list = sx; + + xsp_doc = xmlNewDoc(BAD_CAST "1.0"); + xmlDocSetRootElement(xsp_doc, xmlCopyNode(root, 1)); + sx->xsp = xsltParseStylesheetDoc(xsp_doc); + if (!sx->xsp) + { + xmlFreeDoc(xsp_doc); + yaz_log(YLOG_FATAL, "Failed to parse XSLT"); + return -1; + } + return 0; +} + +/* + * Local variables: + * c-basic-offset: 4 + * c-file-style: "Stroustrup" + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/src/service_xslt.h b/src/service_xslt.h new file mode 100644 index 0000000..fe86cdd --- /dev/null +++ b/src/service_xslt.h @@ -0,0 +1,45 @@ +/* This file is part of Pazpar2. + Copyright (C) 2006-2011 Index Data + +Pazpar2 is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef SERVICE_XSLT_H +#define SERVICE_XSLT_H + +#include +#include + +struct conf_service; + +xsltStylesheetPtr service_xslt_get(struct conf_service *service, + const char *id); + +void service_xslt_destroy(struct conf_service *service); + +int service_xslt_config(struct conf_service *service, xmlNode *n); + +#endif + +/* + * Local variables: + * c-basic-offset: 4 + * c-file-style: "Stroustrup" + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/src/session.c b/src/session.c index 388e94e..8b76a53 100644 --- a/src/session.c +++ b/src/session.c @@ -438,7 +438,7 @@ static int prepare_map(struct session *se, struct session_database *sdb) } } sdb->map = normalize_cache_get(se->normalize_cache, - se->service->server->config, s); + se->service, s); if (!sdb->map) return -1; } diff --git a/test/gils_service.xml b/test/gils_service.xml index 71b4d16..f115422 100644 --- a/test/gils_service.xml +++ b/test/gils_service.xml @@ -18,7 +18,7 @@ - + @@ -33,4 +33,259 @@ + + + + + + + + + + + + + + + + + + + + + + + electronic resource + + + electronic resource + + + electronic resource + + + article + + + book + + + + + + + title + + author + + medium + + + + + test-usersetting-2 data: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/makefile b/win/makefile index adf52b4..6fb8912 100644 --- a/win/makefile +++ b/win/makefile @@ -201,6 +201,7 @@ PAZPAR2_OBJS = \ "$(OBJDIR)\ppmutex.obj" \ "$(OBJDIR)\incref.obj" \ "$(OBJDIR)\sel_thread.obj" \ + "$(OBJDIR)\service_xslt.obj" \ "$(OBJDIR)\connection.obj" \ "$(OBJDIR)\facet_limit.obj" -- 1.7.10.4