From 7f5f7dae65da98e4183e850044f9351cb6e27e1e Mon Sep 17 00:00:00 2001 From: Tpt Date: Sun, 16 May 2021 20:52:13 +0200 Subject: [PATCH] SPARQL XML results parser: Adds RDF-star support --- lib/src/sparql/xml_results.rs | 104 +++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 15 deletions(-) diff --git a/lib/src/sparql/xml_results.rs b/lib/src/sparql/xml_results.rs index c94c397e..044dac8f 100644 --- a/lib/src/sparql/xml_results.rs +++ b/lib/src/sparql/xml_results.rs @@ -257,9 +257,10 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result,_>>().map_err(invalid_data_error)?), Box::new(ResultsIterator { reader, - buffer: Vec::default(), + buffer, namespace_buffer, mapping, + stack: Vec::new() }), ))); } else if event.name() != b"link" && event.name() != b"results" && event.name() != b"boolean" { @@ -327,11 +328,26 @@ pub fn read_xml_results(source: impl BufRead + 'static) -> Result { reader: Reader, buffer: Vec, namespace_buffer: Vec, mapping: BTreeMap, usize>, + stack: Vec, } impl Iterator for ResultsIterator { @@ -344,15 +360,6 @@ impl Iterator for ResultsIterator { impl ResultsIterator { fn read_next(&mut self) -> Result>>, EvaluationError> { - enum State { - Start, - Result, - Binding, - Uri, - BNode, - Literal, - End, - } let mut state = State::Start; let mut new_bindings = Vec::default(); @@ -362,6 +369,9 @@ impl ResultsIterator { let mut term: Option = None; let mut lang = None; let mut datatype = None; + let mut subject = None; + let mut predicate = None; + let mut object = None; loop { let (ns, event) = self .reader @@ -417,13 +427,14 @@ impl ResultsIterator { .into()); } } - State::Binding => { + State::Binding | State::Subject | State::Predicate | State::Object => { if term.is_some() { return Err(invalid_data_error( "There is already a value for the current binding", ) .into()); } + self.stack.push(state); if event.name() == b"uri" { state = State::Uri; } else if event.name() == b"bnode" { @@ -448,6 +459,8 @@ impl ResultsIterator { } } state = State::Literal; + } else if event.name() == b"triple" { + state = State::Triple; } else { return Err(invalid_data_error(format!( "Expecting , or found {}", @@ -456,6 +469,21 @@ impl ResultsIterator { .into()); } } + State::Triple => { + if event.name() == b"subject" { + state = State::Subject + } else if event.name() == b"predicate" { + state = State::Predicate + } else if event.name() == b"object" { + state = State::Object + } else { + return Err(invalid_data_error(format!( + "Expecting , or found {}", + self.reader.decode(event.name()).map_err(map_xml_error)? + )) + .into()); + } + } _ => (), }, Event::Text(event) => { @@ -511,22 +539,68 @@ impl ResultsIterator { State::Result => return Ok(Some(new_bindings)), State::Binding => { if let Some(var) = ¤t_var { - new_bindings[self.mapping[var]] = term.clone() + new_bindings[self.mapping[var]] = term.take() } else { return Err( invalid_data_error("No name found for tag").into() ); } - term = None; state = State::Result; } - State::Uri | State::BNode => state = State::Binding, + State::Subject => { + subject = term.take(); + state = State::Triple; + } + State::Predicate => { + predicate = term.take(); + state = State::Triple; + } + State::Object => { + object = term.take(); + state = State::Triple; + } + State::Uri | State::BNode => state = self.stack.pop().unwrap(), State::Literal => { if term.is_none() { //We default to the empty literal term = Some(build_literal("", lang.take(), datatype.take())?.into()) } - state = State::Binding; + state = self.stack.pop().unwrap(); + } + State::Triple => { + if let (Some(subject), Some(predicate), Some(object)) = + (subject.take(), predicate.take(), object.take()) + { + term = + Some( + Triple::new( + match subject { + Term::NamedNode(subject) => subject.into(), + Term::BlankNode(subject) => subject.into(), + Term::Triple(subject) => Subject::Triple(subject), + Term::Literal(_) => return Err(invalid_data_error( + "The value should not be a ", + ) + .into()), + }, + match predicate { + Term::NamedNode(predicate) => predicate, + _ => { + return Err(invalid_data_error( + "The value should be an ", + ) + .into()) + } + }, + object, + ) + .into(), + ) + } else { + return Err( + invalid_data_error("A should contain a , a and an ").into() + ); + } } _ => (), },