1- import rdf from 'rdf-ext' ;
21import { readRDF } from '../modules/io'
32import { RDF , XSD } from '../modules/namespaces' ;
43import { toCURIE } from '../modules/utils' ;
5- import formatsPretty from '@rdfjs/formats/pretty.js'
4+ import { Store , Writer , DataFactory } from 'n3' ;
5+ const { namedNode, literal } = DataFactory ;
66
77/**
88 * A class wrapping an RDF dataset (quad-store) from the `rdf-ext` library.
@@ -13,8 +13,6 @@ export class RdfDataset {
1313 */
1414 constructor ( data = { } ) {
1515 this . data = data ;
16- this . rdfPretty = rdf . clone ( ) ;
17- this . rdfPretty . formats . import ( formatsPretty ) ;
1816 this . data . prefixes = { } ;
1917 this . data . serializedGraph = '' ;
2018 this . data . graphLoaded = false ;
@@ -37,11 +35,11 @@ export class RdfDataset {
3735
3836 /**
3937 * Create a quad store compliant with the [RDF/JS dataset specification](https://rdf.js.org/dataset-spec/)
40- * via the `rdf-ext ` package
41- * @returns {import("rdf-ext").DatasetCore } The RDF dataset instance.
38+ * via the `n3 ` package
39+ * @returns { } The RDF dataset instance.
4240 */
4341 createDataset ( ) {
44- return rdf . dataset ( )
42+ return new Store ( ) ;
4543 }
4644 /**
4745 * Loads RDF data from a given URL and processes prefixes and quads.
@@ -60,16 +58,14 @@ export class RdfDataset {
6058 // Load prefixes
6159 quadStream . on ( 'prefix' , ( prefix , ns ) => {
6260 this . onPrefixFn ( prefix , ns )
61+ } ) . on ( 'data' , quad => {
62+ this . onDataFn ( quad )
6363 } ) . on ( 'end' , ( ) => {
64+ this . onDataEndFn ( )
6465 this . onPrefixEndFn ( )
65- } )
66- // Load data
67- quadStream . on ( 'data' , quad => {
68- this . onDataFn ( quad )
69- } ) . on ( 'end' , async ( ) => {
70- await this . onDataEndFn ( )
66+ } ) . on ( 'error' , err => {
67+ console . error ( 'Error while processing quadStream:' , err ) ;
7168 } ) ;
72-
7369 return result
7470 }
7571
@@ -83,7 +79,7 @@ export class RdfDataset {
8379 /**
8480 * Process an RDF prefix.
8581 * @param {string } prefix - The prefix string.
86- * @param {import("rdf-ext").NamedNode } ns - The namespace associated with the prefix.
82+ * @param { } ns - The namespace associated with the prefix.
8783 */
8884 onPrefixFn ( prefix , ns ) {
8985 this . data . prefixes [ prefix ] = ns . value ;
@@ -96,63 +92,65 @@ export class RdfDataset {
9692
9793 /**
9894 * Process an RDF quad
99- * @param {import("rdf-ext").Quad } quad - The RDF quad.
95+ * @param { } quad - The RDF quad.
10096 */
10197 onDataFn ( quad ) {
10298 // The first following line, moved here from shacl-vue's graphdata composable,
10399 // was an attempt to solve https://hub.datalad.org/datalink/annotate-trr379-demo/issues/32.
104100 // But it was a faulty attempt, since the object was different. Still, leaving it here since
105101 // deleting matches would prospectively solve the duplication of named node or literal objects
106- this . data . graph . deleteMatches ( quad . subject , quad . predicate , quad . object , null )
102+ // this.data.graph.removeMatches (quad.subject, quad.predicate, quad.object, null)
107103 this . addQuad ( quad )
108104 this . dispatchEvent ( new CustomEvent ( 'quad' , { detail : quad } ) ) ;
109105 }
110- async onDataEndFn ( ) {
111- await this . updateSerializedGraph ( )
106+
107+ onDataEndFn ( ) {
112108 this . data . graphLoaded = true
113109 this . dispatchEvent ( new CustomEvent ( 'graphLoaded' , { detail : this . data . graph } ) ) ;
114110 }
115111
116112 /**
117113 * Add an RDF quad to the dataset
118- * @param {import("rdf-ext").Quad } quad - The RDF quad to add.
114+ * @param { } quad - The RDF quad to add.
119115 */
120116 addQuad ( quad ) {
121- this . data . graph . add ( quad )
117+ this . data . graph . addQuad ( quad )
122118 }
123119
124120 /**
125121 * Serializes the RDF graph to Turtle format.
126122 * @returns {Promise<string> } The serialized RDF graph in Turtle format.
127123 */
128124 async serializeGraph ( ) {
129- return ( await this . rdfPretty . io . dataset . toText ( 'text/turtle' , this . data . graph ) ) . trim ( )
130- }
131-
132- async updateSerializedGraph ( ) {
133- this . data . serializedGraph = ( await this . rdfPretty . io . dataset . toText ( 'text/turtle' , this . data . graph ) ) . trim ( )
125+ // Using N3.Writer to serialize graph to Turtle
126+ return new Promise ( ( resolve , reject ) => {
127+ const writer = new Writer ( { prefixes : this . data . prefixes } ) ;
128+ writer . addQuads ( this . data . graph . getQuads ( null , null , null , null ) ) ;
129+ writer . end ( ( error , result ) => {
130+ if ( error ) reject ( error ) ;
131+ else resolve ( result . trim ( ) ) ;
132+ } ) ;
133+ } ) ;
134134 }
135135
136136 /**
137137 * Checks if a given RDF node represents an RDF list.
138- * @param {import("rdf-ext").Term } node - The RDF node to check.
138+ * @param { } node - The RDF node to check.
139139 * @returns {boolean } True if the node represents an RDF list, otherwise false.
140140 */
141141 isRdfList ( node ) {
142142 let hasFirst = false ;
143143 let hasRest = false ;
144- this . data . graph . forEach ( ( quad ) => {
145- if ( quad . subject . equals ( node ) ) {
146- if ( quad . predicate . value === RDF . first . value ) hasFirst = true ;
147- if ( quad . predicate . value === RDF . rest . value ) hasRest = true ;
148- }
144+ this . data . graph . getQuads ( node , null , null , null ) . forEach ( ( quad ) => {
145+ if ( quad . predicate . value === RDF . first . value ) hasFirst = true ;
146+ if ( quad . predicate . value === RDF . rest . value ) hasRest = true ;
149147 } ) ;
150148 return hasFirst && hasRest ;
151149 } ;
152150
153151 /**
154152 * Converts an RDF list to an array.
155- * @param {import("rdf-ext").Term } startNode - The starting node of the RDF list.
153+ * @param { } startNode - The starting node of the RDF list.
156154 * @returns {Array } The converted RDF list as an array.
157155 */
158156 rdfListToArray ( startNode ) {
@@ -161,79 +159,55 @@ export class RdfDataset {
161159 while ( currentNode && currentNode . value !== RDF . nil . value ) {
162160 let listItem = null ;
163161 // Get the first element in the RDF list
164- this . data . graph . forEach ( ( quad ) => {
165- if ( quad . subject . equals ( currentNode ) && quad . predicate . value === RDF . first . value ) {
166- // Resolve blank nodes recursively, but handle literals and IRIs separately
167- if ( quad . object . termType === "BlankNode" ) {
168- listItem = this . resolveBlankNode ( quad . object , this . data . graph ) ;
169- } else if ( quad . object . termType === "Literal" ) {
170- listItem = quad . object . value ; // Store literal value
171- } else if ( quad . object . termType === "NamedNode" ) {
172- listItem = quad . object . value ; // Store IRI as a string
162+ this . data . graph . getQuads ( currentNode , RDF . first , null , null ) . forEach ( quad => {
163+ if ( quad . object . termType === 'BlankNode' ) {
164+ if ( this . isRdfList ( quad . object ) ) {
165+ listItem = this . rdfListToArray ( quad . object ) ;
166+ } else {
167+ listItem = this . resolveBlankNode ( quad . object ) ;
173168 }
169+ } else if ( quad . object . termType === 'Literal' || quad . object . termType === 'NamedNode' ) {
170+ listItem = quad . object . value ;
174171 }
175172 } ) ;
176173 if ( listItem !== null ) {
177174 listItems . push ( listItem ) ;
178175 }
179176 // Move to the next item in the list (rdf:rest)
180- let nextNode = null ;
181- this . data . graph . forEach ( ( quad ) => {
182- if ( quad . subject . equals ( currentNode ) && quad . predicate . value === RDF . rest . value ) {
183- nextNode = quad . object ;
184- }
185- } ) ;
186- currentNode = nextNode ;
177+ const restQuads = this . data . graph . getQuads ( currentNode , RDF . rest , null , null ) ;
178+ currentNode = restQuads . length > 0 ? restQuads [ 0 ] . object : null ;
187179 }
188180 return listItems ;
189181 } ;
190182
191183 resolveBlankNode ( blankNode ) {
192184 let resolvedObject = { } ;
193- this . data . graph . forEach ( ( quad ) => {
194- if ( quad . subject . equals ( blankNode ) ) {
195- const predicate = quad . predicate . value ;
196- const object = quad . object ;
197-
198- // If the object is a blank node, resolve it recursively
199- if ( object . termType === "BlankNode" ) {
200- // Check if it's an RDF list and convert it to an array
201- if ( this . isRdfList ( object ) ) {
202- resolvedObject [ predicate ] = this . rdfListToArray ( object ) ;
203- } else {
204- resolvedObject [ predicate ] = this . resolveBlankNode ( object ) ;
205- }
206- } else if ( object . termType === "Literal" ) {
207- resolvedObject [ predicate ] = object . value ; // Handle literal values
208- } else if ( object . termType === "NamedNode" ) {
209- resolvedObject [ predicate ] = object . value ; // Handle IRIs as strings
185+ this . data . graph . getQuads ( blankNode , null , null , null ) . forEach ( ( { predicate, object } ) => {
186+ if ( object . termType === 'BlankNode' ) {
187+ if ( this . isRdfList ( object ) ) {
188+ resolvedObject [ predicate . value ] = this . rdfListToArray ( object ) ;
189+ } else {
190+ resolvedObject [ predicate . value ] = this . resolveBlankNode ( object ) ;
210191 }
192+ } else if ( object . termType === 'Literal' || object . termType === 'NamedNode' ) {
193+ resolvedObject [ predicate . value ] = object . value ;
211194 }
212195 } ) ;
213196 return resolvedObject ;
214197 }
215198
216199 getLiteralAndNamedNodes ( predicate , propertyClass , prefixes ) {
217200 var propClassCurie = toCURIE ( propertyClass , prefixes )
218- // a) use the literal node with xsd data type
219- const literalNodes = rdf . grapoi ( { dataset : this . data . graph } )
220- . hasOut ( predicate , rdf . literal ( String ( propClassCurie ) , XSD . anyURI ) )
221- . quads ( ) ;
222- // b) and the named node
223- const uriNodes = rdf . grapoi ( { dataset : this . data . graph } )
224- . hasOut ( predicate , rdf . namedNode ( propertyClass ) )
225- . quads ( ) ;
226- // return as a concatenated array of quads
227- return Array . from ( literalNodes ) . concat ( Array . from ( uriNodes ) )
201+ const literalQuads = this . data . graph . getQuads ( null , predicate , literal ( String ( propClassCurie ) , XSD . anyURI ) , null )
202+ const uriQuads = this . data . graph . getQuads ( null , predicate , namedNode ( propertyClass ) , null )
203+ return literalQuads . concat ( uriQuads )
228204 }
229205
230206 getSubjectTriples ( someTerm ) {
231- const quads = rdf . grapoi ( { dataset : this . data . graph , term : someTerm } ) . out ( ) . quads ( ) ;
232- return Array . from ( quads )
207+ return this . data . graph . getQuads ( someTerm , null , null , null ) ;
233208 }
234209
235210 getObjectTriples ( someTerm ) {
236- const quads = rdf . grapoi ( { dataset : this . data . graph , term : someTerm } ) . in ( ) . quads ( ) ;
237- return Array . from ( quads )
211+ return this . data . graph . getQuads ( null , null , someTerm , null ) ;
238212 }
239213}
0 commit comments