Annotation of java/classes/org/w3c/rdf/SiRPAC.java, revision 1.2
1.1 jsaarela 1: /**
2: * SiRPAC - Simple RDF Parser & Compiler
3: * Copyright © World Wide Web Consortium, (Massachusetts Institute of Technology,
4: * Institut National de Recherche en Informatique et en Automatique, Keio University).
5: * All Rights Reserved.
6: * Please see the full Copyright clause at <http://www.w3.org/COPYRIGHT.html>
7: *
8: * This program translates RDF descriptions into triple representation
9: * This version is suitable for embedded use as well as command line use
10: *
11: * This version uses SAX V1.0 available at <http://www.microstar.com/XML/SAX/>
12: *
13: * $Log$
14: *
15: * @author Janne Saarela <jsaarela@w3.org>
16: */
17: package org.w3c.rdf;
18:
19: import org.xml.sax.HandlerBase;
20: import org.xml.sax.InputSource;
21: import org.xml.sax.Locator;
22: import org.xml.sax.AttributeList;
23: import org.xml.sax.EntityResolver;
24: import org.xml.sax.DTDHandler;
25: import org.xml.sax.DocumentHandler;
26: import org.xml.sax.ErrorHandler;
27: import org.xml.sax.SAXParseException;
28: import org.xml.sax.Parser;
29: import org.xml.sax.InputSource;
30: import org.xml.sax.SAXException;
31:
32: import org.xml.sax.helpers.*;
33:
34: import java.net.URL;
35: import java.util.*;
36: import java.io.*;
37:
38: public class SiRPAC implements EntityResolver, DTDHandler, DocumentHandler,
39: ErrorHandler {
1.2 ! jsaarela 40: final static public String revision = "$Id: SiRPAC.java,v 1.1 1998/07/27 12:21:17 jsaarela Exp $";
1.1 jsaarela 41:
42: private Stack m_elementStack = new Stack ();
43: private Element m_root = null;
44: private Vector m_triples = new Vector ();
45: private String m_sErrorMsg = new String ();
46:
47: /**
48: * Namespace management
49: */
50: static private Hashtable s_namespaces = new Hashtable();
51: public static void addNamespace (String sAs, String sHref) {
52: s_namespaces.put (sAs.toLowerCase(), sHref);
53: }
54:
55: public static String namespace (String sAs) {
56: return (String)s_namespaces.get (sAs.toLowerCase());
57: }
58:
59: public static void main (String args[]) throws Exception
60: {
61: if (args.length != 1) {
1.2 ! jsaarela 62: System.err.println("Usage: java -Dsax.parser=<classname> SiRPAC <document>");
1.1 jsaarela 63: System.exit(1);
64: }
65:
1.2 ! jsaarela 66: SiRPAC compiler = null;
! 67: try {
! 68: // Create a new parser.
! 69: Parser p = ParserFactory.makeParser();
! 70:
! 71: // Create a new handler.
! 72: compiler = new SiRPAC();
! 73:
! 74: // Register the handlers
! 75: p.setEntityResolver(compiler);
! 76: p.setDTDHandler (compiler);
! 77: p.setDocumentHandler(compiler);
! 78: p.setErrorHandler (compiler);
! 79:
! 80: FileInputStream input = new FileInputStream(args[0]);
! 81: InputSource source = new InputSource(input);
! 82: source.setSystemId(args[0]);
! 83:
! 84: p.parse(source);
! 85: } catch (SAXException e) {
! 86: compiler.addError (e.getMessage());
! 87: } catch (Exception e) {
! 88: compiler.addError ("Internal error "+e);
! 89: }
! 90:
! 91: String sErrors = compiler.errors ();
! 92: if (sErrors.length() > 0) {
! 93: System.out.println ("Errors during parsing:\n"+sErrors);
! 94: }
1.1 jsaarela 95: }
96:
97: public InputSource resolveEntity (String publicId, String systemId)
98: {
99: return null;
100: }
101:
102: public void notationDecl (String name, String publicId, String systemId)
103: {
104: }
105:
106: /**
107: * Display unparsed entity declarations as they are reported.
108: *
109: * @see org.xml.sax.DTDHandler#unparsedEntityDecl
110: */
111: public void unparsedEntityDecl (String name,
112: String publicId,
113: String systemId,
114: String notationName)
115: {
116: }
117:
118: public void setDocumentLocator (Locator locator)
119: {
120: }
121:
122: public void startDocument () {
123: m_sErrorMsg = "";
124: }
125:
1.2 ! jsaarela 126: public void endDocument () throws SAXException {
1.1 jsaarela 127: processRDF (m_root);
128: // m_root.linearize (0, System.out);
129: printTriples (System.out);
130: }
131:
132: public void doctype (String name, String publicID, String systemID) {
133: }
134:
1.2 ! jsaarela 135: public void startElement (String name, AttributeList al) throws SAXException {
1.1 jsaarela 136: int iLength = al.getLength ();
137: if (iLength == 0) {
138: // TODO: error reporting: no attributes
139: } else for (int x = 0; x < iLength; x++) {
140: String aname = al.getName (x);
141: String special = "";
142: }
143:
144: /**
145: * Create a new element and update the containment hierarchy
146: * with the stack.
147: */
148: Element newElement = new Element (name, al);
149:
150: if (!m_elementStack.empty()) {
151: Element e = (Element)m_elementStack.peek ();
152: e.addChild (newElement);
153: }
154:
155: /**
156: * Place the new element into the stack
157: */
158: m_elementStack.push (newElement);
159: }
160:
161: public void endElement (String name)
162: {
163: m_root = (Element)m_elementStack.pop ();
164: }
165:
166: public void characters (char ch[], int start, int length)
167: {
168: /**
169: * Place all characters as Data instance to the containment
170: * hierarchy with the help of the stack.
171: */
172: Element e = (Element)m_elementStack.peek ();
173: String s = new String (ch, start, length+start);
174:
175: /**
176: * Warning: this is not correct procedure according to XML spec.
177: * All whitespace matters!
178: */
179: String sTrimmed = s.trim();
180: if (sTrimmed.length() > 0)
181: e.addChild (new Data (s));
182: }
183:
184: public void ignorableWhitespace (char ch[], int start, int length)
185: {
186: }
187:
188: public void processingInstruction (String target, String data)
189: {
190: if (target.equalsIgnoreCase ("xml:namespace")) {
191: /**
192: * Figure out the href and as attributes from the namespace
193: * declaration
194: */
195: StringReader sr = new StringReader (data);
196: StreamTokenizer st = new StreamTokenizer (sr);
197:
198: int token1, token2, token3, token4, token5, token6;
199: try {
200: while ((token1 = st.nextToken()) != StreamTokenizer.TT_EOF) {
201: String sHref = st.sval;
202: token2 = st.nextToken();
203: token3 = st.nextToken();
204: String sHrefValue = st.sval;
205: token4 = st.nextToken();
206: String sAs = st.sval;
207: token5 = st.nextToken();
208: token6 = st.nextToken();
209: String sAsValue = st.sval;
210: if (token1 == StreamTokenizer.TT_WORD &&
211: token2 == '=' &&
212: token3 == 34 &&
213: token4 == StreamTokenizer.TT_WORD &&
214: token5 == '=' &&
215: token6 == 34 &&
216: sHref.equals ("ns") &&
217: sAs.equals ("prefix")) {
218: SiRPAC.addNamespace (sAsValue, sHrefValue);
219: }
220: }
221: } catch (Exception e) {
222: m_sErrorMsg = "# Malformed namespace declaration "+data;
223: e.printStackTrace();
224: }
225: }
226: }
227:
228: /**
229: * Report all warnings, and continue parsing.
230: *
231: * @see org.xml.sax.ErrorHandler#warning
232: */
233: public void warning (SAXParseException exception)
234: {
235: m_sErrorMsg = "Warning: " +
236: exception.getMessage() +
237: " (" +
238: // exception.getSystemId() +
239:
240: "line <a href=\"#" +
241: exception.getLineNumber() +
242: "\">" +
243: exception.getLineNumber() +
244: "</a>, column " +
245: exception.getColumnNumber() +
246: ")<br>";
247: }
248:
249:
250: /**
251: * Report all recoverable errors, and try to continue parsing.
252: *
253: * @see org.xml.sax.ErrorHandler#error
254: */
255: public void error (SAXParseException exception)
256: {
257: m_sErrorMsg = "Recoverable Error: " +
258: exception.getMessage() +
259: " (" +
260: // exception.getSystemId() +
261:
262: "line <a href=\"#" +
263: exception.getLineNumber() +
264: "\">" +
265: exception.getLineNumber() +
266: "</a>, column " +
267: exception.getColumnNumber() +
268: ")<br>";
269: }
270:
271:
272: /**
273: * Report all fatal errors, and try to continue parsing.
274: *
275: * <p>Note: results are no longer reliable once a fatal error has
276: * been reported.</p>
277: *
278: * @see org.xml.sax.ErrorHandler#fatalError
279: */
280: public void fatalError (SAXParseException exception)
281: {
282: m_sErrorMsg = "Fatal Error: " +
283: exception.getMessage() +
284: " (" +
285: // exception.getSystemId() +
286: "line <a href=\"#" +
287: exception.getLineNumber() +
288: "\">" +
289: exception.getLineNumber() +
290: "</a>, column " +
291: exception.getColumnNumber() +
292: ")<br>";
293: }
294:
295: public String errors () {
296: return m_sErrorMsg;
297: }
298:
1.2 ! jsaarela 299: public void addError (String sMsg) {
! 300: m_sErrorMsg += sMsg;
! 301: }
! 302:
1.1 jsaarela 303: public static Parser createParser (String className) {
304: Element.init ();
305: Parser parser = null;
306:
307: try {
308: // Get the named class.
309: Class c = Class.forName(className);
310: // Instantiate the parser.
311: parser = (Parser)(c.newInstance());
312: } catch (ClassNotFoundException e) {
313: System.err.println("SAX parser class " + className +
314: "cannot be loaded.");
315: System.exit(1);
316: } catch (IllegalAccessException e) {
317: System.err.println("SAX parser class " + className +
318: " does not have a zero-argument constructor.");
319: System.exit(1);
320: } catch (InstantiationException e) {
321: System.err.println("SAX parser class " + className +
322: " cannot be instantiated.");
323: System.exit(1);
324: }
325:
326: // Check the the parser object
327: // actually implements the Parser interface.
328: if (!(parser instanceof org.xml.sax.Parser)) {
329: System.err.println("Class " + className +
330: " does not implement org.xml.sax.Parser.");
331: System.exit(1);
332: }
333:
334: return parser;
335: }
336:
337: /**
338: * If a URL is relative, make it absolute against the current directory.
339: */
340: private static String makeAbsoluteURL (String url)
341: throws java.net.MalformedURLException {
342: URL baseURL;
343:
344: String currentDirectory = System.getProperty("user.dir");
345: String fileSep = System.getProperty("file.separator");
346: String file = currentDirectory.replace(fileSep.charAt(0), '/') + '/';
347:
348: if (file.charAt(0) != '/') {
349: file = "/" + file;
350: }
351: baseURL = new URL("file", null, file);
352:
353: return new URL(baseURL, url).toString();
354: }
355:
356:
357: /**
358: * Escape special characters for display.
359: */
360: private static String escapeCharacters(char ch[], int start, int length) {
361: StringBuffer out = new StringBuffer();
362:
363: for (int i = start; i < start+length; i++) {
364: if (ch[i] >= 0x20 && ch[i] < 0x7f) {
365: out.append(ch[i]);
366: } else {
367: out.append("&#" + (int)ch[i] + ';');
368: }
369: }
370:
371: return out.toString();
372: }
373:
374: /**
375: * Start processing an RDF/XML document instance
376: */
1.2 ! jsaarela 377: void processRDF (Element rdf) throws SAXException {
1.1 jsaarela 378: Element.resolve ();
379:
380: Enumeration e = rdf.children();
381: while (e.hasMoreElements()) {
382: Element ele = (Element)e.nextElement();
383:
384: if (isDescription (ele)) {
385: processDescription (ele, false, false, true);
386: } else if (isCollection (ele)) {
387: processCollection (ele);
388: } else if (isTypedProperty (ele)) {
389: processTypedNode (ele);
390: }
391: }
392: }
393:
394: /**
395: * Manage the production 6.12 in the spec
396: */
1.2 ! jsaarela 397: public String processTypedNode (Element typedNode) throws SAXException {
1.1 jsaarela 398: String sID = typedNode.getAttribute ("ID");
399: String sBagID = typedNode.getAttribute ("bagID");
400: String sResource = typedNode.getAttribute ("resource");
401: String sAbout = typedNode.getAttribute ("about");
402: String sAboutEach = typedNode.getAttribute ("aboutEach");
403:
404: // create a new node for this typedNode
405: Enumeration e = typedNode.attributes ();
406: while (e.hasMoreElements()) {
407: String sAttribute = (String)e.nextElement();
408: String sValue = typedNode.getAttribute (sAttribute);
409: sValue = sValue.trim ();
410: if (!sAttribute.equals ("ID") &&
411: !sAttribute.equals ("bagID") &&
412: !sAttribute.equals ("resource") &&
413: !sAttribute.equals ("aboutEach") &&
414: !sAttribute.equals ("about")) {
415: if (sValue.length() > 0) {
416: Element newProperty = new Element (sAttribute,
417: new AttributeListImpl());
418: newProperty.addAttribute ("ID", sID);
419: newProperty.addAttribute ("bagID", sBagID);
420: // make the resource property the about property
421: // of the new Description block
422: newProperty.addAttribute ("about", sResource);
423: Data newData = new Data (sValue);
424: newProperty.addChild (newData);
425: typedNode.addChild (newProperty);
426: typedNode.removeAttribute (sAttribute);
427: }
428: }
429: }
430:
431: String sObject = new String ();
432: if (sResource != null)
433: sObject = sResource;
434: else if (sID != null)
435: sObject = sID;
436: else
437: sObject = Element.newReificationID();
438:
439: typedNode.ID (sObject);
440:
441: // special case: should the typedNode have aboutEach attribute,
442: // the instanceOf property should distribute to pointed
443: // collection also -> create a child node to the typedNode
444: if (sAboutEach != null &&
445: typedNode.target() != null) {
446: Element newProperty = new Element ("rdf:instanceOf",
447: new AttributeListImpl());
448: Data newData = new Data (typedNode.expandName());
449: newProperty.addChild (newData);
450: typedNode.addChild (newProperty);
451: } else {
452: addTriple (Element.RDFSCHEMA + "#instanceOf",
453: sObject,
454: typedNode.expandName());
455: }
456: String sDesc = processDescription (typedNode, false, false, true);
457:
458: return sObject;
459: }
460:
461: /**
462: * processDescription takes the following parameters
463: *
464: * @param description The Description element itself
465: * @param inProperty A flag to tell whether this is a nested description
466: inside a property.
467: * @param reificate Do we need to reificate
468: * @param createBag Do we create a bag collection out of nested properties
469: *
470: * @return An ID for the description
471: */
472: private String processDescription (Element description,
473: boolean inProperty,
474: boolean reificate,
1.2 ! jsaarela 475: boolean createBag) throws SAXException {
1.1 jsaarela 476: /**
477: * Return immediately if the description has already been managed
478: */
479: if (description.done())
480: return description.ID();
481:
482: int iChildCount = 1;
483: boolean bOnce = true;
484:
485: /**
486: * Determine first all relevant values
487: */
488: String sAbout = description.getAttribute ("about");
489: String sAboutEach = description.getAttribute ("aboutEach");
490: String sBagid = description.getAttribute ("bagID");
491: String sID = description.getAttribute ("ID");
492: Element target = description.target();
493:
494: boolean hasTarget = ( target != null );
495: boolean targetIsBag = false;
496: String sTargetAbout = null;
497: String sTargetBagid = null;
498: String sTargetID = null;
499:
500: if (hasTarget) {
501: sTargetAbout = target.getAttribute ("about");
502: sTargetBagid = target.getAttribute ("bagID");
503: sTargetID = target.getAttribute ("ID");
504:
505: if (sAbout != null && sTargetBagid != null) {
506: targetIsBag = (sAbout.substring(1).equals (sTargetBagid));
507: } else {
508: if (sAbout != null &&
509: sTargetID != null &&
510: sAbout.substring(1).equals (sTargetID) &&
511: (target.name().equals ("rdf:Bag") ||
512: target.name().equals ("rdf:Seq") ||
513: target.name().equals ("rdf:Alt"))) {
514: targetIsBag = true;
515: }
516: }
517: }
518:
519: /**
520: * Manage the properties encoded as attributes by creating
521: * a new child node for each one of them. In this way
522: * the code for non-abbreviated properties will also work.
523: */
524:
525: Enumeration e = description.attributes ();
526: while (e.hasMoreElements()) {
527: String sAttribute = (String)e.nextElement ();
528: String sValue = description.getAttribute(sAttribute);
529: sValue = sValue.trim ();
530:
531: /**
532: * Create child nodes for non-RDF specific attributes
533: */
534: if (!sAttribute.equals ("about") &&
535: !sAttribute.equals ("aboutEach") &&
536: !sAttribute.equals ("ID") &&
537: !sAttribute.equals ("bagID")) {
538: if (sValue.length() > 0) {
539: Element ele = new Element (sAttribute,
540: new AttributeListImpl());
541: ele.addChild (new Data (sValue));
542: description.addChild (ele);
543: }
544: }
545: }
546:
547: /**
548: * Resolve distributive referents here
549: *
550: * Use straight-forward replication of properties
551: * to newly created description nodes
552: */
553:
554: if (hasTarget && sAboutEach != null) {
555:
556: e = target.children ();
557: while (e.hasMoreElements()) {
558: Element ele = (Element)e.nextElement ();
559:
560: String sResource = ele.getAttribute ("resource");
561: Element newDescription = null;
562: if (sResource != null) {
563: newDescription = new Element ("rdf:Description",
564: new AttributeListImpl());
565: newDescription.addAttribute ("about", sResource);
566: }
567: Enumeration e2 = description.children();
568: while (e2.hasMoreElements()) {
569: Element ele2 = (Element)e2.nextElement ();
570: if (newDescription != null) {
571: newDescription.addChild (ele2);
572: }
573: }
574: if (newDescription != null)
575: processDescription (newDescription, false, false, false);
576: }
577:
578: // should not return anything I think nor should it
579: // go and generate bags
580: return null;
581: }
582:
583: /**
584: * Enumerate through the children
585: */
586: e = description.children();
587:
588: while (e.hasMoreElements()) {
589: Element n = (Element)e.nextElement();
590:
591: if (isCollection (n)) {
592: processCollection (n);
593:
594: } else if (n instanceof Element) {
595:
596: /**
597: * Quote from the spec:
598: *
599: * The Description element itself creates an instance of a Bag
600: * node. The members of this Bag are the nodes corresponding
601: * to the reification of each of the properties in the
602: * Description. If the BAGID attribute is specified its value
603: * is the identifier of this Bag, else the Bag is anonymous.
604: */
605: String sChildID = null;
606:
607: if (hasTarget && targetIsBag) {
608: sChildID = processProperty (n, description,
609: target.ID(), false);
610: description.ID (sChildID);
611: createBag = false;
612: } else if (hasTarget) {
613: sChildID = processProperty (n, description,
614: sTargetAbout, reificate);
615: // description.ID (sChildID);
616: } else if (!hasTarget && !inProperty) {
617: if (sAbout == null)
618: if (sID != null)
619: sAbout = sID;
620: else
621: sAbout = description.ID();
622: sChildID = processProperty (n, description,
623: ( sAbout != null ? sAbout : sID),
624: createBag);
625: // description.ID (sChildID);
626: } else if (!hasTarget && inProperty) {
627: if (sAbout == null) {
628: if (sID != null) {
629: description.ID (sID);
630: sAbout = sID;
631: } else {
632: if (description.ID() == null)
633: description.ID (Element.newReificationID());
634: sAbout = description.ID();
635: }
636: } else {
637: description.ID (sAbout);
638: }
639: sChildID = processProperty (n, description,
640: sAbout,
641: false);
642: }
643:
644: if (createBag) {
645: String sNamespace = Element.RDFSCHEMA;
646: if (bOnce) {
647: bOnce = false;
648: if (sBagid != null)
649: description.ID (sBagid);
650: else {
651: if (description.ID() == null)
652: description.ID (Element.newReificationID());
653: }
654:
655: addTriple (sNamespace + "#instanceOf",
656: description.ID(),
657: sNamespace + "#Bag");
658: }
659: addTriple (sNamespace + "#"+iChildCount,
660: description.ID(),
661: sChildID);
662: iChildCount++;
663: }
664: }
665: }
666:
667: description.done (true);
668:
669: return description.ID();
670: }
671:
672: /**
673: * processProperty handles all elements not defined as special
674: * RDF elements.
675: *
676: * @param property The Property element itself
677: * @param description The Description element in which this property appears
678: * @param sTarget The target resource
679: * @param reificate Should this property be reificated
680: *
681: * @return the new ID which can be used to identify the property
682: */
683: private String processProperty (Element property,
684: Element description,
685: String sTarget,
1.2 ! jsaarela 686: boolean reificate) throws SAXException {
1.1 jsaarela 687: String sPropertyID = null;
688:
689: /**
690: * Do the same trick as with Description blocks:
691: * if the Property uses abbreviated syntax, transform
692: * the structure into corresponding full tree representation
693: * which is handled correctly by the code for the non-abbreviated
694: * syntax.
695: */
696:
697: String sID = property.getAttribute ("ID");
698: String sResource = property.getAttribute ("resource");
699: String sAbout = property.getAttribute ("about");
700:
701: boolean bAbbreviated = false;
702: Element d = new Element ("RDF:Description",
703: new AttributeListImpl());
704: /*
705: * Tricky part: use the resource attribute to name
706: * the intermediate Description block
707: */
708: if (sResource != null) {
709: d.addAttribute ("about", sResource);
710: }
711:
712: Enumeration e = property.attributes ();
713: while (e.hasMoreElements()) {
714: String sAttribute = (String)e.nextElement();
715: String sValue = property.getAttribute (sAttribute);
716: sValue = sValue.trim ();
717: if (!sAttribute.equals ("resource") &&
718: !sAttribute.equals ("about") &&
719: !sAttribute.equals ("ID") &&
720: !sAttribute.equals ("bagID")) {
721: if (sValue.length() > 0) {
722: bAbbreviated = true;
723: Element newProperty = new Element (sAttribute,
724: new AttributeListImpl());
725: Data newData = new Data (sValue);
726: newProperty.addChild (newData);
727: d.addChild (newProperty);
728: }
729: }
730: }
731: /**
732: * If we found properties and attributes and generated the subtree,
733: * attach it to the property itself and let the code below take
734: * care of the rest.
735: */
736: if (bAbbreviated) {
737: property.addChild (d);
738: }
739:
740: /**
741: * Does this property make a reference somewhere using the
742: * <i>resource</i> attribute
743: */
744: if (sResource != null && property.target() != null) {
745: sPropertyID = processDescription (property.target(),
1.2 ! jsaarela 746: true, false, false);
1.1 jsaarela 747: if (reificate) {
748: sPropertyID = reificate (property.expandName(),
749: sTarget, sPropertyID);
750: property.ID (sPropertyID);
751: } else {
752: addTriple (property.expandName(),
753: sTarget,
754: sPropertyID);
755: }
756:
757: return sPropertyID;
758: }
759:
760: /**
761: * Is the value of the attribute given as a URI in the
762: * about attribute?
763: */
764: if (sAbout != null) {
765: if (reificate) {
766: sPropertyID = reificate (property.expandName(),
767: sTarget,
768: sAbout);
769: property.ID (sPropertyID);
770: } else {
771: addTriple (property.expandName(),
772: sTarget,
773: sAbout);
774: }
775: }
776:
777: Enumeration e2 = property.children();
778: while (e2.hasMoreElements()) {
779: Element n2 = (Element)e2.nextElement();
780:
781: if (isDescription (n2)) {
782: Element d2 = n2;
783:
784: sPropertyID = processDescription (d2, true, false, false);
785:
786: d2.ID (sPropertyID);
787:
788: if (reificate) {
789: sPropertyID = reificate (property.expandName(),
790: sTarget, sPropertyID);
791: } else {
792: addTriple (property.expandName(),
793: sTarget, sPropertyID);
794: }
795:
796: } else if (n2 instanceof Data) {
797: /**
798: * We've got real data
799: */
800: String sValue = ((Data)n2).data();
801:
802: /**
803: * Only if the content is not empty PCDATA (whitespace that is),
804: * print the triple
805: */
806: sValue = sValue.trim();
807: if (sValue.length() > 0) {
808: if (reificate) {
809: sPropertyID = reificate (property.expandName(),
810: sTarget,
811: sValue);
812: property.ID (sPropertyID);
813: } else {
814: addTriple (property.expandName(),
815: sTarget,
816: sValue);
817: }
818: }
819: } else if (isCollection (n2)) {
820:
821: String sCollectionID = processCollection (n2);
822: sPropertyID = sCollectionID;
823:
824: /**
825: * Attach the collection to the current Property
826: */
827: if (description.target() != null) {
828: if (reificate) {
829: sPropertyID = reificate (property.expandName(),
830: description.target().getAttribute ("about"),
831: sCollectionID);
832: property.ID (sPropertyID);
833: } else {
834: addTriple (property.expandName(),
835: description.target().getAttribute ("about"),
836: sCollectionID);
837: }
838: } else {
839: if (reificate) {
840: sPropertyID = reificate (property.expandName(),
841: description.getAttribute ("about"),
842: sCollectionID);
843: property.ID (sPropertyID);
844: } else {
845: addTriple (property.expandName(),
846: description.getAttribute ("about"),
847: sCollectionID);
848: }
849: }
850: } else if (isTypedProperty (n2)) {
851: sPropertyID = processTypedNode (n2);
852: addTriple (property.expandName(),
853: description.ID(),
854: sPropertyID);
855: }
856: }
857:
858: return sPropertyID;
859: }
860:
1.2 ! jsaarela 861: private String processCollection (Element n) throws SAXException {
1.1 jsaarela 862: String sID = n.getAttribute ("ID");
863: if (sID == null)
864: sID = Element.newReificationID();
865:
866: /**
867: * Do the instantiation only once
868: */
869: if (!n.done()) {
870: String sNamespace = Element.RDFSCHEMA;
871: if (isSequence (n)) {
872: addTriple (sNamespace+"#instanceOf",
873: sID,
874: sNamespace+"#Sequence");
875: } else if (isAlternative (n)) {
876: addTriple (sNamespace+"#instanceOf",
877: sID,
878: sNamespace+"#Alt");
879: } else if (isBag (n)) {
880: addTriple (sNamespace+"#instanceOf",
881: sID,
882: sNamespace+"#Bag");
883: }
884: n.done (true);
885: }
886:
887: Enumeration e = ((Element)n).children();
888: int iCounter = 1;
889: while (e.hasMoreElements()) {
890: Element n2 = (Element)e.nextElement();
891: if (n2.name().equalsIgnoreCase ("rdf:li")) {
892: processListItem (sID, n2, iCounter);
893: iCounter++;
894: }
895: }
896:
897: return sID;
898: }
899:
1.2 ! jsaarela 900: private void processListItem (String sID, Element listitem, int iCounter)
! 901: throws SAXException {
1.1 jsaarela 902: /**
903: * Two different cases for
904: * 1. LI element without content (href available)
905: * 2. LI element with content (href unavailable)
906: */
907: String sNamespace = SiRPAC.namespace (listitem.prefix());
908: String sResource = listitem.getAttribute ("resource");
909: if (sResource != null) {
910: addTriple (sNamespace+"#"+iCounter,
911: sID,
912: sResource);
913: } else {
914: Enumeration e = listitem.children();
915: while (e.hasMoreElements()) {
916: Element n = (Element)e.nextElement();
917: if (n instanceof Data) {
918: addTriple (sNamespace+"#"+iCounter,
919: sID,
920: ((Data)n).data());
921: } else if (isDescription (n)) {
922: processDescription (n, false, false, true);
923: }
924: }
925: }
926: }
927:
928: /**
929: * reificate creates one new node and four new triples
930: * and returns the ID of the new node
931: */
932: private String reificate (String sProperty,
933: String sPropertyObject,
934: String sPropertyValue) {
935: /**
936: * Reificate by creating 4 new triples
937: */
938: String sNamespace = Element.RDFSCHEMA;
939: String sNodeID = Element.newReificationID();
940:
941: addTriple (sNamespace + "#PropName",
942: sNodeID,
943: sProperty);
944:
945: addTriple (sNamespace + "#PropObj",
946: sNodeID,
947: sPropertyObject);
948:
949: addTriple (sNamespace + "#PropValue",
950: sNodeID,
951: sPropertyValue);
952:
953: addTriple (sNamespace + "#instanceOf",
954: sNodeID,
955: sNamespace + "#Property");
956:
957: return sNodeID;
958: }
959:
960: private void addTriple (String sProperty, String sPropertyObj, String sPropertyValue) {
961: Triple t = new Triple (sProperty, sPropertyObj, sPropertyValue);
962: m_triples.addElement (t);
963: }
964:
965: public void printTriples (PrintStream ps) {
966: for (int x = 0; x < m_triples.size(); x++) {
967: Triple t = (Triple)m_triples.elementAt (x);
968: ps.println ("triple(\""+t.property()+"\",\""+t.object()+"\",\""+t.value()+"\").");
969: }
970: }
971:
972: public Enumeration triples () {
973: return m_triples.elements ();
974: }
975:
976: /**
977: * Helper functions to identify different elements
978: */
979: public boolean isDescription (Element e) {
980: return e.name().equalsIgnoreCase ("rdf:description");
981: }
982:
983: public boolean isCollection (Element e) {
984: return (e.name().equalsIgnoreCase ("rdf:seq") ||
985: e.name().equalsIgnoreCase ("rdf:alt") ||
986: e.name().equalsIgnoreCase ("rdf:bag"));
987: }
988:
989: public boolean isSequence (Element e) {
990: return e.name().equalsIgnoreCase ("rdf:seq");
991: }
992:
993: public boolean isAlternative (Element e) {
994: return e.name().equalsIgnoreCase ("rdf:alt");
995: }
996:
997: public boolean isBag (Element e) {
998: return e.name().equalsIgnoreCase ("rdf:bag");
999: }
1000:
1001: public boolean isTypedProperty (Element e) {
1002: if (e.name().length() > 0)
1003: return true;
1004: else
1005: return false;
1006: /* int i = e.name().indexOf (":"); can be without prefix
1007: return i > -1; */
1008: }
1009: }
Webmaster