home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / rdf / src / qryparse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  15.3 KB  |  433 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* qryparse.c
  20.  
  21. A parser for queries expressed in RDF syntax.
  22.  
  23. There is a query tag (RDF:Query) which encloses one or more literal tags. 
  24. It has an id (which is currently ignored).
  25. Literal tags (RDF:Literal) are like assertions, except they may contain variables.
  26. Variables are specified as hrefs, the first character of which is $. 
  27.  
  28. The format of a literal whose range is a resource type is: 
  29.  
  30. <RDF:Literal href=domain> 
  31.     <property href=range> 
  32. </RDF:Literal> 
  33.  
  34. a literal whose range is a string or int is expressed as: 
  35.  
  36. <RDF:Literal href=domain> 
  37.     <property>string-or-int-value</property> 
  38. </RDF:Literal> 
  39.  
  40. Note: in order for the query engine to correctly retrieve property values 
  41. which are strings or ints, you must add assertions about the
  42. property's range (otherwise it is assumed to be a resource). 
  43. The range property may be the resource named "String", "Int", or any
  44. other resource. 
  45.  
  46. For example: 
  47. <RDF:Resource id="motto"> 
  48.  <domain href="State.mcf"/> 
  49.  <range href="String"/> 
  50. </RDF:Resource> 
  51.  
  52. Here is an example of a query: 
  53.  
  54. <RDF:Query id="query1"> 
  55.  <result href="$result"/>
  56.  <RDF:Literal href="$var1"> 
  57.   <typeof href="Country.mcf"/> 
  58.  </RDF:Literal> 
  59.  <RDF:Literal href="$var1"> 
  60.   <state href="$var2"/> 
  61.  </RDF:Literal> 
  62.  <RDF:Literal href="$var2"> 
  63.   <capitalCity href="$result"/> 
  64.  </RDF:Literal> 
  65. </RDF:Query> 
  66.   
  67. In the Prolog-like syntax this looks like: 
  68. typeof($var1, Country) & state($var1, $var2) & capitalCity($var2, $result) 
  69. */
  70.  
  71. #include "query.h"
  72. #include "rdf-int.h"
  73.  
  74. #define QUERY_TAG "RDF:Query"
  75. #define LITERAL_TAG "RDF:Literal"
  76. #define RESULT_TAG "RDF:result"
  77. #define SEQ_TAG "RDF:seq"
  78. #define SEQ_END_TAG "</RDF:seq>"
  79. #define LI_TAG "RDF:li"
  80. #define RDF_OBJECT 10 /* status */
  81. #define RDF_PROPERTY 11 /* status */
  82. #define RDF_SEQ 12
  83. #define RDF_LI 13
  84. #define RDF_PARSE_ERROR 5 /* this should go in rdf.h */
  85.  
  86. /* analogous to RDFFile */
  87. typedef struct _QueryParseStruct {
  88.     uint16 status; /* whether we're parsing an object or property */
  89.     PRBool tv; /* truth value of current literal */
  90.     uint16 depth;
  91.     RDF rdf;
  92.     RDF_Query query;
  93.     RDFElement elf;
  94.     TermStruc stack[16];
  95.     TermStruc* value;
  96.     uint8 valueCount;
  97.     uint8 valueSize;
  98. } QueryParseStruct;
  99.  
  100. extern void parseRDFElement(RDFElement elf, char* token);
  101. extern char* getElfProp(char* prop, RDFElement elf);
  102. extern PRBool variableTermp(TermStruc term);
  103. extern PRBool resourceTermp(TermStruc term);
  104. extern PRBool constantTermp(TermStruc term);
  105.  
  106. /* prototypes */
  107. PRBool variablep(char* elf);
  108. RDF_ValueType rangeType(RDF rdf, RDF_Resource prop);
  109. RDF_Error parseNextQueryToken (QueryParseStruct *q, char* token);
  110. RDF_Query parseQuery(RDF rdf, char* blob, int32 size);
  111. RDF_Error parsePropertyValue(QueryParseStruct *q, char* token);
  112. RDF_Error parseEndTag(QueryParseStruct *q, char* token);
  113. RDF_Error parseTag (QueryParseStruct *q, char* token);
  114. RDF_Error addValueToList(QueryParseStruct *q, void* value, RDF_TermType type);
  115. TermStruc* copyTermList(TermStruc* list, uint8 count);
  116.  
  117. PRBool variablep(char* elf) {
  118.     return elf[0] == '$';
  119. }
  120.  
  121. /* Returns the ValueType of the range of the property specified */
  122. RDF_ValueType rangeType(RDF rdf, RDF_Resource prop) {
  123.     RDF_Resource rangeType;
  124.     if (prop == gCoreVocab->RDF_substring) return RDF_STRING_TYPE;
  125.     else if (prop == gCoreVocab->RDF_notSubstring) return RDF_STRING_TYPE;
  126.     else if (prop == gCoreVocab->RDF_stringEquals) return RDF_STRING_TYPE;
  127.     else if (prop == gCoreVocab->RDF_notStringEquals) return RDF_STRING_TYPE;
  128.     else if (prop == gCoreVocab->RDF_lessThan) return RDF_INT_TYPE;
  129.     else if (prop == gCoreVocab->RDF_greaterThan) return RDF_INT_TYPE;
  130.     else if (prop == gCoreVocab->RDF_lessThanOrEqual) return RDF_INT_TYPE;
  131.     else if (prop == gCoreVocab->RDF_greaterThanOrEqual) return RDF_INT_TYPE;
  132.     else if (prop == gCoreVocab->RDF_equals) return RDF_INT_TYPE;
  133.     else if (prop == gCoreVocab->RDF_notEquals) return RDF_INT_TYPE;
  134.     /* fix me - add RDF_stringEquals */
  135.     rangeType = RDF_GetSlotValue(rdf, prop, gCoreVocab->RDF_range, RDF_RESOURCE_TYPE, false, true);
  136.     if (rangeType == NULL) return RDF_RESOURCE_TYPE; /* don't know so assume resource */
  137.     else if (rangeType == gCoreVocab->RDF_StringType) return RDF_STRING_TYPE;
  138.     else if (rangeType == gCoreVocab->RDF_IntType) return RDF_INT_TYPE;
  139.     else return RDF_RESOURCE_TYPE; /* not string or int so must be a resource */
  140. }
  141.  
  142. /* Returns query parsed from blob, NULL if there was a parsing error.
  143.    This is adapted from parseNextRDFXMLBlob, the main differences being that
  144.    a file structure is not maintained. blob must contain the entire query.
  145. */
  146. RDF_Query parseQuery(RDF rdf, char* blob, int32 size) {
  147.     RDF_Error err = noRDFErr;
  148.     QueryParseStruct q;
  149.     char line[LINE_SIZE];
  150.     char holdOver[LINE_SIZE];
  151.     int32 n, last, m;
  152.     PRBool somethingseenp = false;
  153.     n = last = 0;
  154.     q.depth = 0;
  155.     q.elf = (RDFElement)getMem(sizeof(RDFElementStruct));
  156.     q.rdf = rdf;
  157.     q.query = RDF_CreateQuery(rdf);
  158.     q.tv = true;
  159.     q.value = NULL;
  160.     q.valueCount = 0;
  161.     q.valueSize = 0;
  162.  
  163.     memset(holdOver, '\0', LINE_SIZE);
  164.     while (n < size) {
  165.         char c = blob[n];
  166.         m = 0;
  167.         somethingseenp = false;
  168.         memset(line, '\0', LINE_SIZE);
  169.         if (holdOver[0] != '\0') {
  170.           memcpy(line, holdOver, strlen(holdOver));
  171.           m = strlen(holdOver);
  172.           somethingseenp = true;
  173.           memset(holdOver, '\0', LINE_SIZE);
  174.         }
  175.         while ((m < 300) && (c != '<') && (c != '>')) {
  176.             line[m] = c;
  177.             m++;
  178.             somethingseenp = (somethingseenp || ((c != ' ') && (c != '\r') && (c != '\n')));
  179.             n++;
  180.             if (n < size) c = blob[n];
  181.             else break;
  182.         }
  183.         if (c == '>') line[m] = c;
  184.         n++;
  185.         if (m > 0) {
  186.             if ((c == '<') || (c == '>')) {
  187.                 last = n;
  188.                 if (c == '<') holdOver[0] = '<'; 
  189.                 if (somethingseenp == true) {
  190.                     err = parseNextQueryToken(&q, line);
  191.                     if (err != noRDFErr) {
  192.                         if (q.query != NULL) RDF_DestroyQuery(q.query);
  193.                         q.query = NULL;
  194.                         break; /* while (n < size) */
  195.                     }
  196.                 }
  197.             } else if (size > last) {
  198.                 memcpy(holdOver, line, m);
  199.             }
  200.         } else if (c == '<') holdOver[0] = '<';
  201.     }
  202.     if (q.elf != NULL) freeMem(q.elf);
  203.     return q.query;
  204. }
  205.  
  206. RDF_Error addValueToList(QueryParseStruct *q, void* value, RDF_TermType type) {
  207.     RDF_Error err = noRDFErr;
  208.     int increment = 5;
  209.     if (q->valueSize == q->valueCount) {
  210.         TermStruc* old = q->value;
  211.         TermStruc* newTermList = (TermStruc*)getMem((q->valueSize + increment) * sizeof(TermStruc));
  212.         if (newTermList == NULL) return RDF_NO_MEMORY;
  213.         memcpy((char*)newTermList, (char*)q->value, (q->valueSize)* sizeof(TermStruc));
  214.         q->value = newTermList;
  215.         q->valueSize = q->valueSize + increment;
  216.         freeMem(old);
  217.     }
  218.     (q->value + q->valueCount)->value = value;
  219.     (q->value + q->valueCount)->type = type;
  220.     q->valueCount++;
  221.     return err;
  222. }
  223.  
  224. TermStruc* copyTermList(TermStruc* list, uint8 count) {
  225.     TermStruc* newList = (TermStruc*)getMem(count * sizeof(TermStruc));
  226.     if (newList == NULL) return NULL;
  227.     memcpy((char*)newList, (char*)list, count * sizeof(TermStruc));
  228.     return newList;
  229. }
  230.  
  231. RDF_Error parsePropertyValue(QueryParseStruct *q, char* token) {
  232.     RDF_Error err = noRDFErr;
  233.     if ((q->depth == 3) && (q->status == RDF_PROPERTY)) {
  234.         /* parse the property value */
  235.         RDF_Resource slot = (RDF_Resource)q->stack[q->depth-1].value;
  236.         RDF_ValueType type = rangeType(q->rdf, slot);
  237.         TermStruc unitTerm = q->stack[q->depth-2];
  238.         switch (type) { /* switch on value type of property */
  239.             int i;
  240.         case RDF_RESOURCE_TYPE:
  241.             err = RDF_PARSE_ERROR;
  242.             break;
  243.         case RDF_STRING_TYPE:
  244.             if (variablep(token)) {
  245.                 RDF_Variable rangeVar = RDF_GetVariable(q->query, token);
  246.                 if (variableTermp(unitTerm))
  247.                     err = RDF_AddConjunctVRV(q->query, (RDF_Variable)unitTerm.value, slot, rangeVar, type);
  248.                 else err = RDF_AddConjunctRRV(q->query, (RDF_Resource)unitTerm.value, slot, rangeVar, type);
  249.             } else if (variableTermp(unitTerm)) {
  250.                     err = RDF_AddConjunctVRO(q->query, (RDF_Variable)unitTerm.value, slot, (void*)token, type);
  251.             } else err = RDF_AddConjunctRRO(q->query, (RDF_Resource)unitTerm.value, slot, (void*)token, type);
  252.             break;
  253.         case RDF_INT_TYPE:
  254.             if (variablep(token)) {
  255.                 RDF_Variable rangeVar = RDF_GetVariable(q->query, token);
  256.                 if (variableTermp(unitTerm))
  257.                     err = RDF_AddConjunctVRV(q->query, (RDF_Variable)unitTerm.value, slot, rangeVar, type);
  258.                 else err = RDF_AddConjunctRRV(q->query, (RDF_Resource)unitTerm.value, slot, rangeVar, type);
  259.             } else if (sscanf(token, "%d", &i) == 1) { /* fix me */
  260.                 if (variableTermp(unitTerm)) {
  261.                     err = RDF_AddConjunctVRO(q->query, (RDF_Variable)unitTerm.value, slot, (void*)i, type);
  262.                 } else err = RDF_AddConjunctRRO(q->query, (RDF_Resource)unitTerm.value, slot, (void*)i, type);
  263.             } else err = RDF_PARSE_ERROR;
  264.             break;
  265.         default:
  266.             err = RDF_PARSE_ERROR; /* should never get here */
  267.             break;
  268.         }
  269.     } else if (q->status == RDF_LI) {
  270.         RDF_Resource slot = (RDF_Resource)q->stack[q->depth-3].value;
  271.         RDF_ValueType type = rangeType(q->rdf, slot);
  272.         switch (type) {
  273.             int i;
  274.         case RDF_RESOURCE_TYPE:
  275.             err = RDF_PARSE_ERROR;
  276.             break;
  277.         case RDF_STRING_TYPE:
  278.             if (variablep(token))
  279.                 err = addValueToList(q, RDF_GetVariable(q->query, token), RDF_VARIABLE_TERM_TYPE);
  280.             else err = addValueToList(q, copyString(token), RDF_CONSTANT_TERM_TYPE);
  281.             break;
  282.         case RDF_INT_TYPE:
  283.             if (variablep(token)) {
  284.                 err = addValueToList(q, RDF_GetVariable(q->query, token), RDF_VARIABLE_TERM_TYPE);
  285.             } else if (sscanf(token, "%d", &i) == 1) { /* fix me */
  286.                 err = addValueToList(q, (void*)i, RDF_CONSTANT_TERM_TYPE);
  287.             } else err = RDF_PARSE_ERROR;
  288.             break;
  289.         default:
  290.             err = RDF_PARSE_ERROR; /* should never get here */
  291.             break;
  292.         }
  293.     }
  294.     return err;
  295. }
  296.  
  297. RDF_Error parseTag (QueryParseStruct *q, char* token) {
  298.     RDF_Error err = noRDFErr;
  299.     RDFElement elf = q->elf;
  300.     memset((char*)elf, '\0', sizeof(RDFElementStruct));
  301.     parseRDFElement(elf, token);
  302.  
  303.     /* the block can start with Query, Literal or a property name */
  304.  
  305.     if (startsWith(QUERY_TAG, elf->tagName)) {
  306.         char* url = getElfProp("id", elf);
  307.         /* don't have anything to do with id right now */
  308.         q->stack[q->depth++].value = (void*)NULL;
  309.         q->status = RDF_OBJECT;
  310.     } else if (startsWith(LITERAL_TAG, elf->tagName)) {
  311.         char* domain = getElfProp("href", elf);
  312.         if (variablep(domain)) {
  313.             q->stack[q->depth].value = RDF_GetVariable(q->query, domain);
  314.             q->stack[q->depth].type = RDF_VARIABLE_TERM_TYPE;
  315.             q->depth++;
  316.         } else {
  317.             q->stack[q->depth].value = resourceFromID(domain, true);
  318.             q->stack[q->depth].type = RDF_RESOURCE_TERM_TYPE;
  319.             q->depth++;
  320.         }
  321.         q->status = RDF_OBJECT;
  322.         /*
  323.         if (stringEquals(LITERAL_NEGATION_TAG, elf->tagName))
  324.             q->tv = false;
  325.         else q->tv = true;
  326.         */
  327.     } else if (stringEquals(elf->tagName, RESULT_TAG) && (q->depth == 1)) {
  328.         /* set a result variable */
  329.         char* range = getElfProp("href", elf);
  330.         RDF_Variable resultVar = RDF_GetVariable(q->query, range);
  331.         RDF_SetResultVariable(resultVar, true);
  332.         q->status = RDF_OBJECT;
  333.     } else if (stringEquals(elf->tagName, SEQ_TAG) && (q->depth == 3)) {
  334.         /* ignore stack value */
  335.         q->depth++;
  336.         q->status = RDF_SEQ;
  337.         q->valueSize = 10;
  338.         q->valueCount = 0;
  339.         q->value = (TermStruc*)getMem(q->valueSize * sizeof(TermStruc));
  340.         if (q->value == NULL) err = RDF_PARSE_ERROR;
  341.     } else if (stringEquals(elf->tagName, LI_TAG) && (q->depth == 4)) {
  342.         /* ignore stack value */
  343.         if (elf->emptyTagp) { /* <RDF:li href="$var"/> */
  344.             char* range = getElfProp("href", elf);
  345.             RDF_Resource slot = (RDF_Resource)q->stack[q->depth-2].value;
  346.             RDF_ValueType type = rangeType(q->rdf, slot);
  347.             if (type == RDF_RESOURCE_TYPE) {
  348.                 if (variablep(range)) {
  349.                     err = addValueToList(q, RDF_GetVariable(q->query, range), RDF_VARIABLE_TERM_TYPE);
  350.                 } else err = addValueToList(q, resourceFromID(range, true), RDF_RESOURCE_TERM_TYPE);
  351.             } else err = RDF_PARSE_ERROR;
  352.         } else { /* <RDF:li> */
  353.             q->depth++;
  354.             q->status = RDF_LI;
  355.         }
  356.     } else if (q->depth != 1) { /* property */
  357.         char* pname = elf->tagName;
  358.         RDF_Resource slot = resourceFromID(pname, true);
  359.         if (elf->emptyTagp) {
  360.             char* range = getElfProp("href", elf);
  361.             RDF_ValueType type = rangeType(q->rdf, slot);
  362.             TermStruc unitTerm = q->stack[q->depth-1];
  363.             switch (type) { /* switch on value type of property */
  364.             case RDF_RESOURCE_TYPE:
  365.                 if (variablep(range)) {
  366.                     RDF_Variable rangeVar = RDF_GetVariable(q->query, range);
  367.                     if (variableTermp(unitTerm)) {
  368.                         err = RDF_AddConjunctVRV(q->query, (RDF_Variable)unitTerm.value, slot, rangeVar, type);
  369.                     } else {
  370.                         err = RDF_AddConjunctRRV(q->query, (RDF_Resource)unitTerm.value, slot, rangeVar, type);
  371.                     }
  372.                 } else {
  373.                     RDF_Resource rangeRsrc = resourceFromID(range, true);
  374.                     if (variableTermp(unitTerm)) {
  375.                         /* RDF_AddConjunctVRR */
  376.                         err = RDF_AddConjunctVRR(q->query, (RDF_Variable)unitTerm.value, slot, rangeRsrc);
  377.                     } else err = RDF_PARSE_ERROR;
  378.                 }
  379.                 break;
  380.             default:
  381.                 err = RDF_PARSE_ERROR; /* strings and ints cannot be inside href */
  382.                 break;
  383.             }
  384.             q->status = RDF_OBJECT;
  385.         } else {
  386.             /* this isn't really a term, its just a property but we access it in the same way as a term */
  387.             q->stack[q->depth].value = slot;
  388.             q->stack[q->depth].type = RDF_RESOURCE_TERM_TYPE;
  389.             q->depth++;
  390.             q->status = RDF_PROPERTY;
  391.         }
  392.     }
  393.     return err;
  394. }
  395.  
  396. RDF_Error parseEndTag(QueryParseStruct *q, char* token) {
  397.     RDF_Error err = noRDFErr;
  398.     if (stringEquals(SEQ_END_TAG, token)) {
  399.         RDF_Resource slot = (RDF_Resource)q->stack[q->depth-2].value;
  400.         RDF_ValueType type = rangeType(q->rdf, slot);
  401.         TermStruc unitTerm = q->stack[q->depth-3];
  402.         /* copy the value list, add the conjunct, and destroy the list - the engine destroys the copy. */
  403.         TermStruc* copy = copyTermList(q->value, q->valueCount);
  404.         if (copy == NULL) return RDF_NO_MEMORY;
  405.         err = RDF_AddConjunctVRL(q->query, (RDF_Variable)unitTerm.value, slot, (RDF_Term)copy, type, q->valueCount);
  406.         q->valueCount = q->valueSize = 0;
  407.         freeMem(q->value);
  408.     }
  409.     if (q->depth == 0) return RDF_PARSE_ERROR;
  410.     q->depth--;
  411.     if (q->status == RDF_OBJECT)
  412.         q->status = RDF_PROPERTY;
  413.     else if (q->status == RDF_LI)
  414.         q->status = RDF_SEQ;
  415.     else if (q->status == RDF_SEQ)
  416.         q->status = RDF_OBJECT; /* also terminates the property */
  417.     return err;
  418. }
  419.  
  420. /* this is adapted from parseNextRDFToken, the difference being in the actions. */
  421. RDF_Error parseNextQueryToken (QueryParseStruct *q, char* token) {
  422.     RDF_Error err = noRDFErr;
  423.     if (token[0] == '\n' || token[0] == '\r') return err;
  424.     if (token[0] != '<') {
  425.         err = parsePropertyValue(q, token);
  426.     } else if (token[1] == '/') {
  427.         err = parseEndTag(q, token);
  428.     } else { 
  429.         err = parseTag(q, token);
  430.     }
  431.     return err;
  432. }
  433.