Annotation of libwww/Library/src/HTRDF.c, revision 2.3
2.1 frystyk 1: /*
2: ** RDF PARSER
3: **
2.3 ! frystyk 4: ** @(#) $Id: HTRDF.c,v 2.2 1999/04/18 23:16:51 frystyk Exp $
2.1 frystyk 5: **
6: ** Copyright © 1995-1998 World Wide Web Consortium, (Massachusetts
7: ** Institute of Technology, Institut National de Recherche en
8: ** Informatique et en Automatique, Keio University). All Rights
9: ** Reserved. This program is distributed under the W3C's Software
10: ** Intellectual Property License. This program is distributed in the hope
11: ** that it will be useful, but WITHOUT ANY WARRANTY; without even the
12: ** implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13: ** PURPOSE. See W3C License http://www.w3.org/Consortium/Legal/ for more
14: ** details.
15: **
16: ** This module requires expat
17: **
18: ** AUTHOR:
19: ** John Punin <puninj@cs.rpi.edu>,
20: ** Henrik
21: */
22:
23: #include "WWWLib.h"
24: #include "WWWInit.h"
25: #include "WWWXML.h"
26: #include "HTRDF.h"
27:
28: struct _HTStream {
29: const HTStreamClass * isa;
30: int state;
31: HTRequest * request;
32: HTStream * target;
33: HTRDF * rdfparser;
34: };
35:
36: #define PUTC(t,c) (*(t)->target->isa->put_character)((t)->target, (c))
37: #define PUTS(t,s) (*(t)->target->isa->put_string)((t)->target, (s))
38:
39: struct _HTTriple {
2.3 ! frystyk 40: char * m_sPredicate;
! 41: char * m_sSubject;
! 42: char * m_sObject;
2.1 frystyk 43: };
44:
45: struct _HTElement {
2.3 ! frystyk 46: char * m_sName;
2.1 frystyk 47: HTAssocList * m_attributes;
48: HTList * m_children;
2.3 ! frystyk 49: char * m_sID;
! 50: char * m_sBagID;
2.1 frystyk 51: HTList * m_vTargets;
52: BOOL m_bDone;
2.3 ! frystyk 53: char * m_sPrefix;
! 54: char * m_sContent;
2.1 frystyk 55: };
56:
57: struct _HTRDFParser {
58: HTList * m_namespaceStack;
59: HTList * m_elementStack;
60: HTElement * m_root;
61: HTList * m_triples;
2.3 ! frystyk 62: char * m_sSource;
2.1 frystyk 63: HTList * m_vAllNameSpaces;
64:
65: BOOL m_bCreateBags;
66: BOOL m_bFetchSchemas;
67:
68: HTList * m_parseTypeStack;
69: HTList * m_parseElementStack;
2.3 ! frystyk 70: char * m_sLiteral;
2.1 frystyk 71:
72: HTList * m_vResources;
73: HTList * m_vResolveQueue;
74: HTHashtable * m_hIDtable;
75: int m_iReificationCounter;
76:
77: HTStream * ostream;
78:
79: HTTripleCallback_new * newTripleInstance;
80: void * tripleContext;
81: };
82:
83: /* @@@ Should not be global but controlled by name spaces @@@ */
84: PRIVATE HTRDFCallback_new * RDFInstance = NULL;
85: PRIVATE void * RDFInstanceContext = NULL;
86:
2.3 ! frystyk 87: PRIVATE char * HTRDF_processContainer (HTRDF *me, HTElement *e);
! 88: PRIVATE char * HTRDF_processPredicate (HTRDF *me, HTElement *predicate,
2.1 frystyk 89: HTElement *description,
2.3 ! frystyk 90: char * sTarget,
2.1 frystyk 91: BOOL reificate);
2.3 ! frystyk 92: PRIVATE void HTRDF_processListItem (HTRDF *me,char * sID, HTElement *listitem,
2.1 frystyk 93: int iCounter);
94: PRIVATE void HTRDF_checkAttributes (HTRDF *me,HTElement *Element);
95: PRIVATE BOOL HTRDF_expandAttributes (HTRDF *me, HTElement *parent, HTElement *ele);
2.3 ! frystyk 96: PRIVATE char * HTRDF_reificate (HTRDF *me, char * sPredicate, char * sSubject,
! 97: char * sObject, char * sNodeID);
2.1 frystyk 98:
99: /* ------------------------------------------------------------------------- */
100:
101: /*
102: ** Searches a whole list of Strings and returns true if the String is found.
103: */
2.3 ! frystyk 104: PRIVATE BOOL HTList_contains (HTList *list, char * s)
2.1 frystyk 105: {
106: HTList *cur = list;
2.3 ! frystyk 107: char * cs = NULL;
! 108: while ((cs = (char *) HTList_nextObject(cur))) {
2.1 frystyk 109: if (!strcmp(cs, s)) return YES;
110: }
111: return NO;
112: }
113:
114: /*
115: ** Useful function that Trims a string
116: ** @@@ Should use HTStrip() @@@
117: */
118: PRIVATE char * trim (char *s)
119: {
120: char *p = NULL, *t = NULL;
121: int len = s ? strlen(s) : -1;
122: if (s && len > 0) {
123: StrAllocCopy(t, s);
124: p = &(s[len-1]);
125: while(p!=s) {
126: if (!isspace((int)(*p)))
127: break;
128: p--;
129: }
130: t[(int)(p-s)+1] = '\0';
131: if (isspace((int) t[(int)(p-s)]))
132: t[(int)(p-s)] = '\0';
133: }
134: return t;
135: }
136:
137: /* ------------------------------------------------------------------------- */
138: /* TRIPLE of RDF */
139: /* ------------------------------------------------------------------------- */
140:
2.3 ! frystyk 141: PUBLIC HTTriple * HTTriple_new (char * p, char * s, char * o)
2.1 frystyk 142: {
143: HTTriple * me = NULL;
144: if (p && s && o) {
145: if ((me = (HTTriple *) HT_CALLOC(1, sizeof(HTTriple))) == NULL)
146: HT_OUTOFMEM("HTTriple_new");
147: StrAllocCopy(me->m_sPredicate, p);
148: StrAllocCopy(me->m_sSubject, s);
149: StrAllocCopy(me->m_sObject, o);
150: }
151: return me;
152: }
153:
154: PUBLIC BOOL HTTriple_delete (HTTriple * me)
155: {
156: if (me) {
157: HT_FREE(me->m_sPredicate);
158: HT_FREE(me->m_sSubject);
159: HT_FREE(me->m_sObject);
160: HT_FREE(me);
161: return YES;
162: }
163: return NO;
164: }
165:
166: PUBLIC void HTTriple_print (HTTriple * me)
167: {
168: if (me)
169: HTPrint("TRIPLE(%s,%s,%s)\n", me->m_sPredicate, me->m_sSubject,
170: me->m_sObject);
171: }
172:
2.3 ! frystyk 173: PUBLIC char * HTTriple_subject (HTTriple * me)
2.1 frystyk 174: {
175: return me ? me->m_sSubject : NULL;
176: }
177:
2.3 ! frystyk 178: PUBLIC char * HTTriple_predicate (HTTriple * me)
2.1 frystyk 179: {
180: return me ? me->m_sPredicate : NULL;
181: }
182:
2.3 ! frystyk 183: PUBLIC char * HTTriple_object (HTTriple * me)
2.1 frystyk 184: {
185: return me ? me->m_sObject : NULL;
186: }
187:
188: /* ------------------------------------------------------------------------- */
189: /* ELEMENT of RDF */
190: /* ------------------------------------------------------------------------- */
191:
2.3 ! frystyk 192: PUBLIC HTElement * HTElement_new (char * sName, HTAssocList * al)
2.1 frystyk 193: {
194: HTElement * me = NULL;
195: if (sName) {
196: if ((me = (HTElement *) HT_CALLOC(1, sizeof(HTElement))) == NULL)
197: HT_OUTOFMEM("HTElement_new");
198: StrAllocCopy(me->m_sName, sName);
199: me->m_attributes = al ? al : HTAssocList_new();
200: me->m_children = HTList_new();
201: /*me->m_nodes = HTAssocList_new();*/ /* Sirpac does not use nodes list */
202: me->m_vTargets = HTList_new();
203: me->m_bDone = FALSE;
204: }
205: return me;
206: }
207:
208: /*
209: ** Creates a Data Element and saves the data in the Content field.
210: ** Data Element does not have attributes
211: */
2.3 ! frystyk 212: PUBLIC HTElement * HTElement_new2 (char * sContent)
2.1 frystyk 213: {
214: HTElement * me = NULL;
215: if (sContent) {
216: if ((me = (HTElement *) HT_CALLOC(1, sizeof(HTElement))) == NULL)
217: HT_OUTOFMEM("HTElement_new2");
218: StrAllocMCopy(&me->m_sName, "[DATA: ", sContent, "]", NULL);
219: me->m_attributes = NULL;
220: me->m_children = HTList_new();
221: /*me->m_nodes = HTAssocList_new();*/
222: me->m_vTargets = HTList_new();
223: me->m_bDone = FALSE;
224: StrAllocCopy(me->m_sContent, sContent);
225: }
226: return me;
227: }
228:
2.3 ! frystyk 229: PUBLIC BOOL HTElement_addData (HTElement *me, char * sContent)
2.1 frystyk 230: {
231: if (me && sContent) {
232: int l = strlen(me->m_sName);
233: StrAllocCat(me->m_sContent, sContent);
234: me->m_sName[l-1]='\0';
235: StrAllocMCat(&me->m_sName, sContent, "]", NULL);
236: return YES;
237: }
238: return NO;
239: }
240:
241: PUBLIC BOOL HTElement_delete (HTElement * me)
242: {
243: if (me) {
244: HT_FREE(me->m_sName);
245: if (me->m_attributes) HTAssocList_delete(me->m_attributes);
246: if (me->m_children) HTList_delete(me->m_children);
247: HT_FREE(me->m_sID);
248: HT_FREE(me->m_sBagID);
249: if (me->m_vTargets) HTList_delete(me->m_vTargets);
250: HT_FREE(me->m_sPrefix);
251: HT_FREE(me->m_sContent);
252: HT_FREE(me);
253: return YES;
254: }
255: return NO;
256: }
257:
258: PUBLIC BOOL HTElement_addChild (HTElement * me, HTElement * element)
259: {
260: return (me && element) ? HTList_appendObject(me->m_children, element) : NO;
261: }
262:
2.3 ! frystyk 263: PUBLIC BOOL HTElement_addAttribute (HTElement * me, char * sName, char * sValue)
2.1 frystyk 264: {
265: return (me && sName && sValue) ?
266: HTAssocList_addObject(me->m_attributes, sName, sValue) : NO;
267: }
268:
2.3 ! frystyk 269: PUBLIC BOOL HTElement_removeAttribute (HTElement * me, char * sName)
2.1 frystyk 270: {
271: return (me && sName) ? HTAssocList_removeObject(me->m_attributes, sName) : NO;
272: }
273:
2.3 ! frystyk 274: PUBLIC char * HTElement_getAttribute (HTElement * me, char * sName)
2.1 frystyk 275: {
276: return (me && sName) ? HTAssocList_findObjectCaseSensitiveExact(me->m_attributes, sName) : NULL;
277: }
278:
2.3 ! frystyk 279: PUBLIC char * HTElement_getAttribute2 (HTElement * me, char * sNamespace, char * sName)
2.1 frystyk 280: {
2.3 ! frystyk 281: char * fValue = NULL;
! 282: char * fName = NULL;
2.1 frystyk 283: if (me && sNamespace && sName) {
284: StrAllocMCopy(&fName, sNamespace, sName, NULL);
285: fValue = HTAssocList_findObjectCaseSensitiveExact(me->m_attributes, fName);
286: HT_FREE(fName);
287: }
288: return fValue;
289: }
290:
291: PUBLIC BOOL HTElement_addTarget (HTElement * me, HTElement * element)
292: {
293: return (me && element) ? HTList_addObject(me->m_vTargets, element) : NO;
294: }
295:
296: PUBLIC HTElement * HTElement_target (HTElement * me)
297: {
298: return me ? (HTElement *) HTList_lastObject(me->m_vTargets) : NULL;
299: }
300:
301: PUBLIC BOOL HTElement_instanceOfData (HTElement * me)
302: {
303: return (me && me->m_sContent) ? YES : NO;
304: }
305:
306: /* ------------------------------------------------------------------------- */
307: /* EXPAT HANDLERS */
308: /* ------------------------------------------------------------------------- */
309:
310: /*
311: * Called for each new element.
312: * Build up the document tree using an element stack
313: */
314: PRIVATE void XML_startElement (void * userData,
315: const XML_Char * name, const XML_Char ** atts)
316: {
317: HTRDF * rdfp = (HTRDF *) userData;
318: HTAssocList * namespaces = HTAssocList_new();
319: HTAssocList * newAL = HTAssocList_new();
320: int i = 0;
321: /**
322: * The following loop tries to identify special xmlns prefix
323: * attributes and update the namespace stack accordingly.
324: * While doing all this, it builds another AttributeList instance
325: * which will hold the expanded names of the attributes
326: * (I think this approach is only useful for RDF which uses
327: * attributes as an abbreviated syntax for element names)
328: */
329:
330: if (atts) {
331: while (atts[i]) {
2.3 ! frystyk 332: char * aName = (char * ) atts[i];
2.1 frystyk 333: if (!strcmp(aName, "xmlns")) {
2.3 ! frystyk 334: char * aValue = (char *) atts[i+1];
2.1 frystyk 335: int len = aValue ? strlen(aValue) : -1;
336: if (len == 0 && !rdfp->m_sSource)
337: aValue = rdfp->m_sSource;
338: HTAssocList_addObject(namespaces, aName, aValue);
339: /* save all non-RDF schema addresses */
340: if (!HTList_contains(rdfp->m_vAllNameSpaces, aValue) &&
341: strncmp(aValue, RDFMS, strlen(RDFMS)) &&
342: strncmp(aValue, RDFSCHEMA, strlen(RDFSCHEMA))) {
2.3 ! frystyk 343: char * nname = NULL;
2.1 frystyk 344: StrAllocCopy(nname, aValue);
345: HTList_addObject(rdfp->m_vAllNameSpaces, nname);
346: }
347:
348: /* Special case: Don't save document's own address */
349: if (rdfp->m_sSource &&
350: !strncmp(aValue, rdfp->m_sSource, strlen(rdfp->m_sSource))) {
2.3 ! frystyk 351: char * nname = NULL;
2.1 frystyk 352: StrAllocCopy(nname, aValue);
353: HTList_addObject(rdfp->m_vAllNameSpaces, nname);
354: }
355: } else if (!strncmp(aName, "xmlns:", 6)) {
2.3 ! frystyk 356: char * aValue = (char *) atts[i+1];
! 357: char * nName = NULL;
2.1 frystyk 358: int len = aValue ? strlen(aValue) : -1;
359: if (len == 0 && !rdfp->m_sSource)
360: aValue = rdfp->m_sSource;
361: StrAllocCopy(nName, &(aName[6]));
362: HTAssocList_addObject(namespaces, nName, aValue);
363: HT_FREE(nName);
364:
365: /* Save all non-RDF schema addresses */
366: if (!HTList_contains(rdfp->m_vAllNameSpaces, aValue) &&
367: strncmp(aValue, RDFMS, strlen(RDFMS)) &&
368: strncmp(aValue, RDFSCHEMA, strlen(RDFSCHEMA))) {
2.3 ! frystyk 369: char * nname = NULL;
2.1 frystyk 370: StrAllocCopy(nname, aValue);
371: HTList_addObject(rdfp->m_vAllNameSpaces, nname);
372: }
373:
374: /* Special case: Don't save document's own address */
375: if (rdfp->m_sSource &&
376: !strncmp(aValue, rdfp->m_sSource, strlen(rdfp->m_sSource))) {
2.3 ! frystyk 377: char * nname = NULL;
2.1 frystyk 378: StrAllocCopy(nname, aValue);
379: HTList_addObject(rdfp->m_vAllNameSpaces, nname);
380: }
381: }
382: i+=2;
383: } /* end of while */
384: } /* end of if */
385:
386: /*
387: ** Place new namespace declarations into the stack
388: ** (Yes, I could optimize this a bit, not it wastes space
389: ** if there are no xmlns definitions)
390: */
391: HTList_addObject(rdfp->m_namespaceStack, namespaces);
392:
393: /*
394: ** Figure out the prefix part if it exists and
395: ** determine the namespace of the element accordingly
396: */
397: {
2.3 ! frystyk 398: char * sNamespace = NULL;
! 399: char * sElementName = NULL;
! 400: char * sPrefix2 = NULL;
2.1 frystyk 401: HTElement *newElement = NULL;
402: char *pindex = strchr(name, ':');
403: int ix = pindex ? (int) (pindex - name) : -1 ;
404: if (ix > 0) {
405: if (!(sPrefix2 = HT_MALLOC(ix+1)))
406: HT_OUTOFMEM("XML_startELement");
407: strncpy(sPrefix2, name, ix);
408: sPrefix2[ix]='\0';
409: sNamespace = HTRDF_namespace(rdfp, sPrefix2);
410: StrAllocCopy(sElementName, &(name[ix+1]));
411: HT_FREE(sPrefix2);
412: } else {
413: sNamespace = HTRDF_namespace(rdfp, "xmlns");
414: StrAllocCopy(sElementName, name);
415: }
416:
417: /*
418: * Finally look for attributes other than the special xmlns,
419: * expand them, and place to the new Attribute List
420: */
421: i = 0;
422: if (atts) {
423: while (atts[i]) {
2.3 ! frystyk 424: char * aName = (char *) atts[i];
! 425: char * sAttributeNamespace = NULL;
2.1 frystyk 426: if (strncmp(aName, "xmlns", 5)) {
2.3 ! frystyk 427: char * aValue = (char *) atts[i+1];
! 428: char * sPrefix = NULL;
2.1 frystyk 429: /* Expat does not have type for attributes */
430: pindex = strchr(aName, ':');
431: ix = pindex ? (int) (pindex - aName) : -1;
432: if (ix > 0) {
433: if (!(sPrefix = HT_MALLOC(ix+1)))
434: HT_OUTOFMEM("XML_startELement");
435: strncpy(sPrefix, aName, ix);
436: sPrefix[ix] = '\0';
437: sAttributeNamespace = HTRDF_namespace(rdfp, sPrefix);
438: aName = &(aName[ix+1]);
439: HT_FREE(sPrefix);
440: } else {
441: if (!sNamespace)
442: sAttributeNamespace = HTRDF_namespace(rdfp, "xmlns");
443: else
444: StrAllocCopy(sAttributeNamespace, sNamespace);
445: }
446:
447: if (HTRDF_parseLiteral(rdfp)) {
448: if (!sPrefix) {
449: if (!(sPrefix = HT_MALLOC(8)))
450: HT_OUTOFMEM("XML_startELement");
451: sprintf(sPrefix, "gen%d\n", i);
452: }
453: {
2.3 ! frystyk 454: char * fName = NULL;
2.1 frystyk 455: StrAllocMCopy(&fName, sPrefix, ":", aValue, NULL);
456: HTAssocList_addObject(newAL, fName, aValue);
457: HT_FREE(fName);
458: StrAllocMCopy(&fName, "xmlns:", sPrefix, NULL);
459: HTAssocList_addObject(newAL, fName, sAttributeNamespace);
460: HT_FREE(fName);
461: }
462: } else {
2.3 ! frystyk 463: char * fName = NULL;
2.1 frystyk 464: StrAllocMCopy(&fName, sAttributeNamespace, aName, NULL);
465: HTAssocList_addObject(newAL, fName, aValue);
466: HT_FREE(fName);
467: }
468:
469: HT_FREE(sAttributeNamespace);
470:
471: /*
472: ** This call will try to see if the user is using
473: ** RDF look-alike elements from another namespace
474: **
475: ** Note: you can remove the call if you wish
476: */
477: #if 0
478: HTRDF_likeRDF (rdfp, sAttributeNamespace, aName);
479: #endif
480:
481: } /* end of if */
482: i+=2;
483: } /* end of while */
484: } /* end of if atts */
485:
486: /*
487: * If we have parseType="Literal" set earlier, this element
488: * needs some additional attributes to make it stand-alone
489: * piece of XML
490: */
491: if (HTRDF_parseLiteral(rdfp)) {
2.3 ! frystyk 492: char * fName = NULL;
2.1 frystyk 493: if (!sPrefix2) {
494: if (sNamespace)
495: HTAssocList_addObject(newAL, "xmlns:gen", sNamespace);
496: StrAllocMCopy(&fName, "gen", sElementName, NULL);
497: newElement = HTElement_new(fName, newAL);
498: StrAllocCopy(newElement->m_sPrefix, "gen");
499: HT_FREE(fName);
500: } else {
2.3 ! frystyk 501: char * sAttributeNamespace = HTRDF_namespace(rdfp, sPrefix2);
2.1 frystyk 502: if (sAttributeNamespace) {
503: StrAllocMCopy(&fName, "xmlns:", sPrefix2, NULL);
504: HTAssocList_addObject(newAL, fName, sAttributeNamespace);
505: HT_FREE(fName);
506: }
507: StrAllocMCopy(&fName, sPrefix2, ":", sElementName, NULL);
508: newElement = HTElement_new(fName, newAL);
509: HT_FREE(fName);
510: }
511: } else {
2.3 ! frystyk 512: char * fName = NULL;
2.1 frystyk 513: StrAllocMCopy(&fName, sNamespace, sElementName, NULL);
514: newElement = HTElement_new(fName, newAL);
515: HT_FREE(fName);
516: /* HTRDF_likeRDF (rdfp, sNamespace, sElementName); */
517: }
518: HT_FREE(sElementName);
519: HT_FREE(sNamespace);
520: HTRDF_checkAttributes(rdfp, newElement);
521:
522: /*
523: ** Check parseType
524: */
525: {
2.3 ! frystyk 526: char * fName = NULL;
! 527: char * sLiteralValue = NULL;
2.1 frystyk 528: StrAllocMCopy(&fName, RDFMS, "parseType", NULL);
529: sLiteralValue = HTElement_getAttribute(newElement, fName);
530: HT_FREE(fName);
531: if (sLiteralValue && strcmp(sLiteralValue, "Resource")) {
532: /**
533: * This is the management of the element where
534: * parseType="Literal" appears
535: *
536: * You should notice RDF V1.0 conforming implementations
537: * must treat other values than Literal and Resource as
538: * Literal. This is why the condition is !equals("Resource")
539: */
540:
541: HTList_addObject(rdfp->m_parseTypeStack, sLiteralValue);
542: if (!HTList_isEmpty(rdfp->m_elementStack)) {
543: HTElement *e = (HTElement *)
544: HTList_lastObject(rdfp->m_elementStack);
545: HTElement_addChild(e, newElement);
546: }
547: HTList_addObject(rdfp->m_elementStack, newElement);
548: HTList_addObject(rdfp->m_parseElementStack, newElement);
549: HT_FREE(rdfp->m_sLiteral);
550: StrAllocCopy(rdfp->m_sLiteral, "");
551: return;
552: }
553:
554: if (HTRDF_parseLiteral(rdfp)) {
555: /*
556: * This is the management of any element nested within
557: * a parseType="Literal" declaration
558: */
559: HTList_addObject(rdfp->m_elementStack, newElement);
560: return;
561: }
562:
563: /*
564: ** Update the containment hierarchy with the stack.
565: */
566: if (!HTList_isEmpty(rdfp->m_elementStack)) {
567: HTElement *e = (HTElement *)
568: HTList_lastObject(rdfp->m_elementStack);
569: HTElement_addChild(e, newElement);
570: }
571:
572: /*
573: ** Place the new element into the stack
574: */
575: HTList_addObject(rdfp->m_elementStack, newElement);
576: if (sLiteralValue && !strcmp(sLiteralValue, "Resource")) {
577: HTList_addObject(rdfp->m_parseTypeStack, sLiteralValue);
578: HTList_addObject(rdfp->m_parseElementStack, newElement);
579: HT_FREE(rdfp->m_sLiteral);
580: StrAllocCopy(rdfp->m_sLiteral, "");
581:
582: /*
583: * Since parseType="Resource" implies the following
584: * production must match Description, let's create
585: * an additional Description node here in the document tree.
586: */
587: {
2.3 ! frystyk 588: char * fName = NULL;
2.1 frystyk 589: HTElement *desc = NULL;
590: HTAssocList * al = HTAssocList_new ();
591: StrAllocMCopy(&fName, RDFMS, "Description", NULL);
592: desc = HTElement_new(fName, al);
593: HT_FREE(fName);
594: if (!HTList_isEmpty(rdfp->m_elementStack)) {
595: HTElement *e = (HTElement *)
596: HTList_lastObject(rdfp->m_elementStack);
597: HTElement_addChild(e, desc);
598: }
599: HTList_addObject(rdfp->m_elementStack, desc);
600: }
601: } /* end of if */
602: } /* end of block */
603: } /* end of block */
604: }
605:
606: /*
607: * For each end of an element scope step back in the
608: * element and namespace stack
609: */
610: PRIVATE void XML_endElement (void * userData,
611: const XML_Char * name)
612: {
613: HTRDF * rdfp = (HTRDF *) userData;
614: BOOL bParseLiteral = rdfp ? HTRDF_parseLiteral(rdfp) : NO;
615: HTAssocList * namespaces = HTList_removeLastObject(rdfp->m_namespaceStack);
616: rdfp->m_root = (HTElement *) HTList_removeLastObject(rdfp->m_elementStack);
617: if (namespaces) HTAssocList_delete(namespaces);
618:
619: if (bParseLiteral) {
620: HTElement *pe = (HTElement *)
621: HTList_lastObject(rdfp->m_parseElementStack);
622: if (pe != rdfp->m_root) {
623: /* do nothing */
624: } else {
625: HTElement *de = HTElement_new2(rdfp->m_sLiteral);
626: HTElement_addChild(pe, de);
627: HT_FREE(rdfp->m_sLiteral);
628: StrAllocCopy(rdfp->m_sLiteral, "");
629: HTList_removeLastObject(rdfp->m_parseElementStack);
630: HTList_removeLastObject(rdfp->m_parseTypeStack);
631: }
632: } else if (HTRDF_parseResource(rdfp)) {
633: /**
634: * If we are doing parseType="Resource"
635: * we need to explore whether the next element in
636: * the stack is the closing element in which case
637: * we remove it as well (remember, there's an
638: * extra Description element to be removed)
639: */
640:
641: if (!HTList_isEmpty(rdfp->m_elementStack)) {
642: HTElement *pe = (HTElement *)
643: HTList_lastObject(rdfp->m_parseElementStack);
644: HTElement *e = (HTElement *)
645: HTList_lastObject(rdfp->m_elementStack);
646: if (pe == e) {
647: e = (HTElement *) HTList_removeLastObject(rdfp->m_elementStack);
648: HTList_removeLastObject(rdfp->m_parseElementStack);
649: HTList_removeLastObject(rdfp->m_parseTypeStack);
650: }
651: }
652: }
653: }
654:
655: PRIVATE void XML_characterData (void * userData,
656: const XML_Char * s, int len)
657: {
658: /*
659: * Place all characters as Data instance to the containment
660: * hierarchy with the help of the stack.
661: */
662: HTRDF * rdfp = (HTRDF *) userData;
2.3 ! frystyk 663: HTElement * e = (HTElement *) HTList_lastObject(rdfp->m_elementStack);
! 664: char * tstr = NULL;
! 665: char * str = NULL;
! 666: if (!(str = (char *) HT_MALLOC(len+1)))
2.1 frystyk 667: HT_OUTOFMEM("XML_characterData");
668: strncpy(str, s, len);
669: str[len]='\0';
670: if (HTRDF_parseLiteral(rdfp)) {
671: StrAllocCat(rdfp->m_sLiteral, str);
672: HT_FREE(str);
673: return;
674: }
675: /* JUST FOR EXPAT */
676: {
677: HTElement *lch = (HTElement *) HTList_lastObject(e->m_children);
678: if (lch && HTElement_instanceOfData(lch)) {
679: HTElement_addData(lch, str);
680: HT_FREE(str);
681: return;
682: }
683: }
684: /*
685: * Warning: this is not correct procedure according to XML spec.
686: * All whitespace matters!
687: */
688: tstr = trim(str);
689: if (strlen(tstr) > 0) {
690: HTElement * de = HTElement_new2(tstr);
691: HTElement_addChild(e, de);
692: }
693: HT_FREE(str); HT_FREE(tstr);
694: }
695:
696: PRIVATE void XML_processingInstruction (void * userData,
697: const XML_Char * target,
698: const XML_Char * data)
699: {
700: return;
701: }
702:
703: /*
704: ** This is called for any characters in the XML document for
705: ** which there is no applicable handler. This includes both
706: ** characters that are part of markup which is of a kind that is
707: ** not reported (comments, markup declarations), or characters
708: ** that are part of a construct which could be reported but
709: ** for which no handler has been supplied. The characters are passed
710: ** exactly as they were in the XML document except that
711: ** they will be encoded in UTF-8. Line boundaries are not normalized.
712: ** Note that a byte order mark character is not passed to the default handler.
713: ** If a default handler is set, internal entity references
714: ** are not expanded. There are no guarantees about
715: ** how characters are divided between calls to the default handler:
716: ** for example, a comment might be split between multiple calls.
717: */
718: PRIVATE void XML_default (void * userData,
719: const XML_Char * s, int len)
720: {
721: return;
722: }
723:
724: /*
725: ** This is called for a declaration of an unparsed (NDATA)
726: ** entity. The base argument is whatever was set by XML_SetBase.
727: ** The entityName, systemId and notationName arguments will never be null.
728: ** The other arguments may be.
729: */
730: PRIVATE void XML_unparsedEntityDecl (void * userData,
731: const XML_Char * entityName,
732: const XML_Char * base,
733: const XML_Char * systemId,
734: const XML_Char * publicId,
735: const XML_Char * notationName)
736: {
737: return;
738: }
739:
740: /*
741: ** This is called for a declaration of notation.
742: ** The base argument is whatever was set by XML_SetBase.
743: ** The notationName will never be null. The other arguments can be.
744: */
745: PRIVATE void XML_notationDecl (void * userData,
746: const XML_Char * notationName,
747: const XML_Char * base,
748: const XML_Char * systemId,
749: const XML_Char * publicId)
750: {
751: return;
752: }
753:
754: /*
755: ** This is called for a reference to an external parsed general entity.
756: ** The referenced entity is not automatically parsed.
757: ** The application can parse it immediately or later using
758: ** XML_ExternalEntityParserCreate.
759: ** The parser argument is the parser parsing the entity containing the reference;
760: ** it can be passed as the parser argument to XML_ExternalEntityParserCreate.
761: ** The systemId argument is the system identifier as specified in the entity
762: ** declaration; it will not be null.
763: ** The base argument is the system identifier that should be used as the base for
764: ** resolving systemId if systemId was relative; this is set by XML_SetBase;
765: ** it may be null.
766: ** The publicId argument is the public identifier as specified in the entity declaration,
767: ** or null if none was specified; the whitespace in the public identifier
768: ** will have been normalized as required by the XML spec.
769: ** The openEntityNames argument is a space-separated list of the names of the entities
770: ** that are open for the parse of this entity (including the name of the referenced
771: ** entity); this can be passed as the openEntityNames argument to
772: ** XML_ExternalEntityParserCreate; openEntityNames is valid only until the handler
773: ** returns, so if the referenced entity is to be parsed later, it must be copied.
774: ** The handler should return 0 if processing should not continue because of
775: ** a fatal error in the handling of the external entity.
776: ** In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING
777: ** error.
778: ** Note that unlike other handlers the first argument is the parser, not userData.
779: */
780: PRIVATE int XML_externalEntityRef (XML_Parser parser,
781: const XML_Char * openEntityNames,
782: const XML_Char * base,
783: const XML_Char * systemId,
784: const XML_Char * publicId)
785: {
786: return 0;
787: }
788:
789: /*
790: ** This is called for an encoding that is unknown to the parser.
791: ** The encodingHandlerData argument is that which was passed as the
792: ** second argument to XML_SetUnknownEncodingHandler.
793: ** The name argument gives the name of the encoding as specified in
794: ** the encoding declaration.
795: ** If the callback can provide information about the encoding,
796: ** it must fill in the XML_Encoding structure, and return 1.
797: ** Otherwise it must return 0.
798: ** If info does not describe a suitable encoding,
799: ** then the parser will return an XML_UNKNOWN_ENCODING error.
800: */
801: PRIVATE int XML_unknownEncoding (void * encodingHandlerData,
802: const XML_Char * name,
803: XML_Encoding * info)
804: {
805: return 0;
806: }
807:
808: /* ------------------------------------------------------------------------- */
809: /* HTXML STREAM HANDLERS */
810: /* ------------------------------------------------------------------------- */
811:
812: PRIVATE void rdf_setHandlers (XML_Parser me)
813: {
814: XML_SetElementHandler(me, XML_startElement, XML_endElement);
815: XML_SetCharacterDataHandler(me, XML_characterData);
816: XML_SetProcessingInstructionHandler(me, XML_processingInstruction);
817: XML_SetDefaultHandler(me, XML_default);
818: XML_SetUnparsedEntityDeclHandler(me, XML_unparsedEntityDecl);
819: XML_SetNotationDeclHandler(me, XML_notationDecl);
820: XML_SetExternalEntityRefHandler(me, XML_externalEntityRef);
821: XML_SetUnknownEncodingHandler(me, XML_unknownEncoding, NULL);
822: }
823:
824: PRIVATE void rdf_newInstance (HTStream * me,
825: HTRequest * request,
826: HTFormat target_format,
827: HTStream * target_stream,
828: XML_Parser xmlparser,
829: void * context)
830: {
831: if (me && xmlparser) {
832: rdf_setHandlers(xmlparser);
833: XML_SetUserData(xmlparser, context);
834:
835: /* Call the new RDF instance callback (if any) with this new stream */
836: if (RDFInstance)
837: (*RDFInstance)(me, request, target_format, target_stream, context, RDFInstanceContext);
838: }
839: }
840:
841: /* ------------------------------------------------------------------------- */
842: /* RDF PARSER */
843: /* ------------------------------------------------------------------------- */
844:
845: PRIVATE void visit_element_children (HTList *children)
846: {
847: HTElement *child = NULL;
848: HTList *cur = children;
849: while ((child = (HTElement *) HTList_nextObject(cur))) {
850: if (!HTList_isEmpty(child->m_children))
851: visit_element_children(child->m_children);
852: HTElement_delete(child);
853: }
854: }
855:
856: PRIVATE void delete_elements (HTRDF * me)
857: {
858: if (me && me->m_root) {
859: HTElement *r = me->m_root;
860: if (!HTList_isEmpty(r->m_children))
861: visit_element_children(r->m_children);
862: HTElement_delete(r);
863: }
864: }
865:
866: PUBLIC HTRDF * HTRDF_new (void)
867: {
868: HTRDF * me;
869: if ((me = (HTRDF *) HT_CALLOC(1, sizeof(HTRDF))) == NULL)
870: HT_OUTOFMEM("HTRDF_new");
871: me->m_namespaceStack = HTList_new();
872: me->m_elementStack = HTList_new();
873:
874: me->m_triples = HTList_new();
875: me->m_vAllNameSpaces = HTList_new();
876:
877: me->m_bCreateBags = FALSE;
878: me->m_bFetchSchemas = FALSE;
879:
880: me->m_parseTypeStack = HTList_new();
881: me->m_parseElementStack = HTList_new();
882:
883: me->m_vResources = HTList_new();
884: me->m_vResolveQueue = HTList_new();
885: me->m_hIDtable = HTHashtable_new(0);
886:
887: return me;
888: }
889:
890: PUBLIC BOOL HTRDF_delete (HTRDF * me)
891: {
892: if (me) {
893: delete_elements(me);
894: if (me->m_namespaceStack) {
895: HTList *cur = me->m_namespaceStack;
896: HTAssocList *alist = NULL;
897: while ((alist = (HTAssocList *) HTList_nextObject(cur))) {
898: HTAssocList_delete(alist);
899: }
900: HTList_delete(me->m_namespaceStack);
901: }
902: if (me->m_elementStack) HTList_delete(me->m_elementStack);
903: me->m_root = NULL;
904: if (me->m_triples) {
905: HTList *cur = me->m_triples;
906: HTTriple *t = NULL;
907: while ((t = (HTTriple *) HTList_nextObject(cur))) {
908: /*HTTriple_print(t);*/
909: HTTriple_delete(t);
910: }
911: HTList_delete(me->m_triples);
912: }
913: HT_FREE(me->m_sSource);
914: if (me->m_vAllNameSpaces) {
915: HTList *cur = me->m_vAllNameSpaces;
2.3 ! frystyk 916: char * s = NULL;
! 917: while ((s = (char *) HTList_nextObject(cur))) {
2.1 frystyk 918: HT_FREE(s);
919: }
920: HTList_delete(me->m_vAllNameSpaces);
921: }
922: if (me->m_parseTypeStack)
923: HTList_delete(me->m_parseTypeStack);
924: if (me->m_parseElementStack)
925: HTList_delete(me->m_parseElementStack);
926: if (me->m_vResources)
927: HTList_delete(me->m_vResources);
928: if (me->m_vResolveQueue)
929: HTList_delete(me->m_vResolveQueue);
930: if (me->m_hIDtable)
931: HTHashtable_delete(me->m_hIDtable);
932: HT_FREE(me->m_sLiteral);
933: HT_FREE(me);
934: return YES;
935: }
936: return NO;
937: }
938:
939: /*
940: * setSource method saves the name of the source document for
941: * later inspection if needed
942: */
2.3 ! frystyk 943: PUBLIC BOOL HTRDF_setSource(HTRDF *me, char * source)
2.1 frystyk 944: {
945: if (me && source) {
946: StrAllocCopy (me->m_sSource, source);
947: return YES;
948: }
949: return NO;
950: }
951:
952: /*
953: * Go through the m_vResolveQueue and assign
954: * direct object reference for each symbolic reference
955: */
956: PUBLIC BOOL HTRDF_resolve (HTRDF * me)
957: {
958: if (me) {
959: HTList * cur = me->m_vResolveQueue;
960: HTElement *e = NULL;
961: HTElement *e2 = NULL;
962: while ((e = (HTElement *) HTList_nextObject(cur))) {
2.3 ! frystyk 963: char * sAbout = HTElement_getAttribute2(e, RDFMS, "about");
! 964: char * sResource = HTElement_getAttribute2(e, RDFMS, "resource");
! 965: char * sAboutEach = HTElement_getAttribute2(e, RDFMS, "aboutEach");
! 966: char * sAboutEachPrefix = HTElement_getAttribute2(e, RDFMS,
2.1 frystyk 967: "aboutEachPrefix");
968: if (sAbout) {
969: if (sAbout[0]=='#')
970: sAbout = &(sAbout[1]);
971: e2 = (HTElement *) HTRDF_lookforNode(me, sAbout);
972: if (e2)
973: HTElement_addTarget(e, e2);
974: else
975: HTPrint("Unresolved internal reference %s\n", sAbout);
976: }
977: if (sResource) {
978: if (sResource[0]=='#')
979: sResource = &(sResource[1]);
980: e2 = (HTElement *) HTRDF_lookforNode(me, sResource);
981: if (e2)
982: HTElement_addTarget(e, e2);
983: }
984:
985: if (sAboutEach) {
986: sAboutEach = &(sAboutEach[1]);
987: e2 = (HTElement *) HTRDF_lookforNode(me, sAboutEach);
988: if (e2)
989: HTElement_addTarget(e, e2);
990: }
991: if (sAboutEachPrefix) {
992: HTList * curr = me->m_vResources;
993: HTElement *ele = NULL;
994: while ((ele = (HTElement *) HTList_nextObject(curr))) {
2.3 ! frystyk 995: char * sA = HTElement_getAttribute2(ele, RDFMS, "about");
2.1 frystyk 996: if (sA &&
997: !strncmp(sA, sAboutEachPrefix, strlen(sAboutEachPrefix))) {
998: HTElement_addTarget(e, ele);
999: }
1000: }
1001: }
1002: }
1003: HTList_delete(me->m_vResources);
1004: me->m_vResources = HTList_new();
1005: return YES;
1006: }
1007: return NO;
1008: }
1009:
1010: /**
1011: * Check if the element e is from the namespace
1012: * of the RDF schema by comparing only the beginning of
1013: * the expanded element name with the canonical RDFMS
1014: * URI
1015: */
1016: PUBLIC BOOL HTRDF_isRDF(HTRDF * me, HTElement *e)
1017: {
1018: return (me && e && e->m_sName) ?
1019: (!strncmp(e->m_sName, RDFMS, strlen(RDFMS))) : NO;
1020: }
1021:
1022: PUBLIC BOOL HTRDF_isRDFroot (HTRDF * me, HTElement *e)
1023: {
1024: if (me && e && e->m_sName) {
1025: int len = strlen(e->m_sName);
1026: if (len > 3) return (HTRDF_isRDF(me, e) && !strcmp(&(e->m_sName[len-3]), "RDF"));
1027: }
1028: return NO;
1029: }
1030:
1031: /**
1032: * Is the element a Description
1033: */
1034: PUBLIC BOOL HTRDF_isDescription (HTRDF *me, HTElement *e)
1035: {
1036: if (me && e && e->m_sName) {
1037: int len = strlen(e->m_sName);
1038: if (len > 11) return (HTRDF_isRDF(me, e) && !strcmp(&(e->m_sName[len-11]), "Description"));
1039: }
1040: return NO;
1041: }
1042:
1043: /*
1044: * Is the element a ListItem
1045: */
1046: PUBLIC BOOL HTRDF_isListItem (HTRDF *me, HTElement *e)
1047: {
1048: if (me && e && e->m_sName) {
1049: int len = strlen(e->m_sName);
1050: if (len > 2)
1051: return (HTRDF_isRDF(me, e) && (!strcmp(&(e->m_sName[len-2]), "li") || strchr(e->m_sName,'_')));
1052: }
1053: return NO;
1054: }
1055:
1056: /**
1057: * Is the element a Sequence
1058: */
1059: PUBLIC BOOL HTRDF_isSequence (HTRDF *me, HTElement *e)
1060: {
1061: if (me && e && e->m_sName) {
1062: int len = strlen(e->m_sName);
1063: if (len > 3) return (HTRDF_isRDF(me, e) && !strcmp(&(e->m_sName[len-3]), "Seq"));
1064: }
1065: return NO;
1066: }
1067:
1068: /*
1069: * Is the element an Alternative
1070: */
1071: PUBLIC BOOL HTRDF_isAlternative (HTRDF *me, HTElement *e)
1072: {
1073: if (me && e && e->m_sName) {
1074: int len = strlen(e->m_sName);
1075: if (len > 3) return (HTRDF_isRDF(me, e) && !strcmp(&(e->m_sName[len-3]), "Alt"));
1076: }
1077: return NO;
1078: }
1079:
1080: /*
1081: * Is the element a Bag
1082: */
1083: PUBLIC BOOL HTRDF_isBag (HTRDF *me, HTElement *e)
1084: {
1085: if (me && e && e->m_sName) {
1086: int len = strlen(e->m_sName);
1087: if (len > 3) return (HTRDF_isRDF(me, e) && !strcmp(&(e->m_sName[len-3]), "Bag"));
1088: }
1089: return NO;
1090: }
1091:
1092: /**
1093: * Is the element a Container
1094: */
1095: PUBLIC BOOL HTRDF_isContainer (HTRDF *me, HTElement *e)
1096: {
1097: return (HTRDF_isSequence(me, e) ||
1098: HTRDF_isAlternative(me, e) ||
1099: HTRDF_isBag(me, e));
1100: }
1101:
1102: /*
1103: * This method matches all properties but those from RDF namespace
1104: */
1105: PUBLIC BOOL HTRDF_isTypedPredicate(HTRDF *me, HTElement *e)
1106: {
1107: if (me && e && e->m_sName) {
1108: int len = strlen(e->m_sName);
2.3 ! frystyk 1109: char * tp[] = {"predicate", "subject", "object",
2.1 frystyk 1110: "value", "type", "Property", "Statement"};
1111: int i;
1112: if (HTRDF_isRDF(me, e)) {
1113: for(i = 0; i< 7; i++) {
1114: int ntp = strlen(tp[i]);
1115: if (len > ntp) {
1116: if (!strcmp(&(e->m_sName[len-ntp]), tp[i]))
1117: return YES;
1118: }
1119: }
1120: return NO;
1121: }
1122: if (len > 0) return YES;
1123: }
1124: return NO;
1125: }
1126:
2.3 ! frystyk 1127: PRIVATE void HTRDF_processListItem (HTRDF * me, char * sID, HTElement *listitem,
2.1 frystyk 1128: int iCounter)
1129: {
1130: /*
1131: * Two different cases for
1132: * 1. LI element without content (resource available)
1133: * 2. LI element with content (resource unavailable)
1134: */
2.3 ! frystyk 1135: char * cName = NULL;
! 1136: char * sResource = HTRDF_getResource(me, listitem);
2.1 frystyk 1137: char sdig[20];
1138: sprintf(sdig, "_%d", iCounter);
1139: StrAllocMCopy(&cName, RDFMS, sdig, NULL);
1140: if (sResource) {
1141: HTRDF_addTriple(me, cName, sID, sResource);
1142: /* validity checking */
1143: if (!HTList_isEmpty(listitem->m_children)){
1144: HTPrint("Listitem with resource attribute can not have child nodes");
1145: }
1146: StrAllocCopy(listitem->m_sID, sResource);
1147: } else {
1148: HTList *cur = listitem->m_children;
1149: HTElement *n = NULL;
1150: while ((n = (HTElement *) HTList_nextObject(cur))) {
1151: if (HTElement_instanceOfData(n)) {
1152: HTRDF_addTriple(me, cName, sID, n->m_sContent);
1153: } else if (HTRDF_isDescription(me, n)) {
2.3 ! frystyk 1154: char * sNodeID = HTRDF_processDescription(me, n, NO, YES, NO);
2.1 frystyk 1155: HTRDF_addTriple(me, cName, sID, sNodeID);
1156: StrAllocCopy(listitem->m_sID, sNodeID);
1157: } else if (HTRDF_isListItem(me, n)) {
1158: HTPrint("Can not nest list item inside list item\n");
1159: } else if (HTRDF_isContainer(me, n)) {
2.3 ! frystyk 1160: char * c = HTRDF_processContainer(me, n);
2.1 frystyk 1161: HTRDF_addTriple(me, cName, sID, n->m_sID);
1162: HT_FREE(c);
1163: } else if (HTRDF_isTypedPredicate(me, n)) {
2.3 ! frystyk 1164: char * sNodeID = HTRDF_processTypedNode(me, n);
2.1 frystyk 1165: HTRDF_addTriple(me, cName, sID, sNodeID);
1166: HT_FREE(sNodeID);
1167: }
1168: }
1169: }
1170: HT_FREE(cName);
1171: }
1172:
2.3 ! frystyk 1173: PRIVATE char * HTRDF_processContainer(HTRDF *me, HTElement *n)
2.1 frystyk 1174: {
2.3 ! frystyk 1175: char * sID = NULL;
! 1176: char * tName = NULL;
! 1177: char * aName = NULL;
! 1178: char * sName = NULL;
! 1179: char * bName = NULL;
2.1 frystyk 1180: StrAllocMCopy(&tName, RDFMS, "type", NULL);
1181: StrAllocMCopy(&aName, RDFMS, "Alt", NULL);
1182: StrAllocMCopy(&sName, RDFMS, "Seq", NULL);
1183: StrAllocMCopy(&bName, RDFMS, "Bag", NULL);
1184:
1185: StrAllocCopy(sID, n->m_sID);
1186: if (!sID)
1187: sID = HTRDF_newReificationID(me);
1188: /*
1189: * Do the instantiation only once
1190: */
1191: if (!n->m_bDone) {
1192: if (HTRDF_isSequence(me, n)) {
1193: HTRDF_addTriple(me, tName, sID, sName);
1194: } else if (HTRDF_isAlternative(me, n)) {
1195: HTRDF_addTriple(me, tName, sID, aName);
1196: } else if (HTRDF_isBag(me, n)) {
1197: HTRDF_addTriple(me, tName, sID, bName);
1198: }
1199: n->m_bDone = YES;
1200: }
1201: HTRDF_expandAttributes(me, n, n);
1202:
1203: {
1204: HTList *cur = n->m_children;
1205: HTElement *n2 = NULL;
1206: int iCounter = 1;
1207: if (HTList_isEmpty(cur) && HTRDF_isAlternative(me, n))
1208: HTPrint("An RDF:Alt container must have at least one list item\n");
1209: while ((n2 = (HTElement *) HTList_nextObject(cur))) {
1210: if (HTRDF_isListItem(me, n2)) {
1211: HTRDF_processListItem(me, sID, n2, iCounter);
1212: iCounter++;
1213: } else {
1214: HTPrint("Can not nest %s, inside container\n", n2->m_sName);
1215: }
1216: }
1217: } /* end of block */
1218:
1219: HT_FREE(tName); HT_FREE(sName); HT_FREE(aName); HT_FREE(bName);
1220:
1221: return sID;
1222: }
1223: /*
1224: * Manage the typedNode production in the RDF grammar.
1225: *
1226: */
2.3 ! frystyk 1227: PUBLIC char * HTRDF_processTypedNode(HTRDF *me, HTElement *typedNode)
2.1 frystyk 1228: {
2.3 ! frystyk 1229: char * sID = HTElement_getAttribute2(typedNode, RDFMS, "ID");
! 1230: char * sBagID = HTElement_getAttribute2(typedNode, RDFMS, "bagID");
! 1231: char * sAbout = HTElement_getAttribute2(typedNode, RDFMS, "about");
! 1232: char * sAboutEach = HTElement_getAttribute2(typedNode, RDFMS, "aboutEach");
! 1233: /*char * sAboutEachPrefix = HTElement_getAttribute2(typedNode, RDFMS,
2.1 frystyk 1234: "aboutEachPrefix");*/
2.3 ! frystyk 1235: char * resource = HTElement_getAttribute2(typedNode, RDFMS, "resource");
! 1236: char * iName = NULL;
! 1237: char * bName = NULL;
! 1238: char * tName = NULL;
2.1 frystyk 1239:
2.3 ! frystyk 1240: char * sObject = NULL;
2.1 frystyk 1241:
1242: StrAllocMCopy(&iName, RDFMS, "ID", NULL);
1243: StrAllocMCopy(&bName, RDFMS, "bagID", NULL);
1244: StrAllocMCopy(&tName, RDFMS, "type", NULL);
1245:
1246: if (resource)
1247: HTPrint("resource attribute not allowed for a typedNode %s\n",
1248: typedNode->m_sName);
1249:
1250: /*
1251: * We are going to manage this typedNode using the processDescription
1252: * routine later on. Before that, place all properties encoded as
1253: * attributes to separate child nodes.
1254: */
1255: {
1256: HTAssoc * assoc;
1257: HTAssocList *cur = typedNode->m_attributes;
2.3 ! frystyk 1258: char * sAttribute = NULL;
! 1259: char * tValue = NULL;
! 1260: char * sValue = NULL;
2.1 frystyk 1261: while((assoc= (HTAssoc *) HTList_nextObject(cur))) {
1262: sAttribute = HTAssoc_name(assoc);
1263: sValue = HTAssoc_value(assoc);
1264: tValue = trim(sValue);
1265: if (strncmp(sAttribute, RDFMS, strlen(RDFMS)) &&
1266: strncmp(sAttribute, XMLSCHEMA, strlen(XMLSCHEMA))) {
1267: if (strlen(tValue) > 0) {
1268: HTAssocList *newAL = HTAssocList_new();
1269: HTElement *newPredicate = HTElement_new(sAttribute, newAL);
1270: HTElement *d = NULL;
1271: HTElement_addAttribute(newPredicate, iName,
1272: sAbout ? sAbout : sID);
1273: HTElement_addAttribute(newPredicate, bName, sBagID);
1274: d = HTElement_new2(tValue);
1275: HTElement_addChild(newPredicate, d);
1276: HTElement_addChild(typedNode, newPredicate);
1277: HTElement_removeAttribute(typedNode, sAttribute);
1278: }
1279: }
1280: HT_FREE(tValue);
1281: } /* end of while */
1282: }/* end of block */
1283: {
1284: if (sAbout)
1285: StrAllocCopy(sObject, sAbout);
1286: else if (sID)
1287: StrAllocCopy(sObject, sID);
1288: else
1289: sObject = HTRDF_newReificationID(me);
1290: StrAllocCopy(typedNode->m_sID, sObject);
1291:
1292: /* special case: should the typedNode have aboutEach attribute,
1293: ** the type predicate should distribute to pointed
1294: ** collection also -> create a child node to the typedNode
1295: */
1296: if (sAboutEach && !HTList_isEmpty(typedNode->m_vTargets)) {
1297: HTAssocList *newAL = HTAssocList_new();
1298: HTElement *newPredicate = HTElement_new(tName, newAL);
1299: HTElement *d = HTElement_new2(typedNode->m_sName);
1300: HTElement_addChild(newPredicate, d);
1301: HTElement_addChild(typedNode, newPredicate);
1302: } else {
1303: HTRDF_addTriple(me, tName, sObject, typedNode->m_sName);
1304: }
1305: HTRDF_processDescription(me, typedNode, NO, NO, YES);
1306: }/* end of block */
1307:
1308: HT_FREE(iName); HT_FREE(bName); HT_FREE(tName);
1309:
1310: return sObject;
1311: }
1312:
1313: /*
1314: * Start processing an RDF/XML document instance from the
1315: * root element rdf.
1316: *
1317: */
1318: PUBLIC BOOL HTRDF_processRDF (HTRDF *me, HTElement *e)
1319: {
1320: if (me && e) {
1321: HTList *cur = e->m_children;
1322: HTElement *ele = NULL;
1323: if (HTList_isEmpty(e->m_children)) {
1324: HTPrint("Empty RDF Element\n");
1325: return NO;
1326: }
1327: while ((ele= (HTElement *) HTList_nextObject(cur))) {
1328: if (HTRDF_isDescription(me, ele)) {
1329: HTRDF_processDescription(me, ele, NO, me->m_bCreateBags,
1330: me->m_bCreateBags);
1331: } else if (HTRDF_isContainer(me, ele)) {
2.3 ! frystyk 1332: char * c = HTRDF_processContainer(me, ele);
2.1 frystyk 1333: HT_FREE(c);
1334: } else if (HTRDF_isTypedPredicate(me, ele)) {
2.3 ! frystyk 1335: char * t = HTRDF_processTypedNode(me, ele);
2.1 frystyk 1336: HT_FREE(t);
1337: }
1338: }
1339: return YES;
1340: }
1341: return NO;
1342: }
1343:
1344: /*
1345: * processPredicate handles all elements not defined as special
1346: * RDF elements.
1347: *
1348: * predicate The predicate element itself
1349: * description Context for the predicate
1350: * sTarget The target resource
1351: * reificate Should this predicate be reificated
1352: *
1353: * return the new ID which can be used to identify the predicate
1354: *
1355: */
2.3 ! frystyk 1356: PRIVATE char * HTRDF_processPredicate (HTRDF * me,
2.1 frystyk 1357: HTElement * predicate,
1358: HTElement * description,
2.3 ! frystyk 1359: char * sTarget,
2.1 frystyk 1360: BOOL reificate)
1361: {
2.3 ! frystyk 1362: char * sStatementID = HTElement_getAttribute2(predicate, RDFMS, "ID");
! 1363: char * nsStatementID = NULL;
! 1364: char * sBagID = HTElement_getAttribute2(predicate, RDFMS, "bagID");
! 1365: char * sResource = HTRDF_getResource(me, predicate);
2.1 frystyk 1366:
1367: /*
1368: ** If a predicate has other attributes than rdf:ID, rdf:bagID,
1369: ** or xmlns... -> generate new triples according to the spec.
1370: ** (See end of Section 6)
1371: */
1372: {
1373: HTElement * place_holder = NULL;
1374: HTAssocList * newAL = HTAssocList_new();
2.3 ! frystyk 1375: char * fName = NULL;
! 1376: char * aName = NULL;
2.1 frystyk 1377:
1378: StrAllocMCopy(&fName, RDFMS, "Description", NULL);
1379: place_holder = HTElement_new(fName, newAL);
1380: HT_FREE(fName);
1381:
1382: if (HTRDF_expandAttributes(me, place_holder, predicate)) {
1383:
1384: /* error checking */
1385: if (!HTList_isEmpty(predicate->m_children)) {
1386: HTPrint("%s must be an empty element since it uses propAttr grammar production", predicate->m_sName);
1387: HTElement_delete(place_holder);
1388: return NULL;
1389: }
1390: StrAllocMCopy(&aName, RDFMS, "about", NULL);
1391:
1392: /* determine the 'about' part for the new statements */
1393: if (sStatementID) {
1394: HTElement *data = HTElement_new2(sStatementID);
1395: HTElement_addAttribute(place_holder, aName, sStatementID);
1396:
1397: /* hack: make rdf:ID the value of the predicate */
1398: HTElement_addChild(predicate, data);
1399: } else if (sResource) {
1400: HTElement_addAttribute(place_holder, aName, sResource);
1401: } else {
1402: nsStatementID = HTRDF_newReificationID(me);
1403: HTElement_addAttribute(place_holder, aName, nsStatementID);
1404: HT_FREE(nsStatementID);
1405: }
1406: HT_FREE(aName);
1407:
1408: if (sBagID) {
1409: StrAllocMCopy(&fName, RDFMS, "bagID", NULL);
1410: HTElement_addAttribute(place_holder, fName, sBagID);
1411: HT_FREE(fName);
1412: StrAllocCopy(place_holder->m_sBagID, sBagID);
1413: }
1414: HTRDF_processDescription(me, place_holder, NO, NO, me->m_bCreateBags);
1415: } else {
1416:
1417: /* Nothing but xmlns or RDF stuff, so we don't need new element */
1418: HTElement_delete(place_holder);
1419: }
1420: }
1421:
1422: /*
1423: ** Tricky part: if the resource attribute is present for a predicate
1424: ** AND there are no children, the value of the predicate is either
1425: ** 1. the URI in the resource attribute OR
1426: ** 2. the node ID of the resolved #resource attribute
1427: */
1428: if (sResource && HTList_isEmpty(predicate->m_children)) {
1429: if (!HTElement_target(predicate)) {
1430: if (reificate) {
1431: HT_FREE(nsStatementID);
1432: nsStatementID = HTRDF_reificate (me, predicate->m_sName,
1433: sTarget, sResource,
1434: predicate->m_sID);
1435: StrAllocCopy(predicate->m_sID, nsStatementID);
1436: } else {
1437: HTRDF_addTriple(me, predicate->m_sName, sTarget, sResource);
1438: }
1439: } else {
1440: HTElement *target = HTElement_target(predicate);
1441: if (reificate) {
1442: nsStatementID = HTRDF_reificate (me, predicate->m_sName,
1443: sTarget,
1444: target->m_sID,
1445: predicate->m_sID);
1446: StrAllocCopy(predicate->m_sID, nsStatementID);
1447: } else {
1448: HTRDF_addTriple(me, predicate->m_sName, sTarget, target->m_sID);
1449: }
1450: }
1451: StrAllocCopy(nsStatementID, predicate->m_sID);
1452: return nsStatementID;
1453: }
1454:
1455: /*
1456: ** Does this predicate make a reference somewhere using the
1457: ** sResource attribute
1458: */
1459: if (sResource && HTElement_target(predicate)) {
2.3 ! frystyk 1460: char * dStatementID = HTRDF_processDescription(me,
2.1 frystyk 1461: HTElement_target(predicate),
1462: YES, NO, NO);
1463: if (reificate) {
1464: HT_FREE(nsStatementID);
1465: nsStatementID = HTRDF_reificate (me, predicate->m_sName,
1466: sTarget, dStatementID,
1467: predicate->m_sID);
1468: StrAllocCopy(predicate->m_sID, nsStatementID);
1469: } else {
1470: StrAllocCopy(nsStatementID, dStatementID);
1471: HTRDF_addTriple(me, predicate->m_sName, sTarget, nsStatementID);
1472: }
1473: return nsStatementID;
1474: }
1475:
1476: /*
1477: ** Before looping through the children, let's check
1478: ** if there are any. If not, the value of the predicate is
1479: ** an anonymous node
1480: */
1481: {
1482: HTList *cur = predicate->m_children;
1483: BOOL bUsedTypedNodeProduction = NO;
1484: HTElement *n2;
1485: StrAllocCopy(nsStatementID, sStatementID);
1486: if (HTList_isEmpty(cur)) {
1487: if (reificate) {
2.3 ! frystyk 1488: char * nr = HTRDF_newReificationID(me);
2.1 frystyk 1489: HT_FREE(nsStatementID);
1490: nsStatementID = HTRDF_reificate (me, predicate->m_sName,
1491: sTarget, nr,
1492: predicate->m_sID);
1493: HT_FREE(nr);
1494: } else {
2.3 ! frystyk 1495: char * nr = HTRDF_newReificationID(me);
2.1 frystyk 1496: HTRDF_addTriple(me, predicate->m_sName, sTarget, nr);
1497: HT_FREE(nr);
1498: }
1499: }
1500: while ((n2= (HTElement *) HTList_nextObject(cur))) {
1501: if (HTRDF_isDescription(me, n2)) {
1502: HTElement *d2 = n2;
2.3 ! frystyk 1503: char * dStatementID =HTRDF_processDescription(me, d2, YES, NO, NO);
2.1 frystyk 1504: StrAllocCopy(d2->m_sID, dStatementID);
1505:
1506: if (reificate) {
1507: HT_FREE(nsStatementID);
1508: nsStatementID = HTRDF_reificate (me, predicate->m_sName,
1509: sTarget, dStatementID,
1510: predicate->m_sID);
1511: } else {
1512: StrAllocCopy(nsStatementID, dStatementID);
1513: HTRDF_addTriple(me, predicate->m_sName, sTarget,
1514: nsStatementID);
1515: }
1516: } else if (HTElement_instanceOfData(n2)) {
2.3 ! frystyk 1517: char * tValue = NULL;
! 1518: char * sValue = n2->m_sContent;
2.1 frystyk 1519: /* we've got real data */
1520: /*
1521: * Only if the content is not empty PCDATA (whitespace that is)
1522: * print the triple
1523: */
1524: tValue = trim(sValue);
1525: if (tValue && strlen(tValue) > 0) {
1526: if (reificate) {
1527: HT_FREE(nsStatementID);
1528: nsStatementID = HTRDF_reificate (me, predicate->m_sName,
1529: sTarget, tValue,
1530: predicate->m_sID);
1531: StrAllocCopy(predicate->m_sID, nsStatementID);
1532: } else {
1533: HTRDF_addTriple(me, predicate->m_sName, sTarget, tValue);
1534: }
1535: }
1536: HT_FREE(tValue);
1537: } else if (HTRDF_isContainer(me, n2)) {
1538: HTElement *target = HTElement_target(description);
2.3 ! frystyk 1539: char * aboutTarget =
2.1 frystyk 1540: target ?
1541: HTElement_getAttribute2(target, RDFMS, "about") : NULL;
2.3 ! frystyk 1542: char * sCollectionID = HTRDF_processContainer(me, n2);
2.1 frystyk 1543: StrAllocCopy(nsStatementID, sCollectionID);
1544: /* Attach the collection to the current predicate */
1545: if (target) {
1546: if (reificate) {
1547: HT_FREE(nsStatementID);
1548: nsStatementID=HTRDF_reificate (me, predicate->m_sName,
1549: aboutTarget,
1550: sCollectionID,
1551: predicate->m_sID);
1552: StrAllocCopy(predicate->m_sID, nsStatementID);
1553: } else {
1554: HTRDF_addTriple(me, predicate->m_sName, aboutTarget,
1555: sCollectionID);
1556: }
1557: } else {
1558: if (reificate) {
1559: HT_FREE(nsStatementID);
1560: nsStatementID=HTRDF_reificate (me, predicate->m_sName,
1561: sTarget, sCollectionID,
1562: predicate->m_sID);
1563: StrAllocCopy(predicate->m_sID, nsStatementID);
1564: } else {
1565: HTRDF_addTriple(me, predicate->m_sName, sTarget,
1566: sCollectionID);
1567: }
1568: }
1569: HT_FREE(sCollectionID);
1570: } else if (HTRDF_isTypedPredicate(me, n2)) {
1571: if (bUsedTypedNodeProduction) {
1572: HTPrint("Only one typedNode allowed inside a predicate (Extra typedNode: %s )\n", n2->m_sName);
1573: } else {
1574: bUsedTypedNodeProduction = YES;
1575: }
1576: HT_FREE(nsStatementID);
1577: nsStatementID = HTRDF_processTypedNode(me, n2);
1578: HTRDF_addTriple(me, predicate->m_sName, sTarget, nsStatementID);
1579: }
1580: }
1581: return nsStatementID;
1582: } /* end of block */
1583: return NULL;
1584: }
1585:
1586: /*
1587: * processDescription manages Description elements
1588: *
1589: * description The Description element itself
1590: * inPredicate Is this is a nested description
1591: * reificate Do we need to reificate
1592: * createBag Do we create a bag container
1593: *
1594: * return An ID for the description
1595: *
1596: */
2.3 ! frystyk 1597: PUBLIC char * HTRDF_processDescription (HTRDF * me,
2.1 frystyk 1598: HTElement * description,
1599: BOOL inPredicate,
1600: BOOL reificate,
1601: BOOL createBag)
1602: {
1603: int iChildCount = 1;
1604: BOOL bOnce = YES;
1605:
2.3 ! frystyk 1606: char * sAbout = HTElement_getAttribute2(description, RDFMS, "about");
! 1607: char * sAboutEach = HTElement_getAttribute2(description, RDFMS, "aboutEach");
! 1608: char * sAboutEachPrefix = HTElement_getAttribute2(description, RDFMS,
2.1 frystyk 1609: "aboutEachPrefix");
2.3 ! frystyk 1610: char * sBagid = HTElement_getAttribute2(description, RDFMS, "bagID");
! 1611: char * sID = HTElement_getAttribute2(description, RDFMS, "ID");
2.1 frystyk 1612: HTElement *target = HTElement_target(description);
1613: BOOL hasTarget = HTList_isEmpty(description->m_vTargets) ? NO : YES;
1614: BOOL targetIsContainer = NO;
2.3 ! frystyk 1615: char * sTargetAbout = NULL;
! 1616: char * sTargetBagID = NULL;
! 1617: char * sTargetID = NULL;
! 1618: char * dName = NULL;
! 1619: char * aName = NULL;
2.1 frystyk 1620:
1621: /*
1622: ** Return immediately if the description has already been managed
1623: */
1624: if (description->m_bDone) return description->m_sID;
1625:
1626: StrAllocMCopy(&dName, RDFMS, "Description", NULL);
1627: StrAllocMCopy(&aName, RDFMS, "about", NULL);
1628:
1629: /*
1630: ** Determine what the target of the Description reference is
1631: */
1632: if (hasTarget) {
2.3 ! frystyk 1633: char * sTargetID2 = HTElement_getAttribute2(target, RDFMS, "ID");
2.1 frystyk 1634: sTargetAbout = HTElement_getAttribute2(target, RDFMS, "about");
1635: sTargetBagID = HTElement_getAttribute2(target, RDFMS, "bagID");
1636: if (me->m_sSource && sTargetID2) {
1637: StrAllocMCopy(&sTargetID, me->m_sSource, sTargetID2, NULL);
1638: } else {
1639: StrAllocCopy(sTargetID, sTargetID2);
1640: }
1641: /*
1642: * Target is collection if
1643: * 1. it is identified with bagID attribute
1644: * 2. it is identified with ID attribute and is a collection
1645: */
1646: if (sTargetBagID && sAbout) {
1647: targetIsContainer = !strcmp(&(sAbout[1]), sTargetBagID);
1648: } else {
1649: if (sTargetID && sAbout && !strcmp(&(sAbout[1]), sTargetID) &&
1650: HTRDF_isContainer(me, target))
1651: targetIsContainer = YES;
1652: }
1653: HT_FREE(sTargetID);
1654: }
1655:
1656: /*
1657: * Check if there are properties encoded using the abbreviated
1658: * syntax
1659: */
1660: HTRDF_expandAttributes(me, description, description);
1661:
1662: /*
1663: * Manage the aboutEach attribute here
1664: */
1665: if (sAboutEach && hasTarget) {
1666: if (HTRDF_isContainer(me, target)) {
1667: HTList *cur = target->m_children;
1668: HTElement *ele = NULL;
1669: while ((ele= (HTElement *) HTList_nextObject(cur))) {
1670: if (HTRDF_isListItem(me, ele)) {
2.3 ! frystyk 1671: char * sResource = HTRDF_getResource(me, ele);
2.1 frystyk 1672: if (sResource) {
1673: HTElement * newDescription = NULL;
1674: HTElement * ele2;
1675: HTList * cur2 = description->m_children;
1676:
1677: /*
1678: * Manage <li resource="..." /> case
1679: */
1680: if (sResource) {
1681: HTAssocList *newAL = HTAssocList_new();
1682: newDescription = HTElement_new(dName, newAL);
1683: HTElement_addAttribute(newDescription, aName, sResource);
1684: }
1685:
1686: while ((ele2 = (HTElement *) HTList_nextObject(cur2))){
1687: if (newDescription) HTElement_addChild(newDescription, ele2);
1688: }
1689:
1690: if (newDescription)
1691: HTRDF_processDescription(me, newDescription, NO, NO, NO);
1692:
1693: /* Not needed anymore */
1694: HTElement_delete(newDescription);
1695:
1696: } else {
1697: /**
1698: * Otherwise we have a structured value inside <li>
1699: *
1700: * loop through the children of <li>
1701: * (can be only one)
1702: */
1703: HTList *cur2 = ele->m_children;
1704: HTElement *ele2 = NULL;
1705: while ((ele2 = (HTElement *) HTList_nextObject(cur2))) {
1706: HTAssocList *newAL = HTAssocList_new();
1707: HTElement *newNode = HTElement_new(dName, newAL);
1708: HTList *cur3 = description->m_children;
1709: HTElement *ele3 = NULL;
1710: /* loop through the items in the
1711: * description with aboutEach
1712: * and add them to the target
1713: */
1714: while ((ele3 = (HTElement *)
1715: HTList_nextObject(cur3))) {
1716: HTElement_addChild(newNode, ele3);
1717: }
1718: HTElement_addTarget(newNode, ele2);
1719: HTRDF_processDescription(me, newNode, YES, NO, NO);
1720: }
1721: }
1722: } else if (HTRDF_isTypedPredicate(me, ele)) {
1723: HTAssocList *newAL = HTAssocList_new();
1724: HTElement *newNode = HTElement_new(dName, newAL);
1725: HTList *cur2 = description->m_children;
1726: HTElement *ele2 = NULL;
1727: while ((ele2 = (HTElement *) HTList_nextObject(cur2))) {
1728: HTElement_addChild(newNode, ele2);
1729: }
1730: HTElement_addTarget(newNode, ele);
1731: HTRDF_processDescription(me, newNode, YES, NO, NO);
1732: }
1733: } /* end of while */
1734: } else if (HTRDF_isDescription(me, target)) {
1735: HTList *cur = target->m_children;
1736: HTElement *ele = NULL;
1737: while ((ele = (HTElement *) HTList_nextObject(cur))) {
1738: HTAssocList *newAL = HTAssocList_new();
1739: HTElement *newNode = HTElement_new(dName, newAL);
1740: HTList *cur2 = description->m_children;
1741: HTElement *ele2 = NULL;
1742: while ((ele2 = (HTElement *) HTList_nextObject(cur2))) {
1743: HTElement_addChild(newNode, ele2);
1744: }
1745: HTElement_addTarget(newNode, ele);
1746: HTRDF_processDescription(me, newNode, YES, NO, NO);
1747: } /* end of while */
1748: }
1749:
1750: HT_FREE(dName);
1751: HT_FREE(aName);
1752: return NULL;
1753: }
1754:
1755: /*
1756: * Manage the aboutEachPrefix attribute here
1757: */
1758: if (sAboutEachPrefix) {
1759: if (hasTarget) {
1760: HTList *cur = description->m_vTargets;
1761: HTElement *target = NULL;
1762: while ((target = (HTElement *) HTList_nextObject(cur))) {
1763: HTList *cur2 = description->m_children;
1764: HTElement *ele2 = NULL;
1765: HTElement *newDescription = NULL;
1766: HTAssocList *newAL = HTAssocList_new();
1767: sTargetAbout = HTElement_getAttribute2(target, RDFMS, "about");
1768: newDescription = HTElement_new(dName, newAL);
1769: HTElement_addAttribute(newDescription, aName, sTargetAbout);
1770: while ((ele2 = (HTElement *) HTList_nextObject(cur2))) {
1771: HTElement_addChild(newDescription, ele2);
1772: }
1773: HTRDF_processDescription(me, newDescription, NO, NO, NO);
1774: }
1775: }
1776:
1777: HT_FREE(dName);
1778: HT_FREE(aName);
1779: return NULL;
1780: }
1781: /*
1782: * Enumerate through the children
1783: */
1784: {
1785: HTList *cur = description->m_children;
1786: HTElement *n = NULL;
1787: while ((n = (HTElement *) HTList_nextObject(cur))) {
1788: if (HTRDF_isDescription(me, n))
1789: HTPrint("Can not nest Description inside Description\n");
1790: else if (HTRDF_isListItem(me, n))
1791: HTPrint("Can not nest List Item inside Description\n");
1792: else if (HTRDF_isContainer(me, n))
1793: HTPrint("Can not nest Container inside Description\n");
1794: else if (HTRDF_isTypedPredicate(me, n)) {
2.3 ! frystyk 1795: char * sChildID = NULL;
2.1 frystyk 1796: if (hasTarget && targetIsContainer) {
1797: sChildID = HTRDF_processPredicate(me, n, description,
1798: target->m_sBagID ?
1799: target->m_sBagID :
1800: target->m_sID, NO);
1801: StrAllocCopy(description->m_sID, sChildID);
1802: createBag = NO;
1803: } else if (hasTarget) {
1804: sChildID = HTRDF_processPredicate(me, n, description,
1805: target->m_sBagID ?
1806: target->m_sBagID :
1807: target->m_sID, reificate);
1808: StrAllocCopy(description->m_sID, sChildID);
1809: } else if (!hasTarget && !inPredicate) {
1810: if (!description->m_sID) {
2.3 ! frystyk 1811: char * nr = HTRDF_newReificationID(me);
2.1 frystyk 1812: StrAllocCopy(description->m_sID, nr);
1813: HT_FREE(nr);
1814: }
1815: if (!sAbout) {
1816: if (sID)
1817: sAbout = sID;
1818: else
1819: sAbout = description->m_sID;
1820: }
1821: sChildID = HTRDF_processPredicate(me, n, description,
1822: sAbout, sBagid ?
1823: YES : reificate);
1824:
1825: } else if (!hasTarget && inPredicate) {
1826: if (!sAbout) {
1827: if (sID) {
1828: StrAllocCopy(description->m_sID, sID);
1829: sAbout = sID;
1830: } else {
1831: if (!description->m_sID) {
2.3 ! frystyk 1832: char * nr = HTRDF_newReificationID(me);
2.1 frystyk 1833: StrAllocCopy(description->m_sID, nr);
1834: HT_FREE(nr);
1835: }
1836: sAbout = description->m_sID;
1837: }
1838: } else {
1839: StrAllocCopy(description->m_sID, sAbout);
1840: }
1841: sChildID = HTRDF_processPredicate(me, n, description, sAbout, NO);
1842: }
1843: /*
1844: * Each Description block creates also a Bag node which
1845: * has links to all properties within the block IF
1846: * the m_bCreateBags variable is true
1847: */
1848: if (sBagid || (me->m_bCreateBags && createBag)) {
2.3 ! frystyk 1849: char * sNamespace = RDFMS;
2.1 frystyk 1850: if (bOnce && sChildID) {
2.3 ! frystyk 1851: char * tName = NULL;
! 1852: char * bName = NULL;
2.1 frystyk 1853: bOnce = NO;
1854: if (!description->m_sBagID) {
2.3 ! frystyk 1855: char * nr = HTRDF_newReificationID(me);
2.1 frystyk 1856: StrAllocCopy(description->m_sBagID, nr);
1857: HT_FREE(nr);
1858: }
1859: if (!description->m_sID)
1860: StrAllocCopy(description->m_sID,
1861: description->m_sBagID);
1862: StrAllocMCopy(&tName, sNamespace, "type", NULL);
1863: StrAllocMCopy(&bName, sNamespace, "Bag", NULL);
1864: HTRDF_addTriple(me, tName, description->m_sBagID, bName);
1865: HT_FREE(tName);
1866: HT_FREE(bName);
1867:
1868: }
1869: if (sChildID) {
2.3 ! frystyk 1870: char * tName = NULL;
2.1 frystyk 1871: char si[20];
1872: sprintf(si, "%d", iChildCount);
1873: StrAllocMCopy(&tName, sNamespace, "_", si, NULL);
1874: HTRDF_addTriple(me, tName, description->m_sBagID, sChildID);
1875: iChildCount++;
1876: HT_FREE(tName);
1877: }
1878: }
1879: HT_FREE(sChildID);
1880: }
1881: }
1882: } /* end of block*/
1883:
1884: description->m_bDone = YES;
1885:
1886: HT_FREE(dName);
1887: HT_FREE(aName);
1888: return (description->m_sID);
1889: }
1890:
1891: /*
1892: * Given an XML document (well-formed HTML, for example),
1893: * look for a suitable element to start parsing from
1894: *
1895: */
1896: PUBLIC BOOL HTRDF_processXML (HTRDF *me, HTElement *ele)
1897: {
1898: if (me && ele) {
1899: if (HTRDF_isRDF(me, ele)) {
1900: if (HTRDF_isRDFroot(me, ele)) {
1901: HTRDF_processRDF(me, ele);
1902: } else if (HTRDF_isDescription(me, ele)) {
1903: HTRDF_processDescription(me, ele, NO, me->m_bCreateBags,
1904: me->m_bCreateBags);
1905: }
1906: } else {
1907: HTList *cur = ele->m_children;
1908: HTElement *child = NULL;
1909: while ((child = (HTElement *) HTList_nextObject(cur))) {
1910: HTRDF_processXML(me, child);
1911: }
1912: }
1913:
1914: /* MISSING RECURSION */
1915:
1916: return YES;
1917: }
1918: return NO;
1919: }
1920:
1921: /*
1922: * Return the root element pointer. This requires the parsing
1923: * has been already done.
1924: */
1925: PUBLIC HTElement * HTRDF_root (HTRDF *me)
1926: {
1927: return me ? me->m_root : NULL;
1928: }
1929:
1930: /*
1931: * Return the full namespace URI for a given prefix sPrefix.
1932: * The default namespace is identified with xmlns prefix.
1933: * The namespace of xmlns attribute is an empty string.
1934: */
1935:
2.3 ! frystyk 1936: PUBLIC char * HTRDF_namespace(HTRDF * me, char * sPrefix)
2.1 frystyk 1937: {
2.3 ! frystyk 1938: char * nPrefix = NULL;
2.1 frystyk 1939: HTAssocList * calist;
1940: HTList * cur = me->m_namespaceStack;
1941:
1942: if (!sPrefix)
1943: StrAllocCopy(nPrefix, "xmlns");
1944:
1945: while ((calist = (HTAssocList *) HTList_nextObject(cur))) {
2.3 ! frystyk 1946: char * sValue = HTAssocList_findObjectCaseSensitiveExact(calist, sPrefix);
2.1 frystyk 1947: if (sValue) {
1948: StrAllocCopy(nPrefix, sValue);
1949: return nPrefix;
1950: }
1951: }
1952: /*
1953: * Give error only if
1954: * 1. the prefix is not from the reserved xml namespace
1955: * 2. the prefix is not xmlns which is to look for the default
1956: * namespace
1957: */
1958: if (!strcmp(sPrefix, XMLSCHEMA)) {
1959: StrAllocCopy(nPrefix, sPrefix);
1960: return nPrefix;
1961: } else if (!strcmp(sPrefix, "xmlns")) {
1962: StrAllocCopy(nPrefix, "");
1963: return nPrefix;
1964: } else
1965: HTPrint("Unresolved Namespace prefix %s\n", sPrefix);
1966:
1967: StrAllocCopy(nPrefix, "");
1968: return nPrefix;
1969: }
1970:
1971: /*
1972: * Methods to determine whether we are parsing
1973: * parseType="Literal" or parseType="Resource"
1974: */
1975:
1976: PUBLIC BOOL HTRDF_parseLiteral(HTRDF *me)
1977: {
1978: HTElement *e = NULL;
1979: HTList *cur = me->m_elementStack;
1980: if (!HTList_isEmpty(me->m_elementStack)) {
1981: while((e = (HTElement *) HTList_nextObject(cur))) {
2.3 ! frystyk 1982: char * sParseType = NULL;
2.1 frystyk 1983: sParseType = HTElement_getAttribute2(e, RDFMS, "parseType");
1984: if (sParseType) {
1985: if (strcmp(sParseType, "Resource"))
1986: return YES;
1987: }
1988: }
1989: }
1990: return NO;
1991: }
1992:
1993: /*
1994: * Methods to determine whether we are parsing
1995: * parseType="Literal" or parseType="Resource"
1996: */
1997:
1998: PUBLIC BOOL HTRDF_parseResource(HTRDF *me)
1999: {
2000: HTElement *e = NULL;
2001: HTList *cur = me->m_elementStack;
2002: if (!HTList_isEmpty(me->m_elementStack)) {
2003: while((e = (HTElement *) HTList_nextObject(cur))) {
2.3 ! frystyk 2004: char * sParseType = NULL;
2.1 frystyk 2005: sParseType = HTElement_getAttribute2(e, RDFMS, "parseType");
2006: if (sParseType) {
2007: if (!strcmp(sParseType, "Resource"))
2008: return YES;
2009: }
2010: }
2011: }
2012: return NO;
2013: }
2014: /*
2015: * checkAttributes goes through the attributes of element e<
2016: * to see
2017: * 1. if there are symbolic references to other nodes in the data model.
2018: * in which case they must be stored for later resolving with
2019: * resolveLater method.
2020: * 2. if there is an identity attribute, it is registered using
2021: * registerResource or registerID method.
2022: *
2023: */
2024:
2025: PRIVATE void HTRDF_checkAttributes(HTRDF *me, HTElement *e)
2026: {
2027: {
2.3 ! frystyk 2028: char * sResource = HTElement_getAttribute2(e, RDFMS, "resource");
2.1 frystyk 2029:
2030: if (sResource && sResource[0] == '#')
2031: HTRDF_resolveLater(me, e);
2032: }
2033: {
2.3 ! frystyk 2034: char * sAboutEach = HTElement_getAttribute2(e, RDFMS, "aboutEach");
2.1 frystyk 2035:
2036: if (sAboutEach && sAboutEach[0] == '#')
2037: HTRDF_resolveLater(me, e);
2038: }
2039: {
2.3 ! frystyk 2040: char * sAboutEachPrefix = HTElement_getAttribute2(e, RDFMS,
2.1 frystyk 2041: "aboutEachPrefix");
2042:
2043: if (sAboutEachPrefix && sAboutEachPrefix[0] == '#')
2044: HTRDF_resolveLater(me, e);
2045: }
2046: {
2.3 ! frystyk 2047: char * sAbout = HTElement_getAttribute2(e, RDFMS, "about");
2.1 frystyk 2048: if (sAbout) {
2049: if (sAbout[0] == '#')
2050: HTRDF_resolveLater(me, e);
2051: else
2052: HTRDF_registerResource(me, e);
2053: }
2054: }
2055:
2056: {
2.3 ! frystyk 2057: char * sBagID = HTElement_getAttribute2(e, RDFMS, "bagID");
2.1 frystyk 2058:
2059: if (sBagID) {
2060: HTRDF_registerID(me, sBagID, e);
2061: StrAllocCopy(e->m_sBagID, sBagID);
2062: }
2063: }
2064: {
2.3 ! frystyk 2065: char * sID = HTElement_getAttribute2(e, RDFMS, "ID");
2.1 frystyk 2066: if (sID) {
2067: HTRDF_registerID(me, sID, e);
2068: StrAllocCopy(e->m_sID, sID);
2069: }
2070: }
2071: }
2072: /*
2073: * Add the element e to the m_vResolveQueue
2074: * to be resolved later.
2075: */
2076: PUBLIC void HTRDF_resolveLater(HTRDF *me, HTElement *e)
2077: {
2078: HTList_addObject(me->m_vResolveQueue, e);
2079: }
2080: /*
2081: * Add an element e to the Hashtable m_hIDtable
2082: * which stores all nodes with an ID
2083: */
2084:
2.3 ! frystyk 2085: PUBLIC void HTRDF_registerID(HTRDF *me, char * sID, HTElement *e)
2.1 frystyk 2086: {
2087: if (HTHashtable_object(me->m_hIDtable, sID))
2088: HTPrint("Node ID %s redefined", sID);
2089: HTHashtable_addObject(me->m_hIDtable, sID, e);
2090: }
2091: /*
2092: * Add an element e to the Vector m_vResources
2093: * which stores all nodes with an URI
2094: */
2095: PUBLIC void HTRDF_registerResource(HTRDF *me, HTElement *e)
2096: {
2097: HTList_addObject(me->m_vResources, e);
2098: }
2099:
2100: /*
2101: * Look for a node by name sID from the Hashtable
2102: * m_hIDtable of all registered IDs.
2103: */
2104:
2.3 ! frystyk 2105: PUBLIC HTElement *HTRDF_lookforNode(HTRDF *me, char * sID)
2.1 frystyk 2106: {
2107: if (sID)
2108: return (HTElement *) HTHashtable_object(me->m_hIDtable, sID);
2109: return NULL;
2110: }
2111:
2112: /*
2113: ** Special method to deal with rdf:resource attribute
2114: */
2.3 ! frystyk 2115: PUBLIC char * HTRDF_getResource(HTRDF *me, HTElement *e)
2.1 frystyk 2116: {
2.3 ! frystyk 2117: char * sResource = HTElement_getAttribute2(e, RDFMS, "resource");
2.1 frystyk 2118: if (sResource != NULL && sResource[0] == '\0')
2119: sResource = me->m_sSource;
2120: return sResource;
2121: }
2122:
2123: /*
2124: ** Take an element ele with its parent element parent
2125: ** and evaluate all its attributes to see if they are non-RDF specific
2126: ** and non-XML specific in which case they must become children of
2127: ** the ele node.
2128: */
2129: PRIVATE BOOL HTRDF_expandAttributes (HTRDF * me, HTElement * parent, HTElement * ele)
2130: {
2131: BOOL foundAbbreviation = NO;
2.3 ! frystyk 2132: char * sAttribute = NULL;
! 2133: char * sValue = NULL;
2.1 frystyk 2134: HTAssoc * assoc;
2135: HTAssocList * cur = ele->m_attributes;
2136: int lxmlschema = strlen(XMLSCHEMA);
2137: int lrdfms = strlen(RDFMS);
2138:
2139: while ((assoc= (HTAssoc *) HTList_nextObject(cur))) {
2140: int latt;
2141: sAttribute = HTAssoc_name(assoc);
2142: sValue = HTAssoc_value(assoc);
2143: latt = strlen(sAttribute);
2144: if (!strncmp(sAttribute, XMLSCHEMA, lxmlschema))
2145: continue;
2146:
2147: if (!strncmp(sAttribute, RDFMS, lrdfms) &&
2148: (sAttribute[lrdfms]!='_') &&
2149: latt > 5 && strcmp(&(sAttribute[latt-5]), "value") &&
2150: strcmp(&(sAttribute[latt-4]), "type"))
2151: continue;
2152:
2153: if (strlen(sValue) > 0) {
2154: HTAssocList * newAL = HTAssocList_new();
2155: HTElement * newElement = HTElement_new(sAttribute, newAL);
2156: HTElement * newData = HTElement_new2(sValue);
2157: HTElement_addChild(newElement, newData);
2158: HTElement_addChild(parent, newElement);
2159: foundAbbreviation = YES;
2160: }
2161: }
2162: return foundAbbreviation;
2163: }
2164:
2165: /**
2166: * Create a new reification ID by using a name part and an
2167: * incremental counter m_iReificationCounter.
2168: */
2.3 ! frystyk 2169: PUBLIC char * HTRDF_newReificationID (HTRDF *me)
2.1 frystyk 2170: {
2.3 ! frystyk 2171: char * nsid = NULL;
2.1 frystyk 2172: char nsrc[20];
2173: me->m_iReificationCounter++;
2174: sprintf(nsrc, "%d", me->m_iReificationCounter);
2175: if (!me->m_sSource) {
2176: StrAllocMCopy(&nsid, "genid", nsrc, NULL);
2177: } else {
2178: StrAllocMCopy(&nsid, me->m_sSource, "#genid", nsrc, NULL);
2179: }
2180: return nsid;
2181: }
2182:
2183: /*
2184: * reificate creates one new node and four new triples
2185: * and returns the ID of the new node
2186: */
2187:
2.3 ! frystyk 2188: PRIVATE char * HTRDF_reificate(HTRDF *me, char * sPredicate, char * sSubject,
! 2189: char * sObject, char * sNodeID)
2.1 frystyk 2190: {
2.3 ! frystyk 2191: char * sName = NULL;
! 2192: char * pName = NULL;
! 2193: char * oName = NULL;
! 2194: char * tName = NULL;
! 2195: char * stName = NULL;
! 2196: char * tNodeID = NULL;
2.1 frystyk 2197:
2198: if (!sNodeID)
2199: tNodeID = HTRDF_newReificationID(me);
2200: else
2201: StrAllocCopy(tNodeID, sNodeID);
2202:
2203: StrAllocMCopy(&sName, RDFMS, "subject", NULL);
2204: StrAllocMCopy(&pName, RDFMS, "predicate", NULL);
2205: StrAllocMCopy(&oName, RDFMS, "object", NULL);
2206: StrAllocMCopy(&tName, RDFMS, "type", NULL);
2207: StrAllocMCopy(&stName, RDFMS, "Statement", NULL);
2208:
2209: /*
2210: * The original statement must remain in the data model
2211: */
2212: HTRDF_addTriple(me, sPredicate, sSubject, sObject);
2213:
2214: /*
2215: * Do not reificate reificated properties
2216: */
2217: if (strcmp(sPredicate, sName) && strcmp(sPredicate, pName) &&
2218: strcmp(sPredicate, oName) && strcmp(sPredicate, tName)) {
2219:
2220: /* Reificate by creating 4 new triples */
2221: HTRDF_addTriple(me, pName, tNodeID, sPredicate);
2222: HTRDF_addTriple(me, sName, tNodeID, (sSubject[0]=='\0' ? me->m_sSource: sSubject));
2223: HTRDF_addTriple(me, oName, tNodeID, sObject);
2224: HTRDF_addTriple(me, tName, tNodeID, stName);
2225: } else
2226: HT_FREE(tNodeID);
2227:
2228: HT_FREE(sName);
2229: HT_FREE(pName);
2230: HT_FREE(oName);
2231: HT_FREE(tName);
2232: HT_FREE(stName);
2233:
2234: return tNodeID;
2235: }
2236: /*
2237: * Create a new triple and add it to the m_triples List
2238: * Send the triple to the Output stream
2239: */
2240:
2.3 ! frystyk 2241: PUBLIC void HTRDF_addTriple (HTRDF *me, char * sPredicate, char * sSubject,
! 2242: char * sObject)
2.1 frystyk 2243: {
2244: HTTriple *t = NULL;
2245:
2246: /*
2247: * If there is no subject (about=""), then use the URI/filename where
2248: * the RDF description came from
2249: */
2250: if (!sPredicate || !sSubject || !sObject) {
2251: HTPrint("Predicate %s when subject %s and object %s \n",
2252: sPredicate ? sPredicate : "null",
2253: sSubject ? sSubject : "null",
2254: sObject ? sObject : "null");
2255: return;
2256: }
2257:
2258: if (sSubject[0]=='\0')
2259: sSubject = me->m_sSource;
2260:
2261: t = HTTriple_new(sPredicate, sSubject, sObject);
2262:
2263: /* Call the triple callback handler (if any) with this new triple */
2264: if (me->newTripleInstance && t) (*(me->newTripleInstance))(me, t, me->tripleContext);
2265:
2266: HTList_addObject(me->m_triples, t);
2267: }
2268:
2269: /*
2270: * createBags method allows one to determine whether SiRPAC
2271: * produces Bag instances for each Description block.
2272: * The default setting is not to generate them.
2273: */
2274:
2275: PUBLIC void HTRDF_createBags(HTRDF *me, BOOL b)
2276: {
2277: if (me)
2278: me->m_bCreateBags = b;
2279: }
2280:
2281: /*
2282: Set output stream for RDF parser
2283: */
2284:
2285: PUBLIC void HTRDF_setOutputStream(HTRDF *me, HTStream *ostream)
2286: {
2287: if (me)
2288: me->ostream = ostream;
2289: }
2290:
2291: PUBLIC BOOL HTRDF_registerNewTripleCallback (HTRDF * me, HTTripleCallback_new * cbf, void * context)
2292: {
2293: if (me) {
2294: me->newTripleInstance = cbf;
2295: me->tripleContext = context;
2296: return YES;
2297: }
2298: return NO;
2299: }
2300:
2301: PUBLIC BOOL HTRDF_registerNewParserCallback (HTRDFCallback_new * me, void * context)
2302: {
2303: RDFInstance = me;
2304: RDFInstanceContext = context;
2305: return YES;
2306: }
2307:
2308: /* ------------------------------------------------------------------------- */
2309: /* HTRDFTriples STREAM HANDLERS */
2310: /* ------------------------------------------------------------------------- */
2311:
2312: PRIVATE int generate_triples(HTStream *me)
2313: {
2314: HTRDF *rdfp = me ? me->rdfparser : NULL;
2315: if (rdfp) {
2316:
2317: HTRDF_resolve(rdfp);
2318:
2319: HTRDF_processXML(rdfp, HTRDF_root(rdfp));
2320:
2321: return HT_OK;
2322: }
2323: return HT_ERROR;
2324: }
2325:
2326: PRIVATE int HTRDFTriples_flush (HTStream * me)
2327: {
2328: if (me->target)
2329: return (*me->target->isa->flush)(me->target);
2330: return HT_OK;
2331: }
2332:
2333: PRIVATE int HTRDFTriples_free (HTStream * me)
2334: {
2335: int status = HT_OK;
2336:
2337: status = generate_triples(me);
2338:
2339: HTRDF_delete(me->rdfparser);
2340:
2341: if (me->target) {
2342: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
2343: return HT_WOULD_BLOCK;
2344: }
2345: HTTRACE(XML_TRACE, "RDF Parser.. FREEING...\n");
2346: HT_FREE(me);
2347: return status;
2348: }
2349:
2350: PRIVATE int HTRDFTriples_abort (HTStream * me, HTList * e)
2351: {
2352: HTTRACE(XML_TRACE, "RDF Parser.. ABORTING...\n");
2353: HTRDF_delete(me->rdfparser);
2354: if (me->target)
2355: (*me->target->isa->abort)(me->target, NULL);
2356: HT_FREE(me);
2357: return HT_ERROR;
2358: }
2359:
2360: PRIVATE int HTRDFTriples_write (HTStream * me, const char * buf, int len)
2361: {
2362: return HT_OK;
2363: }
2364:
2365: PRIVATE int HTRDFTriples_putCharacter (HTStream * me, char c)
2366: {
2367: return HTRDFTriples_write(me, &c, 1);
2368: }
2369:
2370: PRIVATE int HTRDFTriples_putString (HTStream * me, const char * s)
2371: {
2372: return HTRDFTriples_write(me, s, (int) strlen(s));
2373: }
2374:
2375: PRIVATE const HTStreamClass HTRDFTriplesClass =
2376: {
2377: "rdf",
2378: HTRDFTriples_flush,
2379: HTRDFTriples_free,
2380: HTRDFTriples_abort,
2381: HTRDFTriples_putCharacter,
2382: HTRDFTriples_putString,
2383: HTRDFTriples_write
2384: };
2385:
2386: PRIVATE HTStream * RDFParser_new (HTRequest * request,
2387: void * param,
2388: HTFormat input_format,
2389: HTFormat output_format,
2390: HTStream * output_stream)
2391: {
2392: HTStream * me = NULL;
2393: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
2394: HT_OUTOFMEM("HTRDFTriples_new");
2395: me->isa = &HTRDFTriplesClass;
2396: me->state = HT_OK;
2397: me->request = request;
2398: me->target = output_stream ? output_stream : HTErrorStream();
2399:
2400: /* Now create the RDF parser instance */
2401: if ((me->rdfparser = HTRDF_new()) == NULL) {
2402: HT_FREE(me);
2403: return HTErrorStream();
2404: }
2405:
2406: /* Set the source (I guess mostly to follow SiRPAC API) */
2407: {
2408: char * uri = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
2409: HTRDF_setSource(me->rdfparser, uri);
2410: HT_FREE(uri);
2411: }
2412:
2413: /* Where are we putting data? */
2414: HTRDF_setOutputStream(me->rdfparser, me);
2415:
2416: /* If you want to create Bags, change it to YES */
2417: HTRDF_createBags(me->rdfparser, NO);
2418:
2419: /* Register our new XML Instance handler */
2420: /* @@@ THIS SHOULD BE DONE USING XML NAMESPACE SO THAT WE DON'T CONFLICT @@@ */
2421: HTXMLCallback_registerNew(rdf_newInstance, me->rdfparser);
2422:
2423: HTTRACE(XML_TRACE, "RDF Parser.. Stream created\n");
2424:
2425: return me;
2426: }
2427:
2428: PUBLIC HTStream * HTRDFParser_new (HTRequest * request,
2429: void * param,
2430: HTFormat input_format,
2431: HTFormat output_format,
2432: HTStream * output_stream)
2433: {
2434: return HTXML_new(request, param, input_format, output_format,
2435: RDFParser_new(request, param, input_format, output_format, output_stream));
2436: }
2437:
2438: PRIVATE void triple_newInstance (HTRDF * rdfp, HTTriple * t, void * context)
2439: {
2440: if (rdfp && t) {
2441: HTStream *ostream = rdfp->ostream;
2442: if (ostream) {
2443: PUTC(ostream,'(');
2444: PUTS(ostream, t->m_sPredicate);
2445: PUTC(ostream,',');
2446: PUTS(ostream, t->m_sSubject);
2447: PUTC(ostream,',');
2448: PUTS(ostream, t->m_sObject);
2449: PUTC(ostream,')');
2450: PUTC(ostream,'\n');
2451: }
2452: }
2453: }
2454:
2455: PUBLIC HTStream * HTRDFToTriples (HTRequest * request,
2456: void * param,
2457: HTFormat input_format,
2458: HTFormat output_format,
2459: HTStream * output_stream)
2460: {
2.2 frystyk 2461: HTStream * me = RDFParser_new(request, param, input_format, output_format, output_stream);
2.1 frystyk 2462: HTTRACE(XML_TRACE, "RDF Converter. To Triples\n");
2463:
2464: /* Register our own tripple instance handler */
2465: HTRDF_registerNewTripleCallback(me->rdfparser, triple_newInstance, NULL);
2466:
2467: /* Create an XML parser instance and return */
2468: return HTXML_new(request, param, input_format, output_format, me);
2469: }
2470:
Webmaster