Fork of https://github.com/oxigraph/oxigraph.git for the purpose of NextGraph project
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
5.6 KiB
163 lines
5.6 KiB
use std::fmt;
|
|
|
|
/// [SPARQL query](https://www.w3.org/TR/sparql11-query/) results serialization formats.
|
|
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
|
|
#[non_exhaustive]
|
|
pub enum QueryResultsFormat {
|
|
/// [SPARQL Query Results XML Format](https://www.w3.org/TR/rdf-sparql-XMLres/)
|
|
Xml,
|
|
/// [SPARQL Query Results JSON Format](https://www.w3.org/TR/sparql11-results-json/)
|
|
Json,
|
|
/// [SPARQL Query Results CSV Format](https://www.w3.org/TR/sparql11-results-csv-tsv/)
|
|
Csv,
|
|
/// [SPARQL Query Results TSV Format](https://www.w3.org/TR/sparql11-results-csv-tsv/)
|
|
Tsv,
|
|
}
|
|
|
|
impl QueryResultsFormat {
|
|
/// The format canonical IRI according to the [Unique URIs for file formats registry](https://www.w3.org/ns/formats/).
|
|
///
|
|
/// ```
|
|
/// use sparesults::QueryResultsFormat;
|
|
///
|
|
/// assert_eq!(QueryResultsFormat::Json.iri(), "http://www.w3.org/ns/formats/SPARQL_Results_JSON")
|
|
/// ```
|
|
#[inline]
|
|
pub fn iri(self) -> &'static str {
|
|
match self {
|
|
Self::Xml => "http://www.w3.org/ns/formats/SPARQL_Results_XML",
|
|
Self::Json => "http://www.w3.org/ns/formats/SPARQL_Results_JSON",
|
|
Self::Csv => "http://www.w3.org/ns/formats/SPARQL_Results_CSV",
|
|
Self::Tsv => "http://www.w3.org/ns/formats/SPARQL_Results_TSV",
|
|
}
|
|
}
|
|
/// The format [IANA media type](https://tools.ietf.org/html/rfc2046).
|
|
///
|
|
/// ```
|
|
/// use sparesults::QueryResultsFormat;
|
|
///
|
|
/// assert_eq!(QueryResultsFormat::Json.media_type(), "application/sparql-results+json")
|
|
/// ```
|
|
#[inline]
|
|
pub fn media_type(self) -> &'static str {
|
|
match self {
|
|
Self::Xml => "application/sparql-results+xml",
|
|
Self::Json => "application/sparql-results+json",
|
|
Self::Csv => "text/csv; charset=utf-8",
|
|
Self::Tsv => "text/tab-separated-values; charset=utf-8",
|
|
}
|
|
}
|
|
|
|
/// The format [IANA-registered](https://tools.ietf.org/html/rfc2046) file extension.
|
|
///
|
|
/// ```
|
|
/// use sparesults::QueryResultsFormat;
|
|
///
|
|
/// assert_eq!(QueryResultsFormat::Json.file_extension(), "srj")
|
|
/// ```
|
|
#[inline]
|
|
pub fn file_extension(self) -> &'static str {
|
|
match self {
|
|
Self::Xml => "srx",
|
|
Self::Json => "srj",
|
|
Self::Csv => "csv",
|
|
Self::Tsv => "tsv",
|
|
}
|
|
}
|
|
|
|
/// The format name.
|
|
///
|
|
/// ```
|
|
/// use sparesults::QueryResultsFormat;
|
|
///
|
|
/// assert_eq!(QueryResultsFormat::Json.name(), "SPARQL Results in JSON")
|
|
/// ```
|
|
#[inline]
|
|
pub const fn name(self) -> &'static str {
|
|
match self {
|
|
Self::Xml => "SPARQL Results in XML",
|
|
Self::Json => "SPARQL Results in JSON",
|
|
Self::Csv => "SPARQL Results in CSV",
|
|
Self::Tsv => "SPARQL Results in TSV",
|
|
}
|
|
}
|
|
|
|
/// Looks for a known format from a media type.
|
|
///
|
|
/// It supports some media type aliases.
|
|
/// For example, "application/xml" is going to return `Xml` even if it is not its canonical media type.
|
|
///
|
|
/// Example:
|
|
/// ```
|
|
/// use sparesults::QueryResultsFormat;
|
|
///
|
|
/// assert_eq!(QueryResultsFormat::from_media_type("application/sparql-results+json; charset=utf-8"), Some(QueryResultsFormat::Json))
|
|
/// ```
|
|
#[inline]
|
|
pub fn from_media_type(media_type: &str) -> Option<Self> {
|
|
const MEDIA_SUBTYPES: [(&str, QueryResultsFormat); 8] = [
|
|
("csv", QueryResultsFormat::Csv),
|
|
("json", QueryResultsFormat::Json),
|
|
("plain", QueryResultsFormat::Csv),
|
|
("sparql-results+json", QueryResultsFormat::Json),
|
|
("sparql-results+xml", QueryResultsFormat::Xml),
|
|
("tab-separated-values", QueryResultsFormat::Tsv),
|
|
("tsv", QueryResultsFormat::Tsv),
|
|
("xml", QueryResultsFormat::Xml),
|
|
];
|
|
|
|
let (r#type, subtype) = media_type
|
|
.split_once(';')
|
|
.unwrap_or((media_type, ""))
|
|
.0
|
|
.trim()
|
|
.split_once('/')?;
|
|
let r#type = r#type.trim();
|
|
if !r#type.eq_ignore_ascii_case("application") && !r#type.eq_ignore_ascii_case("text") {
|
|
return None;
|
|
}
|
|
let subtype = subtype.trim();
|
|
let subtype = subtype.strip_prefix("x-").unwrap_or(subtype);
|
|
for (candidate_subtype, candidate_id) in MEDIA_SUBTYPES {
|
|
if candidate_subtype.eq_ignore_ascii_case(subtype) {
|
|
return Some(candidate_id);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
/// Looks for a known format from an extension.
|
|
///
|
|
/// It supports some aliases.
|
|
///
|
|
/// Example:
|
|
/// ```
|
|
/// use sparesults::QueryResultsFormat;
|
|
///
|
|
/// assert_eq!(QueryResultsFormat::from_extension("json"), Some(QueryResultsFormat::Json))
|
|
/// ```
|
|
#[inline]
|
|
pub fn from_extension(extension: &str) -> Option<Self> {
|
|
const MEDIA_TYPES: [(&str, QueryResultsFormat); 7] = [
|
|
("csv", QueryResultsFormat::Csv),
|
|
("json", QueryResultsFormat::Json),
|
|
("srj", QueryResultsFormat::Json),
|
|
("srx", QueryResultsFormat::Xml),
|
|
("tsv", QueryResultsFormat::Tsv),
|
|
("txt", QueryResultsFormat::Csv),
|
|
("xml", QueryResultsFormat::Xml),
|
|
];
|
|
for (candidate_extension, candidate_id) in MEDIA_TYPES {
|
|
if candidate_extension.eq_ignore_ascii_case(extension) {
|
|
return Some(candidate_id);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for QueryResultsFormat {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.write_str(self.name())
|
|
}
|
|
}
|
|
|