Skip to content

Commit a450045

Browse files
authored
Merge pull request #42 from anusii/zy/41_exception_parsing_container
Zy/41 exception parsing container
2 parents db9c6dc + 53ba5f8 commit a450045

File tree

5 files changed

+173
-85
lines changed

5 files changed

+173
-85
lines changed

example/example_5.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import 'dart:io';
2+
3+
import 'package:rdflib/rdflib.dart';
4+
5+
main() async {
6+
String filePath = 'example/sample_ttl_5.ttl';
7+
// Read file content to a local String
8+
String fileContents = await File(filePath).readAsStringSync();
9+
10+
print('-------Original file-------\n$fileContents');
11+
12+
// create a graph to read turtle file and store info
13+
Graph g = Graph();
14+
15+
// Parse with the new method [Graph.parseTurtle] instead of [Graph.parse] (deprecated)
16+
g.parseTurtle(fileContents);
17+
18+
// Serialize the Graph for output
19+
g.serialize(format: 'ttl', abbr: 'short');
20+
print('-------Serialized String--------\n${g.serializedString}');
21+
22+
// Print out full format of triples (will use shorthand in serialization/export)
23+
print('--------All triples in the graph-------');
24+
for (Triple t in g.triples) {
25+
print(t);
26+
}
27+
}

example/sample_ttl_5.ttl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@prefix dc: <http://purl.org/dc/terms/>.
2+
@prefix ldp: <http://www.w3.org/ns/ldp#>.
3+
@prefix posix: <http://www.w3.org/ns/posix/stat#>.
4+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
5+
6+
<> <urn:npm:solid:community-server:meta:contentTypeParameter> _:b22466_b12514_b12510_n3-564;
7+
a ldp:Container, ldp:BasicContainer, ldp:Resource;
8+
dc:modified "2024-07-10T00:36:05.000Z"^^xsd:dateTime.
9+
_:b22466_b12514_b12510_n3-564 <http://www.w3.org/2000/01/rdf-schema#label> "charset";
10+
<urn:npm:solid:community-server:meta:value> "utf-8".
11+
<ind-keys.ttl> a ldp:Resource, <http://www.w3.org/ns/iana/media-types/text/turtle#Resource>;
12+
dc:modified "2024-07-10T04:54:04.000Z"^^xsd:dateTime.
13+
<enc-keys.ttl> a ldp:Resource, <http://www.w3.org/ns/iana/media-types/text/turtle#Resource>;
14+
dc:modified "2024-06-27T12:01:32.000Z"^^xsd:dateTime.
15+
<> posix:mtime 1720571765;
16+
ldp:contains <ind-keys.ttl>, <enc-keys.ttl>.
17+
<ind-keys.ttl> posix:mtime 1720587244;
18+
posix:size 941.
19+
<enc-keys.ttl> posix:mtime 1719489692;
20+
posix:size 2703.

lib/src/graph.dart

Lines changed: 96 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,19 @@ class Graph {
6666
void addTripleToGroups(dynamic s, dynamic p, dynamic o) {
6767
// TODO: subject as a BlankNode
6868
try {
69-
URIRef sub = (s.runtimeType == URIRef) ? s : item(s) as URIRef;
69+
dynamic sub =
70+
(s.runtimeType == URIRef || s.runtimeType == BNode) ? s : item(s);
7071
_updateCtx(sub, ctx);
7172
if (!groups.containsKey(sub)) {
7273
groups[sub] = Map();
7374
}
74-
URIRef pre = (p.runtimeType == URIRef) ? p : item(p) as URIRef;
75+
dynamic pre = (p.runtimeType == URIRef) ? p : item(p);
7576
_updateCtx(pre, ctx);
7677
if (!groups[sub]!.containsKey(pre)) {
7778
groups[sub]![pre] = Set();
7879
}
79-
// var obj = (o.runtimeType == URIRef) ? o : item(o);
8080
var obj = (o.runtimeType == String) ? item(o) : o;
81-
if (obj.runtimeType == URIRef) {
81+
if (obj.runtimeType == URIRef || obj.runtimeType == BNode) {
8282
_updateCtx(obj, ctx);
8383
} else if (obj.runtimeType == Literal) {
8484
Literal objLiteral = obj as Literal;
@@ -88,8 +88,8 @@ class Graph {
8888
} else if (obj.runtimeType == String) {
8989
_updateCtx(XSD.string, ctx);
9090
}
91+
// Updates triple sets as well.
9192
groups[sub]![pre]!.add(obj);
92-
// Update the triples set as well.
9393
triples.add(Triple(sub: sub, pre: pre, obj: obj));
9494
} catch (e) {
9595
print('Error occurred when adding triple ($s, $p, $o), '
@@ -688,22 +688,22 @@ class Graph {
688688
return;
689689
}
690690
List tripleContent = tripleList[0];
691-
URIRef sub = item(tripleContent[0]) as URIRef;
691+
dynamic sub = item(tripleContent[0]);
692692
if (!groups.containsKey(sub)) {
693693
groups[sub] = Map();
694694
}
695695
List predicateObjectLists = tripleContent[1];
696696
for (List predicateObjectList in predicateObjectLists) {
697697
// Predicate is always an iri.
698698
// Uses URIRef as we translate PrefixedName to full form of [URIRef]
699-
URIRef pre;
700-
pre = item(predicateObjectList[0]);
701-
// Use a set to store the triples.
699+
dynamic pre = item(predicateObjectList[0]);
702700
groups[sub]![pre] = Set();
703701
List objectList = predicateObjectList[1];
704-
for (String obj in objectList) {
705-
groups[sub]![pre]!.add(item(obj));
706-
triples.add(Triple(sub: sub, pre: pre, obj: item(obj)));
702+
for (var obj in objectList) {
703+
var parsedObj =
704+
(obj is List) ? item(_combineListItems(obj)) : item(obj);
705+
groups[sub]![pre]!.add(parsedObj);
706+
triples.add(Triple(sub: sub, pre: pre, obj: parsedObj));
707707
}
708708
}
709709
}
@@ -730,83 +730,79 @@ class Graph {
730730
/// Case 4: abc^^xsd:string -> Literal('abc', datatype:xsd:string)
731731
/// Case 5: abc@en -> Literal('abc', lang:'en')
732732
/// Case 6: abc -> Literal('abc')
733-
item(String s) {
734-
s = s.trim();
735-
// 0. a is short for rdf:type
736-
if (s == 'a') {
737-
_saveToContext(['@prefix', 'rdf:', '<${RDF.rdf}>']);
738-
return a;
739-
}
740-
// 1. <>
741-
else if (s.startsWith('<') && s.endsWith('>')) {
742-
String uri = s.substring(1, s.length - 1);
743-
if (URIRef.isValidUri(uri)) {
744-
// Valid uri is sufficient as URIRef.
733+
item(dynamic s) {
734+
if (s is String) {
735+
s = s.trim();
736+
737+
// 0. a is short for rdf:type
738+
if (s == 'a') {
739+
_saveToContext(['@prefix', 'rdf:', '<${RDF.rdf}>']);
740+
return a;
741+
}
742+
// 1. <>
743+
else if (s.startsWith('<') && s.endsWith('>')) {
744+
String uri = s.substring(1, s.length - 1);
745745
return URIRef(uri);
746-
} else {
747-
if (ctx.containsKey(':')) {
748-
// FIXME: if context has base, do we need to stitch them?
749-
// Examples:
750-
// 1. <> -> URIRef('')
751-
// 2. <./> -> URIRef('./')
752-
// 3. <bob#me> -> e.g., URIRef('http://example.org/bob#me')
753-
// or just URIRef('bob#m3') [current implementation]?
754-
return URIRef(uri);
755-
// return URIRef('${ctx[':']!.value}${uri}');
756-
} else {
757-
return URIRef(uri); // or it's just a string within <>
746+
}
747+
// 4. abc^^xsd:string
748+
// Note this needs to come before :abc or abc:efg cases.
749+
else if (s.contains('^^')) {
750+
List<String> lst = s.split('^^');
751+
String value = lst[0];
752+
String datatype = lst[1];
753+
// Note: Literal only supports XSD, OWL namespaces currently
754+
return Literal(value, datatype: item(datatype));
755+
}
756+
// 2. :abc
757+
else if (s.startsWith(':')) {
758+
// When using @base.
759+
if (ctx[':'] == null) {
760+
throw Exception('Base is not defined yet. (caused by $s)');
758761
}
762+
return URIRef('${ctx[":"]!.value}${s.substring(1)}');
759763
}
760-
}
761-
// 4. abc^^xsd:string
762-
// Note this needs to come before :abc or abc:efg cases.
763-
else if (s.contains('^^')) {
764-
List<String> lst = s.split('^^');
765-
String value = lst[0];
766-
String datatype = lst[1];
767-
// Note: Literal only supports XSD, OWL namespaces currently
768-
return Literal(value, datatype: item(datatype));
769-
}
770-
// 2. :abc
771-
else if (s.startsWith(':')) {
772-
// When using @base.
773-
if (ctx[':'] == null) {
774-
throw Exception('Base is not defined yet. (caused by $s)');
764+
// 3. abc:efg
765+
else if (s.contains(':') && !s.startsWith('_:')) {
766+
// When using @prefix
767+
int firstColonPos = s.indexOf(':');
768+
String namespace = s.substring(0, firstColonPos + 1); // including ':'
769+
String localname = s.substring(firstColonPos + 1);
770+
// If the namespace is not defined, we can't proceed.
771+
if (ctx[namespace] == null) {
772+
throw Exception(
773+
'Namespace ${namespace.substring(0, namespace.length - 1)} is used '
774+
'but not defined. (caused by $s)');
775+
}
776+
return URIRef('${ctx[namespace]?.value}$localname');
775777
}
776-
return URIRef('${ctx[":"]!.value}${s.substring(1)}');
777-
}
778-
// 3. abc:efg
779-
else if (s.contains(':')) {
780-
// When using @prefix
781-
int firstColonPos = s.indexOf(':');
782-
String namespace = s.substring(0, firstColonPos + 1); // including ':'
783-
String localname = s.substring(firstColonPos + 1);
784-
// If the namespace is not defined, we can't proceed.
785-
if (ctx[namespace] == null) {
786-
throw Exception(
787-
'Namespace ${namespace.substring(0, namespace.length - 1)} is used '
788-
'but not defined. (caused by $s)');
778+
// 5. abc@en
779+
else if (_existsLangTag(s)) {
780+
String lang = _getLangTag(s);
781+
String value = s.replaceAll('@$lang', '');
782+
return Literal(value, lang: lang);
789783
}
790-
return URIRef('${ctx[namespace]?.value}$localname');
791-
}
792-
// 5. abc@en
793-
else if (_existsLangTag(s)) {
794-
String lang = _getLangTag(s);
795-
String value = s.replaceAll('@$lang', '');
796-
return Literal(value, lang: lang);
797-
}
798-
// AV-20240621: commenting the following and adding above
799-
// as the following will identify non language tags as well
800-
// else if (s.contains('@')) {
801-
// List<String> lst = s.split('@');
802-
// String value = lst[0];
803-
// String lang = lst[1];
804-
// return Literal(value, lang: lang);
805-
// }
806-
// 6. abc
807-
else {
808-
// Treat it as a normal string.
809-
return Literal(s);
784+
// AV-20240621: commenting the following and adding above
785+
// as the following will identify non language tags as well
786+
// else if (s.contains('@')) {
787+
// List<String> lst = s.split('@');
788+
// String value = lst[0];
789+
// String lang = lst[1];
790+
// return Literal(value, lang: lang);
791+
// }
792+
// 6. _:
793+
else if (s.startsWith('_:')) {
794+
return BNode(s);
795+
} else {
796+
// Treat it as a normal string.
797+
return Literal(s);
798+
}
799+
} else if (s is List) {
800+
// Combine all items and sub-items in the list into a single string.
801+
String combinedString = _combineListItems(s);
802+
if (combinedString.startsWith('_:')) {
803+
return BNode(combinedString);
804+
}
805+
return item(combinedString);
810806
}
811807
}
812808

@@ -1064,4 +1060,20 @@ class Graph {
10641060
String _getLangTag(String literal) {
10651061
return langTags.firstWhere((element) => literal.contains('@$element'));
10661062
}
1063+
1064+
/// Recursively combines all items in a list and its sub-items into a single string.
1065+
///
1066+
/// This function traverses a list and concatenates all its elements,
1067+
/// including elements of nested lists, into a single string.
1068+
/// It handles various data types by converting them to their string representations.
1069+
///
1070+
String _combineListItems(dynamic item) {
1071+
if (item is List) {
1072+
// Recursively call combineListItems on each sub-item and join them into a single string.
1073+
return item.map((subItem) => _combineListItems(subItem)).join('');
1074+
} else {
1075+
// Convert non-list item to a string.
1076+
return item.toString();
1077+
}
1078+
}
10671079
}

lib/src/term.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import 'package:logging/logging.dart';
2+
import 'package:uuid/uuid.dart' as uuid;
3+
24
import './namespace.dart';
35

46
Logger logger = Logger('term');
@@ -196,3 +198,29 @@ class Literal {
196198
}
197199
}
198200
}
201+
202+
/// Represents a blank node in an RDF graph.
203+
///
204+
/// A blank node is an anonymous resource that does not have a URI.
205+
/// It is used to represent complex structures and relationships
206+
/// without assigning a global identifier.
207+
class BNode extends URIRef {
208+
static final uuid.Uuid _uuid = uuid.Uuid();
209+
210+
/// Creates a blank node with an optional identifier.
211+
///
212+
/// If no identifier is provided, a unique identifier is generated.
213+
BNode([String? id]) : super(_generateBNodeId(id));
214+
215+
/// Generates a unique identifier for a blank node.
216+
///
217+
/// The identifier is based on a UUID if not provided.
218+
static String _generateBNodeId([String? id]) {
219+
return id ?? '_:' + _uuid.v4();
220+
}
221+
222+
@override
223+
String toString() {
224+
return 'BNode($value)';
225+
}
226+
}

pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ dependencies:
1111
logging: ^1.1.0
1212
petitparser: ^6.0.1
1313
http: ^1.1.0
14-
14+
uuid: ^4.4.1
15+
1516
dev_dependencies:
1617
lints: ^2.0.1
1718
test: ^1.22.0

0 commit comments

Comments
 (0)