Index: src/nongnu/cashews/commons/Pair.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/commons/Pair.java,v retrieving revision 1.2 diff -u -3 -p -u -r1.2 Pair.java --- src/nongnu/cashews/commons/Pair.java 9 Apr 2005 22:11:10 -0000 1.2 +++ src/nongnu/cashews/commons/Pair.java 17 Apr 2005 18:25:18 -0000 @@ -21,6 +21,8 @@ package nongnu.cashews.commons; +import java.io.Serializable; + /** * A small helper class to pair up two arbitrary heterogenously-typed * values. This is where we wish we had a tuple data type. @@ -28,23 +30,33 @@ package nongnu.cashews.commons; * @author Andrew John Hughes (address@hidden) */ public class Pair + implements Serializable { /** + * Serialization ID. + */ + private static final long serialVersionUID = -1924824870778608765L; + + /** * The left-hand value. + * + * @serial the left-hand value. */ private A left; /** * The right-hand value. + * + * @serial the right-hand value. */ private B right; /** * Constructs a new pair using the values specified. * - * @param a the left-hand value. - * @param b the right-hand value. + * @param left the left-hand value. + * @param right the right-hand value. */ public Pair(A left, B right) { @@ -96,7 +108,7 @@ public class Pair * Returns true if the supplied object is also a pair, with equivalent * left and right-hand values. * - * @param object the object to compare. + * @param obj the object to compare. */ public boolean equals(Object obj) { @@ -125,4 +137,14 @@ public class Pair + 17 * right.hashCode(); } + /** + * Returns a String representation of the pair. + * + * @return a String representation. + */ + public String toString() + { + return "(" + left + "," + right + ")"; + } + } Index: src/nongnu/cashews/commons/PairMap.java =================================================================== RCS file: src/nongnu/cashews/commons/PairMap.java diff -N src/nongnu/cashews/commons/PairMap.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/commons/PairMap.java 17 Apr 2005 18:25:18 -0000 @@ -0,0 +1,144 @@ +/* PairMap.java -- A map using a heterogenous pair as the key. + 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.HashMap; + +/** + * A map of a key, consisting of a pair of values, to a value. + * + * @author Andrew John Hughes (address@hidden) + * @see java.util.Map + */ +public class PairMap + extends HashMap,V> +{ + + /** + * Serialization ID. + */ + private static final long serialVersionUID = -3133725540569322674L; + + /** + * Constructs an empty PairMap with the default initial + * capacity (16) and the default load factor (0.75). + */ + public PairMap() + { + this(16); + } + + /** + * Constructs an empty PairMap using the supplied initial + * capacity and the default load factor (0.75). + * + * @param initialCapacity the initial capacity of the map. + */ + public PairMap(int initialCapacity) + { + this(initialCapacity, 0.75f); + } + + /** + * Constructs an empty PairMap using the supplied initial + * capacity and the supplied load factor. + * + * @param initialCapacity the initial capacity of the map. + * @param loadFactor the load factor of the map. + */ + public PairMap(int initialCapacity, float loadFactor) + { + super(initialCapacity, loadFactor); + } + + /** + * Constructs a PairMap using the contents of the supplied + * pair map. + * + * @param m the map whose contents are to be used as the start of the + * contents for the new map. + */ + public PairMap(PairMap m) + { + super(m); + } + + /** + * Returns true if the map contains a mapping for the specified key. + * The key is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return true if the map contains a mapping for the key. + */ + public boolean containsKey(A left, B right) + { + return super.containsKey(new Pair(left,right)); + } + + /** + * Retrieves the value associated with the given key. The key + * is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return the value associated with the key. + */ + public V get(A left, B right) + { + return super.get(new Pair(left,right)); + } + + /** + * Adds a mapping to the specified value from the supplied key. The key + * is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @param value the value which maps from the given key. + * @return the previous value assigned to the supplied key, or + * null if there was no previous value. + * null may also be returned if the map allows + * null values. + */ + public V put(A left, B right, V value) + { + return super.put(new Pair(left,right), value); + } + + /** + * Removes the mapping associated with the specified key. The key + * is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return the previous value assigned to the supplied key, or + * null if there was no previous value. + * null may also be returned if the map allows + * null values. + */ + public V remove(A left, B right) + { + return super.remove(new Pair(left,right)); + } + +} Index: src/nongnu/cashews/commons/PairSet.java =================================================================== RCS file: src/nongnu/cashews/commons/PairSet.java diff -N src/nongnu/cashews/commons/PairSet.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/commons/PairSet.java 17 Apr 2005 18:25:18 -0000 @@ -0,0 +1,124 @@ +/* PairSet.java -- A set 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.HashSet; + +/** + * A set consisting of pairs of values. + * + * @author Andrew John Hughes (address@hidden) + * @see java.util.Set + */ +public class PairSet + extends HashSet> +{ + + /** + * Serialization ID. + */ + private static final long serialVersionUID = 8613032536466128835L; + + /** + * Constructs an empty PairSet with the default initial + * capacity (16) and the default load factor (0.75). + */ + public PairSet() + { + this(16); + } + + /** + * Constructs an empty PairSet using the supplied initial + * capacity and the default load factor (0.75). + * + * @param initialCapacity the initial capacity of the map. + */ + public PairSet(int initialCapacity) + { + this(initialCapacity, 0.75f); + } + + /** + * Constructs an empty PairSet using the supplied initial + * capacity and the supplied load factor. + * + * @param initialCapacity the initial capacity of the map. + * @param loadFactor the load factor of the map. + */ + public PairSet(int initialCapacity, float loadFactor) + { + super(initialCapacity, loadFactor); + } + + /** + * Constructs a PairSet using the contents of the supplied + * pair set. + * + * @param s the set whose contents are to be used as the start of the + * contents for the new set. + */ + public PairSet(PairSet s) + { + super(s); + } + + /** + * Returns true if the set contains the specified value. + * The value is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return true if the set contains the specified value. + */ + public boolean contains(A left, B right) + { + return super.contains(new Pair(left,right)); + } + + /** + * Adds the specified value to the set. The value + * is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return true if the set did not contain the value. + */ + public boolean add(A left, B right) + { + return super.add(new Pair(left,right)); + } + + /** + * Removes the specified value from the set. The value + * is constructed as the pair of the two supplied values. + * + * @param left the left-hand value of the key. + * @param right the right-hand value of the key. + * @return true if the set contained the value. + */ + public boolean remove(A left, B right) + { + return super.remove(new Pair(left,right)); + } + +} Index: src/nongnu/cashews/rdf/Blank.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/Blank.java,v retrieving revision 1.1 diff -u -3 -p -u -r1.1 Blank.java --- src/nongnu/cashews/rdf/Blank.java 4 Apr 2005 16:00:19 -0000 1.1 +++ src/nongnu/cashews/rdf/Blank.java 17 Apr 2005 18:25:18 -0000 @@ -32,7 +32,7 @@ package nongnu.cashews.rdf; * @author Andrew John Hughes (address@hidden) */ public class Blank - implements Subject, RDFObject + extends Node { /** @@ -59,8 +59,9 @@ public class Blank */ public String toString() { - return getClass().getName() + - "[id = " + + String superToString = super.toString(); + return superToString.substring(0, superToString.length() - 1) + + ", id = " + id + "]"; } @@ -72,14 +73,7 @@ public class Blank */ public Blank clone() { - try - { - return (Blank) super.clone(); - } - catch (CloneNotSupportedException e) - { - throw new IllegalStateException("Unexpected exception: " + e, e); - } + return (Blank) super.clone(); } /** Index: src/nongnu/cashews/rdf/Node.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/Node.java,v retrieving revision 1.2 diff -u -3 -p -u -r1.2 Node.java --- src/nongnu/cashews/rdf/Node.java 28 Mar 2005 19:29:21 -0000 1.2 +++ src/nongnu/cashews/rdf/Node.java 17 Apr 2005 18:25:18 -0000 @@ -21,6 +21,9 @@ package nongnu.cashews.rdf; +import java.net.URI; +import java.net.URISyntaxException; + /** *

* This interface represents an RDF node. A node can either be a URI reference @@ -31,7 +34,91 @@ package nongnu.cashews.rdf; * @see RDFURI * @see Blank */ -public interface Node +public abstract class Node + implements Subject, RDFObject { + /** + * The optional type of this node. + */ + private URI type; + + /** + * Returns a deep copy of the node. + * + * @return a deep copy of the node. + */ + public Node clone() + { + try + { + Object clonedObject = super.clone(); + Node clone = (Node) clonedObject; + clone.setType(getType()); + return clone; + } + catch (CloneNotSupportedException e) + { + throw new IllegalStateException("Unexpected exception: " + e, e); + } + } + /** + * Sets the type of this node to that supplied. + * + * @param type the new type of this node. + */ + public void setType(URI type) + { + this.type = type; + } + + /** + * Retrieves a clone of the current type of this node. + * + * @return a clone of the current type. + */ + public URI getType() + { + try + { + return (type == null ? null : new URI(type.toString())); + } + catch (URISyntaxException e) + { + throw new IllegalStateException("The URI is invalid.", e); + } + } + + /** + * Returns a textual representation of the node. + * + * @return a textual representation. + */ + public String toString() + { + return getClass().getName() + + "[type = " + + type + + "]"; + } + + /** + * Sets the type of this node to the URI represented by the supplied + * String. + * + * @param type the new type of the subject, in String form. + */ + public void setType(String type) + { + try + { + setType(new URI(type)); + } + catch (URISyntaxException e) + { + throw new IllegalArgumentException("Failed to parse URI: " + e, e); + } + } + + } Index: src/nongnu/cashews/rdf/RDFHandler.java =================================================================== RCS file: src/nongnu/cashews/rdf/RDFHandler.java diff -N src/nongnu/cashews/rdf/RDFHandler.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/rdf/RDFHandler.java 17 Apr 2005 18:25:18 -0000 @@ -0,0 +1,413 @@ +/* RDFHandler.java -- Handler for RDF in XML form. + 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.rdf; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.logging.Handler; +import java.util.logging.Logger; + +import nongnu.cashews.commons.PairMap; +import nongnu.cashews.commons.PairSet; +import nongnu.cashews.xml.XmlBaseHandler; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * This class deals with the parsing of RDF in XML form, as defined by the + * RDFXML syntax + * standard. It turns an XML-based representation of an RDF graph into a + * Graph object. + * + * @author Andrew John Hughes (address@hidden) + * @see Graph + */ +public class RDFHandler + extends XmlBaseHandler +{ + + /** + * The RDF namespace. + */ + public static final String + RDF_NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + + /** + * The resulting graph. + * + * @serial the graph of RDF triples. + */ + private Graph graph; + + /** + * A Logger instance to log events generated by the + * parsing process. + */ + private Logger rdfLogger; + + /** + * Flag to indicate whether we are inside an RDF document + * or not. There is not a one-to-one correspondence between + * an RDF document and the XML document. RDF is to usually + * to be expected inside an RDF element. However, a single + * Description element may occur on its own, outside + * this context. In either of these cases, this flag should + * be set. + */ + private boolean inRDF; + + /** + * Flag to indicate whether we are inside a subject node or + * not. + */ + private boolean inSubject; + + /** + * Flag to indicate whether we are inside a predicate node or + * not. + */ + private boolean inPredicate; + + /** + * The current triple. + */ + private Triple triple; + + /** + * The current subject in the current RDF triple. + */ + private Subject subject; + + /** + * The current predicate in the current RDF triple. + */ + private Predicate predicate; + + /** + * The current object in the current RDF triple. + */ + private RDFObject object; + + /** + * The String form of the URI of the current predicate. + */ + private String predicateURI; + + /** + * The type of the current literal. + */ + private Type type; + + /** + * The set of ids used in the RDF document. RDF IDs must be unique + * within a particular base URI. + */ + private PairSet ids; + + /** + * Constructs a new RDFHandler, using the specified + * handler for log messages. + * + * @param handler the handler to use for log messages. + */ + public RDFHandler(Handler handler) + { + super(handler); + rdfLogger = Logger.getLogger("nongnu.cashews.rdf.RDFHandler"); + rdfLogger.addHandler(handler); + rdfLogger.setLevel(handler.getLevel()); + } + + /** + * Captures the start of the document and sets up the initial + * state. + */ + public void startDocument() + { + super.startDocument(); + inSubject = false; + inRDF = false; + inPredicate = false; + predicateURI = null; + type = null; + subject = null; + predicate = null; + object = null; + ids = new PairSet(); + graph = new Graph(); + } + + /** + * Captures the start of an XML element. + * + * @param uri the namespace URI. + * @param localName the local name of the element inside the namespace. + * @param qName the local name qualified with the namespace URI. This + * may or may not be provided, as we don't ask for namespace + * prefixes. + * @param attributes the attributes of this element. + * @throws SAXException if some error occurs in parsing. + */ + public void startElement(String uri, String localName, + String qName, Attributes attributes) + throws SAXException + { + super.startElement(uri, localName, qName, attributes); + if (uri.equals(RDF_NAMESPACE)) + { + if (localName.equals("RDF")) + { + /* rdf:RDF */ + inRDF = true; + rdfLogger.finer("Start of RDF block"); + } + else if (localName.equals("Description")) + { + /* rdf:Description */ + rdfLogger.finer("Start of RDF description block"); + inRDF = true; + if (!inSubject) + parseAttributes(attributes); + } + else if (localName.equals("type") && inSubject) + setSubjectType(attributes.getValue(RDF_NAMESPACE, "resource")); + else + rdfLogger.warning("Invalid use of RDF namespace: " + uri + + localName); + } + else + { + if (inRDF) + { + if (inSubject) + { + /* Predicate element */ + predicateURI = uri + localName; + rdfLogger.finer("Start of predicate: " + predicateURI); + predicate = parseRDFURI(predicateURI); + rdfLogger.fine("Created predicate: " + predicate); + inSubject = false; + inPredicate = true; + /* Check for RDF URI object */ + String value = attributes.getValue(RDF_NAMESPACE, + "resource"); + if (value != null) + { + object = parseRDFURI(value); + rdfLogger.fine("Created object: " + object); + } + else + { + /* Check for blank node object */ + value = attributes.getValue(RDF_NAMESPACE, "nodeID"); + if (value != null) + { + object = new Blank(value); + rdfLogger.fine("Created object: " + object); + } + } + /* Check for a type */ + value = attributes.getValue(RDF_NAMESPACE, "datatype"); + if (value != null) + type = TypeFactory.getInstance(value); + } + else + { + /* Abbreviation of typed rdf:Description */ + parseAttributes(attributes); + setSubjectType(uri + localName); + } + } + } + } + + /** + * Attempts to returns the RDF URI parsed from the specified + * String. + * + * @param value the value to parse. + * @return an RDF URI. + * @throws SAXException if the URI can't be parsed. + */ + private RDFURI parseRDFURI(String value) + throws SAXException + { + try + { + return new RDFURI(new URI(value)); + } + catch (URISyntaxException e) + { + throw new SAXException("Failed to parse URI: " + e, e); + } + } + + /** + * Captures characters within an XML element. + * + * @param ch the array of characters. + * @param start the start index of the characters to use. + * @param length the number of characters to use from the start index on. + * @throws SAXException if some error occurs in parsing. + */ + public void characters(char[] ch, int start, int length) + throws SAXException + { + super.characters(ch, start, length); + String value = new String(ch, start, length).trim(); + if (value.length() == 0) + return; + rdfLogger.finer("Characters: " + value); + if (inPredicate) + { + if (type == null) + object = new Literal(value); + else + object = new Literal(value, type); + rdfLogger.fine("Created object: " + object); + } + } + + /** + * Captures the end of an XML element. + * + * @param uri the namespace URI. + * @param localName the local name of the element inside the namespace. + * @param qName the local name qualified with the namespace URI. This + * may or may not be provided, as we don't ask for namespace + * prefixes. + * @throws SAXException if some error occurs in parsing. + */ + public void endElement(String uri, String localName, + String qName) + throws SAXException + { + super.endElement(uri, localName, qName); + if (uri.equals(RDF_NAMESPACE)) + { + if (localName.equals("RDF")) + { + inRDF = false; + rdfLogger.finer("End of RDF block"); + } + else if (localName.equals("Description")) + { + rdfLogger.finer("End of description block"); + inSubject = false; + } + } + else if (inPredicate && predicateURI.equals(uri + localName)) + { + inPredicate = false; + inSubject = true; + predicateURI = null; + type = null; + triple = new Triple(subject, predicate, object); + rdfLogger.fine("Created triple: " + triple); + graph.addTriple(triple); + rdfLogger.finer("End of predicate block"); + } + } + + /** + * Retrieves the graph created by the parsing process. + * + * @return the graph resulting from the parse. + */ + public Graph getGraph() + { + return graph; + } + + /** + * Parses the attribute into a collection, from which used + * attributes can be removed, and then passes them on to + * the handler. + * + * @param attributes the attributes to sort out. + * @throws SAXException if some error occurs in parsing. + */ + private void parseAttributes(Attributes attributes) + throws SAXException + { + PairMap attribs = + new PairMap(); + for (int a = 0; a < attributes.getLength(); ++a) + attribs.put(attributes.getURI(a), attributes.getLocalName(a), + attributes.getValue(a)); + handleAttributes(attribs); + } + + /** + * Handles the attributes resulting from an RDF element. + * + * @param attributes the attributes to sort out. + * @throws SAXException if some error occurs in parsing. + */ + protected void handleAttributes(PairMap attributes) + throws SAXException + { + /* Check for RDF URI subject */ + String value = attributes.get(RDF_NAMESPACE, "about"); + if (value != null) + subject = parseRDFURI(value); + else + { + value = attributes.get(RDF_NAMESPACE, "ID"); + if (value != null) + { + boolean added = + ids.add(getBaseURI(), value); + if (added) + subject = new + RDFURI(getBaseURI().resolve("#" + value)); + } + else + { + /* Check for blank node subject */ + value = attributes.get(RDF_NAMESPACE, "nodeID"); + if (value != null) + subject = new Blank(value); + } + } + if (subject == null) + rdfLogger.severe("No subject found in RDF " + + "description."); + else + { + inSubject = true; + rdfLogger.fine("Created subject: " + subject); + } + } + + private void setSubjectType(String value) + { + if (value != null && subject instanceof Node) + { + Node node = (Node) subject; + node.setType(value); + rdfLogger.fine("Found type: " + node.getType()); + } + } + +} Index: src/nongnu/cashews/rdf/RDFObject.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/RDFObject.java,v retrieving revision 1.3 diff -u -3 -p -u -r1.3 RDFObject.java --- src/nongnu/cashews/rdf/RDFObject.java 4 Apr 2005 00:59:33 -0000 1.3 +++ src/nongnu/cashews/rdf/RDFObject.java 17 Apr 2005 18:25:18 -0000 @@ -33,7 +33,7 @@ package nongnu.cashews.rdf; * @see Literal */ public interface RDFObject - extends Node, Cloneable + extends Cloneable { /** Index: src/nongnu/cashews/rdf/RDFURI.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/RDFURI.java,v retrieving revision 1.5 diff -u -3 -p -u -r1.5 RDFURI.java --- src/nongnu/cashews/rdf/RDFURI.java 4 Apr 2005 16:00:19 -0000 1.5 +++ src/nongnu/cashews/rdf/RDFURI.java 17 Apr 2005 18:25:18 -0000 @@ -33,7 +33,8 @@ import java.net.URISyntaxException; * @see java.net.URI */ public class RDFURI - implements Subject, Predicate, RDFObject + extends Node + implements Predicate { /** @@ -61,8 +62,9 @@ public class RDFURI */ public String toString() { - return getClass().getName() + - "[uri = " + + String superToString = super.toString(); + return superToString.substring(0, superToString.length() - 1) + + ", uri = " + uri + "]"; } @@ -91,17 +93,10 @@ public class RDFURI */ public RDFURI clone() { - try - { - Object clonedObject = super.clone(); - RDFURI clone = (RDFURI) clonedObject; - clone.setURI(getURI()); - return clone; - } - catch (CloneNotSupportedException e) - { - throw new IllegalStateException("Unexpected exception: " + e, e); - } + Object clonedObject = super.clone(); + RDFURI clone = (RDFURI) clonedObject; + clone.setURI(getURI()); + return clone; } /** Index: src/nongnu/cashews/rdf/Subject.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/Subject.java,v retrieving revision 1.3 diff -u -3 -p -u -r1.3 Subject.java --- src/nongnu/cashews/rdf/Subject.java 4 Apr 2005 00:59:33 -0000 1.3 +++ src/nongnu/cashews/rdf/Subject.java 17 Apr 2005 18:25:18 -0000 @@ -24,7 +24,8 @@ package nongnu.cashews.rdf; /** *

* This interface represents an RDF subject. A subject can either be a URI - * reference or a blank node. + * reference or a blank node. Subjects are also defined as being instances + * of a particular class by their type. *

* * @author Andrew John Hughes (address@hidden) @@ -34,7 +35,7 @@ package nongnu.cashews.rdf; * @see Blank */ public interface Subject - extends Node, Cloneable + extends Cloneable { /** Index: src/nongnu/cashews/rdf/XMLParser.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/XMLParser.java,v retrieving revision 1.8 diff -u -3 -p -u -r1.8 XMLParser.java --- src/nongnu/cashews/rdf/XMLParser.java 9 Apr 2005 22:11:10 -0000 1.8 +++ src/nongnu/cashews/rdf/XMLParser.java 17 Apr 2005 18:25:18 -0000 @@ -22,125 +22,48 @@ package nongnu.cashews.rdf; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashSet; -import java.util.Set; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; import java.util.logging.Level; -import java.util.logging.Logger; -import nongnu.cashews.commons.Pair; -import nongnu.cashews.xml.XmlBaseHandler; +import nongnu.cashews.xml.Parser; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.XMLReaderFactory; /** - * This class deals with the parsing of RDF in XML form, as defined by the - * RDFXML syntax - * standard. It turns an XML-based representation of an RDF graph into a - * Graph object. + * This class is simply a wrapper around the existing parser to enable + * the testing of RDF parsing. * * @author Andrew John Hughes (address@hidden) - * @see Graph */ public class XMLParser + extends Parser { /** - * The RDF namespace. - */ - public static final String - RDF_NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; - - /** - * The reader, which interprets the XML file. - * - * @serial the XML reader. - */ - private XMLReader reader; - - /** - * The resulting graph. - * - * @serial the graph of RDF triples. - */ - private Graph graph; - - /** - * The handler for the XML. - * - * @serial the XML handler. - */ - private RDFHandler rdfHandler; - - /** - * Constructs a new XML-based RDF parser, using the specified handler + * Constructs a new RDF-based parser, using the specified handler * for messages. * - * @param handler the handler to use for log messages. + * @param logHandler the handler to use for log messages. * @throws SAXException if the parser fails to obtain an * XMLReader instance. */ public XMLParser(Handler handler) throws SAXException { - reader = XMLReaderFactory.createXMLReader(); - rdfHandler = new RDFHandler(handler); - reader.setContentHandler(rdfHandler); - } - - /** - * Parse an RDF document from the specified system identifier (URI). - * - * @param systemId the URI of the RDF document. - * @return the graph generated by the parsing process. - * @throws SAXException if an error occurs in parsing. - * @throws IOException if an error occurs in the underlying input. - */ - public Graph parse(String systemId) - throws IOException, SAXException - { - return parse(new InputSource(systemId)); - } - - /** - * Parse an RDF document from the specified input source. - * - * @param source the source of the RDF document. - * @return the graph generated by the parsing process. - * @throws SAXException if an error occurs in parsing. - * @throws IOException if an error occurs in the underlying input. - */ - public Graph parse(InputSource source) - throws IOException, SAXException - { - graph = new Graph(); - rdfHandler.setBaseURI(source.getSystemId()); - reader.parse(source); - return graph; + super(handler, new RDFHandler(handler)); } /** - * Parse an RDF document from the specified file. + * Retrieves the RDF handler used by the parser. * - * @param file the file containing the RDF document. - * @return the graph generated by the parsing process. - * @throws SAXException if an error occurs in parsing. - * @throws IOException if an error occurs in the underlying input. + * @return the XML event handler. */ - public Graph parse(File file) - throws IOException, SAXException + public RDFHandler getRDFHandler() { - return parse(new InputSource(new FileInputStream(file))); + return (RDFHandler) getHandler(); } /** @@ -161,312 +84,10 @@ public class XMLParser handler.setLevel(Level.FINE); XMLParser parser = new XMLParser(handler); for (int a = 0; a < args.length; ++a) - System.out.println(parser.parse(new File(args[a]))); - } - - /** - * Handles capturing the XML events and turning them into an RDF - * Graph. - * - * @author Andrew John Hughes (address@hidden) - */ - private class RDFHandler - extends XmlBaseHandler - { - - /** - * A Logger instance to log events generated by the - * parsing process. - */ - private Logger rdfLogger; - - /** - * Flag to indicate whether we are inside an RDF document - * or not. There is not a one-to-one correspondence between - * an RDF document and the XML document. RDF is to usually - * to be expected inside an RDF element. However, a single - * Description element may occur on its own, outside - * this context. In either of these cases, this flag should - * be set. - */ - private boolean inRDF; - - /** - * Flag to indicate whether we are inside a subject node or - * not. - */ - private boolean inSubject; - - /** - * Flag to indicate whether we are inside a predicate node or - * not. - */ - private boolean inPredicate; - - /** - * The current triple. - */ - private Triple triple; - - /** - * The current subject in the current RDF triple. - */ - private Subject subject; - - /** - * The current predicate in the current RDF triple. - */ - private Predicate predicate; - - /** - * The current object in the current RDF triple. - */ - private RDFObject object; - - /** - * The String form of the URI of the current predicate. - */ - private String predicateURI; - - /** - * The type of the current literal. - */ - private Type type; - - /** - * The set of ids used in the RDF document. RDF IDs must be unique - * within a particular base URI. - */ - private Set> ids; - - /** - * Constructs a new RDFHandler, using the specified - * handler for log messages. - * - * @param handler the handler to use for log messages. - */ - public RDFHandler(Handler handler) - { - super(handler); - rdfLogger = Logger.getLogger("nongnu.cashews.rdf.XMLParser"); - rdfLogger.addHandler(handler); - rdfLogger.setLevel(handler.getLevel()); - } - - /** - * Captures the start of the document and sets up the initial - * state. - */ - public void startDocument() - { - super.startDocument(); - inSubject = false; - inRDF = false; - inPredicate = false; - predicateURI = null; - type = null; - subject = null; - predicate = null; - object = null; - ids = new HashSet>(); - } - - /** - * Captures the start of an XML element. - * - * @param uri the namespace URI. - * @param localName the local name of the element inside the namespace. - * @param qName the local name qualified with the namespace URI. This - * may or may not be provided, as we don't ask for namespace - * prefixes. - * @param attributes the attributes of this element. - * @throws SAXException if some error occurs in parsing. - */ - public void startElement(String uri, String localName, - String qName, Attributes attributes) - throws SAXException - { - super.startElement(uri, localName, qName, attributes); - if (uri.equals(RDF_NAMESPACE)) - { - if (localName.equals("RDF")) - { - /* rdf:RDF */ - inRDF = true; - rdfLogger.finer("Start of RDF block"); - } - else if (localName.equals("Description")) - { - /* rdf:Description */ - rdfLogger.finer("Start of RDF description block"); - inRDF = true; - if (!inSubject) - { - /* Check for RDF URI subject */ - String value = attributes.getValue(RDF_NAMESPACE, "about"); - if (value != null) - subject = parseRDFURI(value); - else - { - value = attributes.getValue(RDF_NAMESPACE, "ID"); - if (value != null) - { - boolean added = - ids.add(new Pair(getBaseURI(), value)); - if (added) - subject = new - RDFURI(getBaseURI().resolve("#" + value)); - } - else - { - /* Check for blank node subject */ - value = attributes.getValue(RDF_NAMESPACE, "nodeID"); - if (value != null) - subject = new Blank(value); - } - } - if (subject == null) - rdfLogger.severe("No subject found in RDF " + - "description."); - else - { - inSubject = true; - rdfLogger.fine("Created subject: " + subject); - } - } - else - rdfLogger.warning("Invalid use of RDF namespace: " + uri + - localName); - } - } - else - { - if (inRDF) - { - if (inSubject) - { - /* Predicate element */ - predicateURI = uri + localName; - rdfLogger.finer("Start of predicate: " + predicateURI); - predicate = parseRDFURI(predicateURI); - rdfLogger.fine("Created predicate: " + predicate); - inSubject = false; - inPredicate = true; - /* Check for RDF URI object */ - String value = attributes.getValue(RDF_NAMESPACE, - "resource"); - if (value != null) - { - object = parseRDFURI(value); - rdfLogger.fine("Created object: " + object); - } - else - { - /* Check for blank node object */ - value = attributes.getValue(RDF_NAMESPACE, "nodeID"); - if (value != null) - { - object = new Blank(value); - rdfLogger.fine("Created object: " + object); - } - } - /* Check for a type */ - value = attributes.getValue(RDF_NAMESPACE, "datatype"); - if (value != null) - type = TypeFactory.getInstance(value); - } - } - } - } - - /** - * Attempts to returns the RDF URI parsed from the specified - * String. - * - * @param value the value to parse. - * @return an RDF URI. - * @throws SAXException if the URI can't be parsed. - */ - private RDFURI parseRDFURI(String value) - throws SAXException - { - try - { - return new RDFURI(new URI(value)); - } - catch (URISyntaxException e) - { - throw new SAXException("Failed to parse URI: " + e, e); - } - } - - /** - * Captures characters within an XML element. - * - * @param ch the array of characters. - * @param start the start index of the characters to use. - * @param length the number of characters to use from the start index on. - * @throws SAXException if some error occurs in parsing. - */ - public void characters(char[] ch, int start, int length) - throws SAXException - { - super.characters(ch, start, length); - String value = new String(ch, start, length).trim(); - if (value.length() == 0) - return; - rdfLogger.finer("Characters: " + value); - if (inPredicate) - { - if (type == null) - object = new Literal(value); - else - object = new Literal(value, type); - rdfLogger.fine("Created object: " + object); - } - } - - /** - * Captures the end of an XML element. - * - * @param uri the namespace URI. - * @param localName the local name of the element inside the namespace. - * @param qName the local name qualified with the namespace URI. This - * may or may not be provided, as we don't ask for namespace - * prefixes. - * @throws SAXException if some error occurs in parsing. - */ - public void endElement(String uri, String localName, - String qName) - throws SAXException - { - super.endElement(uri, localName, qName); - if (uri.equals(RDF_NAMESPACE)) - { - if (localName.equals("RDF")) - { - inRDF = false; - rdfLogger.finer("End of RDF block"); - } - else if (localName.equals("Description")) - { - rdfLogger.finer("End of description block"); - inSubject = false; - } - } - else if (inPredicate && predicateURI.equals(uri + localName)) { - inPredicate = false; - inSubject = true; - predicateURI = null; - type = null; - triple = new Triple(subject, predicate, object); - rdfLogger.fine("Created triple: " + triple); - graph.addTriple(triple); - rdfLogger.finer("End of predicate block"); + parser.parse(new File(args[a])); + System.out.println(parser.getRDFHandler().getGraph()); } - } - } } Index: src/nongnu/cashews/xml/Parser.java =================================================================== RCS file: src/nongnu/cashews/xml/Parser.java diff -N src/nongnu/cashews/xml/Parser.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/xml/Parser.java 17 Apr 2005 18:25:18 -0000 @@ -0,0 +1,162 @@ +/* Parser.java -- Basic parser for XML files. + 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.xml; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; +import java.util.logging.Level; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/** + * The parser handles the parsing of XML data from a variety of sources. + * It is designed with extension points, so that more complex handlers + * can be plugged in as necessary. + * + * @author Andrew John Hughes (address@hidden) + */ +public class Parser +{ + + /** + * The reader, which interprets the XML file. + * + * @serial the XML reader. + */ + private XMLReader reader; + + /** + * The handler for the XML. + * + * @serial the XML handler. + */ + private XmlBaseHandler xmlHandler; + + /** + * Constructs a new XML-based parser, using the specified handler + * for messages. + * + * @param logHandler the handler to use for log messages. + * @throws SAXException if the parser fails to obtain an + * XMLReader instance. + */ + public Parser(Handler logHandler) + throws SAXException + { + this(logHandler, new XmlBaseHandler(logHandler)); + } + + /** + * Constructs a new XML-based parser, using the specified handlers + * for messages and XML parsing events. + * + * @param logHandler the handler to use for log messages. + * @param xmlHandler the handler to use for XML parsing events. + * @throws SAXException if the parser fails to obtain an + * XMLReader instance. + */ + public Parser(Handler handler, XmlBaseHandler xmlHandler) + throws SAXException + { + reader = org.xml.sax.helpers.XMLReaderFactory.createXMLReader(); + reader.setContentHandler(xmlHandler); + this.xmlHandler = xmlHandler; + } + + /** + * Parse an XML document from the specified system identifier (URI). + * + * @param systemId the URI of the XML document. + * @throws SAXException if an error occurs in parsing. + * @throws IOException if an error occurs in the underlying input. + */ + public void parse(String systemId) + throws IOException, SAXException + { + parse(new InputSource(systemId)); + } + + /** + * Parse an XML document from the specified input source. + * + * @param source the source of the XML document. + * @throws SAXException if an error occurs in parsing. + * @throws IOException if an error occurs in the underlying input. + */ + public void parse(InputSource source) + throws IOException, SAXException + { + xmlHandler.setBaseURI(source.getSystemId()); + reader.parse(source); + } + + /** + * Parse an XML document from the specified file. + * + * @param file the file containing the XML document. + * @throws SAXException if an error occurs in parsing. + * @throws IOException if an error occurs in the underlying input. + */ + public void parse(File file) + throws IOException, SAXException + { + parse(new InputSource(new FileInputStream(file))); + } + + /** + * Retrieves the XML handler used by the parser. + * + * @return the XML event handler. + */ + public XmlBaseHandler getHandler() + { + return xmlHandler; + } + + /** + * A simple test harness to parse the XML files supplied on the command + * line. + * + * @param args the command line arguments. + * @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 + { + Handler handler = new ConsoleHandler(); + handler.setLevel(Level.FINE); + Parser parser = new Parser(handler); + for (int a = 0; a < args.length; ++a) + parser.parse(new File(args[a])); + } + +}