Annotation of java/classes/org/w3c/rdf/SiRPAC.java, revision 1.15
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.
1.11 jsaarela 6: * Please see the full Copyright clause at
7: * <http://www.w3.org/Consortium/Legal/copyright-software.html>
1.1 jsaarela 8: *
1.11 jsaarela 9: * This program translates RDF descriptions into corresponding
10: * triple representation.
1.1 jsaarela 11: * This version uses SAX V1.0 available at <http://www.microstar.com/XML/SAX/>
12: *
1.4 jsaarela 13: * $Log: SiRPAC.java,v $
1.15 ! jsaarela 14: * Revision 1.14 1998/12/02 19:31:26 jsaarela
! 15: * 1st level implementation of ParseType="Literal".
! 16: *
1.14 jsaarela 17: * Revision 1.13 1998/10/16 08:54:50 jsaarela
18: * Distribution release 1.6 on 16-Oct-98.
19: *
1.13 jsaarela 20: * Revision 1.12 1998/10/09 23:07:19 jsaarela
21: * Distribution release 1.5 9-Oct-98. Conformance with the 8-Oct-98 draft.
22: *
1.12 jsaarela 23: * Revision 1.11 1998/10/07 21:54:53 jsaarela
24: * Intermediate log towards new release. Vocabulary changed, aboutEach
25: * management improved.
26: *
1.11 jsaarela 27: * Revision 1.10 1998/09/08 15:54:11 jsaarela
28: * Distribution release V1.4 - aboutEachPrefix added, namespace management
29: * improved.
30: *
1.10 jsaarela 31: * Revision 1.9 1998/08/28 10:03:25 jsaarela
32: * Distribution release 1.3 on 28-Aug-98.
33: *
1.9 jsaarela 34: * Revision 1.8 1998/08/19 13:18:13 jsaarela
35: * Compatibility with RDF M&S -19980819 and Namespaces in XML -19980820
36: *
1.8 jsaarela 37: * Revision 1.7 1998/08/12 15:12:48 jsaarela
38: * Updated namespace management to correspond with the
39: * Namespaces in XML specification dated 2-Aug-98.
40: *
1.7 jsaarela 41: * Revision 1.6 1998/07/31 09:42:27 jsaarela
42: * Error reporting improved.
43: * This is distribution V1.1
44: *
1.6 jsaarela 45: * Revision 1.5 1998/07/30 13:39:45 jsaarela
46: * multiple internal references fixed,
47: * properties without children fixed.
48: *
1.5 jsaarela 49: * Revision 1.4 1998/07/29 08:27:53 jsaarela
1.13 jsaarela 50: * Bug fix: processPredicate can now correctly determine the target
1.5 jsaarela 51: * of the propertyValue. Didn't work with typedNodes.
52: *
1.4 jsaarela 53: * Revision 1.3 1998/07/28 09:40:41 jsaarela
54: * 1st distribution release.
55: *
1.1 jsaarela 56: *
57: * @author Janne Saarela <jsaarela@w3.org>
58: */
59: package org.w3c.rdf;
60:
61: import org.xml.sax.HandlerBase;
62: import org.xml.sax.InputSource;
63: import org.xml.sax.Locator;
64: import org.xml.sax.AttributeList;
65: import org.xml.sax.EntityResolver;
66: import org.xml.sax.DTDHandler;
67: import org.xml.sax.DocumentHandler;
68: import org.xml.sax.ErrorHandler;
69: import org.xml.sax.SAXParseException;
70: import org.xml.sax.Parser;
71: import org.xml.sax.InputSource;
72: import org.xml.sax.SAXException;
73:
74: import org.xml.sax.helpers.*;
75:
76: import java.net.URL;
77: import java.util.*;
78: import java.io.*;
79:
80: public class SiRPAC implements EntityResolver, DTDHandler, DocumentHandler,
1.10 jsaarela 81: ErrorHandler {
1.15 ! jsaarela 82: final static public String REVISION = "$Id: SiRPAC.java,v 1.14 1998/12/02 19:31:26 jsaarela Exp $";
1.10 jsaarela 83: public final static String RDFSCHEMA = new String ("http://www.w3.org/TR/WD-rdf-syntax#");
1.13 jsaarela 84: public final static String RDFBASE = new String ("http://www.w3.org/TR/WD-rdf");
1.10 jsaarela 85: public final static String XMLSCHEMA = new String ("xml");
86:
87: private Stack m_namespaceStack = new Stack ();
88: private Stack m_elementStack = new Stack ();
89: private Element m_root = null;
90: private Vector m_triples = new Vector ();
91: private String m_sErrorMsg = new String ();
1.13 jsaarela 92: private String m_sSource = null;
93: private Vector m_vAllNamespaces = new Vector ();
94:
95: /**
96: * The following two variables may be changed on the fly
97: * to change the behaviour of the parser
98: */
1.15 ! jsaarela 99: private boolean m_bCreateBags = false;
1.13 jsaarela 100: private boolean m_bFetchSchemas = false;
1.11 jsaarela 101:
102: /**
1.14 jsaarela 103: * The following flag indicates whether the XML markup
104: * should be stored into a string as a literal value
105: * for RDF
106: */
107: private boolean m_bParseLiteral = false;
108: private Element m_LiteralElement = null;
109: private String m_sLiteral = new String ();
110:
111: /**
1.11 jsaarela 112: * createBags method allows one to determine whether SiRPAC
113: * produces Bag instances for each Description block.
114: * The default setting is to generate them.
115: */
116: public void createBags (boolean b) {
117: m_bCreateBags = b;
118: }
1.10 jsaarela 119:
1.13 jsaarela 120: /**
121: * Set whether parser recursively fetches and parses
122: * every RDF schema it finds in the namespace declarations
123: */
124: public void fetchSchemas (boolean b) {
125: m_bFetchSchemas = b;
126: }
127:
128: /**
129: * setSource methods saves the name of the source document for
130: * later inspection if needed
131: */
1.12 jsaarela 132: public void setSource (String sSource) {
133: m_sSource = sSource;
134: }
135:
1.13 jsaarela 136: public String source () {
137: return m_sSource;
138: }
139:
140: /**
141: * Return all non-RDF namespace URIs recognized by the parser
142: */
143: public Enumeration listNamespaces () {
144: return m_vAllNamespaces.elements();
145:
146: }
1.10 jsaarela 147: /**
1.11 jsaarela 148: * Return the full namespace URI for a given prefix <i>sPrefix</i>.
149: * The default namespace is identified with <i>xmlns</i> prefix.
150: * The namespace of <i>xmlns</i> attribute is an empty string.
1.10 jsaarela 151: */
152: public String namespace (String sPrefix) {
153: if (sPrefix == null) {
154: sPrefix = new String ("xmlns");
155: }
156: for (int x = m_namespaceStack.size()-1; x >=0; x--) {
157: Hashtable ht = (Hashtable)m_namespaceStack.elementAt (x);
158: String sURI = (String)ht.get (sPrefix);
159: if (sURI != null)
160: return sURI;
161: }
162: /**
163: * Give error only if
164: * 1. the prefix is not from the reserved xml namespace
165: * 2. the prefix is not xmlns which is to look for the default
166: * namespace
167: */
168: if (sPrefix.equals (XMLSCHEMA)) {
169: return XMLSCHEMA;
170: } else if (sPrefix.equals ("xmlns")) {
171: return "";
172: } else {
173: addError ("Unresolved namespace prefix "+sPrefix);
174: }
175: return "";
176: }
177:
178: public static void main (String args[]) throws Exception {
179: if (args.length != 1) {
1.12 jsaarela 180: System.err.println("Usage: java -Dsax.parser=<classname> org.w3c.rdf.SiRPAC [ URI | filename ]");
1.10 jsaarela 181: System.err.println ("This is revision "+REVISION);
182: System.exit(1);
183: }
184:
185: SiRPAC compiler = null;
186: try {
187: // Create a new parser.
188: Parser p = ParserFactory.makeParser();
1.14 jsaarela 189:
1.10 jsaarela 190: // Create a new handler.
191: compiler = new SiRPAC();
1.2 jsaarela 192:
1.10 jsaarela 193: // Register the handlers
194: p.setEntityResolver(compiler);
195: p.setDTDHandler (compiler);
196: p.setDocumentHandler(compiler);
197: p.setErrorHandler (compiler);
1.12 jsaarela 198:
199: InputSource source = null;
200: try {
201: URL url = new URL (args[0]);
202: source = new InputSource (url.openStream());
203: } catch (Exception e) {
204: FileInputStream input = new FileInputStream(args[0]);
205: source = new InputSource(input);
206: }
207:
1.10 jsaarela 208: source.setSystemId(args[0]);
1.11 jsaarela 209:
1.10 jsaarela 210: p.parse(source);
1.12 jsaarela 211: compiler.setSource (args[0]);
212: compiler.resolve ();
1.15 ! jsaarela 213: // compiler.createBags (true);
1.12 jsaarela 214: compiler.processXML (compiler.root());
1.11 jsaarela 215: // m_root.linearize (0, System.out);
1.10 jsaarela 216: } catch (SAXException e) {
1.11 jsaarela 217: if (compiler != null) {
1.10 jsaarela 218: compiler.addError (e.getMessage());
1.11 jsaarela 219: } else
1.10 jsaarela 220: e.printStackTrace ();
221: } catch (Exception e) {
1.12 jsaarela 222: if (compiler != null) {
1.10 jsaarela 223: compiler.addError ("Internal error "+e);
1.12 jsaarela 224: e.printStackTrace ();
225: }
1.10 jsaarela 226: else
227: e.printStackTrace ();
228: }
1.5 jsaarela 229:
1.10 jsaarela 230: String sErrors = compiler.errors ();
231: if (sErrors != null && sErrors.length() > 0) {
232: System.out.println ("Errors during parsing:\n"+sErrors);
233: } else {
234: compiler.printTriples (System.out);
235: }
1.2 jsaarela 236: }
237:
1.10 jsaarela 238: public InputSource resolveEntity (String publicId, String systemId) {
239: return null;
240: }
1.1 jsaarela 241:
1.10 jsaarela 242: public void notationDecl (String name, String publicId, String systemId) {
243: }
1.7 jsaarela 244:
245: /**
1.10 jsaarela 246: * Display unparsed entity declarations as they are reported.
247: *
248: * @see org.xml.sax.DTDHandler#unparsedEntityDecl
1.7 jsaarela 249: */
1.10 jsaarela 250: public void unparsedEntityDecl (String name,
251: String publicId,
252: String systemId,
253: String notationName) {
254: }
255:
256: public void setDocumentLocator (Locator locator) {
257: }
1.7 jsaarela 258:
1.10 jsaarela 259: public void startDocument () {
260: m_sErrorMsg = "";
261: }
262:
263: public void endDocument () throws SAXException {
1.1 jsaarela 264: }
265:
1.10 jsaarela 266: public void doctype (String name, String publicID, String systemID) {
1.7 jsaarela 267: }
268:
1.11 jsaarela 269: /**
270: * <i>startElement</i> is called for each new element.
271: * Build up the document tree using an element stack
272: */
1.10 jsaarela 273: public void startElement (String name, AttributeList al) throws SAXException {
274: Hashtable namespaces = new Hashtable ();
275:
276: /**
277: * The following loop tries to identify special xmlns prefix
278: * attributes and update the namespace stack accordingly.
279: * While doing all this, it builds another AttributeList instance
280: * which will hold the expanded names of the attributes
281: * (I think this approach is only useful for RDF which uses
282: * attributes as an abbreviated syntax for element names)
283: */
284: AttributeListImpl newAL = new AttributeListImpl ();
285:
286: int iLength = al.getLength ();
287: if (iLength == 0) {
288: // ohwell, no attributes
289: } else for (int x = 0; x < iLength; x++) {
290: String aName = al.getName (x);
291: if (aName.equals ("xmlns")) {
292: String aValue = al.getValue (aName);
293: namespaces.put (aName, aValue);
1.13 jsaarela 294:
295: // save all non-RDF schema addresses
296: if (!m_vAllNamespaces.contains (aValue) &&
297: !aValue.startsWith (RDFBASE))
298: m_vAllNamespaces.addElement (aValue);
299:
1.10 jsaarela 300: } else if (aName.startsWith ("xmlns:")) {
301: String aValue = al.getValue (aName);
302: aName = aName.substring (6);
303: namespaces.put (aName, aValue);
1.13 jsaarela 304:
305: // save all non-RDF schema addresses
306: if (!m_vAllNamespaces.contains (aValue) &&
307: !aValue.startsWith (RDFBASE))
308: m_vAllNamespaces.addElement (aValue);
1.10 jsaarela 309: }
310: }
311: /**
312: * Place new namespace declarations into the stack
313: * (Yes, I could optimize this a bit, not it wastes space
314: * if there are no xmlns definitions)
315: */
316: m_namespaceStack.push (namespaces);
317:
318: /**
319: * Figure out the prefix part if it exists and
320: * determine the namespace of the element accordingly
321: */
322: String sNamespace = null;
323: String sElementName = null;
324: Element newElement = null;
325: int i = name.indexOf (':');
1.14 jsaarela 326: String sPrefix2 = null;
1.10 jsaarela 327: if (i > 0) {
1.14 jsaarela 328: sPrefix2 = name.substring (0, i);
329: sNamespace = namespace (sPrefix2);
1.10 jsaarela 330: sElementName = name.substring (i+1);
331: } else {
332: sNamespace = namespace ("xmlns");
333: sElementName = name;
334: }
335:
336: /**
337: * Finally look for attributes other than the special xmlns,
338: * expand them, and place to the new AttributeListImpl
339: */
340: for (int x = 0; x < iLength; x++) {
341: String sAttributeNamespace = null;
342: String aName = al.getName (x);
343: if (!aName.startsWith ("xmlns")) {
344: String aValue = al.getValue (aName);
345: String aType = al.getType (aName);
346:
347: int iIndex = aName.indexOf (':');
1.14 jsaarela 348: String sPrefix = null;
1.10 jsaarela 349: if (iIndex > 0) {
1.14 jsaarela 350: sPrefix = aName.substring (0, iIndex);
1.10 jsaarela 351: sAttributeNamespace = namespace (sPrefix);
352: aName = aName.substring (iIndex+1);
1.14 jsaarela 353:
1.10 jsaarela 354: } else {
355: if (sNamespace == null)
356: sAttributeNamespace = namespace ("xmlns");
357: else
358: sAttributeNamespace = sNamespace;
359: }
1.14 jsaarela 360: if (m_bParseLiteral) {
361: if (sPrefix == null) {
362: sPrefix = "gen" + x; // x is a handy counter
363: }
364: newAL.addAttribute (sPrefix + ":" + aName,
365: aType,
366: aValue);
367: newAL.addAttribute ("xmlns:"+sPrefix,
368: aType,
369: sAttributeNamespace);
370: } else {
371: newAL.addAttribute (sAttributeNamespace+aName,
372: aType,
373: aValue);
374: }
1.10 jsaarela 375: }
376: }
377:
1.14 jsaarela 378: if (m_bParseLiteral) {
379: if (sPrefix2 == null) {
1.15 ! jsaarela 380: newElement = new Element ("gen:" + sElementName,
! 381: newAL);
! 382: newElement.prefix ("gen");
! 383: } else {
! 384: String sAttributeNamespace = namespace (sPrefix2);
! 385: if (sAttributeNamespace != null)
! 386: newAL.addAttribute ("xmlns:"+sPrefix2,
! 387: "CDATA",
! 388: sAttributeNamespace);
! 389: newElement = new Element (sPrefix2 + ":" + sElementName,
! 390: newAL);
1.14 jsaarela 391: }
1.15 ! jsaarela 392: } else {
! 393: newElement = new Element (sNamespace + sElementName,
1.14 jsaarela 394: newAL);
395: }
396:
1.10 jsaarela 397: checkAttributes (newElement);
398:
399: /**
1.14 jsaarela 400: * Check ParseType
401: */
402: String sLiteralValue = newElement.getAttribute(RDFSCHEMA+"ParseType");
403: if (sLiteralValue != null) {
404: if (sLiteralValue.equals ("Literal")) {
405: m_bParseLiteral = true;
406:
407: if (!m_elementStack.empty()) {
408: Element e = (Element)m_elementStack.peek ();
409: e.addChild (newElement);
410: }
411:
412: m_elementStack.push (newElement);
413: m_LiteralElement = newElement;
414: m_sLiteral = "";
415: return;
416: } else if (sLiteralValue.equals ("Resource")) {
417: m_bParseLiteral = false;
418: m_LiteralElement = null;
419: m_sLiteral = "";
420: }
421: }
422:
423: if (m_bParseLiteral) {
424: makeMarkupST (newElement);
425: m_elementStack.push (newElement);
426: return;
427: }
428:
429: /**
1.10 jsaarela 430: * Update the containment hierarchy
431: * with the stack.
432: */
433: if (!m_elementStack.empty()) {
434: Element e = (Element)m_elementStack.peek ();
435: e.addChild (newElement);
1.7 jsaarela 436: }
1.10 jsaarela 437:
438: /**
439: * Place the new element into the stack
440: */
441: m_elementStack.push (newElement);
442: }
443:
1.11 jsaarela 444: /**
445: * For each end of an element scope step back in the
446: * element and namespace stack
447: */
1.14 jsaarela 448: public void endElement (String name) throws SAXException {
1.10 jsaarela 449: m_root = (Element)m_elementStack.pop ();
450: m_namespaceStack.pop ();
1.14 jsaarela 451:
452: if (m_bParseLiteral) {
453: if (m_LiteralElement != m_root) {
1.15 ! jsaarela 454: makeMarkupET (m_root.prefix()+name);
1.14 jsaarela 455: } else {
456: m_root.addChild (new Data (m_sLiteral));
457: m_LiteralElement = null;
458: m_sLiteral = "";
459: m_bParseLiteral = false;
460: }
461: }
1.7 jsaarela 462: }
463:
1.11 jsaarela 464: /**
465: * Return the root element pointer. This requires the parsing
466: * has been already done.
467: */
468: public Element root () {
469: return m_root;
470: }
471:
1.10 jsaarela 472: public void characters (char ch[], int start, int length)
473: throws SAXException {
1.14 jsaarela 474:
1.10 jsaarela 475: /**
476: * Place all characters as Data instance to the containment
477: * hierarchy with the help of the stack.
478: */
479: Element e = (Element)m_elementStack.peek ();
480: String s = new String (ch, start, length+start);
481:
1.14 jsaarela 482: if (m_bParseLiteral) {
483: makeMarkupChar (s);
484: return;
485: }
486:
1.10 jsaarela 487: /**
488: * Warning: this is not correct procedure according to XML spec.
489: * All whitespace matters!
490: */
491: String sTrimmed = s.trim();
492: if (sTrimmed.length() > 0)
493: e.addChild (new Data (s));
494: }
495:
496: public void ignorableWhitespace (char ch[], int start, int length) {
497: }
498:
499: public void processingInstruction (String target, String data) {
1.1 jsaarela 500: }
501:
502: /**
1.10 jsaarela 503: * Report all warnings, and continue parsing.
504: *
505: * @see org.xml.sax.ErrorHandler#warning
1.1 jsaarela 506: */
1.10 jsaarela 507: public void warning (SAXParseException exception)
508: {
509: m_sErrorMsg = "Warning: " +
510: exception.getMessage() +
511: " (" +
512: // exception.getSystemId() +
513:
514: "line <a href=\"#" +
515: exception.getLineNumber() +
516: "\">" +
517: exception.getLineNumber() +
518: "</a>, column " +
519: exception.getColumnNumber() +
520: ")<br>";
521: }
1.1 jsaarela 522:
523:
524: /**
1.10 jsaarela 525: * Report all recoverable errors, and try to continue parsing.
526: *
527: * @see org.xml.sax.ErrorHandler#error
1.1 jsaarela 528: */
1.10 jsaarela 529: public void error (SAXParseException exception)
530: {
531: m_sErrorMsg = "Recoverable Error: " +
532: exception.getMessage() +
533: " (" +
534: // exception.getSystemId() +
535:
536: "line <a href=\"#" +
537: exception.getLineNumber() +
538: "\">" +
539: exception.getLineNumber() +
540: "</a>, column " +
541: exception.getColumnNumber() +
542: ")<br>";
543: }
544:
1.1 jsaarela 545:
546: /**
1.10 jsaarela 547: * Report all fatal errors, and try to continue parsing.
548: *
549: * <p>Note: results are no longer reliable once a fatal error has
550: * been reported.</p>
551: *
552: * @see org.xml.sax.ErrorHandler#fatalError
1.1 jsaarela 553: */
1.10 jsaarela 554: public void fatalError (SAXParseException exception)
555: {
556: m_sErrorMsg = "Fatal Error: " +
557: exception.getMessage() +
558: " (" +
559: // exception.getSystemId() +
560: "line <a href=\"#" +
561: exception.getLineNumber() +
562: "\">" +
563: exception.getLineNumber() +
564: "</a>, column " +
565: exception.getColumnNumber() +
566: ")<br>";
567: }
1.1 jsaarela 568:
1.10 jsaarela 569: public String errors () {
1.1 jsaarela 570: return m_sErrorMsg;
1.10 jsaarela 571: }
1.1 jsaarela 572:
1.10 jsaarela 573: public void addError (String sMsg) {
1.2 jsaarela 574: m_sErrorMsg += sMsg;
1.6 jsaarela 575: m_sErrorMsg += "<br>\n";
1.10 jsaarela 576: }
1.2 jsaarela 577:
1.10 jsaarela 578: public static Parser createParser (String className) {
579: Parser parser = null;
580:
581: try {
582: // Get the named class.
583: Class c = Class.forName(className);
584: // Instantiate the parser.
585: parser = (Parser)(c.newInstance());
586: } catch (ClassNotFoundException e) {
587: System.err.println("SAX parser class " + className +
588: "cannot be loaded.");
589: System.exit(1);
590: } catch (IllegalAccessException e) {
591: System.err.println("SAX parser class " + className +
592: " does not have a zero-argument constructor.");
593: System.exit(1);
594: } catch (InstantiationException e) {
595: System.err.println("SAX parser class " + className +
596: " cannot be instantiated.");
597: System.exit(1);
598: }
599:
600: // Check the the parser object
601: // actually implements the Parser interface.
602: if (!(parser instanceof org.xml.sax.Parser)) {
603: System.err.println("Class " + className +
604: " does not implement org.xml.sax.Parser.");
605: System.exit(1);
606: }
607:
608: return parser;
609: }
1.1 jsaarela 610:
611: /**
1.10 jsaarela 612: * If a URL is relative, make it absolute against the current directory.
1.1 jsaarela 613: */
1.10 jsaarela 614: private static String makeAbsoluteURL (String url)
615: throws java.net.MalformedURLException {
616: URL baseURL;
617:
618: String currentDirectory = System.getProperty("user.dir");
619: String fileSep = System.getProperty("file.separator");
620: String file = currentDirectory.replace(fileSep.charAt(0), '/') + '/';
621:
622: if (file.charAt(0) != '/') {
623: file = "/" + file;
624: }
625: baseURL = new URL("file", null, file);
626:
627: return new URL(baseURL, url).toString();
628: }
1.1 jsaarela 629:
630:
631: /**
1.10 jsaarela 632: * Escape special characters for display.
1.1 jsaarela 633: */
1.10 jsaarela 634: private static String escapeCharacters(char ch[], int start, int length) {
635: StringBuffer out = new StringBuffer();
1.1 jsaarela 636:
1.10 jsaarela 637: for (int i = start; i < start+length; i++) {
638: if (ch[i] >= 0x20 && ch[i] < 0x7f) {
639: out.append(ch[i]);
640: } else {
641: out.append("&#" + (int)ch[i] + ';');
1.1 jsaarela 642: }
643: }
1.10 jsaarela 644:
645: return out.toString();
1.1 jsaarela 646: }
647:
648: /**
1.12 jsaarela 649: * Given an XML document (well-formed HTML, for example),
650: * look for a suitable element to start parsing from
651: */
652: public void processXML (Element ele) throws SAXException {
653: if (isRDF(ele)) {
654: if (isRDFroot (ele)) {
655: processRDF(ele);
656: } else if (isDescription (ele)) {
657: processDescription (ele, false, m_bCreateBags, m_bCreateBags);
658: }
659: } else {
660: Enumeration e = ele.children();
661: while (e.hasMoreElements()) {
662: Element child = (Element)e.nextElement();
663: processXML (child);
664: }
665: }
1.13 jsaarela 666:
667: /**
668: * Recursively call myself to go through all the schemas
669: */
670: if (m_bFetchSchemas) {
671: if (m_vAllNamespaces.size() > 0) {
672: String sURI = (String)m_vAllNamespaces.elementAt(0);
673: m_vAllNamespaces.removeElementAt(0);
674:
675: setSource (sURI);
676: try {
677: URL url = new URL (sURI);
678: InputStream is = url.openStream ();
679:
680: InputSource source = new InputSource (is);
681:
682: // Create a new parser.
683: Parser p = ParserFactory.makeParser();
684:
685: // Register the handlers
686: p.setEntityResolver(this);
687: p.setDTDHandler (this);
688: p.setDocumentHandler(this);
689: p.setErrorHandler (this);
690:
691: p.parse(source);
692: resolve ();
693: processXML (root());
694: } catch (Exception ex) {
695: addError ("Could not load RDF schema from "+sURI);
696: }
697: }
698: }
1.12 jsaarela 699: }
700:
701: /**
702: * Start processing an RDF/XML document instance from the
1.11 jsaarela 703: * root element <i>rdf</i>.
1.1 jsaarela 704: */
1.11 jsaarela 705: public void processRDF (Element rdf) throws SAXException {
1.10 jsaarela 706: Enumeration e = rdf.children();
1.14 jsaarela 707: if (!e.hasMoreElements()) {
708: addError ("Empty RDF element");
709: return;
710: }
1.1 jsaarela 711: while (e.hasMoreElements()) {
1.10 jsaarela 712: Element ele = (Element)e.nextElement();
1.1 jsaarela 713:
1.10 jsaarela 714: if (isDescription (ele)) {
1.12 jsaarela 715: processDescription (ele, false, m_bCreateBags, m_bCreateBags);
1.10 jsaarela 716: } else if (isContainer (ele)) {
717: processContainer (ele);
1.13 jsaarela 718: } else if (isTypedPredicate (ele)) {
1.10 jsaarela 719: processTypedNode (ele);
1.1 jsaarela 720: }
721: }
722: }
723:
724: /**
1.11 jsaarela 725: * Manage the typedNode production in the RDF grammar.
1.1 jsaarela 726: */
1.10 jsaarela 727: public String processTypedNode (Element typedNode) throws SAXException {
728: String sID = typedNode.getAttribute (RDFSCHEMA, "ID");
1.15 ! jsaarela 729: // if (source() != null && sID != null)
! 730: // sID = source() + sID;
1.10 jsaarela 731: String sBagID = typedNode.getAttribute (RDFSCHEMA, "bagID");
732: String sAbout = typedNode.getAttribute (RDFSCHEMA, "about");
733: String sAboutEach = typedNode.getAttribute (RDFSCHEMA, "aboutEach");
734: String sAboutEachPrefix = typedNode.getAttribute (RDFSCHEMA, "aboutEachPrefix");
1.1 jsaarela 735:
1.10 jsaarela 736: if (typedNode.getAttribute (RDFSCHEMA, "resource") != null) {
737: addError ("'resource' attribute not allowed for a typedNode "+typedNode.name());
738: }
739: /**
740: * We are going to manage this typedNode using the processDescription
741: * routine later on. Before that, place all properties encoded as
742: * attributes to separate child nodes.
743: */
744: Enumeration e = typedNode.attributes ();
745: while (e.hasMoreElements()) {
746: String sAttribute = (String)e.nextElement();
747: String sValue = typedNode.getAttribute (sAttribute);
748: sValue = sValue.trim ();
749:
750: if (!sAttribute.startsWith (RDFSCHEMA) &&
751: !sAttribute.startsWith (XMLSCHEMA)) {
752: if (sValue.length() > 0) {
1.13 jsaarela 753: Element newPredicate = new Element (sAttribute,
1.10 jsaarela 754: new AttributeListImpl ());
1.13 jsaarela 755: newPredicate.addAttribute (RDFSCHEMA + "ID", (sAbout != null ? sAbout : sID));
756: newPredicate.addAttribute (RDFSCHEMA + "bagID", sBagID);
1.10 jsaarela 757: Data newData = new Data (sValue);
1.13 jsaarela 758: newPredicate.addChild (newData);
759: typedNode.addChild (newPredicate);
1.10 jsaarela 760: typedNode.removeAttribute (sAttribute);
1.1 jsaarela 761: }
762: }
763: }
764:
1.10 jsaarela 765: String sObject = new String ();
1.11 jsaarela 766: if (sAbout != null)
767: sObject = sAbout;
768: else if (sID != null)
1.10 jsaarela 769: sObject = sID;
770: else
771: sObject = newReificationID();
772:
773: typedNode.ID (sObject);
1.1 jsaarela 774:
1.10 jsaarela 775: // special case: should the typedNode have aboutEach attribute,
1.13 jsaarela 776: // the type predicate should distribute to pointed
1.10 jsaarela 777: // collection also -> create a child node to the typedNode
778: Enumeration eTargets = typedNode.targets ();
779: if (sAboutEach != null &&
780: eTargets.hasMoreElements()) {
1.13 jsaarela 781: Element newPredicate = new Element (RDFSCHEMA + "type",
1.10 jsaarela 782: new AttributeListImpl());
783: Data newData = new Data (typedNode.name());
1.13 jsaarela 784: newPredicate.addChild (newData);
785: typedNode.addChild (newPredicate);
1.10 jsaarela 786: } else {
787: addTriple (RDFSCHEMA + "type",
788: sObject,
789: typedNode.name());
790: }
1.1 jsaarela 791:
1.10 jsaarela 792: String sDesc = processDescription (typedNode, false, false, true);
1.1 jsaarela 793:
1.10 jsaarela 794: return sObject;
1.1 jsaarela 795: }
796:
1.7 jsaarela 797: /**
1.11 jsaarela 798: * processDescription manages Description elements
1.10 jsaarela 799: *
800: * @param description The Description element itself
1.13 jsaarela 801: * @param inPredicate Is this is a nested description
802: * @param reificate Do we need to reificate
803: * @param createBag Do we create a bag container
1.10 jsaarela 804: *
805: * @return An ID for the description
1.7 jsaarela 806: */
1.11 jsaarela 807: public String processDescription (Element description,
1.13 jsaarela 808: boolean inPredicate,
1.11 jsaarela 809: boolean reificate,
810: boolean createBag) throws SAXException {
1.10 jsaarela 811: /**
812: * Return immediately if the description has already been managed
813: */
814: if (description.done())
815: return description.ID();
816:
817: int iChildCount = 1;
818: boolean bOnce = true;
819:
820: /**
821: * Determine first all relevant values
822: */
823: String sAbout = description.getAttribute (RDFSCHEMA, "about");
824: String sAboutEach = description.getAttribute (RDFSCHEMA, "aboutEach");
825: String sAboutEachPrefix = description.getAttribute (RDFSCHEMA, "aboutEachPrefix");
826: String sBagid = description.getAttribute (RDFSCHEMA, "bagID");
827: String sID = description.getAttribute (RDFSCHEMA, "ID");
1.13 jsaarela 828:
1.10 jsaarela 829: Element target = description.target();
830:
831: boolean hasTarget = description.targets().hasMoreElements();
1.12 jsaarela 832:
1.10 jsaarela 833: boolean targetIsContainer = false;
834: String sTargetAbout = null;
835: String sTargetBagid = null;
836: String sTargetID = null;
1.7 jsaarela 837:
1.10 jsaarela 838: /**
839: * Determine what the target of the Description reference is
840: */
841: if (hasTarget) {
842: sTargetAbout = target.getAttribute (RDFSCHEMA, "about");
843: sTargetBagid = target.getAttribute (RDFSCHEMA, "bagID");
844: sTargetID = target.getAttribute (RDFSCHEMA, "ID");
1.13 jsaarela 845: if (source() != null && sTargetID != null)
846: sTargetID = source() + sTargetID;
1.10 jsaarela 847:
848: /**
849: * Target is collection if
850: * 1. it is identified with bagID attribute
851: * 2. it is identified with ID attribute and is a collection
852: */
1.12 jsaarela 853: if (sTargetBagid != null && sAbout != null) {
1.10 jsaarela 854: targetIsContainer = (sAbout.substring(1).equals (sTargetBagid));
1.5 jsaarela 855: } else {
1.10 jsaarela 856: if (sTargetID != null &&
1.11 jsaarela 857: sAbout != null &&
1.10 jsaarela 858: sAbout.substring(1).equals (sTargetID) &&
859: isContainer (target)) {
860: targetIsContainer = true;
861: }
1.5 jsaarela 862: }
1.10 jsaarela 863: }
864:
865: /**
866: * Check if there are properties encoded using the abbreviated
867: * syntax
868: */
869: expandAttributes (description, description);
870:
871: /**
872: * Manage the aboutEach attribute here
873: */
874: if (sAboutEach != null) {
875: if (hasTarget) {
876: Enumeration e = target.children ();
877: while (e.hasMoreElements()) {
878: Element ele = (Element)e.nextElement ();
1.12 jsaarela 879: if (isListItem (ele)) {
880: String sResource = ele.getAttribute (RDFSCHEMA, "resource");
881: /**
882: * Manage <li resource="..." /> case
883: */
1.11 jsaarela 884: if (sResource != null) {
1.12 jsaarela 885: Element newDescription = null;
886: if (sResource != null) {
887: newDescription = new Element (RDFSCHEMA + "Description",
888: new AttributeListImpl ());
889: newDescription.addAttribute (RDFSCHEMA + "about", sResource);
890: }
891: Enumeration e2 = description.children();
892: while (e2.hasMoreElements()) {
893: Element ele2 = (Element)e2.nextElement ();
894: if (newDescription != null) {
895: newDescription.addChild (ele2);
896: }
897: }
898: if (newDescription != null)
899: processDescription (newDescription, false, false, false);
900: } else {
901: /**
902: * Otherwise we have a structured value inside <li>
903: */
904:
905: // loop through the children of <li>
906: // (can be only one)
907: Enumeration e2 = ele.children ();
908: while (e2.hasMoreElements()) {
909: Element ele2 = (Element)e2.nextElement ();
910:
911: // loop through the items in the
912: // description with aboutEach
913: // and add them to the target
914: Element newNode = new Element (RDFSCHEMA + "Description",
915: new AttributeListImpl());
916: Enumeration e3 = description.children();
917: while (e3.hasMoreElements()) {
918: Element ele3 = (Element)e3.nextElement ();
919: newNode.addChild (ele3);
920: }
921: newNode.addTarget (ele2);
922:
923: processDescription (newNode,
924: true, false, false);
925: }
1.11 jsaarela 926: }
1.13 jsaarela 927: } else if (isTypedPredicate (ele)) {
1.12 jsaarela 928: Element newNode = new Element (RDFSCHEMA + "Description",
929: new AttributeListImpl());
1.11 jsaarela 930: Enumeration e2 = description.children();
931: while (e2.hasMoreElements()) {
932: Element ele2 = (Element)e2.nextElement ();
1.12 jsaarela 933: newNode.addChild (ele2);
1.11 jsaarela 934: }
1.12 jsaarela 935: newNode.addTarget (ele);
1.11 jsaarela 936:
1.12 jsaarela 937: processDescription (newNode,
938: true, false, false);
939:
1.10 jsaarela 940: }
941: }
1.5 jsaarela 942: }
1.10 jsaarela 943: return null;
1.5 jsaarela 944: }
945:
1.10 jsaarela 946: /**
947: * Manage the aboutEachPrefix attribute here
948: */
949: if (sAboutEachPrefix != null) {
950: if (hasTarget) {
951: Enumeration e = description.targets();
952: while (e.hasMoreElements()) {
953: target = (Element)e.nextElement ();
954: sTargetAbout = target.getAttribute (RDFSCHEMA, "about");
955: Element newDescription = new Element (RDFSCHEMA + "Description",
956: new AttributeListImpl ());
957: newDescription.addAttribute (RDFSCHEMA + "about", sTargetAbout);
958:
959: Enumeration e2 = description.children();
960: while (e2.hasMoreElements()) {
961: Element ele2 = (Element)e2.nextElement ();
962: newDescription.addChild (ele2);
963: }
964: processDescription (newDescription, false, false, false);
965: }
966: }
967: return null;
1.1 jsaarela 968: }
969:
1.10 jsaarela 970: /**
971: * Enumerate through the children
972: */
973: Enumeration e = description.children();
974:
975: while (e.hasMoreElements()) {
976: Element n = (Element)e.nextElement();
977:
978: if (isDescription (n)) {
979: addError ("Cannot nest Description inside Description");
980: } else if (isListItem (n)) {
981: addError ("Cannot nest Listitem inside Description");
982: } else if (isContainer (n)) {
983: addError ("Cannot nest container inside Description");
1.13 jsaarela 984: } else if (isTypedPredicate(n)) {
1.10 jsaarela 985:
986: String sChildID = null;
987:
988: if (hasTarget && targetIsContainer) {
1.13 jsaarela 989: sChildID = processPredicate (n, description,
1.10 jsaarela 990: (target.bagID() != null ? target.bagID() : target.ID()),
991: false);
992: description.ID (sChildID);
993: createBag = false;
994: } else if (hasTarget) {
1.13 jsaarela 995: sChildID = processPredicate (n, description,
1.11 jsaarela 996: (target.bagID() != null ? target.bagID() : target.ID()),
997: reificate);
998: description.ID (sChildID);
1.13 jsaarela 999: } else if (!hasTarget && !inPredicate) {
1000: if (description.ID() == null)
1.10 jsaarela 1001: description.ID (newReificationID());
1002: if (sAbout == null)
1003: if (sID != null)
1004: sAbout = sID;
1005: else
1006: sAbout = description.ID();
1.13 jsaarela 1007: sChildID = processPredicate (n, description,
1.15 ! jsaarela 1008: sAbout,
! 1009: ( sBagid != null ? true : reificate));
1.13 jsaarela 1010: //description.ID (sChildID);
1011: } else if (!hasTarget && inPredicate) {
1.10 jsaarela 1012: if (sAbout == null) {
1013: if (sID != null) {
1014: description.ID (sID);
1015: sAbout = sID;
1016: } else {
1017: if (description.ID() == null)
1018: description.ID (newReificationID());
1019: sAbout = description.ID();
1020: }
1021: } else {
1022: description.ID (sAbout);
1023: }
1.13 jsaarela 1024: sChildID = processPredicate (n, description,
1.10 jsaarela 1025: sAbout,
1026: false);
1027: }
1.1 jsaarela 1028:
1.10 jsaarela 1029: /**
1030: * Each Description block creates also a Bag node which
1.11 jsaarela 1031: * has links to all properties within the block IF
1032: * the m_bCreateBags variable is true
1.10 jsaarela 1033: */
1.15 ! jsaarela 1034: if (sBagid != null || (m_bCreateBags && createBag)) {
1.10 jsaarela 1035: String sNamespace = RDFSCHEMA;
1.11 jsaarela 1036: // do only once and only if there is a child
1037: if (bOnce && sChildID != null) {
1.10 jsaarela 1038: bOnce = false;
1039: if (description.bagID() == null)
1040: description.bagID (newReificationID());
1041: if (description.ID() == null)
1042: description.ID (description.bagID());
1043:
1044: addTriple (sNamespace + "type",
1045: description.bagID(),
1046: sNamespace + "Bag");
1047: }
1048: if (sChildID != null) {
1049: addTriple (sNamespace + "_" + iChildCount,
1050: description.bagID(),
1051: sChildID);
1052: iChildCount++;
1053: }
1054: }
1055: }
1.1 jsaarela 1056: }
1.10 jsaarela 1057:
1058: description.done (true);
1059:
1060: return description.ID();
1.1 jsaarela 1061: }
1062:
1.6 jsaarela 1063: /**
1.13 jsaarela 1064: * processPredicate handles all elements not defined as special
1.10 jsaarela 1065: * RDF elements.
1066: *
1.13 jsaarela 1067: * @param predicate The predicate element itself
1068: * @param description Context for the predicate
1.10 jsaarela 1069: * @param sTarget The target resource
1.13 jsaarela 1070: * @param reificate Should this predicate be reificated
1.10 jsaarela 1071: *
1.13 jsaarela 1072: * @return the new ID which can be used to identify the predicate
1.6 jsaarela 1073: */
1.13 jsaarela 1074: private String processPredicate (Element predicate,
1.10 jsaarela 1075: Element description,
1076: String sTarget,
1077: boolean reificate) throws SAXException {
1.11 jsaarela 1078: String sStatementID = null;
1.1 jsaarela 1079:
1.10 jsaarela 1080: /**
1081: * Do the same trick as with Description blocks:
1.13 jsaarela 1082: * if the predicate uses abbreviated syntax, transform
1.10 jsaarela 1083: * the structure into corresponding full tree representation
1084: * which is handled correctly by the code for the non-abbreviated
1085: * syntax.
1086: */
1.1 jsaarela 1087:
1.13 jsaarela 1088: String sResource = predicate.getAttribute (RDFSCHEMA, "resource");
1.1 jsaarela 1089:
1.10 jsaarela 1090: Element d = new Element (RDFSCHEMA + "Description",
1091: new AttributeListImpl());
1.1 jsaarela 1092:
1.10 jsaarela 1093: /**
1094: * Tricky part: use the resource attribute to name
1095: * the intermediate Description block
1096: */
1097: if (sResource != null) {
1098: d.addAttribute (RDFSCHEMA + "about", sResource);
1.1 jsaarela 1099: }
1100:
1101: /**
1.10 jsaarela 1102: * If we found properties and attributes and generated the subtree,
1.13 jsaarela 1103: * attach it to the predicate itself and let the code below take
1.10 jsaarela 1104: * care of the rest.
1.1 jsaarela 1105: */
1.13 jsaarela 1106: if (expandAttributes (d, predicate)) {
1107: predicate.addChild (d);
1.10 jsaarela 1108: }
1.1 jsaarela 1109:
1.10 jsaarela 1110: /**
1.11 jsaarela 1111: * Tricky part 2: if the resource attribute is present for a predicate
1.13 jsaarela 1112: * AND there are no children, the value of the predicate is either
1.10 jsaarela 1113: * 1. the URI in the resource attribute OR
1114: * 2. the node ID of the resolved #resource attribute
1115: */
1.13 jsaarela 1116: if (sResource != null && !predicate.children().hasMoreElements()) {
1117: if (predicate.target() == null) {
1.10 jsaarela 1118: if (reificate) {
1.13 jsaarela 1119: sStatementID = reificate (predicate.name(),
1.11 jsaarela 1120: sTarget,
1121: sResource,
1.13 jsaarela 1122: predicate.ID());
1123: predicate.ID (sStatementID);
1.10 jsaarela 1124: } else {
1.13 jsaarela 1125: addTriple (predicate.name(),
1.10 jsaarela 1126: sTarget,
1127: sResource);
1128: }
1129: } else {
1130: if (reificate) {
1.13 jsaarela 1131: sStatementID = reificate (predicate.name(),
1.11 jsaarela 1132: sTarget,
1.13 jsaarela 1133: predicate.target().ID(),
1134: predicate.ID());
1135: predicate.ID (sStatementID);
1.10 jsaarela 1136: } else {
1.13 jsaarela 1137: addTriple (predicate.name(),
1.10 jsaarela 1138: sTarget,
1.13 jsaarela 1139: predicate.target().ID());
1.10 jsaarela 1140: }
1141: }
1.13 jsaarela 1142: return predicate.ID();
1.10 jsaarela 1143: }
1.1 jsaarela 1144:
1145: /**
1.13 jsaarela 1146: * Does this predicate make a reference somewhere using the
1147: * <i>sResource</i> attribute
1.1 jsaarela 1148: */
1.13 jsaarela 1149: if (sResource != null && predicate.target() != null) {
1150: sStatementID = processDescription (predicate.target(),
1.11 jsaarela 1151: true, false, false);
1.1 jsaarela 1152: if (reificate) {
1.13 jsaarela 1153: sStatementID = reificate (predicate.name(),
1.11 jsaarela 1154: sTarget,
1155: sStatementID,
1.13 jsaarela 1156: predicate.ID());
1157: predicate.ID (sStatementID);
1.1 jsaarela 1158: } else {
1.13 jsaarela 1159: addTriple (predicate.name(),
1.10 jsaarela 1160: sTarget,
1.11 jsaarela 1161: sStatementID);
1.1 jsaarela 1162: }
1.10 jsaarela 1163:
1.11 jsaarela 1164: return sStatementID;
1.10 jsaarela 1165: }
1166:
1167: /**
1168: * Before looping through the children, let's check
1.13 jsaarela 1169: * is there are any. If not, the value of the predicate is
1170: * an anonymous node
1.10 jsaarela 1171: */
1.13 jsaarela 1172: Enumeration e2 = predicate.children();
1.10 jsaarela 1173: if (!(e2.hasMoreElements())) {
1174: if (reificate) {
1.13 jsaarela 1175: sStatementID = reificate (predicate.name(),
1.11 jsaarela 1176: sTarget,
1177: newReificationID(),
1.13 jsaarela 1178: predicate.ID());
1.10 jsaarela 1179: } else {
1.13 jsaarela 1180: addTriple (predicate.name(),
1.10 jsaarela 1181: sTarget,
1182: newReificationID());
1183: }
1184: }
1.12 jsaarela 1185: boolean bUsedTypedNodeProduction = false;
1186:
1.10 jsaarela 1187: while (e2.hasMoreElements()) {
1188: Element n2 = (Element)e2.nextElement();
1189:
1190: if (isDescription (n2)) {
1191: Element d2 = n2;
1192:
1.11 jsaarela 1193: sStatementID = processDescription (d2, true, false, false);
1.10 jsaarela 1194:
1.11 jsaarela 1195: d2.ID (sStatementID);
1.10 jsaarela 1196:
1197: if (reificate) {
1.13 jsaarela 1198: sStatementID = reificate (predicate.name(),
1.11 jsaarela 1199: sTarget,
1200: sStatementID,
1.13 jsaarela 1201: predicate.ID());
1.10 jsaarela 1202: } else {
1.13 jsaarela 1203: addTriple (predicate.name(),
1.11 jsaarela 1204: sTarget, sStatementID);
1.10 jsaarela 1205: }
1206:
1207: } else if (n2 instanceof Data) {
1208: /**
1209: * We've got real data
1210: */
1211: String sValue = ((Data)n2).data();
1212:
1213: /**
1214: * Only if the content is not empty PCDATA (whitespace that is),
1215: * print the triple
1216: */
1217: sValue = sValue.trim();
1218: if (sValue.length() > 0) {
1219: if (reificate) {
1.13 jsaarela 1220: sStatementID = reificate (predicate.name(),
1.11 jsaarela 1221: sTarget,
1222: sValue,
1.13 jsaarela 1223: predicate.ID());
1224: predicate.ID (sStatementID);
1.10 jsaarela 1225: } else {
1.13 jsaarela 1226: addTriple (predicate.name(),
1.10 jsaarela 1227: sTarget,
1228: sValue);
1229: }
1230: }
1231: } else if (isContainer (n2)) {
1232:
1233: String sCollectionID = processContainer (n2);
1.11 jsaarela 1234: sStatementID = sCollectionID;
1.10 jsaarela 1235:
1236: /**
1.13 jsaarela 1237: * Attach the collection to the current predicate
1.10 jsaarela 1238: */
1239: if (description.target() != null) {
1240: if (reificate) {
1.13 jsaarela 1241: sStatementID = reificate (predicate.name(),
1.10 jsaarela 1242: description.target().getAttribute (RDFSCHEMA, "about"),
1243: sCollectionID,
1.13 jsaarela 1244: predicate.ID());
1245: predicate.ID (sStatementID);
1.10 jsaarela 1246: } else {
1.13 jsaarela 1247: addTriple (predicate.name(),
1.10 jsaarela 1248: description.target().getAttribute (RDFSCHEMA, "about"),
1249: sCollectionID);
1250: }
1251: } else {
1252: if (reificate) {
1.13 jsaarela 1253: sStatementID = reificate (predicate.name(),
1.10 jsaarela 1254: sTarget,
1255: sCollectionID,
1.13 jsaarela 1256: predicate.ID());
1257: predicate.ID (sStatementID);
1.10 jsaarela 1258: } else {
1.13 jsaarela 1259: addTriple (predicate.name(),
1.10 jsaarela 1260: sTarget,
1261: sCollectionID);
1262: }
1263: }
1.13 jsaarela 1264: } else if (isTypedPredicate (n2)) {
1.12 jsaarela 1265: if (bUsedTypedNodeProduction) {
1.13 jsaarela 1266: addError ("Only one typedNode allowed inside a predicate (Extra typedNode:"+n2.name()+")");
1.12 jsaarela 1267: } else {
1268: bUsedTypedNodeProduction = true;
1269: }
1.11 jsaarela 1270: sStatementID = processTypedNode (n2);
1.13 jsaarela 1271: addTriple (predicate.name(),
1.5 jsaarela 1272: sTarget,
1.11 jsaarela 1273: sStatementID);
1.1 jsaarela 1274: }
1275: }
1.10 jsaarela 1276:
1.11 jsaarela 1277: return sStatementID;
1.1 jsaarela 1278: }
1279:
1.10 jsaarela 1280: private String processContainer (Element n) throws SAXException {
1281: String sID = n.ID();
1282: if (sID == null)
1283: sID = newReificationID();
1.1 jsaarela 1284:
1.10 jsaarela 1285: /**
1286: * Do the instantiation only once
1287: */
1288: if (!n.done()) {
1289: String sNamespace = RDFSCHEMA;
1290: if (isSequence (n)) {
1291: addTriple (sNamespace+"type",
1292: sID,
1293: sNamespace+"Seq");
1294: } else if (isAlternative (n)) {
1295: addTriple (sNamespace+"type",
1296: sID,
1297: sNamespace+"Alt");
1298: } else if (isBag (n)) {
1299: addTriple (sNamespace+"type",
1300: sID,
1301: sNamespace+"Bag");
1302: }
1303: n.done (true);
1304: }
1305:
1306: expandAttributes (n, n);
1.1 jsaarela 1307:
1.10 jsaarela 1308: Enumeration e = ((Element)n).children();
1309:
1310: if (!e.hasMoreElements() &&
1311: isAlternative (n)) {
1312: addError ("An RDF:Alt container must have at least one listitem");
1313: }
1314:
1315: int iCounter = 1;
1316: while (e.hasMoreElements()) {
1317: Element n2 = (Element)e.nextElement();
1318: if (isListItem (n2)) {
1319: processListItem (sID, n2, iCounter);
1320: iCounter++;
1321: } else {
1322: addError ("Cannot nest "+n2.name()+" inside container");
1323: }
1324: }
1325:
1326: return sID;
1327: }
1328:
1329: private void processListItem (String sID, Element listitem, int iCounter)
1330: throws SAXException {
1331: /**
1332: * Two different cases for
1333: * 1. LI element without content (resource available)
1334: * 2. LI element with content (resource unavailable)
1335: */
1336: String sResource = listitem.getAttribute (RDFSCHEMA, "resource");
1337: if (sResource != null) {
1338: addTriple (RDFSCHEMA+"_"+iCounter,
1.1 jsaarela 1339: sID,
1.10 jsaarela 1340: sResource);
1341: // validity checking
1342: if (listitem.children().hasMoreElements()) {
1343: addError ("Listitem with 'resource' attribute cannot have child nodes");
1344: }
1.12 jsaarela 1345: listitem.ID (sResource);
1.10 jsaarela 1346: } else {
1347: Enumeration e = listitem.children();
1348: while (e.hasMoreElements()) {
1349: Element n = (Element)e.nextElement();
1350: if (n instanceof Data) {
1351: addTriple (RDFSCHEMA+"_"+iCounter,
1352: sID,
1353: ((Data)n).data());
1354: } else if (isDescription (n)) {
1.11 jsaarela 1355: String sNodeID = processDescription (n, false, true, false);
1.10 jsaarela 1356: addTriple (RDFSCHEMA+"_"+iCounter,
1357: sID,
1358: sNodeID);
1.12 jsaarela 1359: listitem.ID (sNodeID);
1.10 jsaarela 1360: } else if (isListItem (n)) {
1361: addError ("Cannot nest listitem inside listitem");
1.11 jsaarela 1362: } else if (isContainer (n)) {
1363: processContainer (n);
1364: addTriple (RDFSCHEMA+"_"+iCounter,
1365: sID,
1366: n.ID());
1.13 jsaarela 1367: } else if (isTypedPredicate (n)) {
1.12 jsaarela 1368: String sNodeID = processTypedNode (n); //
1.10 jsaarela 1369: addTriple (RDFSCHEMA+"_"+iCounter,
1370: sID,
1371: sNodeID);
1372: }
1373: }
1.1 jsaarela 1374: }
1375: }
1376:
1.11 jsaarela 1377: /**
1378: * checkAttributes goes through the attributes of element <i>e</i>
1379: * to see
1380: * 1. if there are symbolic references to other nodes in the data model.
1381: * in which case they must be stored for later resolving with
1382: * <i>resolveLater</i> method.
1383: * 2. if there is an identity attribute, it is registered using
1384: * <i>registerResource</i> or <i>registerID</i> method.
1385: *
1386: * @see resolveLater
1387: * @see registerResource
1388: * @see registerID
1389: */
1.10 jsaarela 1390: private void checkAttributes (Element e) {
1391: String sResource = e.getAttribute (RDFSCHEMA, "resource");
1392: if (sResource != null &&
1393: sResource.startsWith("#")) {
1394: resolveLater (e);
1395: }
1396: String sAboutEach = e.getAttribute (RDFSCHEMA, "aboutEach");
1397: if (sAboutEach != null &&
1398: sAboutEach.startsWith("#")) {
1399: resolveLater (e);
1400: }
1401: String sAboutEachPrefix = e.getAttribute (RDFSCHEMA, "aboutEachPrefix");
1402: if (sAboutEachPrefix != null) {
1403: resolveLater (e);
1404: }
1.8 jsaarela 1405:
1.10 jsaarela 1406: String sAbout = e.getAttribute (RDFSCHEMA, "about");
1407: if (sAbout != null) {
1408: if (sAbout.startsWith("#")) {
1409: resolveLater (e);
1410: } else {
1411: registerResource (e);
1412: }
1413: }
1414:
1415: String sBagID = e.getAttribute (RDFSCHEMA, "bagID");
1416: if (sBagID != null) {
1417: registerID (sBagID, e);
1418: e.bagID (sBagID);
1419: }
1.6 jsaarela 1420:
1.10 jsaarela 1421: String sID = e.getAttribute (RDFSCHEMA, "ID");
1422: if (sID != null) {
1423: registerID (sID, e);
1424: e.ID (sID); // default value
1425: }
1.1 jsaarela 1426:
1.10 jsaarela 1427: if (sID != null && sAbout != null) {
1428: addError ("'ID' and 'about' attribute may not appear within the same Description block");
1.1 jsaarela 1429: }
1430: }
1431:
1.11 jsaarela 1432: /**
1433: * Take an element <i>ele</i> with its parent element <i>parent</i>
1434: * and evaluate all its attributes to see if they are non-RDF specific
1435: * and non-XML specific in which case they must become children of
1436: * the <i>ele</i> node.
1437: */
1.10 jsaarela 1438: private boolean expandAttributes (Element parent, Element ele)
1439: throws SAXException {
1440: boolean foundAbbreviation = false;
1441: Enumeration e = ele.attributes ();
1442: while (e.hasMoreElements()) {
1443: String sAttribute = (String)e.nextElement();
1444: String sValue = ele.getAttribute (sAttribute).trim();
1445:
1446: if (sAttribute.startsWith (XMLSCHEMA))
1447: continue;
1.13 jsaarela 1448: // exception: expand rdf:value
1.10 jsaarela 1449: if (sAttribute.startsWith (RDFSCHEMA) &&
1.13 jsaarela 1450: !sAttribute.startsWith (RDFSCHEMA+"_") &&
1.10 jsaarela 1451: !sAttribute.endsWith ("value"))
1452: continue;
1.8 jsaarela 1453: if (sValue.length() > 0) {
1454: foundAbbreviation = true;
1.10 jsaarela 1455: Element newElement = new Element (sAttribute,
1456: new AttributeListImpl());
1.8 jsaarela 1457: Data newData = new Data (sValue);
1458: newElement.addChild (newData);
1459: parent.addChild (newElement);
1460: }
1461: }
1.10 jsaarela 1462: return foundAbbreviation;
1463: }
1464:
1465: /**
1466: * reificate creates one new node and four new triples
1467: * and returns the ID of the new node
1468: */
1.11 jsaarela 1469: private String reificate (String sPredicate,
1470: String sSubject,
1471: String sObject,
1.10 jsaarela 1472: String sNodeID) {
1473: String sNamespace = RDFSCHEMA;
1474: if (sNodeID == null)
1475: sNodeID = newReificationID();
1476:
1477: /**
1.11 jsaarela 1478: * The original statement must remain in the data model
1.10 jsaarela 1479: */
1.11 jsaarela 1480: addTriple (sPredicate, sSubject, sObject);
1.10 jsaarela 1481:
1482: /**
1483: * Do not reificate reificated properties
1484: */
1.11 jsaarela 1485: if (sPredicate.equals (sNamespace+"subject") ||
1486: sPredicate.equals (sNamespace+"predicate") ||
1487: sPredicate.equals (sNamespace+"object") ||
1488: sPredicate.equals (sNamespace+"type")) {
1.10 jsaarela 1489: return null;
1490: }
1491:
1492: /**
1493: * Reificate by creating 4 new triples
1494: */
1.11 jsaarela 1495: addTriple (sNamespace + "predicate",
1.10 jsaarela 1496: sNodeID,
1.11 jsaarela 1497: sPredicate);
1.10 jsaarela 1498:
1.11 jsaarela 1499: addTriple (sNamespace + "subject",
1.10 jsaarela 1500: sNodeID,
1.13 jsaarela 1501: ( sSubject.length() == 0 ? source() : sSubject));
1.10 jsaarela 1502:
1.11 jsaarela 1503: addTriple (sNamespace + "object",
1.10 jsaarela 1504: sNodeID,
1.11 jsaarela 1505: sObject);
1.10 jsaarela 1506:
1507: addTriple (sNamespace + "type",
1508: sNodeID,
1.11 jsaarela 1509: sNamespace + "Statement");
1.10 jsaarela 1510:
1511: return sNodeID;
1512: }
1513:
1.11 jsaarela 1514: /**
1515: * Create a new triple and add it to the <i>m_triples</i> Vector
1516: */
1.14 jsaarela 1517: public void addTriple (String sPredicate, String sSubject, String sObject) {
1.12 jsaarela 1518: /**
1519: * If there is no subject (about=""), then use the URI/filename where
1520: * the RDF description came from
1521: */
1522: if (sSubject.length() == 0) {
1.13 jsaarela 1523: sSubject = source();
1.12 jsaarela 1524: }
1525:
1.11 jsaarela 1526: Triple t = new Triple (sPredicate, sSubject, sObject);
1.10 jsaarela 1527: m_triples.addElement (t);
1528: }
1529:
1.11 jsaarela 1530: /**
1531: * Print all triples to the <i>ps</i> PrintStream
1532: */
1.10 jsaarela 1533: public void printTriples (PrintStream ps) {
1534: for (int x = 0; x < m_triples.size(); x++) {
1535: Triple t = (Triple)m_triples.elementAt (x);
1.11 jsaarela 1536: ps.println ("triple(\""+t.predicate()+"\",\""+t.subject()+"\",\""+t.object()+"\").");
1.10 jsaarela 1537: }
1538: }
1539:
1.11 jsaarela 1540: /**
1541: * Return all created triples in an Enumeration instance
1542: */
1.10 jsaarela 1543: public Enumeration triples () {
1544: return m_triples.elements ();
1545: }
1546:
1547: /**
1.11 jsaarela 1548: * Is the element a Description
1.10 jsaarela 1549: */
1550: public boolean isDescription (Element e) {
1551: return isRDF(e) &&
1552: e.name().endsWith ("Description");
1553: }
1554:
1.11 jsaarela 1555: /**
1556: * Is the element a ListItem
1557: */
1.10 jsaarela 1558: public boolean isListItem (Element e) {
1559: return isRDF(e) &&
1560: ( e.name().endsWith ("li") ||
1561: e.name().indexOf ("_") > -1);
1.8 jsaarela 1562: }
1563:
1.11 jsaarela 1564: /**
1565: * Is the element a Container
1566: *
1567: * @see isSequence
1568: * @see isAlternative
1569: * @see isBag
1570: */
1.10 jsaarela 1571: public boolean isContainer (Element e) {
1572: return (isSequence (e) ||
1573: isAlternative (e) ||
1574: isBag (e));
1575: }
1576:
1.11 jsaarela 1577: /**
1578: * Is the element a Sequence
1579: */
1.10 jsaarela 1580: public boolean isSequence (Element e) {
1581: return isRDF(e) &&
1582: e.name().endsWith ("Seq");
1583: }
1584:
1.11 jsaarela 1585: /**
1586: * Is the element an Alternative
1587: */
1.10 jsaarela 1588: public boolean isAlternative (Element e) {
1589: return isRDF(e) &&
1590: e.name().endsWith ("Alt");
1591: }
1592:
1.11 jsaarela 1593: /**
1594: * Is the element a Bag
1595: */
1.10 jsaarela 1596: public boolean isBag (Element e) {
1597: return isRDF(e) &&
1598: e.name().endsWith ("Bag");
1599: }
1600:
1601: /**
1.12 jsaarela 1602: * This method matches all properties but those from RDF namespace
1.10 jsaarela 1603: */
1.13 jsaarela 1604: public boolean isTypedPredicate (Element e) {
1.12 jsaarela 1605: if (isRDF(e)) {
1.13 jsaarela 1606: // list all RDF predicates known by the RDF specification
1.12 jsaarela 1607: if (e.name().endsWith ("predicate") ||
1608: e.name().endsWith ("subject") ||
1609: e.name().endsWith ("object") ||
1.13 jsaarela 1610: e.name().endsWith ("type") ||
1.14 jsaarela 1611: e.name().endsWith ("value") ||
1612: e.name().endsWith ("Property") ||
1613: e.name().endsWith ("Statement")) {
1.12 jsaarela 1614: return true;
1615: }
1616: return false;
1617: }
1.10 jsaarela 1618: if (e.name().length() > 0)
1619: return true;
1620: else
1621: return false;
1.12 jsaarela 1622: }
1623:
1624: public boolean isRDFroot (Element e) {
1625: return isRDF(e) &&
1626: e.name().toLowerCase().endsWith ("rdf");
1.10 jsaarela 1627: }
1628:
1.11 jsaarela 1629: /**
1630: * Check if the element <i>e</i> is from the namespace
1631: * of the RDF schema by comparing only the beginning of
1632: * the expanded element name with the canonical RDFSCHEMA
1633: * URI
1634: */
1.10 jsaarela 1635: public boolean isRDF (Element e) {
1.15 ! jsaarela 1636: if (e.name() != null)
! 1637: return e.name().startsWith (RDFSCHEMA);
! 1638: else
! 1639: return false;
1.10 jsaarela 1640: }
1641:
1642: /**
1643: * Methods for node reference management
1644: */
1645: private Vector m_vResources = new Vector ();
1646: private Vector m_vResolveQueue = new Vector ();
1647: private Hashtable m_hIDtable = new Hashtable ();
1648: private int m_iReificationCounter = 0;
1649:
1.11 jsaarela 1650: /**
1651: * Add the element <i>e</i> to the <i>m_vResolveQueue</i>
1652: * to be resolved later.
1653: */
1.10 jsaarela 1654: public void resolveLater (Element e) {
1655: m_vResolveQueue.addElement (e);
1656: }
1657:
1.11 jsaarela 1658: /**
1659: * Go through the <i>m_vResolveQueue</i> and assign
1660: * direct object reference for each symbolic reference
1661: */
1.10 jsaarela 1662: public void resolve () {
1663: for (int x = 0; x < m_vResolveQueue.size(); x++) {
1664: Element e = (Element)m_vResolveQueue.elementAt(x);
1665:
1666: String sAbout = e.getAttribute (RDFSCHEMA, "about");
1667: if (sAbout != null) {
1668: if (sAbout.startsWith ("#"))
1669: sAbout = sAbout.substring (1);
1670: Element e2 = (Element)lookforNode(sAbout);
1671: if (e2 != null) {
1672: e.addTarget (e2);
1673: } else {
1674: addError ("Unresolved internal reference to "+sAbout);
1675: }
1676: }
1677:
1678: String sResource = e.getAttribute (RDFSCHEMA, "resource");
1679: if (sResource != null) {
1680: if (sResource.startsWith ("#"))
1681: sResource = sResource.substring (1);
1682: Element e2 = (Element)lookforNode(sResource);
1683: if (e2 != null) {
1684: e.addTarget (e2);
1.13 jsaarela 1685: }
1.10 jsaarela 1686: }
1687:
1688: String sAboutEach = e.getAttribute (RDFSCHEMA, "aboutEach");
1689: if (sAboutEach != null) {
1690: sAboutEach = sAboutEach.substring (1);
1691: Element e2 = (Element)lookforNode(sAboutEach);
1692: if (e2 != null) {
1693: e.addTarget (e2);
1694: }
1695: }
1696:
1697: String sAboutEachPrefix = e.getAttribute (RDFSCHEMA, "aboutEachPrefix");
1698: if (sAboutEachPrefix != null) {
1699: for (int y = 0; y < m_vResources.size(); y++) {
1700: Element ele = (Element)m_vResources.elementAt(y);
1701: String sA = ele.getAttribute (RDFSCHEMA, "about");
1702: if (sA.startsWith (sAboutEachPrefix)) {
1703: e.addTarget (ele);
1704: }
1705: }
1706: }
1707: }
1708: m_vResolveQueue.removeAllElements();
1709: }
1710:
1.11 jsaarela 1711: /**
1712: * Look for a node by name <i>sID</i> from the Hashtable
1713: * <i>m_hIDtable</i> of all registered IDs.
1714: */
1.10 jsaarela 1715: public Element lookforNode (String sID) {
1716: if (sID == null)
1717: return null;
1718: else
1719: return (Element)m_hIDtable.get (sID);
1720: }
1721:
1.11 jsaarela 1722: /**
1723: * Add an element <i>e</i> to the Hashtable <i>m_hIDtable</i>
1724: * which stores all nodes with an ID
1725: */
1.10 jsaarela 1726: public void registerID (String sID, Element e) {
1727: if (m_hIDtable.get (sID) != null)
1728: addError(sID+" ID already defined.");
1729: m_hIDtable.put (sID, e);
1730: }
1731:
1.11 jsaarela 1732: /**
1733: * Create a new reification ID by using a name part and an
1734: * incremental counter <i>m_iReificationCounter</i>.
1735: */
1.10 jsaarela 1736: public String newReificationID () {
1737: m_iReificationCounter++;
1738: return new String ("genid" + m_iReificationCounter);
1739: }
1740:
1.11 jsaarela 1741: /**
1742: * Add an element <i>e</i> to the Vector <i>m_vResources</i>
1743: * which stores all nodes with an URI
1744: */
1.10 jsaarela 1745: public void registerResource (Element e) {
1746: m_vResources.addElement (e);
1.14 jsaarela 1747: }
1748:
1749: public void makeMarkupST (Element ele) {
1750: m_sLiteral += "<" + ele.name();
1751:
1752: Enumeration e = ele.attributes();
1753: while (e.hasMoreElements()) {
1754: String sAttribute = (String)e.nextElement();
1755: String sAttributeValue = (String)ele.getAttribute (sAttribute);
1756: m_sLiteral += " " + sAttribute + "='" + sAttributeValue + "'";
1757: }
1758: m_sLiteral += ">";
1759: }
1760:
1761: public void makeMarkupET (String name) {
1762: m_sLiteral += "</" + name + ">";
1763: }
1764:
1765: public void makeMarkupChar (String s) {
1766: m_sLiteral += s;
1.10 jsaarela 1767: }
1.1 jsaarela 1768: }
Webmaster