Index: lib/Makefile.am =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/lib/Makefile.am,v retrieving revision 1.3 diff -u -3 -p -u -r1.3 Makefile.am --- lib/Makefile.am 28 Mar 2005 19:29:21 -0000 1.3 +++ lib/Makefile.am 9 Apr 2005 01:13:44 -0000 @@ -52,13 +52,13 @@ JAVAH = $(USER_JAVAH) -jni -classpath .: if INSTALL_GLIBJ_ZIP if FOUND_ECLIPSE -pkgdata_DATA = rdf.jar owls.jar eclipse.jar +pkgdata_DATA = xml.jar rdf.jar owls.jar eclipse.jar install-data-local: genclasses compile-classes eclipse.jar mkdir $(INSTALLDIR) cp eclipse.jar $(INSTALLDIR) cp $(top_srcdir)/resource/plugin.xml $(INSTALLDIR) else -pkgdata_DATA = rdf.jar owls.jar +pkgdata_DATA = xml.jar rdf.jar owls.jar endif endif # INSTALL_GLIBJ_ZIP @@ -79,6 +79,12 @@ endif # INSTALL_CLASS_FILES .PHONY: genclasses +xml.jar: classes compile-classes # resources + if test "$(JAR)" != ""; then rm xml.jar; $(JAR) cf xml.jar `find nongnu -path '*xml\/*' -name '*class'` > /dev/null; fi +if FOUND_GCJ +$(GCJ) -shared -fjni -findirect-dispatch -o xml.jar.so xml.jar +endif + rdf.jar: classes compile-classes # resources if test "$(JAR)" != ""; then rm rdf.jar; $(JAR) cf rdf.jar `find nongnu -path '*rdf*' -name '*class'` > /dev/null; fi if FOUND_GCJ Index: src/nongnu/cashews/commons/Pair.java =================================================================== RCS file: src/nongnu/cashews/commons/Pair.java diff -N src/nongnu/cashews/commons/Pair.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/commons/Pair.java 9 Apr 2005 01:13:44 -0000 @@ -0,0 +1,95 @@ +/* Pair.java -- A heterogenous pair type. + 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; + +/** + * A small helper class to pair up two arbitrary heterogenously-typed + * values. This is where we wish we had a tuple data type. + * + * @author Andrew John Hughes (address@hidden) + */ +public class Pair +{ + + /** + * The left-hand value. + */ + private A left; + + /** + * 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. + */ + public Pair(A left, B right) + { + setLeft(left); + setRight(right); + } + + /** + * Retrieve a reference to the left-hand value. + * + * @return the left-hand value. + */ + public A getLeft() + { + return left; + } + + /** + * Retrieve a reference to the right-hand value. + * + * @return the right-hand value. + */ + public B getRight() + { + return right; + } + + /** + * Set the left-hand value. + * + * @param left the new left-hand value. + */ + public void setLeft(A left) + { + this.left = left; + } + + /** + * Set the right-hand value. + * + * @param right the new right-hand value. + */ + public void setRight(B right) + { + this.right = right; + } + +} Index: src/nongnu/cashews/rdf/XMLParser.java =================================================================== RCS file: /cvsroot/cashew-s-editor/cashews/src/nongnu/cashews/rdf/XMLParser.java,v retrieving revision 1.6 diff -u -3 -p -u -r1.6 XMLParser.java --- src/nongnu/cashews/rdf/XMLParser.java 5 Apr 2005 16:48:53 -0000 1.6 +++ src/nongnu/cashews/rdf/XMLParser.java 9 Apr 2005 01:13:44 -0000 @@ -32,11 +32,12 @@ import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; +import nongnu.cashews.xml.XmlBaseHandler; + 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.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; /** @@ -70,7 +71,14 @@ public class XMLParser * @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 * for messages. @@ -82,8 +90,9 @@ public class XMLParser public XMLParser(Handler handler) throws SAXException { - reader = XMLReaderFactory.createXMLReader(); - reader.setContentHandler(new RDFHandler(handler)); + reader = XMLReaderFactory.createXMLReader(); + rdfHandler = new RDFHandler(handler); + reader.setContentHandler(rdfHandler); } /** @@ -97,9 +106,7 @@ public class XMLParser public Graph parse(String systemId) throws IOException, SAXException { - graph = new Graph(); - reader.parse(systemId); - return graph; + return parse(new InputSource(systemId)); } /** @@ -114,6 +121,7 @@ public class XMLParser throws IOException, SAXException { graph = new Graph(); + rdfHandler.setBaseURI(source.getSystemId()); reader.parse(source); return graph; } @@ -160,14 +168,14 @@ public class XMLParser * @author Andrew John Hughes (address@hidden) */ private class RDFHandler - extends DefaultHandler + extends XmlBaseHandler { /** * A Logger instance to log events generated by the * parsing process. */ - private Logger logger; + private Logger rdfLogger; /** * Flag to indicate whether we are inside an RDF document @@ -230,9 +238,10 @@ public class XMLParser */ public RDFHandler(Handler handler) { - logger = Logger.getLogger("nongnu.cashews.rdf.XMLParser"); - logger.addHandler(handler); - logger.setLevel(handler.getLevel()); + super(handler); + rdfLogger = Logger.getLogger("nongnu.cashews.rdf.XMLParser"); + rdfLogger.addHandler(handler); + rdfLogger.setLevel(handler.getLevel()); } /** @@ -241,6 +250,7 @@ public class XMLParser */ public void startDocument() { + super.startDocument(); inSubject = false; inRDF = false; inPredicate = false; @@ -263,18 +273,19 @@ public class XMLParser 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; - logger.finer("Start of RDF block"); + rdfLogger.finer("Start of RDF block"); } else if (localName.equals("Description")) { /* rdf:Description */ - logger.finer("Start of RDF description block"); + rdfLogger.finer("Start of RDF description block"); inRDF = true; if (!inSubject) { @@ -289,13 +300,14 @@ public class XMLParser if (value != null) subject = new Blank(value); else - logger.warning("No subject found in RDF description."); + rdfLogger.warning("No subject found in RDF " + + "description."); } inSubject = true; - logger.fine("Created subject: " + subject); + rdfLogger.fine("Created subject: " + subject); } else - logger.warning("Invalid use of RDF namespace: " + uri + + rdfLogger.warning("Invalid use of RDF namespace: " + uri + localName); } } @@ -307,9 +319,9 @@ public class XMLParser { /* Predicate element */ predicateURI = uri + localName; - logger.finer("Start of predicate: " + predicateURI); + rdfLogger.finer("Start of predicate: " + predicateURI); predicate = parseRDFURI(predicateURI); - logger.fine("Created predicate: " + predicate); + rdfLogger.fine("Created predicate: " + predicate); inSubject = false; inPredicate = true; /* Check for RDF URI object */ @@ -318,7 +330,7 @@ public class XMLParser if (value != null) { object = parseRDFURI(value); - logger.fine("Created object: " + object); + rdfLogger.fine("Created object: " + object); } else { @@ -327,7 +339,7 @@ public class XMLParser if (value != null) { object = new Blank(value); - logger.fine("Created object: " + object); + rdfLogger.fine("Created object: " + object); } } /* Check for a type */ @@ -371,17 +383,18 @@ public class XMLParser 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; - logger.finer("Characters: " + value); + rdfLogger.finer("Characters: " + value); if (inPredicate) { if (type == null) object = new Literal(value); else object = new Literal(value, type); - logger.fine("Created object: " + object); + rdfLogger.fine("Created object: " + object); } } @@ -399,16 +412,17 @@ public class XMLParser String qName) throws SAXException { + super.endElement(uri, localName, qName); if (uri.equals(RDF_NAMESPACE)) { if (localName.equals("RDF")) { inRDF = false; - logger.finer("End of RDF block"); + rdfLogger.finer("End of RDF block"); } else if (localName.equals("Description")) { - logger.finer("End of description block"); + rdfLogger.finer("End of description block"); inSubject = false; } } @@ -419,9 +433,9 @@ public class XMLParser predicateURI = null; type = null; triple = new Triple(subject, predicate, object); - logger.fine("Created triple: " + triple); + rdfLogger.fine("Created triple: " + triple); graph.addTriple(triple); - logger.finer("End of predicate block"); + rdfLogger.finer("End of predicate block"); } } Index: src/nongnu/cashews/xml/XmlBaseHandler.java =================================================================== RCS file: src/nongnu/cashews/xml/XmlBaseHandler.java diff -N src/nongnu/cashews/xml/XmlBaseHandler.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/nongnu/cashews/xml/XmlBaseHandler.java 9 Apr 2005 01:13:44 -0000 @@ -0,0 +1,262 @@ +/* XMLBaseHandler.java -- Handler for the XML Base standard. + 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.net.URI; +import java.net.URISyntaxException; +import java.util.Stack; +import java.util.logging.Handler; +import java.util.logging.Logger; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * This class deals with the parsing of XML using the + * XML Base standard. + * The current base URI is monitored using a stack, with the default + * URI at the bottom. + * + * @author Andrew John Hughes (address@hidden) + */ +public class XmlBaseHandler + extends DefaultHandler +{ + + /** + * The XML namespace. + */ + public static final String + XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace"; + + /** + * The stack of base URIs. + * + * @serial the base URI stack. + */ + private Stack uris; + + /** + * A Logger instance to log events generated by the + * parsing process. + */ + private Logger xmlBaseLogger; + + /** + * The current hierarchical level. + */ + private long level; + + /** + * The last element at which a base URI was specified. + */ + private String lastElement; + + /** + * The last level at which a base URI was specified. + */ + private long lastLevel; + + /** + * Constructs a new XmlBaseHandler, using the specified + * handler for log messages, and default base URI. + * + * @param handler the handler to use for log messages. + */ + public XmlBaseHandler(Handler handler) + { + xmlBaseLogger = Logger.getLogger("nongnu.cashews.xml.XmlBaseHandler"); + xmlBaseLogger.addHandler(handler); + xmlBaseLogger.setLevel(handler.getLevel()); + uris = new Stack(); + level = -1; + lastLevel = -1; + lastElement = ""; + } + + /** + * Sets the default base URI. This must be done before parsing begins. + * Any existing URIs are discarded. This method should not be used once + * parsing has begun. If this occurs, the behaviour of the parser is + * undefined (and is likely to lead to errors). + * + * @param baseURI the default base URI. + * @throws IllegalArgumentException if the URI is invalid. + */ + public void setBaseURI(String baseURI) + { + if (!uris.empty()) + uris = new Stack(); + try + { + pushURI(baseURI); + } + catch (SAXException e) + { + throw new IllegalArgumentException("The default base URI couldn't " + + "be parsed: " + e, e); + } + } + + /** + * Captures the start of the document and checks that the initial + * state is correct (i.e. we have some default base URI). + * + * @throws IllegalStateException if the default base URI is not set. + */ + public void startDocument() + { + if (uris.empty()) + { + xmlBaseLogger.severe("No default base URI specified."); + throw new IllegalStateException("No default base URI specified."); + } + } + + /** + * 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 + { + xmlBaseLogger.finest("uri: " + uri + ", localName: " + localName); + logAttributes(attributes); + String value = attributes.getValue(XML_NAMESPACE, "base"); + if (value != null) + { + pushURI(value); + lastElement = uri + localName; + lastLevel = level; + } + ++level; + xmlBaseLogger.finest("startElement - level: " + level); + } + + /** + * 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 + { + xmlBaseLogger.finest("uri: " + uri + ", localName: " + localName); + xmlBaseLogger.finest("endElement - level: " + level); + if (lastElement.equals(uri + localName) && lastLevel == level) + popURI(); + --level; + } + + /** + * Push a new base URI on to the stack and notify the logger of this + * event. + * + * @param baseURI the new URI to add. + * @throws SAXException if the URI can't be parsed. + */ + private void pushURI(String baseURI) + throws SAXException + { + URI newURI; + if (baseURI == null) + baseURI = ""; + if (uris.empty()) + { + try + { + newURI = new URI(baseURI); + } + catch (URISyntaxException e) + { + throw new SAXException("Failed to parse URI: " + e, e); + } + } + else + { + URI currentBase = getBaseURI(); + newURI = currentBase.resolve(baseURI); + } + uris.push(newURI); + xmlBaseLogger.fine("New base URI found: " + newURI); + } + + /** + * Remove the most recent base URI from scope. + */ + private void popURI() + { + URI baseURI = uris.pop(); + xmlBaseLogger.fine("Leaving scope of base URI: " + baseURI); + } + + /** + * Retrieve the most recent base URI. + * + * @return the most recent base URI. + */ + protected URI getBaseURI() + { + return uris.peek(); + } + + /** + * Retrieve the current level in the hierarchy. + * + * @return the current hierarchical level. + */ + protected long getHierarchicalLevel() + { + return level; + } + + /** + * Logs a set of XML attributes received by the parser. + * + * @param attributes the attributes to log. + */ + private void logAttributes(Attributes attributes) + { + int length = attributes.getLength(); + for (int a = 0; a < length; ++a) + { + xmlBaseLogger.finest("Attribute " + a + ": " + attributes.getURI(a) + + attributes.getLocalName(a)); + } + } + +}