All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.semanticweb.yars.rdfxml.RdfXmlParserBase Maven / Gradle / Ivy

package org.semanticweb.yars.rdfxml;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;
import java.util.TreeSet;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import org.semanticweb.yars.nx.BNode;
import org.semanticweb.yars.nx.Literal;
import org.semanticweb.yars.nx.Node;
import org.semanticweb.yars.nx.Nodes;
import org.semanticweb.yars.nx.Resource;
import org.semanticweb.yars.nx.namespace.RDF;
import org.semanticweb.yars.nx.parser.Callback;
import org.semanticweb.yars.nx.parser.ParseException;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * RDF/XML parser base using SAX parsing events
 * @author Aidan Hogan
 *
 */
public class RdfXmlParserBase extends DefaultHandler {
	//state = 0, awaiting opening rdf:RDF
	//state = 1, awaiting open resource element
	//state = 2, awaiting close resource element or open property element
	//state = 3, awaiting text, close property element or open resource element
	//state = 4, awaiting close property element
	//state = 5, awaiting text or close property element
	//state = 6, parsetype collection, awaiting open resource element or close property element
	//state = 7, parsetype literal, awaiting valid XML
	//state = 8, parsetype resource, awaiting open property or close property

	private static Logger _log = Logger.getLogger(RdfXmlParserBase.class.getName());

	private static enum State implements Comparable {
		START, OR, CR_OP, T_CP_OR, CP, T_CP, PTC_OR_CP, PTL_XML, PTR_OP_CP, PTA;

//		public boolean expectCloseProperty(){
//			if(this.equals(T_CP_OR) || 
//					this.equals(CP) || this.equals(T_CP) ||
//					this.equals(PTC_OR_CP) || this.equals(PTL_XML)){
//				return true;
//			}
//			return false;
//		}
//
//		public boolean expectCloseResource(){
//			if(this.equals(CR_OP) || this.equals(PTL_XML)){
//				return true;	
//			}
//			return false;
//		}

		public boolean expectText(){
			if(this.equals(T_CP_OR) || this.equals(T_CP) || this.equals(PTL_XML)){
				return true;
			}
			return false;
		}

		public boolean expectOpenResource(){
			if(this.equals(START) || this.equals(OR)
					|| this.equals(T_CP_OR)
					|| this.equals(PTC_OR_CP)
					|| this.equals(PTL_XML)){
				return true;
			}
			return false;
		}

		public boolean expectOpenProperty(){
			if(this.equals(CR_OP) || this.equals(PTR_OP_CP)
					|| this.equals(PTL_XML) ){
				return true;
			}
			return false;
		}

		public boolean equals(State s){
			if(s==null)
				return false;
			else if(s.ordinal()!=ordinal())
				return false;
			return true;
		}
	}

	private boolean _skolemise = false;
	private boolean _strict = false;
	private String _escapedDocURI = null;

	public static final String BNODE_PREFIX = "bnode";
	private static final String XML_BASE = "xml:base";
	private static final String XML_LANG = "xml:lang";
	private static final String XML_SPACE = "xml:space";
	private static final String XML_ID = "xml:id";
	private static final String XML_PREFIX = "xml:";
	private static final String NULL = "";

	private ArrayList _fifoS;

	private ScopedThing _sbq;
//	private ScopedThing _sptr;
	private ScopedThing _slang;


	private TreeSet _sptr;
//	private ScopedThing _sptl = null;

	private Resource _sptlp = null;
	private int _sptldepth = 0;

	private HashMap _li;
	private HashMap _coll;

	private HashMap> _ids;

	private URI _currentBase;
	private int _currentLi = 0;
	private Node _currentColl = null;

	private Node _currentReify = null;

//	private ArrayList _fifoP = new ArrayList();
//	private ArrayList _fifoT = new ArrayList();
	private int _depth = 0;

	private int _bnode = 0;
	private String _currentLang = null;
	private Resource _datatype = null;

	//store prefix mappings for stuff inside an XMLLiteral definition
	private HashMap _xmllPrefixes = null;
	private StringBuffer _prefixDefinition = null;

	private Resource _con = null;

	//state = 0, awaiting opening rdf:RDF
	//state = 1, awaiting open resource element
	//state = 2, awaiting close resource element or open property element
	//state = 3, awaiting text, close property element or open resource element
	//state = 4, awaiting close property element
	//state = 5, awaiting text or close property element
	//state = 6, parsetype collection, awaiting open resource element or close property element
	//state = 7, parsetype literal, awaiting valid XML
	//state = 8, parsetype resource, awaiting open property
	private State _state = State.START;


	//used for resources encoded within empty property nodes
	private ResourceDescription _currentPRD = null;

	private Node _currentS = null;
	private Resource _currentP = null;
	private Locator _loc = null;

	private StringBuffer _currentL = null;

	private Callback _c;

	//elements from RDF (syntax) namespace disallowed as use in nodes in RDF/XML
	private static final Node[] NOT_ALLOWED_NODE =  {RDF.ABOUT, RDF.DATATYPE, RDF.ID, RDF.NODEID, RDF.PARSETYPE, RDF.RESOURCE};
	private final static HashSet NOT_ALLOWED_NODE_TS = new HashSet();
	{
		for(Node n:NOT_ALLOWED_NODE){
			NOT_ALLOWED_NODE_TS.add(n);
		}
	}

	//RDF syntax names and their allowed positions
	private static final String[] RDF_SUBJ_NODE_NAMES =  {"Description", "Bag", "Seq", "Alt", "List", "Statement", "Property"};
	private static final String[] RDF_PROP_NODE_NAMES =  {"type", "subject", "predicate", "object", "first", "rest", "value", "li"};
	private static final String[] RDF_SUBJ_ATTR_NAMES =  {"about", "ID", "nodeID", "type"};
	private static final String[] RDF_PROP_ATTR_NAMES =  {"ID", "nodeID", "datatype", "parseType", "resource"};
	private final static HashSet RDF_SUBJ_NODE_NAMES_TS = new HashSet();
	private final static HashSet RDF_PROP_NODE_NAMES_TS = new HashSet();
	private final static HashSet RDF_SUBJ_ATTR_NAMES_TS = new HashSet();
	private final static HashSet RDF_PROP_ATTR_NAMES_TS = new HashSet();
	{
		for(String s:RDF_SUBJ_NODE_NAMES){
			RDF_SUBJ_NODE_NAMES_TS.add(s);
		}
		for(String s:RDF_PROP_NODE_NAMES){
			RDF_PROP_NODE_NAMES_TS.add(s);
		}
		for(String s:RDF_SUBJ_ATTR_NAMES){
			RDF_SUBJ_ATTR_NAMES_TS.add(s);
		}
		for(String s:RDF_PROP_ATTR_NAMES){
			RDF_PROP_ATTR_NAMES_TS.add(s);
		}
	}

//	public static void main (String argv [])
//	{
//	SAXParserFactory factory = SAXParserFactory.newInstance();
//	factory.setNamespaceAware(true);
//	try {

////	OutputStreamWriter out = new OutputStreamWriter (System.out, "UTF8");
//	SAXParser saxParser = factory.newSAXParser();

//	System.out.println(saxParser.isNamespaceAware()+" "+saxParser.isValidating());
//	saxParser.parse( new File("test/rdfxml/foafsmall.txt"), new RdfXmlParserBase("http://sw.deri.org/~aidanh/_foaf/@-foaf+.rdf", new true) );

//	} catch (Throwable err) {
//	err.printStackTrace ();
//	}
//	}

	public RdfXmlParserBase(String docURI, Callback c) throws SAXException{
		this(docURI, c, true, null);
	}

	public RdfXmlParserBase(String docURI, Callback c, boolean skolemise) throws SAXException{
		this(docURI, c, skolemise, null);
	}

	public RdfXmlParserBase(String docURI, Callback c, boolean skolemise, boolean strict) throws SAXException{
		this(docURI, c, skolemise, strict, null);
	}

	public RdfXmlParserBase(String docURI, Callback c, boolean skolemise, Resource con) throws SAXException{
		this(docURI, c, skolemise, false, con);
	}

	public RdfXmlParserBase(String docURI, Callback c, boolean skolemise, boolean strict, Resource con) throws SAXException{
		_fifoS = new ArrayList();
		initialiseBaseURI(docURI);
		setDocumentURI(docURI);
		_sbq = new ScopedThing(_currentBase);
		//_sptr = new ScopedThing(false);
		_sptr = new TreeSet();
		_slang = new ScopedThing(NULL);
		_li = new HashMap();
		_coll = new HashMap();
		_ids = new HashMap>();
		_skolemise = skolemise;
		_c = c;
		_con = con;
		_strict = strict;
	}

	private void setDocumentURI(String docURI){
		_escapedDocURI = BNode.escapeForBNode(docURI);
	}

	public void startDocument () throws SAXException{
		_c.startDocument();
	}

	public void endDocument () throws SAXException{
		_c.endDocument();
	}

	public void startElement (String name, String lname, String qname, Attributes attrs) throws SAXException{
		final Resource uri;
		if(name==null || name.equals("") && !_state.equals(State.PTL_XML)){
			if(lname.equals("RDF")&&_state.equals(State.START)){
				warning("Unqualified use of 'rdf:RDF' is deprecated.");
				uri = RDF.RDF;
			}else if(RDF_SUBJ_NODE_NAMES_TS.contains(lname) && _state.expectOpenResource()){
				warning("Unqualified use of RDF name '"+lname+"' is deprecated.");
				uri = createResource(RDF.NS+lname);
			}else if(RDF_PROP_NODE_NAMES_TS.contains(lname) && _state.expectOpenProperty()){
				warning("Unqualified use of RDF name '"+lname+"' is deprecated.");
				uri = createResource(RDF.NS+lname);
			}else{
				error("Unqualified attribute name '"+lname+"' found.");
				uri = createResource(resolveFullURI(lname, false));
			}
		}else{
			uri = createResource(name+lname);
		}

		nodeIsAllowed(qname, uri);

		if(_state.equals(State.START)){ //expecting open rdf:RDF or top level standalone element
//			for(int i=0; i");
	}

	private void checkAndHandleBaseURI(final Attributes attrs) throws SAXException{
		int b = attrs.getIndex(XML_BASE);
		if(b==-1){
			return;
		} else{
			initialiseBaseURI(attrs.getValue(b));
			_sbq.addNewScopedElement(_currentBase);
		}
	}

	private void checkAndHandleLang(final Attributes attrs) throws SAXException{
		int b = attrs.getIndex(XML_LANG);
		if(b==-1){
			return;
		} else{
			initialiseLang(attrs.getValue(b));
			if(_currentLang==null) _slang.addNewScopedElement(NULL);
			else _slang.addNewScopedElement(_currentLang);
		}
	}

	private void initialiseLang(final String lang) throws SAXException{
		//should probably check string here to see whether it is a valid language string
		if(lang.isEmpty())
			_currentLang = null;
		else _currentLang = lang.toLowerCase(Locale.ENGLISH);
	}

	private void initialiseBaseURI(String base) throws SAXException{
		if(base.contains(" ")){
			warning("Base uri '"+base+"' contains a space.");
			base = base.replaceAll(" ", "+");
		}

		try {
			_currentBase = new URI(base);
		} catch (URISyntaxException e) {
			fatalError(new SAXException(e));
		}
		if(!_currentBase.isAbsolute()){
			fatalError(new SAXException(new RDFXMLParseException("Cannot have relative xml:base value: '"+base+"'.")));
		}
	}

	private void initialiseCurrentResource(final Resource rq, final Attributes attrs) throws SAXException{
		_currentLi=0;
		_currentS = null;
		ResourceDescription temp = new ResourceDescription();

		if(!rq.equals(RDF.DESCRIPTION)){
			temp.addEdge(RDF.TYPE, rq);
		}

		checkAndHandleBaseURI(attrs);
		checkAndHandleLang(attrs);
		for(int i=0; i urisForId = _ids.get(id);
		if(urisForId==null){
			urisForId = new HashSet();
			_ids.put(id, urisForId);
		}
		return !urisForId.add(uri);
	}

	private  String removeFragment(URI u)throws SAXException{
		// remove fragment
		try {
			
			return new URI(u.getScheme().toLowerCase(),
					u.getUserInfo(), u.getHost().toLowerCase(), u.getPort(),
					u.getPath(), u.getQuery(), null).toString();
		} catch (URISyntaxException e) {
			error("URISyntaxException removing fragment from base:"+u);
			return u.toString();
		}
	}
	
	private Literal createLiteral(final String s){
		Literal l;
		if(_datatype!=null){
			l = new Literal(s, _datatype);
			_datatype = null;
		} else if(_currentLang!=null){
			l = new Literal(s, _currentLang);
		}  else{
			l = new Literal(s);
		}
		return l;
	}

	private void initialiseCurrentProperty(final Resource uri, final Attributes attrs) throws SAXException{
		_currentP = uri;

		if(_currentP.equals(RDF.LI)){
			_currentLi++;
			_li.put(_depth, _currentLi);
			_currentP = createResource(RDF.NS+"_"+_currentLi);
		}

		_depth++;
		checkAndHandleBaseURI(attrs);
		checkAndHandleLang(attrs);
		for(int i=0; i();
				_currentL = new StringBuffer();
			} else if(o.equals("Resource")){
				if(_state.equals(State.CP)){
					fatalError("Cannot have both rdf:resource and rdf:parseType='Resource' attached as attributes to a property.");
				} else if(_state.equals(State.T_CP)){
					fatalError("Cannot have both rdf:datatype and rdf:parseType='Resource' attached as attributes to a property.");
				} else if(_state.equals(State.PTC_OR_CP)){
					fatalError("Cannot have both rdf:parseType='Collection' and rdf:parseType='Resource' attached as attributes to a property.");
				} else if(_state.equals(State.PTL_XML)){
					fatalError("Cannot have both rdf:parseType='Literal' and rdf:parseType='Resource' attached as attributes to a property.");
				}
				_currentL = null;
				_sptr.add(_depth);
				_state=State.PTR_OP_CP; //will be incremented outside of call to 8 :(
			}
		} else if(p.equals(RDF.ID)){
			_currentReify = createResource(resolveFullURI(o, true));  
		} else{
			if(_state.equals(State.T_CP)){
				fatalError("Cannot have both rdf:datatype and "+qname+" attached as attributes to a property.");
			} else if(_state.equals(State.PTC_OR_CP)){
				fatalError("Cannot have both rdf:parseType='Collection' and "+qname+" attached as attributes to a property.");
			} else if(_state.equals(State.PTL_XML)){
				fatalError("Cannot have both rdf:parseType='Literal' and "+qname+" attached as attributes to a property.");
			} else if(_state.equals(State.PTR_OP_CP)){
				fatalError("Cannot have both rdf:parseType='Resource' and "+qname+" attached as attributes to a property.");
			}

			if(_currentPRD==null){
				_currentPRD = new ResourceDescription();
			}
			_currentPRD.addEdge(p, createLiteral(o));
			_state = State.CP;
		}
	}

	public void endElement (String name, String lname, String qname) throws SAXException{
		Resource rq = createResource(name+lname);

		URI base = _sbq.decrementScope();
		if(base!=null){
			_currentBase = base;
		}

		boolean ptr = _sptr.remove(_depth);
		boolean endptl = _sptldepth==0 && _sptlp!=null && (_sptlp.equals(rq) || (isCMP(_sptlp) && isCMP(rq)));

		if(rq.equals(RDF.RDF)){
			//error handled by SAX, not valid XML;
		} else if(_state.equals(State.OR)){
			//error handled by SAX, not valid XML;
		} else if(_state.equals(State.CR_OP)){ //closing resource or closing parseType="Resource" property
			_fifoS.remove(_fifoS.size()-1);
			_li.remove(_depth);

			if(ptr){ //closing parseType="Resource" property
				//close 'virtual' resource
				_currentS = _fifoS.get(_fifoS.size()-1);
				Integer li = _li.get(_depth-1);
				if(li!=null)
					_currentLi = li;

				//then close property, leave in state 2
				_depth--;
			}
			else{
				if(_depth>0){ //not top level resource (not including rdf:RDF)
					_currentS = _fifoS.get(_fifoS.size()-1);
					Integer li = _li.get(_depth-1);
					if(li!=null)
						_currentLi = li;
					_state=State.CP;

					Node cc = _coll.get(_depth);
					if(cc!=null){
						_currentColl = cc;
						_state=State.PTC_OR_CP;
					}
				} else{ //close top level resource (not including rdf:RDF) -- end of document
					_state=State.START;
				}
			}
		} else if(_state.equals(State.T_CP_OR) || _state.equals(State.T_CP)){ //closing empty property or property after some text
			String s = "";
			if(_currentL!=null)
				s = _currentL.toString();

			Literal l = createLiteral(s);
			handleStatement(_currentS, _currentP, l);
			_currentL=null;

			_depth--;
			_state=State.CR_OP;
		} else if(_state.equals(State.CP)){ //closing property after closing resource
			_depth--;
			_state=State.CR_OP;
		} else if(_state.equals(State.PTC_OR_CP)){ //closing parseType="Collection" property
			_coll.remove(_depth);
			if(_currentColl!=null){
				handleStatement(_currentColl, RDF.REST, RDF.NIL);
				_currentColl=null;
			}else{
				handleStatement(_currentS, _currentP, RDF.NIL);
			}

			_depth--;
			_state=State.CR_OP;
		} else if(_state.equals(State.PTL_XML)){ //closing parseType="Literal" property
			if(endptl){
				String s = "";

				_state=State.CR_OP;
				if(_currentL!=null)
					s = _currentL.toString();

				_datatype = RDF.XMLLITERAL;
				Literal l = createLiteral(s);
				handleStatement(_currentS, _currentP, l);
				_currentL=null;
				_sptldepth = 0;
				_sptlp = null;
				_depth--;
			}else{
				if(rq.equals(_sptlp)){
					_sptldepth--;
				}
				handleParseTypeLiteralEndElement(name, lname, qname);
			}

		} else if(_state.equals(State.PTR_OP_CP)){ //closing empty parseType resource property
			handleStatement(_currentS, _currentP, generateBNode());
			_depth--;
			_state=State.CR_OP;
		}

		String lang = _slang.decrementScope();
		if(lang!=null){
			if(lang.equals(""))
				_currentLang = null;
			else
				_currentLang = lang.toLowerCase();
		}
	}

	private static boolean isCMP(Resource p1) {
		return p1.equals(RDF.LI) || p1.toString().startsWith("<" + RDF.NS + "_");
	}

	private void handleParseTypeLiteralEndElement(final String name, final String lname, final String qname){
		_currentL.append("");
	}

	private BNode generateBNode(){
		_bnode++;
		if(_skolemise){
			return new BNode(_escapedDocURI+"xx"+BNODE_PREFIX+(_bnode-1));
		} else{
			return new BNode(BNODE_PREFIX+(_bnode-1));
		}
	}

	private BNode generateBNode(String nodeID) throws SAXException{
		int oldLength = nodeID.length();
		nodeID = nodeID.trim();

		if(oldLength!=nodeID.length())
			warning("Leading or trailing whitespace in rdf:nodeID "+nodeID+".");

		if (!Pattern.matches(XmlRegex.NC_NAME, nodeID))
			warning("nodeID value '"+nodeID+"' is not a valid XML NCName.");

		nodeID = BNode.escapeForBNode(nodeID);
		if(_skolemise){
			return new BNode(_escapedDocURI+"xx"+nodeID);
		} else{
			return new BNode(nodeID);
		}
	}

	/**Create and handle warning exception
	 * @throws SAXException 
	 */
	private void warning(final String msg) throws SAXException{
		SAXException e = new SAXException(new RDFXMLParseException("WARNING: "+msg+" "+getLocation()));

		warning(e);
	}

	/**Create and handle error exception
	 * @throws SAXException 
	 */
	private void error(final String msg) throws SAXException{
		SAXException e = new SAXException(new RDFXMLParseException("ERROR: "+msg+" "+getLocation()));

		error(e);
	}

	/**Create and handle fatal error exception
	 * @throws SAXException 
	 * @throws
	 */
	private void fatalError(final String msg) throws SAXException{
		SAXException e = new SAXException(new RDFXMLParseException("FATAL ERROR: "+msg+" "+getLocation()));

		fatalError(e);
	}

	/**Warning
	 * @throws SAXException
	 */
	public void warning(SAXException e) throws SAXException{
		_log.warning(e.getMessage());
		if(_strict)
			throw e;
	}

	/**
	 * Recoverable error
	 * @throws SAXException
	 */
	public void error(SAXException e) throws SAXException{
		_log.warning(e.getMessage());
		if(_strict)
			throw e;
	}

	/**
	 * Unrecoverable error
	 * @throws SAXException
	 */
	public void fatalError(SAXException e) throws SAXException{
		_log.severe(e.getMessage());
		throw e;
	}

	public void ignorableWhitespace(char[] buf, int offset, int len) throws SAXException{
		char[] cs = new char[len];
		System.arraycopy(buf, offset, cs, 0, len);
		String s = new String(cs);

		if(_state.expectText()){
			if(_currentL==null){
				_currentL = new StringBuffer();
			}

			_currentL.append(s);
		}
	}

	private boolean nodeIsAllowed(final String qname, final Resource r) throws SAXException {
		if(NOT_ALLOWED_NODE_TS.contains(r)){
			error("Attribute '"+qname+"' not allowed to be used as a node element.");
			return false;
		}
		return true;
	}

	public void characters (char buf [], int offset, int len) throws SAXException{
		char[] cs = new char[len];
		System.arraycopy(buf, offset, cs, 0, len);
		String v = new String(cs);
		boolean ws = v.trim().equals("");
		if(ws){
			ignorableWhitespace(buf, offset, len);
			return;
		}

		if(_state.expectText()){
			if(_currentL==null){
//				if(_state.equals(State.PTL_XML)){
//				fatalError("Dangling text '"+v+"' found outside of enclosing tags, inside parseType=\"Literal\" tags.");
//				}
				_currentL = new StringBuffer();
			}

			for(int i=offset; i<(len+offset); i++){
				char c = buf[i];

				if(_state.equals(State.PTL_XML)){
					if (c == '"')
						_currentL.append(""");
					else if (c == '&')
						_currentL.append("&");
					else if (c == '<')
						_currentL.append("<");
					else if (c == '>')
						_currentL.append(">");
					else {
						int ci = 0xffff & c;
						if (ci < 160 )
							// nothing special only 7 Bit
							_currentL.append(c);
						else {
							// Not 7 Bit use the unicode system
							_currentL.append("&#");
							_currentL.append(new Integer(ci).toString());
							_currentL.append(';');
						}
					}
				}
				else _currentL.append(c);
			}

			if(_state.equals(State.T_CP_OR))
				_state=State.T_CP;
		} else{
			fatalError("Dangling text '"+v+"' found outside of enclosing property tags.");
		}
	}
	
	public void skippedEntity(String name) throws SAXException{
		;
	}
	
	public InputSource resolveEntity(String publicId,
            String systemId)
     throws SAXException{
		return null;
	}
	
	public void unparsedEntityDecl(String name,
			String publicId,
            String systemId,
            String notationName)
     throws SAXException{
		;
	}

	public void setDocumentLocator(Locator loc) {
		_loc = loc;
	}

	private String getLocation(){
		if(_loc!=null)
			return "Line "+_loc.getLineNumber()+" column "+_loc.getColumnNumber()+".";
		return "";
	}
	
	public static Resource createResource(String raw){
		return new Resource(raw);
	}
	
	private void handleStatement(final Node... triple){
		processStatement(triple);
		if(_currentReify!=null){
			processStatement(_currentReify, RDF.TYPE, RDF.STATEMENT);
			processStatement(_currentReify, RDF.SUBJECT, triple[0]);
			processStatement(_currentReify, RDF.PREDICATE, triple[1]);
			processStatement(_currentReify, RDF.OBJECT, triple[2]);
			_currentReify = null;
		}
	}

	private void processStatement(final Node... triple){
		if(_con!=null){
			_c.processStatement(new Node[]{triple[0],triple[1],triple[2],_con});
		}
		else _c.processStatement(triple);
	}

	public static class ResourceDescription{
		private Node _id = null;
		private ArrayList _edges;

		public ResourceDescription(){
			_edges = new ArrayList();
		}

		public ResourceDescription(Node id){
			_edges = new ArrayList();
			_id = id;
		}

		public void setIdentifier(Node id){
			_id = id;
		}

		public Node getIdentifier(){
			return _id;
		}

		public void addEdge(Node... po){
			_edges.add(po);
		}

		public ArrayList getEdges(){
			return _edges;
		}

		public String toString(){
			StringBuffer buf = new StringBuffer();
			for(Node[] edge:_edges){
				buf.append(_id.toString()+" "+new Nodes(edge) +"\n");
			}

			return buf.toString();
		}
	}

	public static class RDFXMLParseException extends ParseException{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public RDFXMLParseException(){
			super();
		}

		public RDFXMLParseException(String msg){
			super(msg);
		}
	}

//	public static class NodeIntPair{
//	private Node _n;
//	private int _i;

//	public NodeIntPair(Node n, int i){
//	_n = n;
//	_i = i;
//	}

//	public boolean equals(Object o){
//	if(o instanceof NodeIntPair){
//	return equals((NodeIntPair)o);
//	} return false;
//	}

//	public boolean equals(NodeIntPair nip){
//	if(nip._i==_i){
//	return nip._n.equals(_n);
//	} return false;
//	}

//	public Node getNode() {
//	return _n;
//	}

//	public void setNode(Node n) {
//	_n = n;
//	}

//	public int getInt() {
//	return _i;
//	}

//	public void setInt(int i) {
//	_i = i;
//	}

//	public String toString(){
//	return(_n.toN3()+" "+_i);
//	}

//	public int hashCode(){
//	return _n.hashCode() + _i;
//	}
//	}

	public static class ScopedThing{
		private LinkedList _skip;
		private LinkedList _scoped;
		private int _currentSkip = -1;
		private E _current = null;
		private E _global;

		public ScopedThing(){
			this(null);
		}

		/**
		 * Checks if an element is in-scope. Not used at the moment/not optimised.
		 */
		public boolean inScope(E element){
			if(_current!=null && _current.equals(element)){
				return true;
			} else if(_global!=null && _global.equals(element)){
				return true;
			} else if(_scoped.contains(element)){
				return true;
			}
			return false;
		}

		public ScopedThing(E global){
			_currentSkip = -1;
			_skip = new LinkedList();
			_scoped = new LinkedList();
			_global = global;
		}

		/**
		 * Increments scope of all objects in stack.
		 */
		public void incrementScope(){
			if(_currentSkip!=-1)
				_currentSkip++;
		}

		/**
		 * Decrements scope, removes out of scope objects as applicable and checks if in-scope object has changed.
		 * @return New in-scope object iff the current in-scope object changes, otherwise null.
		 */
		public E decrementScope(){
			if(_currentSkip==-1){
				return null;
			} 
			else{
				_currentSkip--;
				if(_currentSkip==0){
					if(_skip.size()>0){
						_currentSkip = _skip.removeLast();
						_current = _scoped.removeLast();
						return _current;
					} else{
						_currentSkip=-1;
						return _global;
					}
				}
				return null;
			}
		}

		/**
		 * Adds a new scoped element to the stack.
		 */
		public void addNewScopedElement(E element){
			if(_currentSkip!=-1){
				_skip.add(_currentSkip);
				_scoped.add(_current);
			}

			_currentSkip=0;
			_current = element;
		}

		/**
		 * Sets current scoped element.
		 */
		public void setCurrent(E element){
			_current = element;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy