Annotation of java/classes/org/w3c/rdf/SiRPAC.java, revision 1.4

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

Webmaster