package rdfimport ()// ---- Turtle serialization ----// Turtle serializes the graph as Turtle, declaring the given namespace prefixes// (prefix label -> namespace IRI) and compacting IRIs against them. Triples are// grouped by subject in first-seen order, using `a` for rdf:type.func ( *Graph) ( map[string]string) []byte {returnappend(TurtleHeader(), .TurtleBody()...)}// TurtleHeader returns the @prefix declaration block for the given prefixes,// terminated by a blank line. Collection writers emit it once.func ( map[string]string) []byte {iflen() == 0 {returnnil } := make([]string, 0, len())for := range { = append(, ) }sort.Strings()var []bytefor , := range { = append(, "@prefix "...) = append(, ...) = append(, ": <"...) = appendEscapedIRI(, []) = append(, "> .\n"...) }returnappend(, '\n')}// TurtleBody serializes the triples grouped by subject, without a prefix header.func ( *Graph) ( map[string]string) []byte {varEncoderreturn .AppendTurtle(nil, , )}// AppendTurtle appends g's triples to b as a Turtle body (no @prefix header),// grouped by subject, in a fresh blank-node scope. It groups without a// per-subject map: subjects are ranked by first appearance, then a stable sort// of triple indices by that rank makes each subject's triples contiguous in// document order — turning thousands of small allocations into a handful.func ( *Encoder) ( []byte, *Graph, map[string]string) []byte { := len(.Triples)if == 0 {return } .bn.newScope() := make(map[Term]int, ) := make([]int, ) := 0for , := range .Triples { , := [.S]if ! { , = , +1 [.S] = } [] = } := make([]int, )for := range { [] = }sort.SliceStable(, func(, int) bool { return [[]] < [[]] })var []bool// reused across subjectsfor := 0; < ; { := + 1for < && .Triples[[]].S == .Triples[[]].S { ++ } = appendTurtleSubject(, .Triples, [:], , &, &.bn) = }return}// appendTurtleSubject writes one subject's predicate-object list, grouping objects// by predicate with a linear scan over the subject's (contiguous) triples and a// caller-reused scratch buffer.func appendTurtleSubject( []byte, []Triple, []int, map[string]string, *[]bool, *blankNamer) []byte { = appendTurtleTerm(, [[0]].S, , false, ) := (*)[:0]forrange { = append(, false) } * = := truefor := range {if [] {continue } := [[]]if { = append(, ' ') = false } else { = append(, " ;\n "...) } = appendTurtleTerm(, .P, , true, ) = append(, ' ') = appendTurtleTerm(, .O, , false, ) [] = truefor := + 1; < len(); ++ {if ![] && [[]].P == .P { = append(, ", "...) = appendTurtleTerm(, [[]].O, , false, ) [] = true } } }returnappend(, " .\n"...)}// appendTurtleTerm writes a term in Turtle syntax. In predicate position rdf:type// is written as `a`.func appendTurtleTerm( []byte, Term, map[string]string, bool, *blankNamer) []byte {switch .Kind {caseIRI:if && .Value == TypeIRI {returnappend(, 'a') }if , := appendCompactIRI(, .Value, ); {return } = append(, '<') = appendEscapedIRI(, .Value)returnappend(, '>')caseBlank: = append(, '_', ':')returnappend(, .name(.Value)...)default: = append(, '"') = appendEscapedLiteral(, .Value) = append(, '"')if .Lang != "" { = append(, '@')returnappend(, .Lang...) }if .Datatype != "" && .Datatype != XSDString { = append(, "^^"...)if , := appendCompactIRI(, .Datatype, ); {return } = append(, '<') = appendEscapedIRI(, .Datatype)returnappend(, '>') }return }}// appendCompactIRI appends iri as a prefixed name against the longest matching// namespace when the remaining local part is a valid bare local name, reporting// whether it compacted. It writes straight to b, allocating no intermediate// string.func appendCompactIRI( []byte, string, map[string]string) ([]byte, bool) { , := "", ""for , := range {iflen() > len() && strings.HasPrefix(, ) {if := [len():]; validLocal() { , = , } } }if == "" {return , false } = append(, ...) = append(, ':') = append(, [len():]...)return , true}// validLocal reports whether s is a non-empty local name that can be written bare// (matching what the reader accepts), so a round-trip is lossless.func validLocal( string) bool {if == "" || [len()-1] == '.' {returnfalse }for := 0; < len(); ++ {if !isNameChar([]) {returnfalse } }returntrue}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.