1package gojsonld 2 3import ( 4 "math" 5 "strconv" 6 "strings" 7) 8 9func toRDF(activeContext *Context, element interface{}) (*Dataset, error) { 10 // 1) 11 expanded, expandErr := Expand(element, activeContext.options) 12 if !isNil(expandErr) { 13 return nil, expandErr 14 } 15 // 2) 16 nodeMap := make(map[string]interface{}, 0) 17 var idGenerator = BlankNodeIdGenerator{} 18 idGenerator.counter = 0 19 idGenerator.identifierMap = make(map[string]string, 0) 20 defaultArg := "@default" 21 err := generateNodeMap(expanded, nodeMap, &defaultArg, nil, 22 nil, nil, &idGenerator) 23 if !isNil(err) { 24 return nil, err 25 } 26 // 3) 27 dataset := NewDataset() 28 // 4) 29 keys := sortedKeys(nodeMap) 30 for _, graphName := range keys { 31 graph := nodeMap[graphName] 32 // 4.1) 33 if isRelativeIri(graphName) { 34 continue 35 } 36 // 4.2) 37 triples := make([]*Triple, 0) 38 // 4.3) 39 graphMap := graph.(map[string]interface{}) 40 graphKeys := sortedKeys(graphMap) 41 for _, id := range graphKeys { 42 node := graphMap[id] 43 // 4.3.1) 44 if !isAbsoluteIri(id) { 45 continue 46 } 47 nodeMapValue := node.(map[string]interface{}) 48 keysNode := sortedKeys(nodeMapValue) 49 for _, property := range keysNode { 50 values := nodeMapValue[property] 51 // 4.3.2.1) 52 if property == "@type" { 53 property = RDF_TYPE 54 // 4.3.2.2) 55 } else if isKeyword(property) { 56 continue 57 // 4.3.2.3) 58 } else if strings.HasPrefix(property, "_:") && 59 !activeContext.options.ProduceGeneralizedRdf { 60 continue 61 // 4.3.2.4) 62 } else if isRelativeIri(property) { 63 continue 64 } 65 // RDF subject 66 var subject Term 67 if strings.HasPrefix(id, "_:") { 68 subject = NewBlankNode(id[2:]) 69 } else { 70 subject = NewResource(id) 71 } 72 // RDF predicate 73 var predicate Term 74 if strings.HasPrefix(property, "_:") { 75 predicate = NewBlankNode(property[2:]) 76 } else { 77 predicate = NewResource(property) 78 } 79 valuesArray := values.([]interface{}) 80 for _, item := range valuesArray { 81 if isListObject(item) { 82 list := item.(map[string]interface{})["@list"].([]interface{}) 83 listHead, listTriples := listToRDF(list, &idGenerator) 84 triples = append(triples, NewTriple(subject, predicate, 85 listHead)) 86 for _, triple := range listTriples { 87 triples = append(triples, triple) 88 } 89 } else { 90 object := objectToRDF(item) 91 if !isNil(object) { 92 triples = append(triples, NewTriple(subject, predicate, 93 object)) 94 } 95 } 96 } 97 } 98 } 99 // 4.4 + 4.5) 100 if strings.HasPrefix(graphName, "_:") { 101 graphName = graphName[2:] 102 } 103 dataset.Graphs[graphName] = triples 104 } 105 return dataset, nil 106} 107 108func objectToRDF(item interface{}) Term { 109 //TODO spec is wrong 110 if itemString, isString := item.(string); isString { 111 if strings.HasPrefix(itemString, "_:") { 112 return NewBlankNode(itemString[2:]) 113 } else { 114 return NewResource(itemString) 115 } 116 } 117 id, hasID := item.(map[string]interface{})["@id"] 118 language, hasLanguage := item.(map[string]interface{})["@language"] 119 // 1) 120 if isNodeObject(item) && hasID && isRelativeIri(id.(string)) { 121 return nil 122 } 123 // 2) 124 if isNodeObject(item) { 125 if strings.HasPrefix(id.(string), "_:") { 126 idString := id.(string) 127 return NewBlankNode(idString[2:]) 128 } else { 129 return NewResource(id.(string)) 130 } 131 } 132 // 3) 133 value := item.(map[string]interface{})["@value"] 134 // 4) 135 datatype, hasDatatype := item.(map[string]interface{})["@type"] 136 if !hasDatatype { 137 datatype = "" 138 } 139 valueBool, isBool := value.(bool) 140 valueFloat, isFloat := value.(float64) 141 valueInt, isInt := value.(int64) 142 // 5) 143 if isBool { 144 if valueBool { 145 value = "true" 146 } else { 147 value = "false" 148 } 149 if datatype == "" { 150 datatype = XSD_BOOLEAN 151 } 152 // 6) 153 } else if isFloat { 154 var tmpDatatype string 155 if valueFloat != math.Trunc(valueFloat) || datatype.(string) == XSD_DOUBLE { 156 value = strconv.FormatFloat(valueFloat, 'E', -1, 64) 157 value = convertFloatValue(value.(string)) 158 tmpDatatype = XSD_DOUBLE 159 } else { 160 value = strconv.FormatFloat(valueFloat, 'f', 0, 64) 161 tmpDatatype = XSD_INTEGER 162 } 163 if datatype == "" { 164 datatype = tmpDatatype 165 } 166 // 7 167 } else if isInt || datatype.(string) == XSD_INTEGER { 168 value = strconv.FormatInt(valueInt, 10) 169 if datatype == "" { 170 datatype = XSD_INTEGER 171 } 172 // 8) 173 } else { 174 if datatype == "" { 175 if hasLanguage { 176 //TODO fix spec 177 //datatype = RDF_LANGSTRING 178 datatype = XSD_STRING 179 } else { 180 datatype = XSD_STRING 181 } 182 } 183 } 184 datatypeTerm := NewResource(datatype.(string)) 185 if hasLanguage { 186 return NewLiteralWithLanguageAndDatatype(value.(string), language.(string), 187 datatypeTerm.(Term)) 188 } 189 return NewLiteralWithDatatype(value.(string), datatypeTerm.(Term)) 190} 191 192func listToRDF(list []interface{}, idGenerator *BlankNodeIdGenerator) (Term, []*Triple) { 193 listTriples := make([]*Triple, 0) 194 // 1) 195 if len(list) == 0 { 196 return NewResource(RDF_NIL), listTriples 197 } 198 // 2) 199 bnodes := make([]Term, 0) 200 for i := 0; i < len(list); i++ { 201 id := idGenerator.generateBlankNodeIdentifier(nil) 202 bnodes = append(bnodes, 203 NewBlankNode(id[2:])) 204 } 205 // 3) 206 listTriples = make([]*Triple, 0) 207 // 4) 208 for i := 0; i < len(list); i++ { 209 subject := bnodes[i] 210 item := list[i] 211 // 4.1) 212 object := objectToRDF(item) 213 // 4.2) 214 if !isNil(object) { 215 listTriples = append(listTriples, 216 NewTriple(subject, NewResource(RDF_FIRST), object)) 217 } 218 // 4.3) 219 var rest Term 220 if i == len(list)-1 { 221 rest = NewResource(RDF_NIL) 222 } else { 223 rest = bnodes[i+1] 224 } 225 listTriples = append(listTriples, 226 NewTriple(subject, NewResource(RDF_REST), rest)) 227 } 228 // 5) 229 return bnodes[0], listTriples 230} 231 232func fromRDF(dataset *Dataset, useNativeTypes bool, 233 useRdfType bool) []interface{} { 234 // 1) 235 defaultGraph := make(map[string]interface{}, 0) 236 // 2) 237 graphMap := make(map[string]interface{}) 238 graphMap["@default"] = defaultGraph 239 //TODO possible draft error 240 nodeUsagesMap := make(map[string]interface{}, 0) 241 // 3) 242 for name, graph := range dataset.Graphs { 243 // 3.2) 244 if _, hasGraph := graphMap[name]; !hasGraph { 245 graphMap[name] = make(map[string]interface{}, 0) 246 } 247 // 3.3) 248 _, hasName := defaultGraph[name] 249 if name != "@default" && !hasName { 250 tmpMap := make(map[string]interface{}, 0) 251 tmpMap["@id"] = name 252 defaultGraph[name] = tmpMap 253 254 } 255 // 3.4) 256 nodeMap := graphMap[name].(map[string]interface{}) 257 // 3.5) 258 for _, triple := range graph { 259 subject := triple.Subject.RawValue() 260 predicate := triple.Predicate.RawValue() 261 object := triple.Object.RawValue() 262 // 3.5.1) 263 if _, hasSubject := nodeMap[subject]; !hasSubject { 264 tmpMap := make(map[string]interface{}, 0) 265 tmpMap["@id"] = subject 266 nodeMap[subject] = tmpMap 267 } 268 // 3.5.2) 269 node := nodeMap[subject].(map[string]interface{}) 270 // 3.5.3) 271 _, hasObject := nodeMap[object] 272 if (isBlankNodeIdentifier(object) || isIRI(object)) && !hasObject { 273 tmpMap := make(map[string]interface{}, 0) 274 tmpMap["@id"] = object 275 nodeMap[object] = tmpMap 276 } 277 // 3.5.4) 278 if predicate == RDF_TYPE && !useRdfType && 279 (isBlankNodeIdentifier(object) || isIRI(object)) { 280 mergeValue(node, "@type", object) 281 continue 282 } 283 // 3.5.5) 284 value := rdfToObject(triple.Object, useNativeTypes) 285 // 3.5.6+7) 286 mergeValue(node, predicate, value) 287 // 3.5.8) 288 if isIRI(object) || isBlankNodeIdentifier(object) { 289 nodeObjectMap := nodeMap[object].(map[string]interface{}) 290 tmpMap := make(map[string]interface{}, 0) 291 tmpMap["node"] = node 292 tmpMap["property"] = predicate 293 tmpMap["value"] = value 294 mergeValue(nodeObjectMap, "usages", tmpMap) 295 nodeMap[object] = nodeObjectMap 296 //TODO spec is wrong 297 mergeValue(nodeUsagesMap, object, name+" "+node["@id"].(string)) 298 } 299 } 300 } 301 // 4) 302 for name := range graphMap { 303 graphObject := graphMap[name].(map[string]interface{}) 304 // 4.1) 305 if _, hasNil := graphObject[RDF_NIL]; !hasNil { 306 continue 307 } 308 // 4.2) 309 //Spec defines this variable's name as nil, but nil is a reserved 310 //keyword in go so I named it as nilValue instead 311 nilValue := graphObject[RDF_NIL].(map[string]interface{}) 312 // 4.3) 313 usages := nilValue["usages"].([]interface{}) 314 for index := range usages { 315 usage := usages[index].(map[string]interface{}) 316 // 4.3.1) 317 node := usage["node"].(map[string]interface{}) 318 property := usage["property"].(string) 319 head := usage["value"].(map[string]interface{}) 320 // 4.3.2) 321 list := make([]interface{}, 0) 322 //TODO check type of listNodes 323 listNodes := make([]interface{}, 0) 324 // 4.3.3) 325 for RDF_REST == property && isWellFormedListNode(node) && 326 len(nodeUsagesMap[node["@id"].(string)].([]interface{})) == 1 { 327 // 4.3.3.1) 328 list = append(list, node[RDF_FIRST].([]interface{})[0]) 329 // 4.3.3.2) 330 listNodes = append(listNodes, node["@id"]) 331 // 4.3.3.3) 332 nodeUsage := node["usages"].([]interface{})[0].(map[string]interface{}) 333 // 4.3.3.4) 334 node = nodeUsage["node"].(map[string]interface{}) 335 property = nodeUsage["property"].(string) 336 head = nodeUsage["value"].(map[string]interface{}) 337 // 4.3.3.5) 338 if !isBlankNodeIdentifier(node["@id"].(string)) { 339 break 340 } 341 } 342 // 4.3.4) 343 if property == RDF_FIRST { 344 // 4.3.4.1) 345 if RDF_NIL == node["@id"].(string) { 346 continue 347 } 348 //4.3.4.3) 349 headID := head["@id"].(string) 350 // 4.3.4.4) 351 head = graphObject[headID].(map[string]interface{}) 352 // 4.3.4.5) 353 head = head[RDF_REST].([]interface{})[0].(map[string]interface{}) 354 // 4.3.4.6) 355 list = list[:(len(list) - 1)] 356 listNodes = listNodes[:(len(listNodes) - 1)] 357 } 358 // 4.3.5) 359 delete(head, "@id") 360 // 4.3.6) 361 for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 { 362 list[i], list[j] = list[j], list[i] 363 } 364 // 4.3.7) 365 head["@list"] = list 366 // 4.3.8) 367 for _, nodeID := range listNodes { 368 delete(graphObject, nodeID.(string)) 369 } 370 } 371 372 } 373 // 5) 374 result := make([]interface{}, 0) 375 // 6) 376 keys := sortedKeys(defaultGraph) 377 for _, subject := range keys { 378 node := defaultGraph[subject].(map[string]interface{}) 379 // 6.1) 380 if _, hasSubject := graphMap[subject]; hasSubject { 381 // 6.1.1) 382 node["@graph"] = make([]interface{}, 0) 383 // 6.1.2) 384 keysGraph := sortedKeys(graphMap[subject].(map[string]interface{})) 385 for _, s := range keysGraph { 386 n := graphMap[subject].(map[string]interface{})[s] 387 nMap := n.(map[string]interface{}) 388 _, hasID := nMap["@id"] 389 delete(nMap, "usages") 390 if len(nMap) == 1 && hasID { 391 continue 392 } 393 node["@graph"] = append(node["@graph"].([]interface{}), nMap) 394 } 395 } 396 // 6.2) 397 delete(node, "usages") 398 if _, hasID := node["@id"]; !(len(node) == 1 && hasID) { 399 result = append(result, node) 400 } 401 } 402 // 7) 403 return result 404} 405 406func isWellFormedListNode(node interface{}) bool { 407 nodeMap := node.(map[string]interface{}) 408 //TODO spec has no mention of @id 409 for key := range nodeMap { 410 if key != "@id" && key != "@type" && key != RDF_FIRST && 411 key != RDF_REST && key != "usages" { 412 return false 413 } 414 } 415 if !isBlankNodeIdentifier(nodeMap["@id"].(string)) { 416 return false 417 } 418 if usages, hasUsages := nodeMap["usages"]; hasUsages { 419 usagesArray, isArray := usages.([]interface{}) 420 if !(isArray && len(usagesArray) == 1) { 421 return false 422 } 423 } else { 424 return false 425 } 426 if first, hasKey := nodeMap[RDF_FIRST]; hasKey { 427 firstArray, isArray := first.([]interface{}) 428 if !(isArray && len(firstArray) == 1) { 429 return false 430 } 431 } else { 432 return false 433 } 434 if rest, hasKey := nodeMap[RDF_REST]; hasKey { 435 restArray, isArray := rest.([]interface{}) 436 if !(isArray && len(restArray) == 1) { 437 return false 438 } 439 } else { 440 return false 441 } 442 if typeValue, hasType := nodeMap["@type"]; hasType { 443 typeArray, isArray := typeValue.([]interface{}) 444 if !(isArray && len(typeArray) == 1 && RDF_LIST == typeArray[0]) { 445 return false 446 } 447 } 448 return true 449} 450 451func rdfToObject(value Term, useNativeTypes bool) map[string]interface{} { 452 // 1) 453 if isTermResource(value) || isTermBlankNode(value) { 454 returnValue := make(map[string]interface{}, 0) 455 returnValue["@id"] = value.RawValue() 456 return returnValue 457 } 458 //2) 459 valueLiteral := value.(*Literal) 460 // 2.1) 461 result := make(map[string]interface{}, 0) 462 // 2.2) 463 var convertedValue interface{} 464 convertedValue = valueLiteral.Value 465 // 2.3) 466 var typeValue interface{} 467 typeValue = nil 468 // 2.4) 469 if useNativeTypes { 470 // 2.4.1) 471 if valueLiteral.Datatype.RawValue() == XSD_STRING { 472 //TODO java version is different and does not add 473 //string to result in this case 474 //does nothing 475 // 2.4.2) 476 } else if valueLiteral.Datatype.RawValue() == XSD_BOOLEAN { 477 if convertedValue == "true" { 478 convertedValue = true 479 } else if convertedValue == "false" { 480 convertedValue = false 481 } 482 // 2.4.3) 483 } else if valueLiteral.Datatype.RawValue() == XSD_DOUBLE || 484 valueLiteral.Datatype.RawValue() == XSD_INTEGER { 485 floatValue, floatErr := strconv.ParseFloat(convertedValue.(string), 64) 486 if isNil(floatErr) { 487 convertedValue = floatValue 488 } 489 } else { 490 typeValue = valueLiteral.Datatype.RawValue() 491 } 492 // 2.5) 493 } else if valueLiteral.Language != "" { 494 result["@language"] = valueLiteral.Language 495 // 2.6) 496 } else { 497 if valueLiteral.Datatype.RawValue() != XSD_STRING { 498 typeValue = valueLiteral.Datatype.RawValue() 499 } 500 } 501 // 2.7) 502 result["@value"] = convertedValue 503 // 2.8) 504 if !isNil(typeValue) { 505 result["@type"] = typeValue 506 } 507 // 2.9) 508 return result 509} 510