Added function to count occurences of a tag spec in a data1 tree.
[yaz-moved-to-github.git] / retrieval / d1_if.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * d1_if.c : A simple interface for extracting strings from data1_node tree structures
7  *
8  * $Log: d1_if.c,v $
9  * Revision 1.2  2000-01-04 17:46:17  ian
10  * Added function to count occurences of a tag spec in a data1 tree.
11  *
12  * Revision 1.1  1999/12/21 14:16:19  ian
13  * Changed retrieval module to allow data1 trees with no associated absyn.
14  * Also added a simple interface for extracting values from data1 trees using
15  * a string based tagpath.
16  *
17  *
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <yaz/data1.h>
26 #include <yaz/log.h>
27
28 #include <string.h>
29
30
31 /*
32  * Search for a token in the supplied string up to the supplied list of stop characters or EOL
33  * At the end, return the character causing the break and fill pTokenBuffer with the token string so far
34  * After the scan, *pPosInBuffer will point to the next character after the one causing the break and
35  *                 pTokenBuffer will contain the actual token
36  */
37 char data1_ScanNextToken(char* pBuffer,
38                          char** pPosInBuffer,
39                          char* pBreakChars,
40                          char* pWhitespaceChars,
41                          char* pTokenBuffer)
42 {
43     char* pBuff = pTokenBuffer;
44     *pBuff = '\0';
45
46     while ( **pPosInBuffer )
47     {
48         if ( strchr(pBreakChars,**pPosInBuffer) != NULL )
49         {
50             /* Current character is a break character */
51             *pBuff++ = '\0';
52             return *((*pPosInBuffer)++);
53         }
54         else
55         {
56             if ( strchr(pWhitespaceChars, **pPosInBuffer) != NULL )
57                 *pPosInBuffer++;
58             else
59                 *pBuff++ = *((*pPosInBuffer)++);
60         }
61     }
62
63     *pBuff++ = *((*pPosInBuffer)++);
64     return(**pPosInBuffer);
65 }
66
67 /* 
68  * Attempt to find a string value given the specified tagpath
69  * 
70  * Need to make this safe by passing in a buffer..... 
71  *
72  */
73 char *data1_getNodeValue(data1_node* node, char* pTagPath)
74 {
75     data1_node* n = NULL;
76
77     n = data1_LookupNode(node, pTagPath );
78
79     if ( n )
80     {
81         /* n should be a tag node with some data under it.... */
82         if ( n->child )
83         {
84             if ( n->child->which == DATA1N_data )
85             {
86                 return n->child->u.data.data;
87             }
88             else
89             {
90                 yaz_log(LOG_WARN,"Attempting to lookup data for tagpath: Child node is not a data node");
91             }
92         }
93         else
94         {
95             yaz_log(LOG_WARN,"Found a node matching the tagpath, but it has no child data nodes");
96         }
97     }
98     else
99     {
100         yaz_log(LOG_WARN,"Unable to lookup a node on the specified tag path");
101     }
102
103     return "";
104 }
105
106
107 /* 
108  * data1_LookupNode : Try and find a node as specified by a tagpath
109  */
110 data1_node *data1_LookupNode(data1_node* node, char* pTagPath)
111 {
112     /* Node matching the pattern in the tagpath */
113     data1_node* matched_node = NULL;
114
115     /* Current Child node as we search for nodes matching the pattern in the tagpath */
116     data1_node* current_child = node->child;
117
118     /* Max length of a tag */
119     int iMaxTagSize=50;
120
121     /* Current position in string */
122     char* pCurrCharInPath = pTagPath;
123
124     /* Work buffer */
125     char Buffer[iMaxTagSize];
126
127     /* The tag type of this node */
128     int iTagType = 0;
129
130     /* for non string tags, the tag value */
131     int iTagValue = 0;
132
133     /* for string tags, the tag value */
134     char StringTagVal[iMaxTagSize];
135
136     /* Which occurence of that tag under this node */
137     int iOccurences=0;
138
139     /* Character causing a break */
140     char sepchr = '\0';
141     Buffer[0] = '\0';
142     StringTagVal[0] = '\0';
143
144     sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ",[(."," ", Buffer);
145
146     if ( sepchr == '[' )
147     {
148         /* Next component in node value is [ TagType, TagVal, TagOccurence ] */
149         sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ","," ", Buffer);
150         iTagType = atoi(Buffer);
151
152         /* Occurence is optional... */
153         sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ",]."," ", Buffer);
154
155         if ( iTagType == 3 )
156             strcpy(StringTagVal,Buffer);
157         else
158             iTagValue = atoi(Buffer);
159
160         /* If sepchar was a ',' there should be an instance */
161         if ( sepchr == ',' )
162         {
163             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "]."," ", Buffer);
164             iOccurences = atoi(Buffer);
165         }
166
167         if ( sepchr == ']' )
168         {
169             /* See if we can scan the . for the next component or the end of the line... */
170             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "."," ", Buffer);
171         }
172         else
173         {
174             yaz_log(LOG_FATAL,"Node does not end with a ]");
175             /* Fatal Error */
176             return(NULL);
177         }
178     }
179     else
180     {
181         /* We have a TagName so Read up to ( or . or EOL */
182         iTagType = 3;
183         strcpy(StringTagVal,Buffer);
184
185         if ( sepchr == '(' )
186         {
187             /* Read the occurence */
188             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, ")"," ", Buffer);
189             iOccurences = atoi(Buffer);
190
191             /* See if we can find the . at the end of this clause */
192             sepchr = data1_ScanNextToken(pTagPath, &pCurrCharInPath, "."," ", Buffer);
193         }
194         
195     }
196
197     yaz_log(LOG_DEBUG,"search node for child like [%d,%d,%s,%d]",iTagType,iTagValue,StringTagVal,iOccurences);
198     
199
200     /* OK.. We have extracted tagtype, Value and Occurence, see if we can find a node */
201     /* Under the current parent matching that description                             */
202
203     while ( ( current_child ) && ( matched_node == NULL ) )
204     {
205         if ( current_child->which == DATA1N_tag )
206         {
207             if ( iTagType == 3 )
208             {
209                 if ( ( current_child->u.tag.element == NULL ) &&
210                      ( strcmp(current_child->u.tag.tag, StringTagVal) == 0 ) )
211                 {
212                     if ( iOccurences )
213                     {
214                         // Everything matched, but not yet found the right occurence of the given tag
215                         iOccurences--;
216                     }
217                     else
218                     {
219                         /* We have matched a string tag... Is there more to process? */
220                         matched_node = current_child;
221                     }
222                 }
223             }
224             else /* Attempt to match real element */
225             {
226                 yaz_log(LOG_WARN,"Non string tag matching not yet implemented");
227             }
228         }
229         current_child = current_child->next;
230     }
231
232
233     /* If there is more... Continue */
234     if ( ( sepchr == '.' ) && ( matched_node ) )
235     {
236         return data1_LookupNode(matched_node, pCurrCharInPath);
237     }
238     else
239     {
240         return matched_node;
241     }
242 }
243
244 /**
245
246 data1_CountOccurences
247
248 Count the number of occurences of the last instance on a tagpath.
249
250 @param data1_node* node : The root of the tree we wish to look for occurences in
251 @param const char* pTagPath : The tagpath we want to count the occurences of... 
252
253 */
254 int data1_CountOccurences(data1_node* node, char* pTagPath)
255 {
256     int iRetVal = 0;
257     data1_node* n = NULL;
258     data1_node* pParent = NULL;
259
260     n = data1_LookupNode(node, pTagPath );
261
262
263     if ( ( n ) &&
264          ( n->which == DATA1N_tag ) &&
265          ( n->parent ) )
266     {
267         data1_node* current_child;
268         pParent = n->parent;
269
270         for ( current_child = pParent->child;
271               current_child;
272               current_child = current_child->next )
273         {
274             if ( current_child->which == DATA1N_tag )
275             {
276                 if ( current_child->u.tag.element == NULL )
277                 {
278                     if ( ( n->u.tag.tag ) &&
279                          ( current_child->u.tag.tag ) &&
280                          ( strcmp(current_child->u.tag.tag, n->u.tag.tag) == 0 ) )
281                     {
282                         iRetVal++;
283                     }
284                 }
285                 else if ( current_child->u.tag.element == n->u.tag.element )
286                 {
287                     /* Hmmm... Is the above right for non string tags???? */
288                     iRetVal++;
289                 }
290             }
291         }
292     }
293
294     return iRetVal;
295 }