// Copyright ©2020 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rdf_test import ( "fmt" "log" "os" "strings" "text/tabwriter" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/encoding" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/graph/formats/rdf" "gonum.org/v1/gonum/graph/multi" ) // dotNode implements graph.Node and dot.Node to allow the // RDF term value to be given to the DOT encoder. type dotNode struct { rdf.Term } func (n dotNode) DOTID() string { return n.Term.Value } // dotLine implements graph.Line and encoding.Attributer to // allow the line's RDF term value to be given to the DOT // encoder and for the nodes to be shimmed to the dotNode // type. // // Because the graph here is directed and we are not performing // any line reversals, it is safe not to implement the // ReversedLine method on dotLine; it will never be called. type dotLine struct { *rdf.Statement } func (l dotLine) From() graph.Node { return dotNode{l.Subject} } func (l dotLine) To() graph.Node { return dotNode{l.Object} } func (l dotLine) Attributes() []encoding.Attribute { return []encoding.Attribute{{Key: "label", Value: l.Predicate.Value}} } func Example_graph() { const statements = ` _:alice _:bob . _:alice "Alice" . _:alice "Smith" . _:bob _:alice . _:bob "Bob" . _:bob "Smith" . ` // Decode the statement stream and insert the lines into a multigraph. g := multi.NewDirectedGraph() dec := rdf.NewDecoder(strings.NewReader(statements)) for { l, err := dec.Unmarshal() if err != nil { break } // Wrap the line with a shim type to allow the RDF values // to be passed to the DOT marshaling routine. g.SetLine(dotLine{l}) } // Marshal the graph into DOT. b, err := dot.MarshalMulti(g, "smiths", "", "\t") if err != nil { log.Fatal(err) } fmt.Printf("%s\n\n", b) // Get the ID look-up table. w := tabwriter.NewWriter(os.Stdout, 0, 4, 1, ' ', 0) fmt.Fprintln(w, "Term\tID") for t, id := range dec.Terms() { fmt.Fprintf(w, "%s\t%d\n", t, id) } w.Flush() // Unordered output: // // digraph smiths { // // Node definitions. // "_:alice"; // "_:bob"; // "Alice"; // "Smith"; // "Bob"; // // // Edge definitions. // "_:alice" -> "_:bob" [label=]; // "_:alice" -> "Alice" [label=]; // "_:alice" -> "Smith" [label=]; // "_:bob" -> "_:alice" [label=]; // "_:bob" -> "Smith" [label=]; // "_:bob" -> "Bob" [label=]; // } // // Term ID // _:alice 1 // _:bob 2 // 3 // "Alice" 4 // 5 // "Smith" 6 // 7 // "Bob" 8 }