parent
06c0773e5a
commit
153eeb1033
@ -0,0 +1,123 @@ |
||||
//! Implementation of [SPARQL Query Results XML Format](https://www.w3.org/TR/sparql11-results-json/)
|
||||
|
||||
use crate::model::*; |
||||
use crate::sparql::model::*; |
||||
use crate::Result; |
||||
use failure::format_err; |
||||
use std::io::Write; |
||||
|
||||
pub fn write_json_results<W: Write>(results: QueryResult<'_>, mut sink: W) -> Result<W> { |
||||
match results { |
||||
QueryResult::Boolean(value) => { |
||||
sink.write_all(b"{\"head\":{},\"boolean\":")?; |
||||
sink.write_all(if value { b"true" } else { b"false" })?; |
||||
sink.write_all(b"}")?; |
||||
} |
||||
QueryResult::Bindings(bindings) => { |
||||
let (variables, results) = bindings.destruct(); |
||||
sink.write_all(b"{\"head\":{\"vars\":[")?; |
||||
let mut start_vars = true; |
||||
for variable in &variables { |
||||
if start_vars { |
||||
start_vars = false; |
||||
} else { |
||||
sink.write_all(b",")?; |
||||
} |
||||
write_escaped_json_string(variable.name()?, &mut sink)?; |
||||
} |
||||
sink.write_all(b"]},\"results\":{\"bindings\":[")?; |
||||
let mut start_bindings = true; |
||||
for result in results { |
||||
if start_bindings { |
||||
start_bindings = false; |
||||
} else { |
||||
sink.write_all(b",")?; |
||||
} |
||||
sink.write_all(b"{")?; |
||||
|
||||
let result = result?; |
||||
let mut start_binding = true; |
||||
for (i, value) in result.into_iter().enumerate() { |
||||
if let Some(term) = value { |
||||
if start_binding { |
||||
start_binding = false; |
||||
} else { |
||||
sink.write_all(b",")?; |
||||
} |
||||
write_escaped_json_string(variables[i].name()?, &mut sink)?; |
||||
match term { |
||||
Term::NamedNode(uri) => { |
||||
sink.write_all(b":{\"type\":\"uri\",\"value\":")?; |
||||
write_escaped_json_string(uri.as_str(), &mut sink)?; |
||||
sink.write_all(b"}")?; |
||||
} |
||||
Term::BlankNode(bnode) => { |
||||
sink.write_all(b":{\"type\":\"bnode\",\"value\":")?; |
||||
sink.write_fmt(format_args!("{}", bnode.as_uuid().to_simple()))?; |
||||
sink.write_all(b"}")?; |
||||
} |
||||
Term::Literal(literal) => { |
||||
sink.write_all(b":{\"type\":\"literal\",\"value\":")?; |
||||
write_escaped_json_string(&literal.value(), &mut sink)?; |
||||
if let Some(language) = literal.language() { |
||||
sink.write_all(b",\"xml:lang\":")?; |
||||
write_escaped_json_string(language, &mut sink)?; |
||||
} else if !literal.is_plain() { |
||||
sink.write_all(b",\"datatype\":")?; |
||||
write_escaped_json_string( |
||||
literal.datatype().as_str(), |
||||
&mut sink, |
||||
)?; |
||||
} |
||||
sink.write_all(b"}")?; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
sink.write_all(b"}")?; |
||||
} |
||||
sink.write_all(b"]}}")?; |
||||
} |
||||
QueryResult::Graph(_) => { |
||||
return Err(format_err!( |
||||
"Graphs could not be formatted to SPARQL query results XML format" |
||||
)); |
||||
} |
||||
} |
||||
Ok(sink) |
||||
} |
||||
|
||||
fn write_escaped_json_string(s: &str, sink: &mut impl Write) -> Result<()> { |
||||
sink.write_all(b"\"")?; |
||||
for c in s.chars() { |
||||
match c { |
||||
'\\' => sink.write_all(b"\\\\"), |
||||
'"' => sink.write_all(b"\\\""), |
||||
c => { |
||||
if c < char::from(32) { |
||||
match c { |
||||
'\u{08}' => sink.write_all(b"\\b"), |
||||
'\u{0C}' => sink.write_all(b"\\f"), |
||||
'\n' => sink.write_all(b"\\n"), |
||||
'\r' => sink.write_all(b"\\r"), |
||||
'\t' => sink.write_all(b"\\t"), |
||||
c => { |
||||
let mut c = c as u8; |
||||
let mut result = [b'\\', b'u', 0, 0, 0, 0]; |
||||
for i in (2..6).rev() { |
||||
let ch = c % 16; |
||||
result[i] = ch + if ch < 10 { b'0' } else { b'A' }; |
||||
c /= 16; |
||||
} |
||||
sink.write_all(&result) |
||||
} |
||||
} |
||||
} else { |
||||
sink.write_fmt(format_args!("{}", c)) |
||||
} |
||||
} |
||||
}?; |
||||
} |
||||
sink.write_all(b"\"")?; |
||||
Ok(()) |
||||
} |
Loading…
Reference in new issue