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

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

Webmaster