/// <summary> /// Generates Output for Nodes in Turtle syntax /// </summary> /// <param name="globalContext">Context for writing the Store</param> /// <param name="context">Context for writing the Graph</param> /// <param name="n">Node to generate output for</param> /// <param name="segment">Segment of the Triple being written</param> /// <returns></returns> private String GenerateNodeOutput(TriGWriterContext globalContext, TurtleWriterContext context, INode n, TripleSegment segment) { switch (n.NodeType) { case NodeType.Blank: if (segment == TripleSegment.Predicate) { throw new RdfOutputException(WriterErrorMessages.BlankPredicatesUnserializable("TriG")); } break; case NodeType.GraphLiteral: throw new RdfOutputException(WriterErrorMessages.GraphLiteralsUnserializable("TriG")); case NodeType.Literal: if (segment == TripleSegment.Subject) { throw new RdfOutputException(WriterErrorMessages.LiteralSubjectsUnserializable("TriG")); } if (segment == TripleSegment.Predicate) { throw new RdfOutputException(WriterErrorMessages.LiteralPredicatesUnserializable("TriG")); } break; case NodeType.Uri: break; default: throw new RdfOutputException(WriterErrorMessages.UnknownNodeTypeUnserializable("TriG")); } return(context.NodeFormatter.Format(n, segment)); }
/// <summary> /// Thread Worker method which writes Graphs to the output /// </summary> /// <param name="globalContext">Context for writing the Store</param> private void SaveGraphs(TriGWriterContext globalContext) { try { Uri u = globalContext.GetNextUri(); while (u != null) { //Get the Graph from the Store if (WriterHelper.IsDefaultGraph(u) && !globalContext.Store.HasGraph(u)) { u = null; } IGraph g = globalContext.Store.Graphs[u]; //Generate the Graph Output and add to Stream TurtleWriterContext context = new TurtleWriterContext(g, new System.IO.StringWriter(), globalContext.PrettyPrint, globalContext.HighSpeedModePermitted); if (globalContext.CompressionLevel > WriterCompressionLevel.None) { context.NodeFormatter = new TurtleFormatter(globalContext.QNameMapper); } else { context.NodeFormatter = new UncompressedTurtleFormatter(); } String graphContent = this.GenerateGraphOutput(globalContext, context); try { Monitor.Enter(globalContext.Output); globalContext.Output.WriteLine(graphContent); globalContext.Output.Flush(); } catch { throw; } finally { Monitor.Exit(globalContext.Output); } //Get the Next Uri u = globalContext.GetNextUri(); } } catch (ThreadAbortException) { //We've been terminated, don't do anything #if !SILVERLIGHT Thread.ResetAbort(); #endif } catch (Exception ex) { throw new RdfStorageException("Error in Threaded Writer in Thread ID " + Thread.CurrentThread.ManagedThreadId, ex); } }
/// <summary> /// Thread Worker method which writes Graphs to the output /// </summary> /// <param name="globalContext">Context for writing the Store</param> private void SaveGraphs(TriGWriterContext globalContext) { try { Uri u = null; while (globalContext.TryGetNextUri(out u)) { // Get the Graph from the Store IGraph g = globalContext.Store.Graphs[u]; // Generate the Graph Output and add to Stream TurtleWriterContext context = new TurtleWriterContext(g, new System.IO.StringWriter(), globalContext.PrettyPrint, globalContext.HighSpeedModePermitted); if (globalContext.CompressionLevel > WriterCompressionLevel.None) { context.NodeFormatter = new TurtleFormatter(globalContext.QNameMapper); } else { context.NodeFormatter = new UncompressedTurtleFormatter(); } String graphContent = this.GenerateGraphOutput(globalContext, context); try { Monitor.Enter(globalContext.Output); globalContext.Output.WriteLine(graphContent); globalContext.Output.Flush(); } catch { throw; } finally { Monitor.Exit(globalContext.Output); } } } #if !NETCORE // PCL has no Thread.Abort() method or ThreadAbortException catch (ThreadAbortException) { // We've been terminated, don't do anything Thread.ResetAbort(); } #endif catch (Exception ex) { throw new RdfStorageException("Error in Threaded Writer in Thread ID " + Thread.CurrentThread.ManagedThreadId, ex); } }
/// <summary> /// Generates the Output for a Graph as a String in TriG syntax /// </summary> /// <param name="globalContext">Context for writing the Store</param> /// <param name="context">Context for writing the Graph</param> /// <returns></returns> private String GenerateGraphOutput(TriGWriterContext globalContext, TurtleWriterContext context) { if (!WriterHelper.IsDefaultGraph(context.Graph.BaseUri)) { //Named Graph String gname; String sep = (globalContext.N3CompatabilityMode) ? " = " : " "; if (globalContext.CompressionLevel > WriterCompressionLevel.None && globalContext.QNameMapper.ReduceToQName(context.Graph.BaseUri.ToString(), out gname)) { if (TurtleSpecsHelper.IsValidQName(gname)) { context.Output.WriteLine(gname + sep + "{"); } else { context.Output.WriteLine("<" + context.UriFormatter.FormatUri(context.Graph.BaseUri) + ">" + sep + "{"); } } else { context.Output.WriteLine("<" + context.UriFormatter.FormatUri(context.Graph.BaseUri) + ">" + sep + "{"); } } else { context.Output.WriteLine("{"); } //Generate Triples this.GenerateTripleOutput(globalContext, context); //Close the Graph context.Output.WriteLine("}"); return(context.Output.ToString()); }
/// <summary> /// Generates the Output for a Triple as a String in Turtle syntax /// </summary> /// <param name="globalContext">Context for writing the Store</param> /// <param name="context">Context for writing the Graph</param> private void GenerateTripleOutput(TriGWriterContext globalContext, TurtleWriterContext context) { //Decide which write mode to use bool hiSpeed = false; double subjNodes = context.Graph.Triples.SubjectNodes.Count(); double triples = context.Graph.Triples.Count; if ((subjNodes / triples) > 0.75) { hiSpeed = true; } if (globalContext.CompressionLevel == WriterCompressionLevel.None || hiSpeed && context.HighSpeedModePermitted) { //Use High Speed Write Mode String indentation = new String(' ', 4); context.Output.Write(indentation); if (globalContext.CompressionLevel > WriterCompressionLevel.None) { context.Output.WriteLine("# Written using High Speed Mode"); } foreach (Triple t in context.Graph.Triples) { context.Output.Write(indentation); context.Output.Write(this.GenerateNodeOutput(globalContext, context, t.Subject, TripleSegment.Subject)); context.Output.Write(' '); context.Output.Write(this.GenerateNodeOutput(globalContext, context, t.Predicate, TripleSegment.Predicate)); context.Output.Write(' '); context.Output.Write(this.GenerateNodeOutput(globalContext, context, t.Object, TripleSegment.Object)); context.Output.WriteLine("."); } } else { //Get the Triples as a Sorted List List <Triple> ts = context.Graph.Triples.ToList(); ts.Sort(); //Variables we need to track our writing INode lastSubj, lastPred; lastSubj = lastPred = null; int subjIndent = 0, predIndent = 0; int baseIndent = 4; String temp; for (int i = 0; i < ts.Count; i++) { Triple t = ts[i]; if (lastSubj == null || !t.Subject.Equals(lastSubj)) { //Terminate previous Triples if (lastSubj != null) { context.Output.WriteLine("."); } if (context.PrettyPrint) { context.Output.Write(new String(' ', baseIndent)); } //Start a new set of Triples temp = this.GenerateNodeOutput(globalContext, context, t.Subject, TripleSegment.Subject); context.Output.Write(temp); context.Output.Write(" "); subjIndent = baseIndent + temp.Length + 1; lastSubj = t.Subject; //Write the first Predicate temp = this.GenerateNodeOutput(globalContext, context, t.Predicate, TripleSegment.Predicate); context.Output.Write(temp); context.Output.Write(" "); predIndent = temp.Length + 1; lastPred = t.Predicate; } else if (lastPred == null || !t.Predicate.Equals(lastPred)) { //Terminate previous Predicate Object list context.Output.WriteLine(";"); if (context.PrettyPrint) { context.Output.Write(new String(' ', subjIndent)); } //Write the next Predicate temp = this.GenerateNodeOutput(globalContext, context, t.Predicate, TripleSegment.Predicate); context.Output.Write(temp); context.Output.Write(" "); predIndent = temp.Length + 1; lastPred = t.Predicate; } else { //Continue Object List context.Output.WriteLine(","); if (context.PrettyPrint) { context.Output.Write(new String(' ', subjIndent + predIndent)); } } //Write the Object context.Output.Write(this.GenerateNodeOutput(globalContext, context, t.Object, TripleSegment.Object)); } //Terminate Triples if (ts.Count > 0) { context.Output.WriteLine("."); } } }
/// <summary> /// Saves a Store in TriG (Turtle with Named Graphs) format /// </summary> /// <param name="store">Store to save</param> /// <param name="parameters">Parameters indicating a Stream to write to</param> public void Save(ITripleStore store, IStoreParams parameters) { //Try and determine the TextWriter to output to TriGWriterContext context = null; if (parameters is StreamParams) { //Create a new Writer Context ((StreamParams)parameters).Encoding = new UTF8Encoding(Options.UseBomForUtf8); context = new TriGWriterContext(store, ((StreamParams)parameters).StreamWriter, this._prettyprint, this._allowHiSpeed, this._compressionLevel, this._n3compat); } else if (parameters is TextWriterParams) { context = new TriGWriterContext(store, ((TextWriterParams)parameters).TextWriter, this._prettyprint, this._allowHiSpeed, this._compressionLevel, this._n3compat); } if (context != null) { //Check there's something to do if (context.Store.Graphs.Count == 0) { context.Output.Close(); return; } //Write the Header of the File foreach (IGraph g in context.Store.Graphs) { context.NamespaceMap.Import(g.NamespaceMap); } if (context.CompressionLevel > WriterCompressionLevel.None) { //Only add @prefix declarations if compression is enabled context.QNameMapper = new ThreadSafeQNameOutputMapper(context.NamespaceMap); foreach (String prefix in context.NamespaceMap.Prefixes) { if (TurtleSpecsHelper.IsValidQName(prefix + ":")) { context.Output.WriteLine("@prefix " + prefix + ": <" + context.FormatUri(context.NamespaceMap.GetNamespaceUri(prefix)) + ">."); } } context.Output.WriteLine(); } else { context.QNameMapper = new ThreadSafeQNameOutputMapper(new NamespaceMapper(true)); } if (this._useMultiThreading) { //Standard Multi-Threaded Writing //Queue the Graphs to be written foreach (IGraph g in context.Store.Graphs) { if (g.BaseUri == null) { context.Add(new Uri(GraphCollection.DefaultGraphUri)); } else { context.Add(g.BaseUri); } } //Start making the async calls List <IAsyncResult> results = new List <IAsyncResult>(); SaveGraphsDelegate d = new SaveGraphsDelegate(this.SaveGraphs); for (int i = 0; i < this._threads; i++) { results.Add(d.BeginInvoke(context, null, null)); } //Wait for all the async calls to complete WaitHandle.WaitAll(results.Select(r => r.AsyncWaitHandle).ToArray()); RdfThreadedOutputException outputEx = new RdfThreadedOutputException(WriterErrorMessages.ThreadedOutputFailure("TriG")); foreach (IAsyncResult result in results) { try { d.EndInvoke(result); } catch (Exception ex) { outputEx.AddException(ex); } } //Make sure to close the output context.Output.Close(); //If there were any errors we'll throw an RdfThreadedOutputException now if (outputEx.InnerExceptions.Any()) { throw outputEx; } } else { try { //Optional Single Threaded Writing foreach (IGraph g in store.Graphs) { TurtleWriterContext graphContext = new TurtleWriterContext(g, new System.IO.StringWriter(), context.PrettyPrint, context.HighSpeedModePermitted); if (context.CompressionLevel > WriterCompressionLevel.None) { graphContext.NodeFormatter = new TurtleFormatter(context.QNameMapper); } else { graphContext.NodeFormatter = new UncompressedTurtleFormatter(); } context.Output.WriteLine(this.GenerateGraphOutput(context, graphContext)); } //Make sure to close the output context.Output.Close(); } catch { try { //Close the output context.Output.Close(); } catch { //No catch actions, just cleaning up the output stream } throw; } } } else { throw new RdfStorageException("Parameters for the TriGWriter must be of the type StreamParams/TextWriterParams"); } }
/// <summary> /// Saves a Store in TriG (Turtle with Named Graphs) format. /// </summary> /// <param name="store">Store to save.</param> /// <param name="writer">Writer to save to.</param> /// <param name="leaveOpen">Boolean flag indicating if <paramref name="writer"/> should be left open after the store is saved.</param> public void Save(ITripleStore store, TextWriter writer, bool leaveOpen) { if (store == null) { throw new RdfOutputException("Cannot output a null Triple Store"); } if (writer == null) { throw new RdfOutputException("Cannot output to a null writer"); } TriGWriterContext context = new TriGWriterContext(store, writer, _prettyprint, _allowHiSpeed, _compressionLevel, _n3compat); // Check there's something to do if (context.Store.Graphs.Count == 0) { if (!leaveOpen) { context.Output.Close(); } return; } // Write the Header of the File foreach (var g in context.Store.Graphs) { context.NamespaceMap.Import(g.NamespaceMap); } if (context.CompressionLevel > WriterCompressionLevel.None) { // Only add @prefix declarations if compression is enabled context.QNameMapper = new ThreadSafeQNameOutputMapper(context.NamespaceMap); foreach (string prefix in context.NamespaceMap.Prefixes) { if (TurtleSpecsHelper.IsValidQName(prefix + ":")) { context.Output.WriteLine("@prefix " + prefix + ": <" + context.FormatUri(context.NamespaceMap.GetNamespaceUri(prefix)) + ">."); } } context.Output.WriteLine(); } else { context.QNameMapper = new ThreadSafeQNameOutputMapper(new NamespaceMapper(true)); } if (_useMultiThreading) { // Standard Multi-Threaded Writing // Queue the Graphs to be written foreach (IGraph g in context.Store.Graphs) { context.Add(g.BaseUri); } // Start making the async calls var workers = new Task[_threads]; for (int i = 0; i < _threads; i++) { workers[i] = Task.Factory.StartNew(() => SaveGraphs(context)); } try { Task.WaitAll(workers); } catch (AggregateException ex) { var outputException = new RdfThreadedOutputException(WriterErrorMessages.ThreadedOutputFailure("TriG")); foreach (var innerException in ex.InnerExceptions) { outputException.AddException(innerException); } } finally { // Make sure to close the output if (!leaveOpen) { context.Output.Close(); } } } else { try { // Optional Single Threaded Writing foreach (IGraph g in store.Graphs) { TurtleWriterContext graphContext = new TurtleWriterContext(g, new System.IO.StringWriter(), context.PrettyPrint, context.HighSpeedModePermitted); if (context.CompressionLevel > WriterCompressionLevel.None) { graphContext.NodeFormatter = new TurtleFormatter(context.QNameMapper); } else { graphContext.NodeFormatter = new UncompressedTurtleFormatter(); } context.Output.WriteLine(GenerateGraphOutput(context, graphContext)); } // Make sure to close the output if (!leaveOpen) { context.Output.Close(); } } catch { try { // Close the output if (!leaveOpen) { context.Output.Close(); } } catch { // No catch actions, just cleaning up the output stream } throw; } } }
/// <summary> /// Saves a Store in TriG (Turtle with Named Graphs) format /// </summary> /// <param name="store">Store to save</param> /// <param name="writer">Writer to save to</param> /// <param name="leaveOpen">Boolean flag indicating if <paramref name="writer"/> should be left open after the store is saved</param> public void Save(ITripleStore store, TextWriter writer, bool leaveOpen) { if (store == null) { throw new RdfOutputException("Cannot output a null Triple Store"); } if (writer == null) { throw new RdfOutputException("Cannot output to a null writer"); } TriGWriterContext context = new TriGWriterContext(store, writer, _prettyprint, _allowHiSpeed, _compressionLevel, _n3compat); // Check there's something to do if (context.Store.Graphs.Count == 0) { if (!leaveOpen) { context.Output.Close(); } return; } // Write the Header of the File foreach (var g in context.Store.Graphs) { context.NamespaceMap.Import(g.NamespaceMap); } if (context.CompressionLevel > WriterCompressionLevel.None) { // Only add @prefix declarations if compression is enabled context.QNameMapper = new ThreadSafeQNameOutputMapper(context.NamespaceMap); foreach (string prefix in context.NamespaceMap.Prefixes) { if (TurtleSpecsHelper.IsValidQName(prefix + ":")) { context.Output.WriteLine("@prefix " + prefix + ": <" + context.FormatUri(context.NamespaceMap.GetNamespaceUri(prefix)) + ">."); } } context.Output.WriteLine(); } else { context.QNameMapper = new ThreadSafeQNameOutputMapper(new NamespaceMapper(true)); } if (_useMultiThreading) { // Standard Multi-Threaded Writing // Queue the Graphs to be written foreach (IGraph g in context.Store.Graphs) { context.Add(g.BaseUri); } // Start making the async calls List <IAsyncResult> results = new List <IAsyncResult>(); SaveGraphsDelegate d = new SaveGraphsDelegate(SaveGraphs); for (int i = 0; i < _threads; i++) { results.Add(d.BeginInvoke(context, null, null)); } // Wait for all the async calls to complete WaitHandle.WaitAll(results.Select(r => r.AsyncWaitHandle).ToArray()); RdfThreadedOutputException outputEx = new RdfThreadedOutputException(WriterErrorMessages.ThreadedOutputFailure("TriG")); foreach (IAsyncResult result in results) { try { d.EndInvoke(result); } catch (Exception ex) { outputEx.AddException(ex); } } // Make sure to close the output if (!leaveOpen) { context.Output.Close(); } // If there were any errors we'll throw an RdfThreadedOutputException now if (outputEx.InnerExceptions.Any()) { throw outputEx; } } else { try { // Optional Single Threaded Writing foreach (IGraph g in store.Graphs) { TurtleWriterContext graphContext = new TurtleWriterContext(g, new System.IO.StringWriter(), context.PrettyPrint, context.HighSpeedModePermitted); if (context.CompressionLevel > WriterCompressionLevel.None) { graphContext.NodeFormatter = new TurtleFormatter(context.QNameMapper); } else { graphContext.NodeFormatter = new UncompressedTurtleFormatter(); } context.Output.WriteLine(GenerateGraphOutput(context, graphContext)); } // Make sure to close the output if (!leaveOpen) { context.Output.Close(); } } catch { try { // Close the output if (!leaveOpen) { context.Output.Close(); } } catch { // No catch actions, just cleaning up the output stream } throw; } } }