oxttl and oxrdfio: improves prefixes and base_iri getters

pull/752/head
Tpt 10 months ago committed by Thomas Tanon
parent 6494ba6e31
commit 54489aacfb
  1. 191
      lib/oxrdfio/src/parser.rs
  2. 68
      lib/oxttl/src/n3.rs
  3. 9
      lib/oxttl/src/terse.rs
  4. 68
      lib/oxttl/src/trig.rs
  5. 68
      lib/oxttl/src/turtle.rs

@ -8,7 +8,7 @@ use oxrdfxml::FromTokioAsyncReadRdfXmlReader;
use oxrdfxml::{FromReadRdfXmlReader, RdfXmlParser}; use oxrdfxml::{FromReadRdfXmlReader, RdfXmlParser};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
use oxttl::n3::FromTokioAsyncReadN3Reader; use oxttl::n3::FromTokioAsyncReadN3Reader;
use oxttl::n3::{FromReadN3Reader, N3Parser, N3Quad, N3Term}; use oxttl::n3::{FromReadN3Reader, N3Parser, N3PrefixesIter, N3Quad, N3Term};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
use oxttl::nquads::FromTokioAsyncReadNQuadsReader; use oxttl::nquads::FromTokioAsyncReadNQuadsReader;
use oxttl::nquads::{FromReadNQuadsReader, NQuadsParser}; use oxttl::nquads::{FromReadNQuadsReader, NQuadsParser};
@ -17,10 +17,10 @@ use oxttl::ntriples::FromTokioAsyncReadNTriplesReader;
use oxttl::ntriples::{FromReadNTriplesReader, NTriplesParser}; use oxttl::ntriples::{FromReadNTriplesReader, NTriplesParser};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
use oxttl::trig::FromTokioAsyncReadTriGReader; use oxttl::trig::FromTokioAsyncReadTriGReader;
use oxttl::trig::{FromReadTriGReader, TriGParser}; use oxttl::trig::{FromReadTriGReader, TriGParser, TriGPrefixesIter};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
use oxttl::turtle::FromTokioAsyncReadTurtleReader; use oxttl::turtle::FromTokioAsyncReadTurtleReader;
use oxttl::turtle::{FromReadTurtleReader, TurtleParser}; use oxttl::turtle::{FromReadTurtleReader, TurtleParser, TurtlePrefixesIter};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Read; use std::io::Read;
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
@ -428,6 +428,77 @@ impl<R: Read> Iterator for FromReadQuadReader<R> {
} }
} }
impl<R: Read> FromReadQuadReader<R> {
/// The list of IRI prefixes considered at the current step of the parsing.
///
/// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
///
/// An empty iterator is return if the format does not support prefixes.
///
/// ```
/// use oxrdfio::{RdfFormat, RdfParser};
///
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
/// schema:name "Foo" ."#;
///
/// let mut reader = RdfParser::from_format(RdfFormat::Turtle).parse_read(file.as_slice());
/// assert!(reader.prefixes().collect::<Vec<_>>().is_empty()); // No prefix at the beginning
///
/// reader.next().unwrap()?; // We read the first triple
/// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
pub fn prefixes(&self) -> PrefixesIter<'_> {
PrefixesIter {
inner: match &self.parser {
FromReadQuadReaderKind::N3(p) => PrefixesIterKind::N3(p.prefixes()),
FromReadQuadReaderKind::TriG(p) => PrefixesIterKind::TriG(p.prefixes()),
FromReadQuadReaderKind::Turtle(p) => PrefixesIterKind::Turtle(p.prefixes()),
FromReadQuadReaderKind::NQuads(_)
| FromReadQuadReaderKind::NTriples(_)
| FromReadQuadReaderKind::RdfXml(_) => PrefixesIterKind::None, /* TODO: implement for RDF/XML */
},
}
}
/// The base IRI considered at the current step of the parsing.
///
/// `None` is returned if no base IRI is set or the format does not support base IRIs.
///
/// ```
/// use oxrdfio::{RdfFormat, RdfParser};
///
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
/// schema:name "Foo" ."#;
///
/// let mut reader = RdfParser::from_format(RdfFormat::Turtle).parse_read(file.as_slice());
/// assert!(reader.base_iri().is_none()); // No base at the beginning because none has been given to the parser.
///
/// reader.next().unwrap()?; // We read the first triple
/// assert_eq!(reader.base_iri(), Some("http://example.com/")); // There is now a base IRI.
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
pub fn base_iri(&self) -> Option<&str> {
match &self.parser {
FromReadQuadReaderKind::N3(p) => p.base_iri(),
FromReadQuadReaderKind::TriG(p) => p.base_iri(),
FromReadQuadReaderKind::Turtle(p) => p.base_iri(),
FromReadQuadReaderKind::NQuads(_)
| FromReadQuadReaderKind::NTriples(_)
| FromReadQuadReaderKind::RdfXml(_) => None, // TODO: implement for RDF/XML
}
}
}
/// Parses a RDF file from a Tokio [`AsyncRead`] implementation. Can be built using [`RdfParser::parse_tokio_async_read`]. /// Parses a RDF file from a Tokio [`AsyncRead`] implementation. Can be built using [`RdfParser::parse_tokio_async_read`].
/// ///
/// Reads are buffered. /// Reads are buffered.
@ -494,6 +565,120 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadQuadReader<R> {
}, },
}) })
} }
/// The list of IRI prefixes considered at the current step of the parsing.
///
/// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
///
/// An empty iterator is return if the format does not support prefixes.
///
/// ```
/// use oxrdfio::{RdfFormat, RdfParser};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
/// schema:name "Foo" ."#;
///
/// let mut reader = RdfParser::from_format(RdfFormat::Turtle).parse_read(file.as_slice());
/// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
///
/// reader.next().await.unwrap()?; // We read the first triple
/// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Ok(())
/// # }
/// ```
pub fn prefixes(&self) -> PrefixesIter<'_> {
PrefixesIter {
inner: match &self.parser {
FromReadQuadReaderKind::N3(p) => PrefixesIterKind::N3(p.prefixes()),
FromReadQuadReaderKind::TriG(p) => PrefixesIterKind::TriG(p.prefixes()),
FromReadQuadReaderKind::Turtle(p) => PrefixesIterKind::Turtle(p.prefixes()),
FromReadQuadReaderKind::NQuads(_)
| FromReadQuadReaderKind::NTriples(_)
| FromReadQuadReaderKind::RdfXml(_) => PrefixesIterKind::None, /* TODO: implement for RDF/XML */
},
}
}
/// The base IRI considered at the current step of the parsing.
///
/// `None` is returned if no base IRI is set or the format does not support base IRIs.
///
/// ```
/// use oxrdfio::{RdfFormat, RdfParser};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
/// schema:name "Foo" ."#;
///
/// let mut reader =
/// RdfParser::from_format(RdfFormat::Turtle).parse_tokio_async_read(file.as_slice());
/// assert!(reader.base_iri().is_none()); // No base IRI at the beginning
///
/// reader.next().await.unwrap()?; // We read the first triple
/// assert_eq!(reader.base_iri(), Some("http://example.com/")); // There is now a base IRI
/// # Ok(())
/// # }
/// ```
pub fn base_iri(&self) -> Option<&str> {
match &self.parser {
FromReadQuadReaderKind::N3(p) => p.base_iri(),
FromReadQuadReaderKind::TriG(p) => p.base_iri(),
FromReadQuadReaderKind::Turtle(p) => p.base_iri(),
FromReadQuadReaderKind::NQuads(_)
| FromReadQuadReaderKind::NTriples(_)
| FromReadQuadReaderKind::RdfXml(_) => None, // TODO: implement for RDF/XML
}
}
}
/// Iterator on the file prefixes.
///
/// See [`FromReadQuadReader::prefixes`].
pub struct PrefixesIter<'a> {
inner: PrefixesIterKind<'a>,
}
enum PrefixesIterKind<'a> {
Turtle(TurtlePrefixesIter<'a>),
TriG(TriGPrefixesIter<'a>),
N3(N3PrefixesIter<'a>),
None,
}
impl<'a> Iterator for PrefixesIter<'a> {
type Item = (&'a str, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match &mut self.inner {
PrefixesIterKind::Turtle(iter) => iter.next(),
PrefixesIterKind::TriG(iter) => iter.next(),
PrefixesIterKind::N3(iter) => iter.next(),
PrefixesIterKind::None => None,
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.inner {
PrefixesIterKind::Turtle(iter) => iter.size_hint(),
PrefixesIterKind::TriG(iter) => iter.size_hint(),
PrefixesIterKind::N3(iter) => iter.size_hint(),
PrefixesIterKind::None => (0, Some(0)),
}
}
} }
struct QuadMapper { struct QuadMapper {

@ -15,6 +15,7 @@ use oxrdf::{
BlankNode, GraphName, Literal, NamedNode, NamedNodeRef, NamedOrBlankNode, Quad, Subject, Term, BlankNode, GraphName, Literal, NamedNode, NamedNodeRef, NamedOrBlankNode, Quad, Subject, Term,
Variable, Variable,
}; };
use std::collections::hash_map::Iter;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::io::Read; use std::io::Read;
@ -403,7 +404,7 @@ pub struct FromReadN3Reader<R: Read> {
impl<R: Read> FromReadN3Reader<R> { impl<R: Read> FromReadN3Reader<R> {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -416,14 +417,19 @@ impl<R: Read> FromReadN3Reader<R> {
/// schema:name "Foo" ."#; /// schema:name "Foo" ."#;
/// ///
/// let mut reader = N3Parser::new().parse_read(file.as_ref()); /// let mut reader = N3Parser::new().parse_read(file.as_ref());
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
/// ///
/// reader.next().unwrap()?; // We read the first triple /// reader.next().unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Result::<_,Box<dyn std::error::Error>>::Ok(()) /// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> N3PrefixesIter<'_> {
&self.inner.parser.context.prefixes N3PrefixesIter {
inner: self.inner.parser.context.prefixes.iter(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -508,7 +514,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadN3Reader<R> {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -523,15 +529,20 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadN3Reader<R> {
/// schema:name "Foo" ."#; /// schema:name "Foo" ."#;
/// ///
/// let mut reader = N3Parser::new().parse_tokio_async_read(file.as_ref()); /// let mut reader = N3Parser::new().parse_tokio_async_read(file.as_ref());
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
/// ///
/// reader.next().await.unwrap()?; // We read the first triple /// reader.next().await.unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> N3PrefixesIter<'_> {
&self.inner.parser.context.prefixes N3PrefixesIter {
inner: self.inner.parser.context.prefixes.iter(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -636,7 +647,7 @@ impl LowLevelN3Reader {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -650,14 +661,19 @@ impl LowLevelN3Reader {
/// ///
/// let mut reader = N3Parser::new().parse(); /// let mut reader = N3Parser::new().parse();
/// reader.extend_from_slice(file); /// reader.extend_from_slice(file);
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
/// ///
/// reader.read_next().unwrap()?; // We read the first triple /// reader.read_next().unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Result::<_,Box<dyn std::error::Error>>::Ok(()) /// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> N3PrefixesIter<'_> {
&self.parser.context.prefixes N3PrefixesIter {
inner: self.parser.context.prefixes.iter(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -1299,3 +1315,25 @@ enum N3State {
FormulaContent, FormulaContent,
FormulaContentExpectDot, FormulaContentExpectDot,
} }
/// Iterator on the file prefixes.
///
/// See [`LowLevelN3Reader::prefixes`].
pub struct N3PrefixesIter<'a> {
inner: Iter<'a, String, Iri<String>>,
}
impl<'a> Iterator for N3PrefixesIter<'a> {
type Item = (&'a str, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (key, value) = self.inner.next()?;
Some((key.as_str(), value.as_str()))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}

@ -8,6 +8,7 @@ use oxrdf::vocab::{rdf, xsd};
#[cfg(feature = "rdf-star")] #[cfg(feature = "rdf-star")]
use oxrdf::Triple; use oxrdf::Triple;
use oxrdf::{BlankNode, GraphName, Literal, NamedNode, NamedOrBlankNode, Quad, Subject, Term}; use oxrdf::{BlankNode, GraphName, Literal, NamedNode, NamedOrBlankNode, Quad, Subject, Term};
use std::collections::hash_map::Iter;
use std::collections::HashMap; use std::collections::HashMap;
pub struct TriGRecognizer { pub struct TriGRecognizer {
@ -24,7 +25,13 @@ pub struct TriGRecognizerContext {
pub with_graph_name: bool, pub with_graph_name: bool,
#[cfg(feature = "rdf-star")] #[cfg(feature = "rdf-star")]
pub with_quoted_triples: bool, pub with_quoted_triples: bool,
pub prefixes: HashMap<String, Iri<String>>, prefixes: HashMap<String, Iri<String>>,
}
impl TriGRecognizerContext {
pub fn prefixes(&self) -> Iter<'_, String, Iri<String>> {
self.prefixes.iter()
}
} }
impl RuleRecognizer for TriGRecognizer { impl RuleRecognizer for TriGRecognizer {

@ -8,6 +8,7 @@ use crate::toolkit::{FromReadIterator, ParseError, Parser, SyntaxError};
use oxiri::{Iri, IriParseError}; use oxiri::{Iri, IriParseError};
use oxrdf::vocab::xsd; use oxrdf::vocab::xsd;
use oxrdf::{GraphName, NamedNode, Quad, QuadRef, Subject, TermRef}; use oxrdf::{GraphName, NamedNode, Quad, QuadRef, Subject, TermRef};
use std::collections::hash_map::Iter;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
@ -253,7 +254,7 @@ pub struct FromReadTriGReader<R: Read> {
impl<R: Read> FromReadTriGReader<R> { impl<R: Read> FromReadTriGReader<R> {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -266,14 +267,19 @@ impl<R: Read> FromReadTriGReader<R> {
/// schema:name "Foo" ."#; /// schema:name "Foo" ."#;
/// ///
/// let mut reader = TriGParser::new().parse_read(file.as_ref()); /// let mut reader = TriGParser::new().parse_read(file.as_ref());
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
/// ///
/// reader.next().unwrap()?; // We read the first triple /// reader.next().unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Result::<_,Box<dyn std::error::Error>>::Ok(()) /// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> TriGPrefixesIter<'_> {
&self.inner.parser.context.prefixes TriGPrefixesIter {
inner: self.inner.parser.context.prefixes(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -357,7 +363,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTriGReader<R> {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -372,15 +378,20 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTriGReader<R> {
/// schema:name "Foo" ."#; /// schema:name "Foo" ."#;
/// ///
/// let mut reader = TriGParser::new().parse_tokio_async_read(file.as_ref()); /// let mut reader = TriGParser::new().parse_tokio_async_read(file.as_ref());
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
/// ///
/// reader.next().await.unwrap()?; // We read the first triple /// reader.next().await.unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> TriGPrefixesIter<'_> {
&self.inner.parser.context.prefixes TriGPrefixesIter {
inner: self.inner.parser.context.prefixes(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -484,7 +495,7 @@ impl LowLevelTriGReader {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -498,14 +509,19 @@ impl LowLevelTriGReader {
/// ///
/// let mut reader = TriGParser::new().parse(); /// let mut reader = TriGParser::new().parse();
/// reader.extend_from_slice(file); /// reader.extend_from_slice(file);
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
/// ///
/// reader.read_next().unwrap()?; // We read the first triple /// reader.read_next().unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Result::<_,Box<dyn std::error::Error>>::Ok(()) /// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> TriGPrefixesIter<'_> {
&self.parser.context.prefixes TriGPrefixesIter {
inner: self.parser.context.prefixes(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -536,6 +552,28 @@ impl LowLevelTriGReader {
} }
} }
/// Iterator on the file prefixes.
///
/// See [`LowLevelTriGReader::prefixes`].
pub struct TriGPrefixesIter<'a> {
inner: Iter<'a, String, Iri<String>>,
}
impl<'a> Iterator for TriGPrefixesIter<'a> {
type Item = (&'a str, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (key, value) = self.inner.next()?;
Some((key.as_str(), value.as_str()))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
/// A [TriG](https://www.w3.org/TR/trig/) serializer. /// A [TriG](https://www.w3.org/TR/trig/) serializer.
/// ///
/// Support for [TriG-star](https://w3c.github.io/rdf-star/cg-spec/2021-12-17.html#trig-star) is available behind the `rdf-star` feature. /// Support for [TriG-star](https://w3c.github.io/rdf-star/cg-spec/2021-12-17.html#trig-star) is available behind the `rdf-star` feature.

@ -10,6 +10,7 @@ use crate::trig::ToTokioAsyncWriteTriGWriter;
use crate::trig::{LowLevelTriGWriter, ToWriteTriGWriter, TriGSerializer}; use crate::trig::{LowLevelTriGWriter, ToWriteTriGWriter, TriGSerializer};
use oxiri::{Iri, IriParseError}; use oxiri::{Iri, IriParseError};
use oxrdf::{GraphNameRef, Triple, TripleRef}; use oxrdf::{GraphNameRef, Triple, TripleRef};
use std::collections::hash_map::Iter;
use std::collections::HashMap; use std::collections::HashMap;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
@ -254,7 +255,7 @@ pub struct FromReadTurtleReader<R: Read> {
impl<R: Read> FromReadTurtleReader<R> { impl<R: Read> FromReadTurtleReader<R> {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -267,14 +268,19 @@ impl<R: Read> FromReadTurtleReader<R> {
/// schema:name "Foo" ."#; /// schema:name "Foo" ."#;
/// ///
/// let mut reader = TurtleParser::new().parse_read(file.as_ref()); /// let mut reader = TurtleParser::new().parse_read(file.as_ref());
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert!(reader.prefixes().collect::<Vec<_>>().is_empty()); // No prefix at the beginning
/// ///
/// reader.next().unwrap()?; // We read the first triple /// reader.next().unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Result::<_,Box<dyn std::error::Error>>::Ok(()) /// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> TurtlePrefixesIter<'_> {
&self.inner.parser.context.prefixes TurtlePrefixesIter {
inner: self.inner.parser.context.prefixes(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -358,7 +364,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -373,15 +379,20 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> {
/// schema:name "Foo" ."#; /// schema:name "Foo" ."#;
/// ///
/// let mut reader = TurtleParser::new().parse_tokio_async_read(file.as_ref()); /// let mut reader = TurtleParser::new().parse_tokio_async_read(file.as_ref());
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
/// ///
/// reader.next().await.unwrap()?; // We read the first triple /// reader.next().await.unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> TurtlePrefixesIter<'_> {
&self.inner.parser.context.prefixes TurtlePrefixesIter {
inner: self.inner.parser.context.prefixes(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -485,7 +496,7 @@ impl LowLevelTurtleReader {
/// The list of IRI prefixes considered at the current step of the parsing. /// The list of IRI prefixes considered at the current step of the parsing.
/// ///
/// This method returns the mapping from prefix name to prefix value. /// This method returns (prefix name, prefix value) tuples.
/// It is empty at the beginning of the parsing and gets updated when prefixes are encountered. /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
/// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned). /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
/// ///
@ -499,14 +510,19 @@ impl LowLevelTurtleReader {
/// ///
/// let mut reader = TurtleParser::new().parse(); /// let mut reader = TurtleParser::new().parse();
/// reader.extend_from_slice(file); /// reader.extend_from_slice(file);
/// assert!(reader.prefixes().is_empty()); // No prefix at the beginning /// assert_eq!(reader.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
/// ///
/// reader.read_next().unwrap()?; // We read the first triple /// reader.read_next().unwrap()?; // We read the first triple
/// assert_eq!(reader.prefixes()["schema"], "http://schema.org/"); // There are now prefixes /// assert_eq!(
/// reader.prefixes().collect::<Vec<_>>(),
/// [("schema", "http://schema.org/")]
/// ); // There are now prefixes
/// # Result::<_,Box<dyn std::error::Error>>::Ok(()) /// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ``` /// ```
pub fn prefixes(&self) -> &HashMap<String, Iri<String>> { pub fn prefixes(&self) -> TurtlePrefixesIter<'_> {
&self.parser.context.prefixes TurtlePrefixesIter {
inner: self.parser.context.prefixes(),
}
} }
/// The base IRI considered at the current step of the parsing. /// The base IRI considered at the current step of the parsing.
@ -537,6 +553,28 @@ impl LowLevelTurtleReader {
} }
} }
/// Iterator on the file prefixes.
///
/// See [`LowLevelTurtleReader::prefixes`].
pub struct TurtlePrefixesIter<'a> {
inner: Iter<'a, String, Iri<String>>,
}
impl<'a> Iterator for TurtlePrefixesIter<'a> {
type Item = (&'a str, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (key, value) = self.inner.next()?;
Some((key.as_str(), value.as_str()))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
/// A [Turtle](https://www.w3.org/TR/turtle/) serializer. /// A [Turtle](https://www.w3.org/TR/turtle/) serializer.
/// ///
/// Support for [Turtle-star](https://w3c.github.io/rdf-star/cg-spec/2021-12-17.html#turtle-star) is available behind the `rdf-star` feature. /// Support for [Turtle-star](https://w3c.github.io/rdf-star/cg-spec/2021-12-17.html#turtle-star) is available behind the `rdf-star` feature.

Loading…
Cancel
Save