66# Email: stefan.stratulat1997@gmail.com
77
88import io
9+ import json
10+ import pathlib
911from abc import ABC , abstractmethod
1012from pathlib import Path
1113from string import Template
1214
1315import pandas as pd
14- from SPARQLWrapper import SPARQLWrapper , CSV , JSON
16+ import rdflib
17+ from SPARQLWrapper import SPARQLWrapper , CSV , JSON , RDF
1518
1619DEFAULT_ENCODING = 'utf-8'
20+ DEFAULT_RDF_FILE_FORMAT = "n3"
1721
1822
1923class SubstitutionTemplate (Template ):
@@ -40,7 +44,6 @@ class TripleStoreEndpointABC(ABC):
4044 This class provides an abstraction for a TripleStore.
4145 """
4246
43- @abstractmethod
4447 def with_query (self , sparql_query : str , substitution_variables : dict = None ,
4548 sparql_prefixes : str = "" ) -> 'TripleStoreEndpointABC' :
4649 """
@@ -50,15 +53,32 @@ def with_query(self, sparql_query: str, substitution_variables: dict = None,
5053 :param sparql_prefixes:
5154 :return:
5255 """
56+ if substitution_variables :
57+ template_query = SubstitutionTemplate (sparql_query )
58+ sparql_query = template_query .safe_substitute (substitution_variables )
59+
60+ sparql_query = (sparql_prefixes + " " + sparql_query ).strip ()
61+ self ._set_sparql_query (sparql_query = sparql_query )
62+ return self
5363
54- @abstractmethod
5564 def with_query_from_file (self , sparql_query_file_path : str , substitution_variables : dict = None ,
56- prefixes : str = "" ) -> 'TripleStoreEndpointABC' :
65+ sparql_prefixes : str = "" ) -> 'TripleStoreEndpointABC' :
5766 """
5867 This method will read a query from a file
5968 :param sparql_query_file_path:
6069 :param substitution_variables:
61- :param prefixes:
70+ :param sparql_prefixes:
71+ :return:
72+ """
73+ sparql_query = Path (sparql_query_file_path ).resolve ().read_text (encoding = "utf-8" )
74+ return self .with_query (sparql_query = sparql_query , substitution_variables = substitution_variables ,
75+ sparql_prefixes = sparql_prefixes )
76+
77+ @abstractmethod
78+ def _set_sparql_query (self , sparql_query : str ):
79+ """
80+ This method is used to set sparql query for future query operation.
81+ :param sparql_query:
6282 :return:
6383 """
6484
@@ -76,45 +96,27 @@ def fetch_tree(self) -> dict:
7696 :return:
7797 """
7898
79-
80- class SPARQLTripleStoreEndpoint (TripleStoreEndpointABC ):
81-
82- def __init__ (self , endpoint_url : str ):
83- self .endpoint = SPARQLClientPool .create_or_reuse_connection (endpoint_url )
84-
85- def with_query (self , sparql_query : str , substitution_variables : dict = None ,
86- sparql_prefixes : str = "" ) -> TripleStoreEndpointABC :
99+ @abstractmethod
100+ def fetch_rdf (self ) -> rdflib .Graph :
87101 """
88- Set the query text and return the reference to self for chaining.
102+ This method will return the result of the SPARQL query in a RDF format,
103+ use this method only for SPARQL queries of type CONSTRUCT.
89104 :return:
90105 """
91- if substitution_variables :
92- template_query = SubstitutionTemplate (sparql_query )
93- sparql_query = template_query .safe_substitute (substitution_variables )
94106
95- new_query = (sparql_prefixes + " " + sparql_query ).strip ()
96107
97- self .endpoint .setQuery (new_query )
98- return self
108+ class SPARQLTripleStoreEndpoint (TripleStoreEndpointABC ):
99109
100- def with_query_from_file (self , sparql_query_file_path : str , substitution_variables : dict = None ,
101- prefixes : str = "" ) -> TripleStoreEndpointABC :
110+ def __init__ (self , endpoint_url : str ):
111+ self .endpoint = SPARQLClientPool .create_or_reuse_connection (endpoint_url )
112+
113+ def _set_sparql_query (self , sparql_query : str ):
102114 """
103- Set the query text and return the reference to self for chaining.
115+ This method is used to set sparql query for future query operation.
116+ :param sparql_query:
104117 :return:
105118 """
106-
107- with open (Path (sparql_query_file_path ).resolve (), 'r' ) as file :
108- query_from_file = file .read ()
109-
110- if substitution_variables :
111- template_query = SubstitutionTemplate (query_from_file )
112- query_from_file = template_query .safe_substitute (substitution_variables )
113-
114- new_query = (prefixes + " " + query_from_file ).strip ()
115-
116- self .endpoint .setQuery (new_query )
117- return self
119+ self .endpoint .setQuery (sparql_query )
118120
119121 def fetch_tabular (self ) -> pd .DataFrame :
120122 """
@@ -139,5 +141,71 @@ def fetch_tree(self):
139141 self .endpoint .setReturnFormat (JSON )
140142 return self .endpoint .queryAndConvert ()
141143
144+ def fetch_rdf (self ) -> rdflib .Graph :
145+ """
146+ This method will return the result of the SPARQL query in a RDF format,
147+ use this method only for SPARQL queries of type CONSTRUCT or DESCRIBE.
148+ :return:
149+ """
150+ self .endpoint .setReturnFormat (RDF )
151+ return self .endpoint .queryAndConvert ()
152+
142153 def __str__ (self ):
143154 return f"from <...{ str (self .endpoint .endpoint )[- 30 :]} > { str (self .endpoint .queryString )[:60 ]} ..."
155+
156+
157+ class SPARQLStringEndpoint (TripleStoreEndpointABC ):
158+ """
159+ This class is specialized to query an RDF string content using SPARQL queries.
160+ """
161+
162+ def __init__ (self , rdf_content : str , rdf_content_format : str = DEFAULT_RDF_FILE_FORMAT ):
163+ self .graph = rdflib .Graph ()
164+ self .graph .parse (data = rdf_content , format = rdf_content_format )
165+ self .sparql_query = None
166+
167+ def _set_sparql_query (self , sparql_query : str ):
168+ """
169+ This method is used to set sparql query for future query operation.
170+ :param sparql_query:
171+ :return:
172+ """
173+ self .sparql_query = sparql_query
174+
175+ def fetch_tabular (self ) -> pd .DataFrame :
176+ """
177+ Get query results in a tabular format
178+ :return:
179+ """
180+ query_result = self .graph .query (query_object = self .sparql_query )
181+ return pd .DataFrame (data = query_result , columns = [str (var ) for var in query_result .vars ])
182+
183+ def fetch_tree (self ) -> dict :
184+ """
185+ Get query results in a dict format
186+ :return:
187+ """
188+ query_result = self .graph .query (query_object = self .sparql_query )
189+ return json .loads (query_result .serialize (format = "json" ))
190+
191+ def fetch_rdf (self ) -> rdflib .Graph :
192+ """
193+ This method will return the result of the SPARQL query in a RDF format,
194+ use this method only for SPARQL queries of type CONSTRUCT or DESCRIBE.
195+ :return:
196+ """
197+ query_result = self .graph .query (query_object = self .sparql_query )
198+ if query_result .type in ("CONSTRUCT" , "DESCRIBE" ):
199+ return query_result .graph
200+ else :
201+ raise Exception ("Fetch RDF method work only with CONSTRUCT and DESCRIBE sparql queries!" )
202+
203+
204+ class SPARQLFileEndpoint (SPARQLStringEndpoint ):
205+ """
206+ This class is specialized to query an RDF file using SPARQL queries.
207+ """
208+
209+ def __init__ (self , rdf_file_path : pathlib .Path ):
210+ rdf_content = rdf_file_path .read_text (encoding = "utf-8" )
211+ super ().__init__ (rdf_content )
0 commit comments