/// <summary> /// Loads the named Graphs from the TriG input using the given RDF Handler /// </summary> /// <param name="handler">RDF Handler to use</param> /// <param name="input">Input to load from</param> public void Load(IRdfHandler handler, TextReader input) { if (handler == null) { throw new RdfParseException("Cannot parse an RDF Dataset using a null handler"); } if (input == null) { throw new RdfParseException("Cannot parse an RDF Dataset from a null input"); } try { //Create the Parser Context and Invoke the Parser TriGParserContext context = new TriGParserContext(handler, new TriGTokeniser(input, this._syntax), this._queueMode, false, this._tracetokeniser); context.Syntax = this._syntax; this.Parse(context); } catch { throw; } finally { try { input.Close(); } catch { //No catch actions just cleaning up } } }
private void TryParseDirective(TriGParserContext context) { //See what type of directive it is IToken directive = context.Tokens.Dequeue(); if (directive.TokenType == Token.BASEDIRECTIVE) { //Base Directives Invalid in TriG throw ParserHelper.Error("The Base Directive is not a valid in TriG", directive); } else if (directive.TokenType == Token.PREFIXDIRECTIVE) { //Prefix Directive IToken prefix = context.Tokens.Dequeue(); if (prefix.TokenType == Token.PREFIX) { IToken uri = context.Tokens.Dequeue(); if (uri.TokenType == Token.URI) { //Ensure the Uri is absolute try { Uri u = new Uri(uri.Value, UriKind.Absolute); String pre = (prefix.Value.Equals(":")) ? String.Empty : prefix.Value.Substring(0, prefix.Value.Length - 1); context.Namespaces.AddNamespace(pre, u); if (!context.Handler.HandleNamespace(pre, u)) { ParserHelper.Stop(); } //Expect a DOT to Terminate IToken dot = context.Tokens.Dequeue(); if (dot.TokenType != Token.DOT) { throw ParserHelper.Error("Unexpected Token '" + dot.GetType().ToString() + "' encountered, expected a Dot (Line Terminator) Token to terminate a Prefix Directive", dot); } } catch (UriFormatException) { throw ParserHelper.Error("The URI '" + uri.Value + "' given for the prefix '" + prefix.Value + "' is not a valid Absolute URI", uri); } } else { throw ParserHelper.Error("Unexpected Token '" + prefix.GetType().ToString() + "' encountered, expected a URI Token after a Prefix Token", uri); } } else { throw ParserHelper.Error("Unexpected Token '" + prefix.GetType().ToString() + "' encountered, expected a Prefix Token after a Prefix Directive Token", prefix); } } else { throw ParserHelper.Error("Unexpected Token '" + directive.GetType().ToString() + "' encountered, expected a Base/Prefix Directive Token", directive); } }
private void TryParseCollection(TriGParserContext context, Uri graphUri, INode subj) { //Create the Nodes we need IUriNode rdfFirst, rdfRest, rdfNil; rdfFirst = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListFirst)); rdfRest = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListRest)); rdfNil = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListNil)); IToken next; INode item, temp; item = null; do { next = context.Tokens.Dequeue(); //Create a Node for this Token switch (next.TokenType) { case Token.COMMENT: //Discard and continue; continue; case Token.QNAME: case Token.URI: item = ParserHelper.TryResolveUri(context, next); break; case Token.LITERAL: case Token.LONGLITERAL: break; case Token.PLAINLITERAL: Uri plt = TurtleSpecsHelper.InferPlainLiteralType((PlainLiteralToken)next, TurtleSyntax.Original); item = context.Handler.CreateLiteralNode(next.Value, plt); break; case Token.LEFTSQBRACKET: //Check whether an anonymous Blank Node or a Blank Node Collection item = context.Handler.CreateBlankNode(); next = context.Tokens.Peek(); if (next.TokenType == Token.RIGHTSQBRACKET) { //Anonymous Blank Node context.Tokens.Dequeue(); } else { //Blank Node Collection this.TryParsePredicateObjectList(context, graphUri, item); } break; case Token.LEFTBRACKET: //Check whether an Empty Collection next = context.Tokens.Peek(); if (next.TokenType == Token.RIGHTBRACKET) { //Empty Collection context.Tokens.Dequeue(); item = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListNil)); } else { //Collection item = context.Handler.CreateBlankNode(); this.TryParseCollection(context, graphUri, item); } break; case Token.EOF: throw ParserHelper.Error("Unexpected End of File while trying to parse a Collection", next); default: //Unexpected Token throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a URI/QName/Literal/Blank Node as an item in a Collection", next); } //Create the subj rdf:first item Triple if (!context.Handler.HandleTriple((new Triple(subj, rdfFirst, item, graphUri)))) { ParserHelper.Stop(); } //Create the rdf:rest Triple if (context.Tokens.Peek().TokenType == Token.RIGHTBRACKET) { //End of Collection context.Tokens.Dequeue(); if (!context.Handler.HandleTriple(new Triple(subj, rdfRest, rdfNil, graphUri))) { ParserHelper.Stop(); } return; } else { //Continuing Collection temp = context.Handler.CreateBlankNode(); if (!context.Handler.HandleTriple(new Triple(subj, rdfRest, temp, graphUri))) { ParserHelper.Stop(); } subj = temp; } } while (true); }
private void TryParseObjectList(TriGParserContext context, Uri graphUri, INode subj, INode pred) { bool ok = false; do { //After the first run through we'll need to discard commas here if (ok) { context.Tokens.Dequeue(); } //Try to get the Object IToken obj = context.Tokens.Dequeue(); IToken next; INode objNode; switch (obj.TokenType) { case Token.COMMENT: //Discard and Continue ok = false; continue; case Token.QNAME: case Token.URI: objNode = ParserHelper.TryResolveUri(context, obj); break; case Token.LITERAL: case Token.LONGLITERAL: //Literals //See whether we get a Language Specifier/Data Type next next = context.Tokens.Peek(); if (next.TokenType == Token.LANGSPEC) { //Literal with Language Specifier context.Tokens.Dequeue(); objNode = context.Handler.CreateLiteralNode(obj.Value, next.Value); } else if (next.TokenType == Token.HATHAT) { //Literal with DataType context.Tokens.Dequeue(); //Now expect a QName/Uri Token next = context.Tokens.Dequeue(); if (next.TokenType == Token.QNAME || next.TokenType == Token.URI) { Uri dt = UriFactory.Create(Tools.ResolveUriOrQName(next, context.Namespaces, context.BaseUri)); objNode = context.Handler.CreateLiteralNode(obj.Value, dt); } else { throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a URI/QName Token to specify a Data Type after a ^^ Token", next); } } else { //Just a string literal objNode = context.Handler.CreateLiteralNode(obj.Value); } break; case Token.PLAINLITERAL: //Plain Literals Uri plt = TurtleSpecsHelper.InferPlainLiteralType((PlainLiteralToken)obj, TurtleSyntax.Original); objNode = context.Handler.CreateLiteralNode(obj.Value, plt); break; case Token.BLANKNODEWITHID: //Blank Node with ID objNode = context.Handler.CreateBlankNode(obj.Value.Substring(2)); break; case Token.LEFTSQBRACKET: //Blank Node next = context.Tokens.Peek(); if (next.TokenType == Token.RIGHTSQBRACKET) { //Anonymous Blank Node context.Tokens.Dequeue(); objNode = context.Handler.CreateBlankNode(); } else { //Blank Node Collection objNode = context.Handler.CreateBlankNode(); //Do an extra call to TryParsePredicateObjectList to parse the Blank Node Collection this.TryParsePredicateObjectList(context, graphUri, objNode); } break; case Token.RIGHTSQBRACKET: //End of Blank Node Collection if (!ok) { throw ParserHelper.Error("Unexpected Token '" + obj.GetType().ToString() + "' encountered before an Object list of a Blank Node Collection was parsed", obj); } return; case Token.LEFTBRACKET: //Collection //Check whether an Empty Collection next = context.Tokens.Peek(); if (next.TokenType == Token.RIGHTBRACKET) { //Empty Collection context.Tokens.Dequeue(); objNode = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListNil)); } else { //Collection objNode = context.Handler.CreateBlankNode(); this.TryParseCollection(context, graphUri, objNode); } break; case Token.EOF: throw ParserHelper.Error("Unexpected End of File while trying to parse Object List", obj); case Token.DOT: case Token.RIGHTCURLYBRACKET: case Token.SEMICOLON: if (!ok) { throw ParserHelper.Error("Unexpected Token '" + obj.GetType().ToString() + "' encountered before an Object list was parsed", obj); } return; default: //Unexpected Token throw ParserHelper.Error("Unexpected Token '" + obj.GetType().ToString() + "' encountered, expected a URI/QName/Blank Node as the Object of a Triple", obj); } ok = true; if (!context.Handler.HandleTriple(new Triple(subj, pred, objNode, graphUri))) { ParserHelper.Stop(); } } while (context.Tokens.Peek().TokenType == Token.COMMA); //Expect a comma if we are to continue }
private void TryParsePredicateObjectList(TriGParserContext context, Uri graphUri, INode subj) { bool ok = false; do { //After our first run through we'll need to discard semicolons here if (ok) { context.Tokens.Dequeue(); //Watch out for Trailing Semicolons if (context.Tokens.Peek().TokenType == Token.RIGHTSQBRACKET) { //Allow trailing semicolons to terminate Blank Node Collections context.Tokens.Dequeue(); return; } } //Try to get the Predicate IToken pred = context.Tokens.Dequeue(); INode predNode; switch (pred.TokenType) { case Token.COMMENT: //Discard and continue ok = false; continue; case Token.QNAME: case Token.URI: predNode = ParserHelper.TryResolveUri(context, pred); break; case Token.KEYWORDA: //'a' Keyword predNode = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfType)); break; case Token.EOF: throw ParserHelper.Error("Unexpected End of File while trying to parse Predicate Object list", pred); case Token.DOT: case Token.RIGHTCURLYBRACKET: if (!ok) { throw ParserHelper.Error("Unexpected Token '" + pred.GetType().ToString() + "' encountered before a Predicate Object list was parsed", pred); } return; case Token.RIGHTSQBRACKET: if (!ok) { throw ParserHelper.Error("Unexpected Token '" + pred.GetType().ToString() + "' encountered before a Predicate Object list of a Blank Node Collection was parsed", pred); } return; default: //Unexpected Token throw ParserHelper.Error("Unexpected Token '" + pred.GetType().ToString() + "' encountered, expected a URI/QName as the Predicate of a Triple", pred); } ok = true; //Parse the Object List this.TryParseObjectList(context, graphUri, subj, predNode); //Return if we hit the Dot Token/Right Curly Bracket/Right Square Bracket if (context.Tokens.LastTokenType == Token.DOT || context.Tokens.LastTokenType == Token.RIGHTCURLYBRACKET || context.Tokens.LastTokenType == Token.RIGHTSQBRACKET) { return; } //Check for End of Blank Node Collections if (context.Tokens.Peek().TokenType == Token.RIGHTSQBRACKET) { context.Tokens.Dequeue(); return; } } while (context.Tokens.Peek().TokenType == Token.SEMICOLON); //Expect a semicolon if we are to continue }
private void TryParseTriples(TriGParserContext context, Uri graphUri) { do { //Try to get the Subject IToken subj = context.Tokens.Dequeue(); INode subjNode; //Turn the Subject Token into a Node switch (subj.TokenType) { case Token.COMMENT: //Discard and continue continue; case Token.QNAME: case Token.URI: subjNode = ParserHelper.TryResolveUri(context, subj); break; case Token.BLANKNODEWITHID: //Blank Node with ID subjNode = context.Handler.CreateBlankNode(subj.Value.Substring(2)); break; case Token.LEFTSQBRACKET: //Blank Node IToken next = context.Tokens.Peek(); if (next.TokenType == Token.RIGHTSQBRACKET) { //Anonymous Blank Node context.Tokens.Dequeue(); subjNode = context.Handler.CreateBlankNode(); } else { //Blank Node Collection subjNode = context.Handler.CreateBlankNode(); //Do an extra call to TryParsePredicateObjectList to parse the Blank Node Collection this.TryParsePredicateObjectList(context, graphUri, subjNode); } break; case Token.LEFTBRACKET: //Collection //Check whether an Empty Collection next = context.Tokens.Peek(); if (next.TokenType == Token.RIGHTBRACKET) { //Empty Collection context.Tokens.Dequeue(); subjNode = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListNil)); } else { //Collection subjNode = context.Handler.CreateBlankNode(); this.TryParseCollection(context, graphUri, subjNode); } break; case Token.PREFIXDIRECTIVE: case Token.BASEDIRECTIVE: if (context.Syntax == TriGSyntax.Original) { throw ParserHelper.Error("@base/@prefix directives are not permitted to occur inside a Graph in this version of TriG, later versions of TriG support this feature and may be enabled by changing your syntax setting when you create a TriG Parser", subj); } //Parse the directive then continue this.TryParseDirective(context, subj); continue; case Token.EOF: throw ParserHelper.Error("Unexpected End of File while trying to parse Triples", subj); default: //Unexpected Token throw ParserHelper.Error("Unexpected Token '" + subj.GetType().ToString() + "' encountered, expected a URI/QName/Blank Node as the Subject of a Triple", subj); } //Parse the Predicate Object List this.TryParsePredicateObjectList(context, graphUri, subjNode); //Expect a Dot to Terminate if (context.Tokens.LastTokenType != Token.DOT && context.Tokens.LastTokenType != Token.RIGHTCURLYBRACKET) { //We only do this if we haven't returned because we already hit the Dot Token/Right Curly Bracket IToken dot = context.Tokens.Dequeue(); if (dot.TokenType != Token.DOT && dot.TokenType != Token.RIGHTCURLYBRACKET) { throw ParserHelper.Error("Unexpected Token '" + dot.GetType().ToString() + "' encountered, expected a Dot (Line Terminator) Token to terminate Triples", dot); } } //If we already hit the Right Curly Bracket return if (context.Tokens.LastTokenType == Token.RIGHTCURLYBRACKET) { return; } } while (context.Tokens.Peek().TokenType != Token.RIGHTCURLYBRACKET); //Discard the ending Right Curly Bracket context.Tokens.Dequeue(); }
private void TryParseGraph(TriGParserContext context) { //Is there a name for the Graph? IToken next = context.Tokens.Dequeue(); Uri graphUri; if (next.TokenType == Token.QNAME) { //Try to resolve the QName graphUri = UriFactory.Create(Tools.ResolveQName(next.Value, context.Namespaces, null)); //Get the Next Token next = context.Tokens.Dequeue(); } else if (next.TokenType == Token.URI) { try { //Ensure an absolute Uri graphUri = new Uri(next.Value, UriKind.Absolute); } catch (UriFormatException) { throw ParserHelper.Error("The URI '" + next.Value + "' given as a Graph Name is not a valid Absolute URI", next); } //Get the Next Token next = context.Tokens.Dequeue(); } else { //No Name so is a Default Graph if (!context.DefaultGraphExists) { graphUri = null; } else { throw new RdfParseException("You cannot specify more than one Default (Unnamed) Graph in a TriG file", next); } } //Is there a discardable Equals token? if (next.TokenType == Token.EQUALS) { next = context.Tokens.Dequeue(); } //Should the see a Left Curly Bracket if (next.TokenType == Token.LEFTCURLYBRACKET) { //Check that the Graph isn't empty i.e. the next token is not a } to close the Graph next = context.Tokens.Peek(); if (next.TokenType == Token.RIGHTCURLYBRACKET) { //Empty Graph so just discard the } context.Tokens.Dequeue(); } else { //Parse Graph Contents this.TryParseTriples(context, graphUri); } } else { throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered, expected a Left Curly Bracket to start a Graph", next); } //May optionally end with a Dot Token next = context.Tokens.Peek(); if (next.TokenType == Token.DOT) { //Discard context.Tokens.Dequeue(); } }
/// <summary> /// Tries to parse directives /// </summary> /// <param name="context"></param> /// <param name="directive"></param> /// <remarks> /// This overload is needed because in some cases we may dequeue a token before we know it is a directive /// </remarks> private void TryParseDirective(TriGParserContext context, IToken directive) { //See what type of directive it is if (directive.TokenType == Token.BASEDIRECTIVE) { IToken baseUri = context.Tokens.Dequeue(); if (baseUri.TokenType == Token.URI) { try { Uri newBase = new Uri(Tools.ResolveUri(baseUri.Value, context.BaseUri.ToSafeString())); context.BaseUri = newBase; this.RaiseWarning("The @base directive is not valid in all versions of the TriG specification, your data may not be compatible with some older tools which do not support this version of TriG"); if (!context.Handler.HandleBaseUri(newBase)) { ParserHelper.Stop(); } } catch (UriFormatException) { throw ParserHelper.Error("The URI '" + baseUri.Value + "' given for the Base URI is not a valid URI", baseUri); } } else { throw ParserHelper.Error("Unexpected Token '" + baseUri.GetType().ToString() + "' encountered, expected a URI Token after a @base directive", baseUri); } } else if (directive.TokenType == Token.PREFIXDIRECTIVE) { //Prefix Directive IToken prefix = context.Tokens.Dequeue(); if (prefix.TokenType == Token.PREFIX) { IToken uri = context.Tokens.Dequeue(); if (uri.TokenType == Token.URI) { //Ensure the Uri is absolute try { Uri u = new Uri(Tools.ResolveUri(uri.Value, context.BaseUri.ToSafeString())); String pre = (prefix.Value.Equals(":")) ? String.Empty : prefix.Value.Substring(0, prefix.Value.Length - 1); context.Namespaces.AddNamespace(pre, u); if (!context.Handler.HandleNamespace(pre, u)) { ParserHelper.Stop(); } } catch (UriFormatException) { throw ParserHelper.Error("The URI '" + uri.Value + "' given for the prefix '" + prefix.Value + "' is not a valid URI", uri); } } else { throw ParserHelper.Error("Unexpected Token '" + prefix.GetType().ToString() + "' encountered, expected a URI Token after a Prefix Token", uri); } } else { throw ParserHelper.Error("Unexpected Token '" + prefix.GetType().ToString() + "' encountered, expected a Prefix Token after a Prefix Directive Token", prefix); } } else { throw ParserHelper.Error("Unexpected Token '" + directive.GetType().ToString() + "' encountered, expected a Base/Prefix Directive Token", directive); } //Expect a DOT to Terminate IToken dot = context.Tokens.Dequeue(); if (dot.TokenType != Token.DOT) { throw ParserHelper.Error("Unexpected Token '" + dot.GetType().ToString() + "' encountered, expected a Dot (Line Terminator) Token to terminate a Base/Prefix Directive", dot); } }
/// <summary> /// Tries to parse a directive /// </summary> /// <param name="context"></param> private void TryParseDirective(TriGParserContext context) { IToken directive = context.Tokens.Dequeue(); this.TryParseDirective(context, directive); }
private void Parse(TriGParserContext context) { try { context.Handler.StartRdf(); //Expect a BOF Token IToken first = context.Tokens.Dequeue(); if (first.TokenType != Token.BOF) { throw ParserHelper.Error("Unexpected Token '" + first.GetType().ToString() + "' encountered, expected a BOF Token", first); } //Expect either a Directive or a Graph IToken next; do { next = context.Tokens.Peek(); switch (next.TokenType) { case Token.COMMENT: //Discard context.Tokens.Dequeue(); break; case Token.EOF: //End of File context.Tokens.Dequeue(); break; case Token.BASEDIRECTIVE: case Token.PREFIXDIRECTIVE: //Parse a Directive this.TryParseDirective(context); break; case Token.QNAME: case Token.URI: case Token.LEFTCURLYBRACKET: //Parse a Graph if (context.Syntax != TriGSyntax.Original) { //We must take care here because @prefix and @base directives may be Graph scoped so anything visible currently //remains visible and must be restored afterwards but anything inside the Graph is not visible outside of it Uri extBase = context.BaseUri; INamespaceMapper nsmap = new NamespaceMapper(context.Namespaces); this.TryParseGraph(context); //After we parse the Graph restore the state if (!context.Handler.HandleBaseUri(extBase)) { ParserHelper.Stop(); } context.BaseUri = extBase; context.Namespaces.Clear(); foreach (String prefix in nsmap.Prefixes) { if (!context.Handler.HandleNamespace(prefix, nsmap.GetNamespaceUri(prefix))) { ParserHelper.Stop(); } } context.Namespaces.Import(nsmap); } else { //With the old syntax declarations are file scoped so no need to worry about graph scoping this.TryParseGraph(context); } break; default: throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered", next); } } while (next.TokenType != Token.EOF); context.Handler.EndRdf(true); } catch (RdfParsingTerminatedException) { context.Handler.EndRdf(true); //Discard this - it justs means the Handler told us to stop } catch { context.Handler.EndRdf(false); throw; } }
/// <summary> /// Loads the named Graphs from the TriG input using the given RDF Handler /// </summary> /// <param name="handler">RDF Handler to use</param> /// <param name="parameters">Parameters indicating the input to read from</param> public void Load(IRdfHandler handler, IStoreParams parameters) { if (handler == null) { throw new ArgumentNullException("handler", "Cannot parse an RDF Dataset using a null RDF Handler"); } if (parameters == null) { throw new ArgumentNullException("parameters", "Cannot parse an RDF Dataset using null Parameters"); } //Try and get the Input from the parameters TextReader input = null; if (parameters is StreamParams) { //Get Input Stream input = ((StreamParams)parameters).StreamReader; //Issue a Warning if the Encoding of the Stream is not UTF-8 if (!((StreamReader)input).CurrentEncoding.Equals(Encoding.UTF8)) { #if !SILVERLIGHT this.RaiseWarning("Expected Input Stream to be encoded as UTF-8 but got a Stream encoded as " + ((StreamReader)input).CurrentEncoding.EncodingName + " - Please be aware that parsing errors may occur as a result"); #else this.RaiseWarning("Expected Input Stream to be encoded as UTF-8 but got a Stream encoded as " + ((StreamReader)input).CurrentEncoding.GetType().Name + " - Please be aware that parsing errors may occur as a result"); #endif } } else if (parameters is TextReaderParams) { input = ((TextReaderParams)parameters).TextReader; } if (input != null) { try { //Create the Parser Context and Invoke the Parser TriGParserContext context = new TriGParserContext(handler, new TriGTokeniser(input), TokenQueueMode.SynchronousBufferDuringParsing, false, this._tracetokeniser); this.Parse(context); } catch { throw; } finally { try { input.Close(); } catch { //No catch actions just cleaning up } } } else { throw new RdfStorageException("Parameters for the TriGParser must be of the type StreamParams/TextReaderParams"); } }
private void Parse(TriGParserContext context) { try { context.Handler.StartRdf(); //Expect a BOF Token IToken first = context.Tokens.Dequeue(); if (first.TokenType != Token.BOF) { throw ParserHelper.Error("Unexpected Token '" + first.GetType().ToString() + "' encountered, expected a BOF Token", first); } //Expect either a Directive or a Graph IToken next; do { next = context.Tokens.Peek(); switch (next.TokenType) { case Token.COMMENT: //Discard context.Tokens.Dequeue(); break; case Token.EOF: //End of File context.Tokens.Dequeue(); break; case Token.BASEDIRECTIVE: case Token.PREFIXDIRECTIVE: //Parse a Directive this.TryParseDirective(context); break; case Token.QNAME: case Token.URI: case Token.LEFTCURLYBRACKET: //Parse a Graph this.TryParseGraph(context); break; default: throw ParserHelper.Error("Unexpected Token '" + next.GetType().ToString() + "' encountered", next); } } while (next.TokenType != Token.EOF); context.Handler.EndRdf(true); } catch (RdfParsingTerminatedException) { context.Handler.EndRdf(true); //Discard this - it justs means the Handler told us to stop } catch { context.Handler.EndRdf(false); throw; } }