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

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

Webmaster