From a0e27aac0589d493172c73f6660b844fc6460d7c Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Tue, 2 May 2006 20:47:45 +0000 Subject: [PATCH] Added nmem_text_node_cdata which takes xmlNode CDATA content and creates NMEM string. Added first parts of record conversion utility (yaz_record_conv_t). --- include/yaz/Makefile.am | 4 +- include/yaz/nmem.h | 3 +- include/yaz/record_conv.h | 113 ++++++++++++++++++++ src/Makefile.am | 3 +- src/marcdisp.c | 27 +---- src/nmemsdup.c | 26 ++++- src/record_conv.c | 254 +++++++++++++++++++++++++++++++++++++++++++++ src/xmlquery.c | 16 +-- test/.cvsignore | 2 + test/Makefile.am | 7 +- test/tst_record_conv.c | 124 ++++++++++++++++++++++ 11 files changed, 533 insertions(+), 46 deletions(-) create mode 100644 include/yaz/record_conv.h create mode 100644 src/record_conv.c create mode 100644 test/tst_record_conv.c diff --git a/include/yaz/Makefile.am b/include/yaz/Makefile.am index 3a71989..7f56a0b 100644 --- a/include/yaz/Makefile.am +++ b/include/yaz/Makefile.am @@ -1,9 +1,9 @@ -## $Id: Makefile.am,v 1.27 2006-01-27 17:31:52 adam Exp $ +## $Id: Makefile.am,v 1.28 2006-05-02 20:47:45 adam Exp $ pkginclude_HEADERS= backend.h ccl.h cql.h comstack.h \ diagbib1.h diagsrw.h sortspec.h log.h logrpn.h marcdisp.h nmem.h odr.h \ oid.h options.h otherinfo.h pquery.h prt-ext.h querytowrbuf.h \ - readconf.h statserv.h \ + readconf.h record_conv.h statserv.h \ tcpip.h test.h unix.h tpath.h wrbuf.h xmalloc.h \ yaz-ccl.h yaz-iconv.h yaz-util.h yaz-version.h yconfig.h proto.h \ xmlquery.h \ diff --git a/include/yaz/nmem.h b/include/yaz/nmem.h index bd4ff09..c0ebc9b 100644 --- a/include/yaz/nmem.h +++ b/include/yaz/nmem.h @@ -23,7 +23,7 @@ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. * - * $Id: nmem.h,v 1.17 2005-06-25 15:46:03 adam Exp $ + * $Id: nmem.h,v 1.18 2006-05-02 20:47:45 adam Exp $ */ /** @@ -68,6 +68,7 @@ YAZ_EXPORT void nmem_strsplit_blank(NMEM nmem, const char *dstr, YAZ_EXPORT void nmem_strsplit(NMEM nmem, const char *delim, const char *dstr, char ***darray, int *num); +YAZ_EXPORT char *nmem_text_node_cdata(const void *ptr_cdata, NMEM nmem); YAZ_EXPORT int *nmem_intdup (NMEM mem, int v); YAZ_EXPORT void nmem_transfer (NMEM dst, NMEM src); diff --git a/include/yaz/record_conv.h b/include/yaz/record_conv.h new file mode 100644 index 0000000..1ffae60 --- /dev/null +++ b/include/yaz/record_conv.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2006, Index Data ApS + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation, in whole or in part, for any purpose, is hereby granted, + * provided that: + * + * 1. This copyright and permission notice appear in all copies of the + * software and its documentation. Notices of copyright or attribution + * which appear at the beginning of any file must remain unchanged. + * + * 2. The name of Index Data or the individual authors may not be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR + * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * $Id: record_conv.h,v 1.1 2006-05-02 20:47:45 adam Exp $ + */ +/** + * \file record_conv.h + * \brief Record Conversions Utility + */ + +#ifndef YAZ_RECORD_CONV_H +#define YAZ_RECORD_CONV_H + +#include +#include + +YAZ_BEGIN_CDECL + +/** record conversion handle */ +typedef struct yaz_record_conv_struct *yaz_record_conv_t; + +/** creates record handle + \return record handle +*/ +YAZ_EXPORT yaz_record_conv_t yaz_record_conv_create(void); + +/** destroys record handle + \param p record conversion handle +*/ +YAZ_EXPORT void yaz_record_conv_destroy(yaz_record_conv_t p); + + +/** configures record conversion + \param p record conversion handle + \param node xmlNode pointer (root element of XML config) + \retval 0 success + \retval -1 failure + + \verbatim + + + + + \endverbatim + + \verbatim + + + + + + \endverbatim + + For retrieval (ignore here): + \verbatim + + + MARCXML + + + + + + + + \endverbatim +*/ +YAZ_EXPORT +int yaz_record_conv_configure(yaz_record_conv_t p, const void *node); + + +/** returns error string (for last error) + \param p record conversion handle + \return error string +*/ +YAZ_EXPORT +const char *yaz_record_conv_get_error(yaz_record_conv_t p); + +YAZ_END_CDECL + +#endif +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/src/Makefile.am b/src/Makefile.am index 27112a1..0a8ce04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ ## This file is part of the YAZ toolkit. ## Copyright (C) 1994-2006, Index Data, All rights reserved. -## $Id: Makefile.am,v 1.32 2006-04-21 12:54:36 marc Exp $ +## $Id: Makefile.am,v 1.33 2006-05-02 20:47:45 adam Exp $ YAZ_VERSION_INFO=2:1:0 @@ -71,6 +71,7 @@ libyaz_la_SOURCES=version.c options.c log.c marcdisp.c oid.c wrbuf.c \ eventl.c seshigh.c statserv.c requestq.c tcpdchk.c \ eventl.h service.c service.h session.h test.c \ xmlquery.c \ + record_conv.c \ mime.c mime.h libyaz_la_LDFLAGS=-version-info $(YAZ_VERSION_INFO) diff --git a/src/marcdisp.c b/src/marcdisp.c index f56f280..da04f45 100644 --- a/src/marcdisp.c +++ b/src/marcdisp.c @@ -2,7 +2,7 @@ * Copyright (C) 1995-2006, Index Data ApS * See the file LICENSE for details. * - * $Id: marcdisp.c,v 1.28 2006-04-20 20:35:02 adam Exp $ + * $Id: marcdisp.c,v 1.29 2006-05-02 20:47:45 adam Exp $ */ /** @@ -132,25 +132,6 @@ void yaz_marc_add_comment(yaz_marc_t mt, char *comment) n->u.comment = nmem_strdup(mt->nmem, comment); } -#if HAVE_XML2 -static char *yaz_marc_get_xml_text(const xmlNode *ptr_cdata, NMEM nmem) -{ - char *cdata; - int len = 0; - const xmlNode *ptr; - - for (ptr = ptr_cdata; ptr; ptr = ptr->next) - if (ptr->type == XML_TEXT_NODE) - len += xmlStrlen(ptr->content); - cdata = (char *) nmem_malloc(nmem, len+1); - *cdata = '\0'; - for (ptr = ptr_cdata; ptr; ptr = ptr->next) - if (ptr->type == XML_TEXT_NODE) - strcat(cdata, (const char *) ptr->content); - return cdata; -} -#endif - void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...) { va_list ap; @@ -206,8 +187,8 @@ void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag, { struct yaz_marc_node *n = yaz_marc_add_node(mt); n->which = YAZ_MARC_CONTROLFIELD; - n->u.controlfield.tag = yaz_marc_get_xml_text(ptr_tag, mt->nmem); - n->u.controlfield.data = yaz_marc_get_xml_text(ptr_data, mt->nmem); + n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem); + n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem); } #endif @@ -231,7 +212,7 @@ void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag, { struct yaz_marc_node *n = yaz_marc_add_node(mt); n->which = YAZ_MARC_DATAFIELD; - n->u.datafield.tag = yaz_marc_get_xml_text(ptr_tag, mt->nmem); + n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem); n->u.datafield.indicator = nmem_strdupn(mt->nmem, indicator, indicator_len); n->u.datafield.subfields = 0; diff --git a/src/nmemsdup.c b/src/nmemsdup.c index 2c8e7d8..2c537f6 100644 --- a/src/nmemsdup.c +++ b/src/nmemsdup.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 1995-2005, Index Data ApS + * Copyright (C) 1995-2006, Index Data ApS * See the file LICENSE for details. * - * $Id: nmemsdup.c,v 1.5 2005-06-25 15:46:04 adam Exp $ + * $Id: nmemsdup.c,v 1.6 2006-05-02 20:47:45 adam Exp $ */ /** @@ -16,6 +16,9 @@ #include #include +#if HAVE_XML2 +#include +#endif char *nmem_strdup (NMEM mem, const char *src) { @@ -78,6 +81,25 @@ void nmem_strsplit(NMEM nmem, const char *delim, const char *dstr, } } +#if HAVE_XML2 +char *nmem_text_node_cdata(const void *ptr_cdata, NMEM nmem) +{ + char *cdata; + int len = 0; + const xmlNode *ptr; + + for (ptr = (const xmlNode *) ptr_cdata; ptr; ptr = ptr->next) + if (ptr->type == XML_TEXT_NODE) + len += xmlStrlen(ptr->content); + cdata = (char *) nmem_malloc(nmem, len+1); + *cdata = '\0'; + for (ptr = (const xmlNode *) ptr_cdata; ptr; ptr = ptr->next) + if (ptr->type == XML_TEXT_NODE) + strcat(cdata, (const char *) ptr->content); + return cdata; +} +#endif + /* * Local variables: * c-basic-offset: 4 diff --git a/src/record_conv.c b/src/record_conv.c new file mode 100644 index 0000000..4ceb023 --- /dev/null +++ b/src/record_conv.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2005-2006, Index Data ApS + * See the file LICENSE for details. + * + * $Id: record_conv.c,v 1.1 2006-05-02 20:47:45 adam Exp $ + */ +/** + * \file record_conv.c + * \brief Record Conversions utility + */ + +#if HAVE_CONFIG_H +#include +#endif + +#if HAVE_XML2 +#include +#include +#endif + +#include + +#include +#include +#include +#include + +/** \brief The internal structure for yaz_record_conv_t */ +struct yaz_record_conv_struct { + /** memory for configuration */ + NMEM nmem; + + /** conversion rules (allocated using NMEM) */ + struct yaz_record_conv_rule *rules; + + /** pointer to last conversion rule pointer in chain */ + struct yaz_record_conv_rule **rules_p; + + /** string buffer for error messages */ + WRBUF wr_error; +}; + +/** \brief tranformation types (rule types) */ +enum YAZ_RECORD_CONV_RULE +{ + YAZ_RECORD_CONV_RULE_XSLT, + YAZ_RECORD_CONV_RULE_MARC_TO_XML, + YAZ_RECORD_CONV_RULE_XML_TO_MARC +}; + +/** \brief tranformation info (rule info) */ +struct yaz_record_conv_rule { + enum YAZ_RECORD_CONV_RULE which; + union { + struct { + const char *stylesheet; + } xslt; + struct { + const char *charset; + } marc_to_xml; + struct { + const char *charset; + } xml_to_marc; + } u; + struct yaz_record_conv_rule *next; +}; + +yaz_record_conv_t yaz_record_conv_create() +{ + yaz_record_conv_t p = xmalloc(sizeof(*p)); + p->nmem = nmem_create(); + p->wr_error = wrbuf_alloc(); + return p; +} + +void yaz_record_conv_destroy(yaz_record_conv_t p) +{ + if (p) + { + nmem_destroy(p->nmem); + wrbuf_free(p->wr_error, 1); + xfree(p); + } +} + +#if HAVE_XML2 +static struct yaz_record_conv_rule *add_rule(yaz_record_conv_t p, + enum YAZ_RECORD_CONV_RULE type) +{ + struct yaz_record_conv_rule *r = nmem_malloc(p->nmem, sizeof(*r)); + r->which = type; + r->next = 0; + *p->rules_p = r; + p->rules_p = &r->next; + return r; +} + +static void yaz_record_conv_reset(yaz_record_conv_t p) +{ + wrbuf_rewind(p->wr_error); + nmem_reset(p->nmem); + p->rules = 0; + p->rules_p = &p->rules; +} + +static int conv_xslt(yaz_record_conv_t p, const xmlNode *ptr) +{ + struct _xmlAttr *attr; + const char *stylesheet = 0; + + for (attr = ptr->properties; attr; attr = attr->next) + { + if (!xmlStrcmp(attr->name, BAD_CAST "stylesheet") && + attr->children && attr->children->type == XML_TEXT_NODE) + stylesheet = (const char *) attr->children->content; + else + { + wrbuf_printf(p->wr_error, "Bad attribute '%s'." + "Expected stylesheet.", attr->name); + return -1; + } + } + if (stylesheet) + { + struct yaz_record_conv_rule *r = + add_rule(p, YAZ_RECORD_CONV_RULE_XSLT); + r->u.xslt.stylesheet = nmem_strdup(p->nmem, stylesheet); + return 0; + } + wrbuf_printf(p->wr_error, "Missing attribute 'stylesheet'"); + return -1; +} + +static int conv_marc_to_xml(yaz_record_conv_t p, const xmlNode *ptr) +{ + struct _xmlAttr *attr; + const char *charset = 0; + struct yaz_record_conv_rule *r; + + for (attr = ptr->properties; attr; attr = attr->next) + { + if (!xmlStrcmp(attr->name, BAD_CAST "charset") && + attr->children && attr->children->type == XML_TEXT_NODE) + charset = (const char *) attr->children->content; + else + { + wrbuf_printf(p->wr_error, "Bad attribute '%s'." + "Expected charset.", attr->name); + return -1; + } + } + r = add_rule(p, YAZ_RECORD_CONV_RULE_MARC_TO_XML); + if (charset) + r->u.marc_to_xml.charset = nmem_strdup(p->nmem, charset); + else + r->u.marc_to_xml.charset = 0; + return 0; +} + +static int conv_xml_to_marc(yaz_record_conv_t p, const xmlNode *ptr) +{ + struct _xmlAttr *attr; + const char *charset = 0; + struct yaz_record_conv_rule *r; + + for (attr = ptr->properties; attr; attr = attr->next) + { + if (!xmlStrcmp(attr->name, BAD_CAST "charset") && + attr->children && attr->children->type == XML_TEXT_NODE) + charset = (const char *) attr->children->content; + else + { + wrbuf_printf(p->wr_error, "Bad attribute '%s'." + "Expected charset.", attr->name); + return -1; + } + } + r = add_rule(p, YAZ_RECORD_CONV_RULE_XML_TO_MARC); + if (charset) + r->u.xml_to_marc.charset = nmem_strdup(p->nmem, charset); + else + r->u.xml_to_marc.charset = 0; + return 0; +} + + +int yaz_record_conv_configure(yaz_record_conv_t p, const void *ptr_v) +{ + const xmlNode *ptr = ptr_v; + + yaz_record_conv_reset(p); + + if (ptr && ptr->type == XML_ELEMENT_NODE && + !strcmp((const char *) ptr->name, "convert")) + { + for (ptr = ptr->children; ptr; ptr = ptr->next) + { + if (ptr->type != XML_ELEMENT_NODE) + continue; + if (!strcmp((const char *) ptr->name, "xslt")) + { + if (conv_xslt(p, ptr)) + return -1; + } + else if (!strcmp((const char *) ptr->name, "marc_to_xml")) + { + if (conv_marc_to_xml(p, ptr)) + return -1; + } + else if (!strcmp((const char *) ptr->name, "xml_to_marc")) + { + if (conv_xml_to_marc(p, ptr)) + return -1; + } + else + { + wrbuf_printf(p->wr_error, "Bad element '%s'." + "Expected xslt, marc_to_xml,...", ptr->name); + return -1; + } + } + } + else + { + wrbuf_printf(p->wr_error, "Missing 'convert' element"); + return -1; + } + return 0; +} + +#else +/* HAVE_XML2 */ +int yaz_record_conv_configure(yaz_record_conv_t p, const void *ptr_v) +{ + wrbuf_rewind(p->wr_error); + wrbuf_printf(p->wr_error, "No XML support for yaz_record_conv"); + return -1; +} + +#endif + +const char *yaz_record_conv_get_error(yaz_record_conv_t p) +{ + return wrbuf_buf(p->wr_error); +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/src/xmlquery.c b/src/xmlquery.c index 4b15a36..2323509 100644 --- a/src/xmlquery.c +++ b/src/xmlquery.c @@ -2,7 +2,7 @@ * Copyright (C) 1995-2006, Index Data ApS * All rights reserved. * - * $Id: xmlquery.c,v 1.8 2006-04-20 20:50:51 adam Exp $ + * $Id: xmlquery.c,v 1.9 2006-05-02 20:47:45 adam Exp $ */ /** \file xmlquery.c @@ -500,19 +500,7 @@ void yaz_xml2query_attribute_element(const xmlNode *ptr, char *strVal(const xmlNode *ptr_cdata, ODR odr) { - char *cdata; - int len = 0; - const xmlNode *ptr; - - for (ptr = ptr_cdata; ptr; ptr = ptr->next) - if (ptr->type == XML_TEXT_NODE) - len += xmlStrlen(ptr->content); - cdata = (char *) odr_malloc(odr, len+1); - *cdata = '\0'; - for (ptr = ptr_cdata; ptr; ptr = ptr->next) - if (ptr->type == XML_TEXT_NODE) - strcat(cdata, (const char *) ptr->content); - return cdata; + return nmem_text_node_cdata(ptr_cdata, odr->mem); } void yaz_xml2query_term(const xmlNode *ptr, diff --git a/test/.cvsignore b/test/.cvsignore index db75146..3280e94 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -17,3 +17,5 @@ tstodrstack tstlogthread tstxmlquery tstpquery +tst_filepath +tst_record_conv diff --git a/test/Makefile.am b/test/Makefile.am index 78756d6..7ddfe2d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,10 +1,10 @@ -## Copyright (C) 1994-2006, Index Data +## Copyright (C) 1994-2006, Index Data ApS ## All rights reserved. -## $Id: Makefile.am,v 1.14 2006-04-26 09:40:43 adam Exp $ +## $Id: Makefile.am,v 1.15 2006-05-02 20:47:46 adam Exp $ check_PROGRAMS = tsticonv tstnmem tstmatchstr tstwrbuf tstodr tstccl tstlog \ tstsoap1 tstsoap2 tstodrstack tstlogthread tstxmlquery tstpquery \ - tst_filepath + tst_filepath tst_record_conv check_SCRIPTS = tstcql.sh tstmarciso.sh tstmarcxml.sh TESTS = $(check_PROGRAMS) $(check_SCRIPTS) @@ -50,4 +50,5 @@ tstlogthread_SOURCES = tstlogthread.c tstxmlquery_SOURCES = tstxmlquery.c tstpquery_SOURCES = tstpquery.c tst_filepath_SOURCES = tst_filepath.c +tst_record_conv_SOURCES = tst_record_conv.c diff --git a/test/tst_record_conv.c b/test/tst_record_conv.c new file mode 100644 index 0000000..66460e0 --- /dev/null +++ b/test/tst_record_conv.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2005-2006, Index Data ApS + * See the file LICENSE for details. + * + * $Id: tst_record_conv.c,v 1.1 2006-05-02 20:47:46 adam Exp $ + * + */ +#include +#include +#include +#include + +#if HAVE_XML2 + +#include +#include + +yaz_record_conv_t conv_from_xml(const char *xmlstring, WRBUF w) +{ + xmlDocPtr doc = xmlParseMemory(xmlstring, strlen(xmlstring)); + if (!doc) + { + wrbuf_printf(w, "xmlParseMemory"); + return 0; + } + else + { + xmlNodePtr ptr = xmlDocGetRootElement(doc); + yaz_record_conv_t p = yaz_record_conv_create(); + + if (!ptr) + { + wrbuf_printf(w, "xmlDocGetRootElement"); + yaz_record_conv_destroy(p); + p = 0; + } + else if (!p) + { + wrbuf_printf(w, "yaz_record_conv_create"); + } + else + { + int r = yaz_record_conv_configure(p, ptr); + + if (r) + { + wrbuf_puts(w, yaz_record_conv_get_error(p)); + yaz_record_conv_destroy(p); + p = 0; + } + } + xmlFreeDoc(doc); + return p; + } +} + +int conv_from_xml_compare(const char *xmlstring, const char *expect_error, + yaz_record_conv_t *pt) +{ + WRBUF w = wrbuf_alloc(); + int ret; + + yaz_record_conv_t p = conv_from_xml(xmlstring, w); + + if (!p) + { + if (expect_error && !strcmp(wrbuf_buf(w), expect_error)) + ret = 1; + else + ret = 0; + } + else + { + if (expect_error) + { + ret = 0; + yaz_record_conv_destroy(p); + } + else + { + if (pt) + *pt = p; + else + yaz_record_conv_destroy(p); + ret = 1; + } + } + wrbuf_free(w, 1); + return ret; +} + +static void tst() +{ + YAZ_CHECK(conv_from_xml_compare("", "Missing 'convert' element", 0)); + YAZ_CHECK(conv_from_xml_compare("", 0, 0)); + YAZ_CHECK(conv_from_xml_compare("", + "Bad element 'bad'." + "Expected xslt, marc_to_xml,...", 0)); + YAZ_CHECK(conv_from_xml_compare("" + "" + "" + "", + 0, 0)); +} +#endif + +int main(int argc, char **argv) +{ + YAZ_CHECK_INIT(argc, argv); +#if HAVE_XML2 + tst(); +#endif + YAZ_CHECK_TERM; +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + -- 1.7.10.4