/// <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(UriFactory.Create(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> /// Generates the Output for a Graph /// </summary> /// <param name="context">Context for writing the Graph</param> private void GenerateOutput(TurtleWriterContext context) { //Write Base Uri if (context.Graph.BaseUri != null) { context.Output.WriteLine("@base <" + context.UriFormatter.FormatUri(context.Graph.BaseUri) + ">."); context.Output.WriteLine(); } //Write Prefixes foreach (String prefix in context.Graph.NamespaceMap.Prefixes) { if (TurtleSpecsHelper.IsValidQName(prefix + ":")) { context.Output.Write("@prefix " + prefix + ": <"); String nsUri = context.UriFormatter.FormatUri(context.Graph.NamespaceMap.GetNamespaceUri(prefix)); context.Output.WriteLine(nsUri + ">."); } } context.Output.WriteLine(); //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 (hiSpeed && context.HighSpeedModePermitted) { //High Speed Writing Mode //Writes everything as individual Triples this.RaiseWarning("High Speed Write Mode in use - minimal syntax compressions will be used"); context.NodeFormatter = new UncompressedTurtleFormatter(); foreach (Triple t in context.Graph.Triples) { context.Output.Write(this.GenerateNodeOutput(context, t.Subject, TripleSegment.Subject)); context.Output.Write(" "); context.Output.Write(this.GenerateNodeOutput(context, t.Predicate, TripleSegment.Predicate)); context.Output.Write(" "); context.Output.Write(this.GenerateNodeOutput(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; 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("."); } //Start a new set of Triples temp = this.GenerateNodeOutput(context, t.Subject, TripleSegment.Subject); context.Output.Write(temp); context.Output.Write(" "); subjIndent = temp.Length + 1; lastSubj = t.Subject; //Write the first Predicate temp = this.GenerateNodeOutput(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(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(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="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 Graph using an arbitrary <see cref="TextWriter">TextWriter</see> /// </summary> /// <param name="g">Graph to save</param> /// <param name="output">Writer to save using</param> protected override void SaveInternal(IGraph g, TextWriter output) { TurtleWriterContext context = new TurtleWriterContext(g, output, this._prettyprint, this._allowhispeed, this._syntax); this.GenerateOutput(context); }
/// <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; } } }