* Copyright (C) 1995-2005, Index Data ApS
* All rights reserved.
*
- * $Id: xmlquery.c,v 1.3 2006-02-02 15:00:58 adam Exp $
+ * $Id: xmlquery.c,v 1.4 2006-02-19 18:44:23 adam Exp $
*/
/**
*/
#include <stdio.h>
+#include <string.h>
#include <assert.h>
#if HAVE_XML2
xmlNewProp(node, BAD_CAST "knownProximityUnit",
BAD_CAST formstr);
break;
+ case Z_ProximityOperator_private:
default:
xmlNewProp(node, BAD_CAST "privateProximityUnit",
BAD_CAST "private");
child_node = yaz_query2xml_cql(q->u.type_104->u.cql, top_node);
}
}
-
if (child_node && type)
{
*docp = xmlNewDoc(BAD_CAST "1.0");
}
}
-void yaz_xml2query(const xmlNode node, Z_Query **q, ODR odr)
+bool_t *boolVal(ODR odr, const char *str)
{
+ if (*str == '\0' || strchr("0fF", *str))
+ return odr_intdup(odr, 0);
+ return odr_intdup(odr, 1);
+}
+
+int *intVal(ODR odr, const char *str)
+{
+ return odr_intdup(odr, atoi(str));
+}
+void yaz_xml2query_operator(const xmlNode *ptr, Z_Operator **op,
+ ODR odr, int *error_code, const char **addinfo)
+{
+ const char *type = (const char *)
+ xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
+ if (!type)
+ {
+ *error_code = 1;
+ *addinfo = "no operator type";
+ return;
+ }
+ *op = (Z_Operator*) odr_malloc(odr, sizeof(Z_Operator));
+ if (!strcmp(type, "and"))
+ {
+ (*op)->which = Z_Operator_and;
+ (*op)->u.op_and = odr_nullval();
+ }
+ else if (!strcmp(type, "or"))
+ {
+ (*op)->which = Z_Operator_or;
+ (*op)->u.op_or = odr_nullval();
+ }
+ else if (!strcmp(type, "not"))
+ {
+ (*op)->which = Z_Operator_and_not;
+ (*op)->u.and_not = odr_nullval();
+ }
+ else if (!strcmp(type, "prox"))
+ {
+ const char *atval;
+ Z_ProximityOperator *pop = (Z_ProximityOperator *)
+ odr_malloc(odr, sizeof(Z_ProximityOperator));
+
+ (*op)->which = Z_Operator_prox;
+ (*op)->u.prox = pop;
+
+ atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
+ BAD_CAST "exclusion");
+ if (atval)
+ pop->exclusion = boolVal(odr, atval);
+ else
+ pop->exclusion = 0;
+
+ atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
+ BAD_CAST "distance");
+ if (atval)
+ pop->distance = intVal(odr, atval);
+ else
+ pop->distance = odr_intdup(odr, 1);
+
+ atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
+ BAD_CAST "ordered");
+ if (atval)
+ pop->ordered = boolVal(odr, atval);
+ else
+ pop->ordered = odr_intdup(odr, 1);
+
+ atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
+ BAD_CAST "relationType");
+ if (atval)
+ pop->relationType = intVal(odr, atval);
+ else
+ pop->relationType =
+ odr_intdup(odr, Z_ProximityOperator_Prox_lessThanOrEqual);
+
+ atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
+ BAD_CAST "knownProximityUnit");
+ if (atval)
+ {
+ pop->which = Z_ProximityOperator_known;
+ pop->u.known = intVal(odr, atval);
+ }
+ else
+ {
+ pop->which = Z_ProximityOperator_known;
+ pop->u.known = odr_intdup(odr, Z_ProxUnit_word);
+ }
+
+ atval = (const char *) xmlGetProp((xmlNodePtr) ptr,
+ BAD_CAST "privateProximityUnit");
+ if (atval)
+ {
+ pop->which = Z_ProximityOperator_private;
+ pop->u.zprivate = intVal(odr, atval);
+ }
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "bad operator type";
+ }
+}
+
+void yaz_xml2query_attribute_element(const xmlNode *ptr,
+ Z_AttributeElement **elem, ODR odr,
+ int *error_code, const char **addinfo)
+{
+ int i;
+ xmlChar *set = 0;
+ xmlChar *type = 0;
+ xmlChar *value = 0;
+ int num_values = 0;
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!xmlStrcmp(attr->name, BAD_CAST "set") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ set = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ type = attr->children->content;
+ else if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ {
+ value = attr->children->content;
+ num_values++;
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "bad attribute for attr content";
+ return;
+ }
+ }
+ if (!type)
+ {
+ *error_code = 1;
+ *addinfo = "missing type attribute for att content";
+ return;
+ }
+ if (!value)
+ {
+ *error_code = 1;
+ *addinfo = "missing value attribute for att content";
+ return;
+ }
+
+ *elem = (Z_AttributeElement *) odr_malloc(odr, sizeof(**elem));
+ if (set)
+ (*elem)->attributeSet = yaz_str_to_z3950oid(odr, CLASS_ATTSET,
+ (const char *)set);
+ else
+ (*elem)->attributeSet = 0;
+ (*elem)->attributeType = intVal(odr, (const char *) type);
+
+ /* looks like a number ? */
+ for (i = 0; value[i] && value[i] >= '0' && value[i] <= '9'; i++)
+ ;
+ if (num_values > 1 || value[i])
+ { /* multiple values or string, so turn to complex attribute */
+ (*elem)->which = Z_AttributeValue_complex;
+ (*elem)->value.complex =
+ (Z_ComplexAttribute*) odr_malloc(odr, sizeof(Z_ComplexAttribute));
+ (*elem)->value.complex->num_list = num_values;
+ (*elem)->value.complex->list = (Z_StringOrNumeric **)
+ odr_malloc(odr, sizeof(Z_StringOrNumeric*) * num_values);
+
+ /* second pass over attr values */
+ i = 0;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!xmlStrcmp(attr->name, BAD_CAST "value") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ {
+ const char *val = (const char *) attr->children->content;
+ assert (i < num_values);
+ (*elem)->value.complex->list[i] = (Z_StringOrNumeric *)
+ odr_malloc(odr, sizeof(Z_StringOrNumeric));
+ (*elem)->value.complex->list[i]->which =
+ Z_StringOrNumeric_string;
+ (*elem)->value.complex->list[i]->u.string =
+ odr_strdup(odr, val);
+ i++;
+ }
+ }
+ (*elem)->value.complex->num_semanticAction = 0;
+ (*elem)->value.complex->semanticAction = 0;
+ }
+ else
+ { /* good'ld numeric value */
+ (*elem)->which = Z_AttributeValue_numeric;
+ (*elem)->value.numeric = intVal(odr, (const char *) value);
+ }
+}
+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;
}
+void yaz_xml2query_term(const xmlNode *ptr,
+ Z_Term **term, ODR odr,
+ int *error_code, const char **addinfo)
+{
+ xmlChar *type = 0;
+ struct _xmlAttr *attr;
+ char *cdata = strVal(ptr->children, odr);
+
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!xmlStrcmp(attr->name, BAD_CAST "type") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ type = attr->children->content;
+ else
+ {
+ *error_code = 1;
+ *addinfo = "bad attribute for attr content";
+ return;
+ }
+ }
+ *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term));
+
+ if (!type || !xmlStrcmp(type, BAD_CAST "general"))
+ {
+ (*term)->which = Z_Term_general;
+ (*term)->u.general =
+ odr_create_Odr_oct(odr, (unsigned char *)cdata, strlen(cdata));
+ }
+ else if (!xmlStrcmp(type, BAD_CAST "numeric"))
+ {
+ (*term)->which = Z_Term_numeric;
+ (*term)->u.numeric = intVal(odr, cdata);
+ }
+ else if (!xmlStrcmp(type, BAD_CAST "string"))
+ {
+ (*term)->which = Z_Term_characterString;
+ (*term)->u.characterString = cdata;
+ }
+ else if (!xmlStrcmp(type, BAD_CAST "oid"))
+ {
+ *error_code = 1;
+ *addinfo = "unhandled term type: oid";
+ }
+ else if (!xmlStrcmp(type, BAD_CAST "dateTime"))
+ {
+ *error_code = 1;
+ *addinfo = "unhandled term type: dateTime";
+ }
+ else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit"))
+ {
+ *error_code = 1;
+ *addinfo = "unhandled term type: integerAndUnit";
+ }
+ else if (!xmlStrcmp(type, BAD_CAST "null"))
+ {
+ (*term)->which = Z_Term_null;
+ (*term)->u.null = odr_nullval();
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "unhandled term type";
+ }
+}
+
+void yaz_xml2query_apt(const xmlNode *ptr_apt,
+ Z_AttributesPlusTerm **zapt, ODR odr,
+ int *error_code, const char **addinfo)
+{
+ const xmlNode *ptr = ptr_apt->children;
+ int i, num_attr = 0;
+
+ *zapt = (Z_AttributesPlusTerm *)
+ odr_malloc(odr, sizeof(Z_AttributesPlusTerm));
+
+ /* deal with attributes */
+ (*zapt)->attributes = (Z_AttributeList*)
+ odr_malloc(odr, sizeof(Z_AttributeList));
+
+ /* how many attributes? */
+ for (; ptr; ptr = ptr->next)
+ if (ptr->type == XML_ELEMENT_NODE)
+ {
+ if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
+ num_attr++;
+ else
+ break;
+ }
+
+ /* allocate and parse for real */
+ (*zapt)->attributes->num_attributes = num_attr;
+ (*zapt)->attributes->attributes = (Z_AttributeElement **)
+ odr_malloc(odr, sizeof(Z_AttributeElement*) * num_attr);
+
+ i = 0;
+ ptr = ptr_apt->children;
+ for (; ptr; ptr = ptr->next)
+ if (ptr->type == XML_ELEMENT_NODE)
+ {
+ if (!xmlStrcmp(ptr->name, BAD_CAST "attr"))
+ {
+ yaz_xml2query_attribute_element(
+ ptr, &(*zapt)->attributes->attributes[i], odr,
+ error_code, addinfo);
+ i++;
+ }
+ else
+ break;
+ }
+ if (ptr && ptr->type == XML_ELEMENT_NODE)
+ {
+ if (!xmlStrcmp(ptr->name, BAD_CAST "term"))
+ {
+ /* deal with term */
+ yaz_xml2query_term(ptr, &(*zapt)->term, odr, error_code, addinfo);
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "bad element in apt content";
+ }
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "missing term node in apt content";
+ }
+}
+
+void yaz_xml2query_rset(const xmlNode *ptr, Z_ResultSetId **rset,
+ ODR odr, int *error_code, const char **addinfo)
+{
+ if (ptr->children)
+ {
+ *rset = strVal(ptr->children, odr);
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "missing rset content";
+ }
+}
+
+void yaz_xml2query_rpnstructure(const xmlNode *ptr, Z_RPNStructure **zs,
+ ODR odr, int *error_code, const char **addinfo)
+{
+ while (ptr && ptr->type != XML_ELEMENT_NODE)
+ ptr = ptr->next;
+
+ if (!ptr || ptr->type != XML_ELEMENT_NODE)
+ {
+ *error_code = 1;
+ *addinfo = "missing rpn structure node";
+ return;
+ }
+ *zs = (Z_RPNStructure *) odr_malloc(odr, sizeof(Z_RPNStructure));
+ if (!xmlStrcmp(ptr->name, BAD_CAST "binary"))
+ {
+ Z_Complex *zc = odr_malloc(odr, sizeof(Z_Complex));
+
+ (*zs)->which = Z_RPNStructure_complex;
+ (*zs)->u.complex = zc;
+
+ yaz_xml2query_operator(ptr, &zc->roperator, odr, error_code, addinfo);
+
+ ptr = ptr->children;
+ while (ptr && ptr->type != XML_ELEMENT_NODE)
+ ptr = ptr->next;
+ yaz_xml2query_rpnstructure(ptr, &zc->s1, odr, error_code, addinfo);
+ if (ptr)
+ ptr = ptr->next;
+ while (ptr && ptr->type != XML_ELEMENT_NODE)
+ ptr = ptr->next;
+ yaz_xml2query_rpnstructure(ptr, &zc->s2, odr, error_code, addinfo);
+ }
+ else
+ {
+ Z_Operand *s = (Z_Operand *) odr_malloc(odr, sizeof(Z_Operand));
+ (*zs)->which = Z_RPNStructure_simple;
+ (*zs)->u.simple = s;
+ if (!xmlStrcmp(ptr->name, BAD_CAST "apt"))
+ {
+ s->which = Z_Operand_APT;
+ yaz_xml2query_apt(ptr, &s->u.attributesPlusTerm,
+ odr, error_code, addinfo);
+ }
+ else if (!xmlStrcmp(ptr->name, BAD_CAST "rset"))
+ {
+ s->which = Z_Operand_resultSetId;
+ yaz_xml2query_rset(ptr, &s->u.resultSetId,
+ odr, error_code, addinfo);
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "bad element: expected binary, apt or rset";
+ }
+ }
+}
+
+void yaz_xml2query_rpn(const xmlNode *ptr, Z_RPNQuery **query, ODR odr,
+ int *error_code, const char **addinfo)
+{
+ const char *set = (const char *)
+ xmlGetProp((xmlNodePtr) ptr, BAD_CAST "set");
+
+ *query = (Z_RPNQuery*) odr_malloc(odr, sizeof(Z_RPNQuery));
+ if (set)
+ (*query)->attributeSetId = yaz_str_to_z3950oid(odr, CLASS_ATTSET, set);
+ else
+ (*query)->attributeSetId = 0;
+ yaz_xml2query_rpnstructure(ptr->children, &(*query)->RPNStructure,
+ odr, error_code, addinfo);
+}
+
+static void yaz_xml2query_(const xmlNode *ptr, Z_Query **query, ODR odr,
+ int *error_code, const char **addinfo)
+{
+ if (ptr && ptr->type == XML_ELEMENT_NODE &&
+ !xmlStrcmp(ptr->name, BAD_CAST "query"))
+ {
+ const char *type = (const char *)
+ xmlGetProp((xmlNodePtr) ptr, BAD_CAST "type");
+ *query = (Z_Query*) odr_malloc(odr, sizeof(Z_Query));
+ if (!type || !strcmp(type, "rpn"))
+ {
+ (*query)->which = Z_Query_type_1;
+ yaz_xml2query_rpn(ptr, &(*query)->u.type_1, odr,
+ error_code, addinfo);
+ }
+ else if (!strcmp(type, "ccl"))
+ {
+ *error_code = 1;
+ *addinfo = "ccl not supported yet";
+ }
+ else if (!strcmp(type, "z39.58"))
+ {
+ *error_code = 1;
+ *addinfo = "z39.58 not supported yet";
+ }
+ else if (!strcmp(type, "cql"))
+ {
+ *error_code = 1;
+ *addinfo = "cql not supported yet";
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "unsupported query type";
+ }
+ }
+ else
+ {
+ *error_code = 1;
+ *addinfo = "missing query element";
+ }
+}
+
+void yaz_xml2query(const void *xmlnodep, Z_Query **query, ODR odr,
+ int *error_code, const char **addinfo)
+{
+ return yaz_xml2query_(xmlnodep, query, odr, error_code, addinfo);
+}
/* HAVE_XML2 */
#endif
* Copyright (C) 1995-2005, Index Data ApS
* See the file LICENSE for details.
*
- * $Id: tstxmlquery.c,v 1.8 2006-02-02 15:00:58 adam Exp $
+ * $Id: tstxmlquery.c,v 1.9 2006-02-19 18:44:23 adam Exp $
*/
#include <stdlib.h>
#include <stdio.h>
#include <yaz/wrbuf.h>
+#include <yaz/querytowrbuf.h>
#include <yaz/xmlquery.h>
#include <yaz/pquery.h>
#include <yaz/test.h>
XML_NO_ERROR
};
-enum pqf2xml_status pqf2xml_text(const char *pqf, const char *expect_xml)
+enum pqf2xml_status pqf2xml_text(const char *pqf, const char *expect_xml,
+ const char *expect_pqf)
{
YAZ_PQF_Parser parser = yaz_pqf_create();
ODR odr = odr_createmem(ODR_ENCODE);
if (len_out == strlen(expect_xml)
&& memcmp(buf_out, expect_xml, len_out) == 0)
{
- status = XML_MATCH;
+ Z_Query *query2 = 0;
+ int error_code = 0;
+ const char *addinfo = 0;
+ const xmlNode *root_element = xmlDocGetRootElement(doc);
+ ODR odr2 = odr_createmem(ODR_ENCODE);
+
+ yaz_xml2query(root_element, &query2, odr2,
+ &error_code, &addinfo);
+ if (error_code || !query2)
+ status = XML_NO_MATCH;
+ else
+ {
+ WRBUF w = wrbuf_alloc();
+ yaz_query_to_wrbuf(w, query2);
+ if (!expect_pqf || strcmp(expect_pqf, wrbuf_buf(w)) == 0)
+ status = XML_MATCH;
+ else
+ {
+ status = XML_NO_MATCH;
+ printf("Result: %s\n", wrbuf_buf(w));
+ }
+ wrbuf_free(w, 1);
+ }
+ odr_destroy(odr2);
}
else
{
return status;
}
-void tst()
+static void tst()
{
- YAZ_CHECK_EQ(pqf2xml_text("@attr 1=4 bad query", ""), PQF_FAILED);
+ YAZ_CHECK_EQ(pqf2xml_text("@attr 1=4 bad query", "", 0), PQF_FAILED);
#if HAVE_XML2
YAZ_CHECK_EQ(pqf2xml_text(
"@attr 1=4 computer",
"<query set=\"Bib-1\" type=\"rpn\">"
"<apt><attr type=\"1\" value=\"4\"/>"
"<term type=\"general\">computer</term></apt>"
- "</query>\n"), XML_MATCH);
+ "</query>\n",
+ "RPN: @attrset Bib-1 @attr 1=4 computer"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
"@attr 2=1 @attr 1=title computer",
"<apt><attr type=\"1\" value=\"title\"/>"
"<attr type=\"2\" value=\"1\"/>"
"<term type=\"general\">computer</term></apt>"
- "</query>\n"), XML_MATCH);
+ "</query>\n",
+ "RPN: @attrset Bib-1 @attr \"1=title\" @attr 2=1 computer"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
"@attr 2=1 @attr exp1 1=1 computer",
"<apt><attr set=\"Exp-1\" type=\"1\" value=\"1\"/>"
"<attr type=\"2\" value=\"1\"/>"
"<term type=\"general\">computer</term></apt>"
- "</query>\n"), XML_MATCH);
+ "</query>\n",
+ "RPN: @attrset Bib-1 @attr Exp-1 1=1 @attr 2=1 computer"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
"@and a b",
"<binary type=\"and\">"
"<apt><term type=\"general\">a</term></apt>"
"<apt><term type=\"general\">b</term></apt>"
- "</binary></query>\n"), XML_MATCH);
+ "</binary></query>\n",
+ "RPN: @attrset Bib-1 @and a b"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
"@or @and a b c",
"<apt><term type=\"general\">a</term></apt>"
"<apt><term type=\"general\">b</term></apt></binary>"
"<apt><term type=\"general\">c</term></apt>"
- "</binary></query>\n"), XML_MATCH);
+ "</binary></query>\n",
+ "RPN: @attrset Bib-1 @or @and a b c"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
"@set abe",
"<?xml version=\"1.0\"?>\n"
"<query set=\"Bib-1\" type=\"rpn\">"
- "<rset>abe</rset></query>\n"), XML_MATCH);
+ "<rset>abe</rset></query>\n",
+ "RPN: @attrset Bib-1 @set abe"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
/* exclusion, distance, ordered, relationtype,
"knownProximityUnit=\"2\">"
"<apt><term type=\"general\">a</term></apt>"
"<apt><term type=\"general\">b</term></apt>"
- "</binary></query>\n"), XML_MATCH);
+ "</binary></query>\n",
+ "RPN: @attrset Bib-1 @prox 0 3 1 2 k 2 a b"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
"@term numeric 32",
"<query set=\"Bib-1\" type=\"rpn\">"
"<apt>"
"<term type=\"numeric\">32</term></apt>"
- "</query>\n"), XML_MATCH);
+ "</query>\n",
+ "RPN: @attrset Bib-1 @term numeric 32"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
"@term string computer",
"<query set=\"Bib-1\" type=\"rpn\">"
"<apt>"
"<term type=\"string\">computer</term></apt>"
- "</query>\n"), XML_MATCH);
+ "</query>\n",
+ "RPN: @attrset Bib-1 @term string computer"
+ ), XML_MATCH);
YAZ_CHECK_EQ(pqf2xml_text(
"@term null void",
"<query set=\"Bib-1\" type=\"rpn\">"
"<apt>"
"<term type=\"null\"/></apt>"
- "</query>\n"), XML_MATCH);
-
+ "</query>\n",
+ "RPN: @attrset Bib-1 @term null x"
+ ), XML_MATCH);
+
+ YAZ_CHECK_EQ(pqf2xml_text(
+ "@attrset gils @attr 4=2 x",
+ "<?xml version=\"1.0\"?>\n"
+ "<query set=\"GILS\" type=\"rpn\">"
+ "<apt>"
+ "<attr type=\"4\" value=\"2\"/>"
+ "<term type=\"general\">x</term></apt>"
+ "</query>\n",
+ "RPN: @attrset GILS @attr 4=2 x"
+ ), XML_MATCH);
#endif
}