Index: doc/api/.cvsignore =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/doc/api/.cvsignore,v retrieving revision 1.1.1.1 diff -u -3 -p -u -r1.1.1.1 .cvsignore --- doc/api/.cvsignore 31 Jan 2005 04:02:18 -0000 1.1.1.1 +++ doc/api/.cvsignore 18 Apr 2005 00:45:44 -0000 @@ -1,2 +1,4 @@ Makefile Makefile.in +create_html +html Index: lib/.cvsignore =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/lib/.cvsignore,v retrieving revision 1.2 diff -u -3 -p -u -r1.2 .cvsignore --- lib/.cvsignore 28 Mar 2005 19:29:21 -0000 1.2 +++ lib/.cvsignore 18 Apr 2005 00:45:44 -0000 @@ -5,6 +5,8 @@ classes eclipse.jar owls.jar rdf.jar +commons.jar +xml.jar deps.sh gen-classlist.sh mkdep.pl Index: src/nongnu/cashews/commons/Pair.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/commons/Pair.java,v retrieving revision 1.3 diff -u -3 -p -u -r1.3 Pair.java --- src/nongnu/cashews/commons/Pair.java 17 Apr 2005 18:35:32 -0000 1.3 +++ src/nongnu/cashews/commons/Pair.java 18 Apr 2005 00:45:44 -0000 @@ -132,9 +132,7 @@ public class Pair */ public int hashCode() { - return super.hashCode() - + 13 * left.hashCode() - + 17 * right.hashCode(); + return 13 * left.hashCode() + 17 * right.hashCode(); } /** Index: src/nongnu/cashews/commons/PairStack.java =================================================================== RCS file: src/nongnu/cashews/commons/PairStack.java diff -N src/nongnu/cashews/commons/PairStack.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/commons/PairStack.java 18 Apr 2005 00:45:44 -0000 @@ -0,0 +1,100 @@ +/* PairStack.java -- A stack of heterogenous pairs. + Copyright (C) 2005 The University of Sheffield. + + This file is part of the CASheW-s editor. + + The CASheW-s editor is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The CASheW-s editor is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with The CASheW-s editor; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. +*/ + +package nongnu.cashews.commons; + +import java.util.Stack; + +/** + * A stack of heterogenous pairs. + * + * @author Andrew John Hughes (address@hidden) + * @see java.util.Stack + */ +public class PairStack + extends Stack> +{ + + /** + * Serialization ID. + */ + private static final long serialVersionUID = 4077300638060255809L; + + /** + * Constructs an empty PairStack. + */ + public PairStack() + { + super(); + } + + /** + * Returns the pair at the top of the stack, without removing it. + * + * @return the pair at the top of the stack. + */ + public Pair peek() + { + return super.peek(); + } + + /** + * Pops the pair at the top of the stack, and returns it. + * + * @return the pair at the top of the stack. The top of the stack is + * now the item below that returned. + */ + public Pair pop() + { + return super.pop(); + } + + /** + * Pushes the supplied value onto the top of the stack. The value + * is a pair composed of the two supplied values. + * + * @param left the left-hand value of the pair. + * @param right the right-hand value of the pair. + * @return the pair that was added. + */ + public Pair push(A left, B right) + { + return super.push(new Pair(left,right)); + } + + /** + * Returns the distance of the supplied value from the top of the stack, + * or -1 if the value is not on the stack. 1 represents the top item + * on the stack. The value used is a pair composed + * of the two supplied values. Values are compared using the equality + * test of the pair. + * + * @param left the left-hand value of the pair. + * @param right the right-hand value of the pair. + * @return the index of the pair of values on the stack, or -1 if the + * pair isn't present. + */ + public int search(A left, B right) + { + return super.search(new Pair(left,right)); + } + +} Index: src/nongnu/cashews/rdf/RDFHandler.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/RDFHandler.java,v retrieving revision 1.1 diff -u -3 -p -u -r1.1 RDFHandler.java --- src/nongnu/cashews/rdf/RDFHandler.java 17 Apr 2005 18:35:32 -0000 1.1 +++ src/nongnu/cashews/rdf/RDFHandler.java 18 Apr 2005 00:45:44 -0000 @@ -23,11 +23,16 @@ package nongnu.cashews.rdf; import java.net.URI; import java.net.URISyntaxException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.logging.Handler; import java.util.logging.Logger; +import nongnu.cashews.commons.Pair; import nongnu.cashews.commons.PairMap; import nongnu.cashews.commons.PairSet; +import nongnu.cashews.commons.PairStack; import nongnu.cashews.xml.XmlBaseHandler; import org.xml.sax.Attributes; @@ -109,6 +114,11 @@ public class RDFHandler private RDFObject object; /** + * The String form of the URI of the current subject. + */ + private String subjectURI; + + /** * The String form of the URI of the current predicate. */ private String predicateURI; @@ -123,7 +133,19 @@ public class RDFHandler * within a particular base URI. */ private PairSet ids; - + + /** + * The stack of current subject and predicate pairs. This allows + * us to handle nested triples, where the object of one triple + * is the triple nested inside that triple. + */ + private PairStack currentState; + + /** + * The set of blank node IDs. + */ + private Set nodeIDs; + /** * Constructs a new RDFHandler, using the specified * handler for log messages. @@ -155,6 +177,9 @@ public class RDFHandler object = null; ids = new PairSet(); graph = new Graph(); + subjectURI = null; + currentState = new PairStack(); + nodeIDs = new HashSet(); } /** @@ -235,7 +260,9 @@ public class RDFHandler { /* Abbreviation of typed rdf:Description */ parseAttributes(attributes); - setSubjectType(uri + localName); + subjectURI = uri + localName; + rdfLogger.finer("Start of subject with type: " + subjectURI); + setSubjectType(subjectURI); } } } @@ -311,10 +338,7 @@ public class RDFHandler rdfLogger.finer("End of RDF block"); } else if (localName.equals("Description")) - { - rdfLogger.finer("End of description block"); - inSubject = false; - } + endSubject(); } else if (inPredicate && predicateURI.equals(uri + localName)) { @@ -327,6 +351,8 @@ public class RDFHandler graph.addTriple(triple); rdfLogger.finer("End of predicate block"); } + else if (inSubject && subjectURI.equals(uri + localName)) + endSubject(); } /** @@ -355,6 +381,7 @@ public class RDFHandler for (int a = 0; a < attributes.getLength(); ++a) attribs.put(attributes.getURI(a), attributes.getLocalName(a), attributes.getValue(a)); + rdfLogger.finer("Attributes: " + attribs); handleAttributes(attribs); } @@ -367,27 +394,52 @@ public class RDFHandler protected void handleAttributes(PairMap attributes) throws SAXException { + if (inPredicate) + { + /* A nested triple */ + rdfLogger.finer("Left state: " + + currentState.push(subject,predicate)); + inPredicate = false; + subject = null; + predicate = null; + } /* Check for RDF URI subject */ String value = attributes.get(RDF_NAMESPACE, "about"); if (value != null) - subject = parseRDFURI(value); + { + subject = parseRDFURI(value); + attributes.remove(RDF_NAMESPACE, "about"); + } else { value = attributes.get(RDF_NAMESPACE, "ID"); if (value != null) { + attributes.remove(RDF_NAMESPACE, "ID"); boolean added = ids.add(getBaseURI(), value); if (added) subject = new RDFURI(getBaseURI().resolve("#" + value)); + else + rdfLogger.severe("Duplicate node ID: " + + getBaseURI().resolve("#" + value)); } else { /* Check for blank node subject */ value = attributes.get(RDF_NAMESPACE, "nodeID"); if (value != null) - subject = new Blank(value); + { + attributes.remove(RDF_NAMESPACE, "nodeID"); + boolean added = nodeIDs.add(value); + if (added) + subject = new Blank(value); + else + rdfLogger.severe("Duplicate blank node ID: " + value); + } + else + subject = new Blank(generateBlankID()); } } if (subject == null) @@ -398,8 +450,24 @@ public class RDFHandler inSubject = true; rdfLogger.fine("Created subject: " + subject); } + /* Handle any remaining attributes as property attributes */ + for (Map.Entry,String> entry : attributes.entrySet()) + { + Pair key = entry.getKey(); + triple = new Triple(subject, + parseRDFURI(key.getLeft() + key.getRight()), + new Literal(entry.getValue())); + rdfLogger.fine("Created triple using property attribute: " + triple); + graph.addTriple(triple); + } } + /** + * Sets the type of the subject node to the value + * parsed from the supplied string. + * + * @param value the value to parse. + */ private void setSubjectType(String value) { if (value != null && subject instanceof Node) @@ -410,4 +478,54 @@ public class RDFHandler } } + /** + * Generate an ID for a blank node. + * + * @return a blank node ID. + */ + private String generateBlankID() + { + boolean added = false; + String randomID; + do + { + randomID = Long.toString(Math.round(Math.random() * Long.MAX_VALUE)); + added = nodeIDs.add(randomID); + } while (!added); + return randomID; + } + + /** + * Handle the end of a subject node, including one that is + * nested inside another. Subject nodes take two forms, so + * it becomes necessary to have common handling for these. + */ + private void endSubject() + { + inSubject = false; + subjectURI = null; + predicateURI = null; + if (currentState.empty()) + subject = null; + else + { + /* Closure of nested triple; return to previous state */ + object = (RDFObject) subject; + Pair previous = currentState.pop(); + rdfLogger.finer("New state: " + previous); + subject = previous.getLeft(); + predicate = previous.getRight(); + if (subject instanceof Node) + { + URI subjectType = ((Node) subject).getType(); + if (subjectType != null) + subjectURI = subjectType.toString(); + } + if (predicate instanceof RDFURI) + predicateURI = ((RDFURI) predicate).getURI().toString(); + inPredicate = true; + } + rdfLogger.finer("End of subject block"); + } + } Index: src/nongnu/cashews/rdf/XMLParser.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/XMLParser.java,v retrieving revision 1.9 diff -u -3 -p -u -r1.9 XMLParser.java --- src/nongnu/cashews/rdf/XMLParser.java 17 Apr 2005 18:35:32 -0000 1.9 +++ src/nongnu/cashews/rdf/XMLParser.java 18 Apr 2005 00:45:44 -0000 @@ -21,8 +21,6 @@ package nongnu.cashews.rdf; -import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; @@ -74,18 +72,16 @@ public class XMLParser * @throws SAXException if a XMLReader can't be obtained * or an error occurs during parsing. * @throws IOException if an error occurs in the underlying input. - * @throws FileNotFoundException if one of the specified files can't - * be found. */ public static void main(String[] args) - throws SAXException, IOException, FileNotFoundException + throws SAXException, IOException { Handler handler = new ConsoleHandler(); handler.setLevel(Level.FINE); XMLParser parser = new XMLParser(handler); for (int a = 0; a < args.length; ++a) { - parser.parse(new File(args[a])); + parser.parse(args[a]); System.out.println(parser.getRDFHandler().getGraph()); } } Index: src/nongnu/cashews/xml/Parser.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/xml/Parser.java,v retrieving revision 1.1 diff -u -3 -p -u -r1.1 Parser.java --- src/nongnu/cashews/xml/Parser.java 17 Apr 2005 18:35:32 -0000 1.1 +++ src/nongnu/cashews/xml/Parser.java 18 Apr 2005 00:45:44 -0000 @@ -22,7 +22,6 @@ package nongnu.cashews.xml; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.logging.ConsoleHandler; @@ -125,7 +124,7 @@ public class Parser public void parse(File file) throws IOException, SAXException { - parse(new InputSource(new FileInputStream(file))); + parse(file.toURI().toString()); } /** @@ -156,7 +155,7 @@ public class Parser handler.setLevel(Level.FINE); Parser parser = new Parser(handler); for (int a = 0; a < args.length; ++a) - parser.parse(new File(args[a])); + parser.parse(args[a]); } }