Skip to main content

oxrdfxml/
parser.rs

1use crate::error::{RdfXmlParseError, RdfXmlSyntaxError};
2use crate::utils::*;
3use oxilangtag::LanguageTag;
4use oxiri::{Iri, IriParseError};
5#[cfg(feature = "rdf-12")]
6use oxrdf::BaseDirection;
7use oxrdf::vocab::rdf;
8use oxrdf::{BlankNode, Literal, NamedNode, NamedOrBlankNode, Term, Triple};
9use quick_xml::escape::{resolve_xml_entity, unescape_with};
10use quick_xml::events::attributes::Attribute;
11use quick_xml::events::*;
12use quick_xml::name::{LocalName, Namespace, PrefixDeclaration, PrefixIter, ResolveResult};
13use quick_xml::{Decoder, Error, NsReader, Writer};
14use std::borrow::Cow;
15use std::collections::{HashMap, HashSet};
16use std::io::{BufReader, Read};
17use std::str;
18#[cfg(feature = "async-tokio")]
19use tokio::io::{AsyncRead, BufReader as AsyncBufReader};
20
21/// A [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/) streaming parser.
22///
23/// It reads the file in streaming.
24/// It does not keep data in memory except a stack for handling nested XML tags, and a set of all
25/// seen `rdf:ID`s to detect duplicate ids and fail according to the specification.
26///
27/// Its performances are not optimized yet and hopefully could be significantly enhanced by reducing the
28/// number of allocations and copies done by the parser.
29///
30/// Count the number of people:
31/// ```
32/// use oxrdf::NamedNodeRef;
33/// use oxrdf::vocab::rdf;
34/// use oxrdfxml::RdfXmlParser;
35///
36/// let file = r#"<?xml version="1.0"?>
37/// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
38///  <rdf:Description rdf:about="http://example.com/foo">
39///    <rdf:type rdf:resource="http://schema.org/Person" />
40///    <schema:name>Foo</schema:name>
41///  </rdf:Description>
42///  <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
43/// </rdf:RDF>"#;
44///
45/// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
46/// let mut count = 0;
47/// for triple in RdfXmlParser::new().for_reader(file.as_bytes()) {
48///     let triple = triple?;
49///     if triple.predicate == rdf::TYPE && triple.object == schema_person.into() {
50///         count += 1;
51///     }
52/// }
53/// assert_eq!(2, count);
54/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
55/// ```
56#[derive(Default, Clone)]
57#[must_use]
58pub struct RdfXmlParser {
59    lenient: bool,
60    base: Option<Iri<String>>,
61}
62
63impl RdfXmlParser {
64    /// Builds a new [`RdfXmlParser`].
65    #[inline]
66    pub fn new() -> Self {
67        Self::default()
68    }
69
70    /// Assumes the file is valid to make parsing faster.
71    ///
72    /// It will skip some validations.
73    ///
74    /// Note that if the file is actually not valid, the parser might emit broken RDF.
75    #[inline]
76    pub fn lenient(mut self) -> Self {
77        self.lenient = true;
78        self
79    }
80
81    #[deprecated(note = "Use `lenient()` instead", since = "0.2.0")]
82    #[inline]
83    pub fn unchecked(self) -> Self {
84        self.lenient()
85    }
86
87    #[inline]
88    pub fn with_base_iri(mut self, base_iri: impl Into<String>) -> Result<Self, IriParseError> {
89        self.base = Some(Iri::parse(base_iri.into())?);
90        Ok(self)
91    }
92
93    /// Parses a RDF/XML file from a [`Read`] implementation.
94    ///
95    /// Count the number of people:
96    /// ```
97    /// use oxrdf::NamedNodeRef;
98    /// use oxrdf::vocab::rdf;
99    /// use oxrdfxml::RdfXmlParser;
100    ///
101    /// let file = r#"<?xml version="1.0"?>
102    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
103    ///  <rdf:Description rdf:about="http://example.com/foo">
104    ///    <rdf:type rdf:resource="http://schema.org/Person" />
105    ///    <schema:name>Foo</schema:name>
106    ///  </rdf:Description>
107    ///  <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
108    /// </rdf:RDF>"#;
109    ///
110    /// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
111    /// let mut count = 0;
112    /// for triple in RdfXmlParser::new().for_reader(file.as_bytes()) {
113    ///     let triple = triple?;
114    ///     if triple.predicate == rdf::TYPE && triple.object == schema_person.into() {
115    ///         count += 1;
116    ///     }
117    /// }
118    /// assert_eq!(2, count);
119    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
120    /// ```
121    pub fn for_reader<R: Read>(self, reader: R) -> ReaderRdfXmlParser<R> {
122        ReaderRdfXmlParser {
123            results: Vec::new(),
124            parser: self.into_internal(BufReader::new(reader)),
125            reader_buffer: Vec::default(),
126        }
127    }
128
129    /// Parses a RDF/XML file from a [`AsyncRead`] implementation.
130    ///
131    /// Count the number of people:
132    /// ```
133    /// # #[tokio::main(flavor = "current_thread")]
134    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
135    /// use oxrdf::NamedNodeRef;
136    /// use oxrdf::vocab::rdf;
137    /// use oxrdfxml::RdfXmlParser;
138    ///
139    /// let file = r#"<?xml version="1.0"?>
140    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
141    ///   <rdf:Description rdf:about="http://example.com/foo">
142    ///     <rdf:type rdf:resource="http://schema.org/Person" />
143    ///     <schema:name>Foo</schema:name>
144    ///   </rdf:Description>
145    ///   <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
146    /// </rdf:RDF>"#;
147    ///
148    /// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
149    /// let mut count = 0;
150    /// let mut parser = RdfXmlParser::new().for_tokio_async_reader(file.as_bytes());
151    /// while let Some(triple) = parser.next().await {
152    ///     let triple = triple?;
153    ///     if triple.predicate == rdf::TYPE && triple.object == schema_person.into() {
154    ///         count += 1;
155    ///     }
156    /// }
157    /// assert_eq!(2, count);
158    /// # Ok(())
159    /// # }
160    /// ```
161    #[cfg(feature = "async-tokio")]
162    pub fn for_tokio_async_reader<R: AsyncRead + Unpin>(
163        self,
164        reader: R,
165    ) -> TokioAsyncReaderRdfXmlParser<R> {
166        TokioAsyncReaderRdfXmlParser {
167            results: Vec::new(),
168            parser: self.into_internal(AsyncBufReader::new(reader)),
169            reader_buffer: Vec::default(),
170        }
171    }
172
173    /// Parses a RDF/XML file from a byte slice.
174    ///
175    /// Count the number of people:
176    /// ```
177    /// use oxrdf::NamedNodeRef;
178    /// use oxrdf::vocab::rdf;
179    /// use oxrdfxml::RdfXmlParser;
180    ///
181    /// let file = r#"<?xml version="1.0"?>
182    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
183    ///  <rdf:Description rdf:about="http://example.com/foo">
184    ///    <rdf:type rdf:resource="http://schema.org/Person" />
185    ///    <schema:name>Foo</schema:name>
186    ///  </rdf:Description>
187    ///  <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
188    /// </rdf:RDF>"#;
189    ///
190    /// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
191    /// let mut count = 0;
192    /// for triple in RdfXmlParser::new().for_slice(file) {
193    ///     let triple = triple?;
194    ///     if triple.predicate == rdf::TYPE && triple.object == schema_person.into() {
195    ///         count += 1;
196    ///     }
197    /// }
198    /// assert_eq!(2, count);
199    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
200    /// ```
201    pub fn for_slice(self, slice: &(impl AsRef<[u8]> + ?Sized)) -> SliceRdfXmlParser<'_> {
202        SliceRdfXmlParser {
203            results: Vec::new(),
204            parser: self.into_internal(slice.as_ref()),
205        }
206    }
207
208    fn into_internal<T>(self, reader: T) -> InternalRdfXmlParser<T> {
209        let mut reader = NsReader::from_reader(reader);
210        reader.config_mut().expand_empty_elements = true;
211        InternalRdfXmlParser {
212            reader,
213            state: vec![RdfXmlState::Doc {
214                base_iri: self.base.clone(),
215            }],
216            custom_entities: HashMap::new(),
217            in_literal_depth: 0,
218            known_rdf_id: HashSet::default(),
219            is_end: false,
220            lenient: self.lenient,
221        }
222    }
223}
224
225/// Parses a RDF/XML file from a [`Read`] implementation.
226///
227/// Can be built using [`RdfXmlParser::for_reader`].
228///
229/// Count the number of people:
230/// ```
231/// use oxrdf::NamedNodeRef;
232/// use oxrdf::vocab::rdf;
233/// use oxrdfxml::RdfXmlParser;
234///
235/// let file = r#"<?xml version="1.0"?>
236/// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
237///  <rdf:Description rdf:about="http://example.com/foo">
238///    <rdf:type rdf:resource="http://schema.org/Person" />
239///    <schema:name>Foo</schema:name>
240///  </rdf:Description>
241///  <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
242/// </rdf:RDF>"#;
243///
244/// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
245/// let mut count = 0;
246/// for triple in RdfXmlParser::new().for_reader(file.as_bytes()) {
247///     let triple = triple?;
248///     if triple.predicate == rdf::TYPE && triple.object == schema_person.into() {
249///         count += 1;
250///     }
251/// }
252/// assert_eq!(2, count);
253/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
254/// ```
255#[must_use]
256pub struct ReaderRdfXmlParser<R: Read> {
257    results: Vec<Triple>,
258    parser: InternalRdfXmlParser<BufReader<R>>,
259    reader_buffer: Vec<u8>,
260}
261
262impl<R: Read> Iterator for ReaderRdfXmlParser<R> {
263    type Item = Result<Triple, RdfXmlParseError>;
264
265    fn next(&mut self) -> Option<Self::Item> {
266        loop {
267            if let Some(triple) = self.results.pop() {
268                return Some(Ok(triple));
269            } else if self.parser.is_end {
270                return None;
271            }
272            if let Err(e) = self.parse_step() {
273                return Some(Err(e));
274            }
275        }
276    }
277}
278
279impl<R: Read> ReaderRdfXmlParser<R> {
280    /// The list of IRI prefixes considered at the current step of the parsing.
281    ///
282    /// This method returns (prefix name, prefix value) tuples.
283    /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
284    /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
285    ///
286    /// ```
287    /// use oxrdfxml::RdfXmlParser;
288    ///
289    /// let file = r#"<?xml version="1.0"?>
290    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
291    ///  <rdf:Description rdf:about="http://example.com/foo">
292    ///    <rdf:type rdf:resource="http://schema.org/Person" />
293    ///    <schema:name>Foo</schema:name>
294    ///  </rdf:Description>
295    ///  <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
296    /// </rdf:RDF>"#;
297    ///
298    /// let mut parser = RdfXmlParser::new().for_reader(file.as_bytes());
299    /// assert_eq!(parser.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
300    ///
301    /// parser.next().unwrap()?; // We read the first triple
302    /// assert_eq!(
303    ///     parser.prefixes().collect::<Vec<_>>(),
304    ///     [
305    ///         ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
306    ///         ("schema", "http://schema.org/")
307    ///     ]
308    /// ); // There are now prefixes
309    /// //
310    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
311    /// ```
312    pub fn prefixes(&self) -> RdfXmlPrefixesIter<'_> {
313        RdfXmlPrefixesIter {
314            inner: self.parser.reader.prefixes(),
315            decoder: self.parser.reader.decoder(),
316            lenient: self.parser.lenient,
317        }
318    }
319
320    /// The base IRI considered at the current step of the parsing.
321    ///
322    /// ```
323    /// use oxrdfxml::RdfXmlParser;
324    ///
325    /// let file = r#"<?xml version="1.0"?>
326    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xml:base="http://example.com/">
327    ///  <rdf:Description rdf:about="foo">
328    ///    <rdf:type rdf:resource="http://schema.org/Person" />
329    ///  </rdf:Description>
330    /// </rdf:RDF>"#;
331    ///
332    /// let mut parser = RdfXmlParser::new().for_reader(file.as_bytes());
333    /// assert!(parser.base_iri().is_none()); // No base at the beginning because none has been given to the parser.
334    ///
335    /// parser.next().unwrap()?; // We read the first triple
336    /// assert_eq!(parser.base_iri(), Some("http://example.com/")); // There is now a base IRI.
337    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
338    /// ```
339    pub fn base_iri(&self) -> Option<&str> {
340        Some(self.parser.current_base_iri()?.as_str())
341    }
342
343    /// The current byte position in the input data.
344    pub fn buffer_position(&self) -> u64 {
345        self.parser.reader.buffer_position()
346    }
347
348    fn parse_step(&mut self) -> Result<(), RdfXmlParseError> {
349        self.reader_buffer.clear();
350        let event = self
351            .parser
352            .reader
353            .read_event_into(&mut self.reader_buffer)?;
354        self.parser.parse_event(event, &mut self.results)
355    }
356}
357
358/// Parses a RDF/XML file from a [`AsyncRead`] implementation.
359///
360/// Can be built using [`RdfXmlParser::for_tokio_async_reader`].
361///
362/// Count the number of people:
363/// ```
364/// # #[tokio::main(flavor = "current_thread")]
365/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
366/// use oxrdf::NamedNodeRef;
367/// use oxrdf::vocab::rdf;
368/// use oxrdfxml::RdfXmlParser;
369///
370/// let file = r#"<?xml version="1.0"?>
371/// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
372///   <rdf:Description rdf:about="http://example.com/foo">
373///     <rdf:type rdf:resource="http://schema.org/Person" />
374///     <schema:name>Foo</schema:name>
375///   </rdf:Description>
376///   <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
377/// </rdf:RDF>"#;
378///
379/// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
380/// let mut count = 0;
381/// let mut parser = RdfXmlParser::new().for_tokio_async_reader(file.as_bytes());
382/// while let Some(triple) = parser.next().await {
383///     let triple = triple?;
384///     if triple.predicate == rdf::TYPE && triple.object == schema_person.into() {
385///         count += 1;
386///     }
387/// }
388/// assert_eq!(2, count);
389/// # Ok(())
390/// # }
391/// ```
392#[cfg(feature = "async-tokio")]
393#[must_use]
394pub struct TokioAsyncReaderRdfXmlParser<R: AsyncRead + Unpin> {
395    results: Vec<Triple>,
396    parser: InternalRdfXmlParser<AsyncBufReader<R>>,
397    reader_buffer: Vec<u8>,
398}
399
400#[cfg(feature = "async-tokio")]
401impl<R: AsyncRead + Unpin> TokioAsyncReaderRdfXmlParser<R> {
402    /// Reads the next triple or returns `None` if the file is finished.
403    pub async fn next(&mut self) -> Option<Result<Triple, RdfXmlParseError>> {
404        loop {
405            if let Some(triple) = self.results.pop() {
406                return Some(Ok(triple));
407            } else if self.parser.is_end {
408                return None;
409            }
410            if let Err(e) = self.parse_step().await {
411                return Some(Err(e));
412            }
413        }
414    }
415
416    /// The list of IRI prefixes considered at the current step of the parsing.
417    ///
418    /// This method returns (prefix name, prefix value) tuples.
419    /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
420    /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
421    ///
422    /// ```
423    /// # #[tokio::main(flavor = "current_thread")]
424    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
425    /// use oxrdfxml::RdfXmlParser;
426    ///
427    /// let file = r#"<?xml version="1.0"?>
428    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
429    ///  <rdf:Description rdf:about="http://example.com/foo">
430    ///    <rdf:type rdf:resource="http://schema.org/Person" />
431    ///    <schema:name>Foo</schema:name>
432    ///  </rdf:Description>
433    ///  <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
434    /// </rdf:RDF>"#;
435    ///
436    /// let mut parser = RdfXmlParser::new().for_tokio_async_reader(file.as_bytes());
437    /// assert_eq!(parser.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
438    ///
439    /// parser.next().await.unwrap()?; // We read the first triple
440    /// assert_eq!(
441    ///     parser.prefixes().collect::<Vec<_>>(),
442    ///     [
443    ///         ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
444    ///         ("schema", "http://schema.org/")
445    ///     ]
446    /// ); // There are now prefixes
447    /// //
448    /// # Ok(())
449    /// # }
450    /// ```
451    pub fn prefixes(&self) -> RdfXmlPrefixesIter<'_> {
452        RdfXmlPrefixesIter {
453            inner: self.parser.reader.prefixes(),
454            decoder: self.parser.reader.decoder(),
455            lenient: self.parser.lenient,
456        }
457    }
458
459    /// The base IRI considered at the current step of the parsing.
460    ///
461    /// ```
462    /// # #[tokio::main(flavor = "current_thread")]
463    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
464    /// use oxrdfxml::RdfXmlParser;
465    ///
466    /// let file = r#"<?xml version="1.0"?>
467    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xml:base="http://example.com/">
468    ///  <rdf:Description rdf:about="foo">
469    ///    <rdf:type rdf:resource="http://schema.org/Person" />
470    ///  </rdf:Description>
471    /// </rdf:RDF>"#;
472    ///
473    /// let mut parser = RdfXmlParser::new().for_tokio_async_reader(file.as_bytes());
474    /// assert!(parser.base_iri().is_none()); // No base at the beginning because none has been given to the parser.
475    ///
476    /// parser.next().await.unwrap()?; // We read the first triple
477    /// assert_eq!(parser.base_iri(), Some("http://example.com/")); // There is now a base IRI.
478    /// # Ok(())
479    /// # }
480    /// ```
481    pub fn base_iri(&self) -> Option<&str> {
482        Some(self.parser.current_base_iri()?.as_str())
483    }
484
485    /// The current byte position in the input data.
486    pub fn buffer_position(&self) -> u64 {
487        self.parser.reader.buffer_position()
488    }
489
490    async fn parse_step(&mut self) -> Result<(), RdfXmlParseError> {
491        self.reader_buffer.clear();
492        let event = self
493            .parser
494            .reader
495            .read_event_into_async(&mut self.reader_buffer)
496            .await?;
497        self.parser.parse_event(event, &mut self.results)
498    }
499}
500
501/// Parses a RDF/XML file from a byte slice.
502///
503/// Can be built using [`RdfXmlParser::for_slice`].
504///
505/// Count the number of people:
506/// ```
507/// use oxrdf::NamedNodeRef;
508/// use oxrdf::vocab::rdf;
509/// use oxrdfxml::RdfXmlParser;
510///
511/// let file = r#"<?xml version="1.0"?>
512/// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
513///  <rdf:Description rdf:about="http://example.com/foo">
514///    <rdf:type rdf:resource="http://schema.org/Person" />
515///    <schema:name>Foo</schema:name>
516///  </rdf:Description>
517///  <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
518/// </rdf:RDF>"#;
519///
520/// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
521/// let mut count = 0;
522/// for triple in RdfXmlParser::new().for_slice(file) {
523///     let triple = triple?;
524///     if triple.predicate == rdf::TYPE && triple.object == schema_person.into() {
525///         count += 1;
526///     }
527/// }
528/// assert_eq!(2, count);
529/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
530/// ```
531#[must_use]
532pub struct SliceRdfXmlParser<'a> {
533    results: Vec<Triple>,
534    parser: InternalRdfXmlParser<&'a [u8]>,
535}
536
537impl Iterator for SliceRdfXmlParser<'_> {
538    type Item = Result<Triple, RdfXmlSyntaxError>;
539
540    fn next(&mut self) -> Option<Self::Item> {
541        loop {
542            if let Some(triple) = self.results.pop() {
543                return Some(Ok(triple));
544            } else if self.parser.is_end {
545                return None;
546            }
547            if let Err(RdfXmlParseError::Syntax(e)) = self.parse_step() {
548                // I/O errors can't happen
549                return Some(Err(e));
550            }
551        }
552    }
553}
554
555impl SliceRdfXmlParser<'_> {
556    /// The list of IRI prefixes considered at the current step of the parsing.
557    ///
558    /// This method returns (prefix name, prefix value) tuples.
559    /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
560    /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
561    ///
562    /// ```
563    /// use oxrdfxml::RdfXmlParser;
564    ///
565    /// let file = r#"<?xml version="1.0"?>
566    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
567    ///  <rdf:Description rdf:about="http://example.com/foo">
568    ///    <rdf:type rdf:resource="http://schema.org/Person" />
569    ///    <schema:name>Foo</schema:name>
570    ///  </rdf:Description>
571    ///  <schema:Person rdf:about="http://example.com/bar" schema:name="Bar" />
572    /// </rdf:RDF>"#;
573    ///
574    /// let mut parser = RdfXmlParser::new().for_slice(file);
575    /// assert_eq!(parser.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
576    ///
577    /// parser.next().unwrap()?; // We read the first triple
578    /// assert_eq!(
579    ///     parser.prefixes().collect::<Vec<_>>(),
580    ///     [
581    ///         ("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
582    ///         ("schema", "http://schema.org/")
583    ///     ]
584    /// ); // There are now prefixes
585    /// //
586    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
587    /// ```
588    pub fn prefixes(&self) -> RdfXmlPrefixesIter<'_> {
589        RdfXmlPrefixesIter {
590            inner: self.parser.reader.prefixes(),
591            decoder: self.parser.reader.decoder(),
592            lenient: self.parser.lenient,
593        }
594    }
595
596    /// The base IRI considered at the current step of the parsing.
597    ///
598    /// ```
599    /// use oxrdfxml::RdfXmlParser;
600    ///
601    /// let file = r#"<?xml version="1.0"?>
602    /// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xml:base="http://example.com/">
603    ///  <rdf:Description rdf:about="foo">
604    ///    <rdf:type rdf:resource="http://schema.org/Person" />
605    ///  </rdf:Description>
606    /// </rdf:RDF>"#;
607    ///
608    /// let mut parser = RdfXmlParser::new().for_slice(file);
609    /// assert!(parser.base_iri().is_none()); // No base at the beginning because none has been given to the parser.
610    ///
611    /// parser.next().unwrap()?; // We read the first triple
612    /// assert_eq!(parser.base_iri(), Some("http://example.com/")); // There is now a base IRI.
613    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
614    /// ```
615    pub fn base_iri(&self) -> Option<&str> {
616        Some(self.parser.current_base_iri()?.as_str())
617    }
618
619    /// The current byte position in the input data.
620    pub fn buffer_position(&self) -> u64 {
621        self.parser.reader.buffer_position()
622    }
623
624    fn parse_step(&mut self) -> Result<(), RdfXmlParseError> {
625        let event = self.parser.reader.read_event()?;
626        self.parser.parse_event(event, &mut self.results)
627    }
628}
629
630/// Iterator on the file prefixes.
631///
632/// See [`ReaderRdfXmlParser::prefixes`].
633pub struct RdfXmlPrefixesIter<'a> {
634    inner: PrefixIter<'a>,
635    decoder: Decoder,
636    lenient: bool,
637}
638
639impl<'a> Iterator for RdfXmlPrefixesIter<'a> {
640    type Item = (&'a str, &'a str);
641
642    #[inline]
643    fn next(&mut self) -> Option<Self::Item> {
644        loop {
645            let (key, value) = self.inner.next()?;
646            return Some((
647                match key {
648                    PrefixDeclaration::Default => "",
649                    PrefixDeclaration::Named(name) => {
650                        let Ok(Cow::Borrowed(name)) = self.decoder.decode(name) else {
651                            continue;
652                        };
653                        let Ok(Cow::Borrowed(name)) = unescape_with(name, |_| None) else {
654                            continue;
655                        };
656                        if !self.lenient && !is_nc_name(name) {
657                            continue; // We don't return invalid prefixes
658                        }
659                        name
660                    }
661                },
662                {
663                    let Ok(Cow::Borrowed(value)) = self.decoder.decode(value.0) else {
664                        continue;
665                    };
666                    let Ok(Cow::Borrowed(value)) = unescape_with(value, |_| None) else {
667                        continue;
668                    };
669                    if !self.lenient && Iri::parse(value).is_err() {
670                        continue; // We don't return invalid prefixes
671                    }
672                    value
673                },
674            ));
675        }
676    }
677
678    #[inline]
679    fn size_hint(&self) -> (usize, Option<usize>) {
680        self.inner.size_hint()
681    }
682}
683
684const RDF_ABOUT: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#about";
685const RDF_ABOUT_EACH: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#aboutEach";
686const RDF_ABOUT_EACH_PREFIX: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#aboutEachPrefix";
687const RDF_BAG_ID: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#bagID";
688const RDF_DATATYPE: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#datatype";
689const RDF_DESCRIPTION: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#Description";
690const RDF_ID: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#ID";
691const RDF_LI: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#li";
692const RDF_NODE_ID: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#nodeID";
693const RDF_PARSE_TYPE: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#parseType";
694const RDF_RDF: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#RDF";
695const RDF_RESOURCE: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#resource";
696const RDF_VERSION: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#version";
697const RDF_ANNOTATION: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#annotation";
698const RDF_ANNOTATION_NODE_ID: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#annotationNodeID";
699
700const RESERVED_RDF_ELEMENTS: [&str; 11] = [
701    RDF_ABOUT,
702    RDF_ABOUT_EACH,
703    RDF_ABOUT_EACH_PREFIX,
704    RDF_BAG_ID,
705    RDF_DATATYPE,
706    RDF_ID,
707    RDF_LI,
708    RDF_NODE_ID,
709    RDF_PARSE_TYPE,
710    RDF_RDF,
711    RDF_RESOURCE,
712];
713
714const RESERVED_RDF_ATTRIBUTES: [&str; 5] = [
715    RDF_ABOUT_EACH,
716    RDF_ABOUT_EACH_PREFIX,
717    RDF_LI,
718    RDF_RDF,
719    RDF_RESOURCE,
720];
721
722#[derive(Clone, Debug)]
723enum NodeOrText {
724    Node(NamedOrBlankNode),
725    Text(String),
726}
727
728enum RdfXmlState {
729    Doc {
730        base_iri: Option<Iri<String>>,
731    },
732    Rdf {
733        base_iri: Option<Iri<String>>,
734        language: Option<String>,
735        #[cfg(feature = "rdf-12")]
736        base_direction: Option<BaseDirection>,
737        #[cfg(feature = "rdf-12")]
738        rdf_version: Option<RdfVersion>,
739    },
740    NodeElt {
741        base_iri: Option<Iri<String>>,
742        language: Option<String>,
743        #[cfg(feature = "rdf-12")]
744        base_direction: Option<BaseDirection>,
745        subject: NamedOrBlankNode,
746        li_counter: u64,
747        #[cfg(feature = "rdf-12")]
748        rdf_version: Option<RdfVersion>,
749    },
750    PropertyElt {
751        // Resource, Literal or Empty property element
752        iri: NamedNode,
753        base_iri: Option<Iri<String>>,
754        language: Option<String>,
755        #[cfg(feature = "rdf-12")]
756        base_direction: Option<BaseDirection>,
757        subject: NamedOrBlankNode,
758        object: Option<NodeOrText>,
759        id_attr: Option<NamedNode>,
760        #[cfg(feature = "rdf-12")]
761        annotation_attr: Option<NamedNode>,
762        #[cfg(feature = "rdf-12")]
763        annotation_node_id_attr: Option<BlankNode>,
764        datatype_attr: Option<NamedNode>,
765        #[cfg(feature = "rdf-12")]
766        rdf_version: Option<RdfVersion>,
767    },
768    ParseTypeCollectionPropertyElt {
769        iri: NamedNode,
770        base_iri: Option<Iri<String>>,
771        language: Option<String>,
772        #[cfg(feature = "rdf-12")]
773        base_direction: Option<BaseDirection>,
774        subject: NamedOrBlankNode,
775        objects: Vec<NamedOrBlankNode>,
776        id_attr: Option<NamedNode>,
777        #[cfg(feature = "rdf-12")]
778        annotation_attr: Option<NamedNode>,
779        #[cfg(feature = "rdf-12")]
780        annotation_node_id_attr: Option<BlankNode>,
781        #[cfg(feature = "rdf-12")]
782        rdf_version: Option<RdfVersion>,
783    },
784    ParseTypeLiteralPropertyElt {
785        iri: NamedNode,
786        base_iri: Option<Iri<String>>,
787        language: Option<String>,
788        #[cfg(feature = "rdf-12")]
789        base_direction: Option<BaseDirection>,
790        subject: NamedOrBlankNode,
791        writer: Writer<Vec<u8>>,
792        id_attr: Option<NamedNode>,
793        #[cfg(feature = "rdf-12")]
794        annotation_attr: Option<NamedNode>,
795        #[cfg(feature = "rdf-12")]
796        annotation_node_id_attr: Option<BlankNode>,
797        emit: bool, // false for parseTypeOtherPropertyElt support
798        #[cfg(feature = "rdf-12")]
799        rdf_version: Option<RdfVersion>,
800    },
801    #[cfg(feature = "rdf-12")]
802    ParseTypeTriplePropertyElt {
803        iri: NamedNode,
804        base_iri: Option<Iri<String>>,
805        language: Option<String>,
806        base_direction: Option<BaseDirection>,
807        subject: NamedOrBlankNode,
808        id_attr: Option<NamedNode>,
809        annotation_attr: Option<NamedNode>,
810        annotation_node_id_attr: Option<BlankNode>,
811        rdf_version: Option<RdfVersion>,
812        triples: Vec<Triple>,
813    },
814}
815
816struct InternalRdfXmlParser<R> {
817    reader: NsReader<R>,
818    state: Vec<RdfXmlState>,
819    custom_entities: HashMap<String, String>,
820    in_literal_depth: usize,
821    known_rdf_id: HashSet<String>,
822    is_end: bool,
823    lenient: bool,
824}
825
826impl<R> InternalRdfXmlParser<R> {
827    fn parse_event(
828        &mut self,
829        event: Event<'_>,
830        results: &mut Vec<Triple>,
831    ) -> Result<(), RdfXmlParseError> {
832        match event {
833            Event::Start(event) => self.parse_start_event(&event, results),
834            Event::End(event) => self.parse_end_event(&event, results),
835            Event::Empty(_) => Err(RdfXmlSyntaxError::msg(
836                "The expand_empty_elements option must be enabled",
837            )
838            .into()),
839            Event::Text(event) => self.parse_text_event(&event),
840            Event::CData(event) => self.parse_text_event(&event.escape()?),
841            Event::Comment(_) | Event::PI(_) => Ok(()),
842            Event::Decl(decl) => {
843                if let Some(encoding) = decl.encoding() {
844                    if !is_utf8(&encoding?) {
845                        return Err(RdfXmlSyntaxError::msg(
846                            "Only UTF-8 is supported by the RDF/XML parser",
847                        )
848                        .into());
849                    }
850                }
851                Ok(())
852            }
853            Event::DocType(dt) => self.parse_doctype(&dt),
854            Event::Eof => {
855                self.is_end = true;
856                Ok(())
857            }
858        }
859    }
860
861    fn parse_doctype(&mut self, dt: &BytesText<'_>) -> Result<(), RdfXmlParseError> {
862        // we extract entities
863        for input in self
864            .reader
865            .decoder()
866            .decode(dt.as_ref())?
867            .split('<')
868            .skip(1)
869        {
870            if let Some(input) = input.strip_prefix("!ENTITY") {
871                let input = input.trim_start().strip_prefix('%').unwrap_or(input);
872                let (entity_name, input) = input.trim_start().split_once(|c: char| c.is_ascii_whitespace()).ok_or_else(|| {
873                    RdfXmlSyntaxError::msg(
874                        "<!ENTITY declarations should contain both an entity name and an entity value",
875                    )
876                })?;
877                let input = input.trim_start().strip_prefix('\"').ok_or_else(|| {
878                    RdfXmlSyntaxError::msg("<!ENTITY values should be enclosed in double quotes")
879                })?;
880                let (entity_value, input) = input.split_once('"').ok_or_else(|| {
881                    RdfXmlSyntaxError::msg(
882                        "<!ENTITY declarations values should be enclosed in double quotes",
883                    )
884                })?;
885                input.trim_start().strip_prefix('>').ok_or_else(|| {
886                    RdfXmlSyntaxError::msg("<!ENTITY declarations values should end with >")
887                })?;
888
889                // Resolves custom entities within the current entity definition.
890                let entity_value =
891                    unescape_with(entity_value, |e| self.resolve_entity(e)).map_err(Error::from)?;
892                self.custom_entities
893                    .insert(entity_name.to_owned(), entity_value.to_string());
894            }
895        }
896        Ok(())
897    }
898
899    fn parse_start_event(
900        &mut self,
901        event: &BytesStart<'_>,
902        results: &mut Vec<Triple>,
903    ) -> Result<(), RdfXmlParseError> {
904        #[derive(PartialEq, Eq)]
905        enum RdfXmlParseType {
906            Default,
907            Collection,
908            Literal,
909            Resource,
910            #[cfg(feature = "rdf-12")]
911            Triple,
912            Other,
913        }
914
915        #[derive(PartialEq, Eq)]
916        enum RdfXmlNextProduction {
917            Rdf,
918            NodeElt,
919            PropertyElt { subject: NamedOrBlankNode },
920        }
921
922        // Literal case
923        if let Some(RdfXmlState::ParseTypeLiteralPropertyElt { writer, .. }) = self.state.last_mut()
924        {
925            let mut clean_event = BytesStart::new(
926                self.reader
927                    .decoder()
928                    .decode(event.name().as_ref())?
929                    .to_string(),
930            );
931            for attr in event.attributes() {
932                clean_event.push_attribute(attr.map_err(Error::InvalidAttr)?);
933            }
934            if self.in_literal_depth == 0 {
935                for (prefix, namespace) in self.reader.prefixes() {
936                    match prefix {
937                        PrefixDeclaration::Default => {
938                            clean_event.push_attribute(("xmlns".as_bytes(), namespace.into_inner()))
939                        }
940                        PrefixDeclaration::Named(name) => {
941                            let mut attr = Vec::with_capacity(6 + name.len());
942                            attr.extend_from_slice(b"xmlns:");
943                            attr.extend_from_slice(name);
944                            clean_event.push_attribute((attr.as_slice(), namespace.into_inner()))
945                        }
946                    }
947                }
948            }
949            writer.write_event(Event::Start(clean_event))?;
950            self.in_literal_depth += 1;
951            return Ok(());
952        }
953
954        let (tag_namespace, tag_local_name) = self.reader.resolve_element(event.name());
955        let tag_name = self.resolve_ns_name(tag_namespace, tag_local_name)?;
956
957        // We read attributes
958        let mut language = None;
959        let mut base_iri = None;
960        let mut id_attr = None;
961        let mut node_id_attr = None;
962        let mut about_attr = None;
963        let mut property_attrs = Vec::default();
964        let mut resource_attr = None;
965        let mut datatype_attr = None;
966        let mut parse_type = RdfXmlParseType::Default;
967        let mut type_attr = None;
968        #[cfg(feature = "rdf-12")]
969        let mut base_direction_attr = None;
970        #[cfg(feature = "rdf-12")]
971        let mut rdf_version = None;
972        #[cfg(feature = "rdf-12")]
973        let mut annotation_attr = None;
974        #[cfg(feature = "rdf-12")]
975        let mut annotation_node_id_attr = None;
976
977        for attribute in event.attributes() {
978            let attribute = attribute.map_err(Error::InvalidAttr)?;
979            let (attribute_namespace, attribute_local_name) =
980                self.reader.resolve_attribute(attribute.key);
981            if attribute_namespace
982                == ResolveResult::Bound(Namespace(b"http://www.w3.org/XML/1998/namespace"))
983            {
984                match attribute.key.local_name().as_ref() {
985                    b"lang" => {
986                        let tag = self.convert_attribute(&attribute)?.to_ascii_lowercase();
987                        language = Some(if self.lenient {
988                            tag
989                        } else {
990                            LanguageTag::parse(tag.clone())
991                                .map_err(|error| {
992                                    RdfXmlSyntaxError::invalid_language_tag(tag, error)
993                                })?
994                                .into_inner()
995                        });
996                    }
997                    b"base" => {
998                        let iri = self.convert_attribute(&attribute)?;
999                        base_iri = Some(if self.lenient {
1000                            Iri::parse_unchecked(iri.into_owned())
1001                        } else {
1002                            Iri::parse(iri.clone().into_owned()).map_err(|error| {
1003                                RdfXmlSyntaxError::invalid_iri(iri.into(), error)
1004                            })?
1005                        })
1006                    }
1007                    _ => (), // We ignore other xml attributes
1008                }
1009            } else if attribute.key.as_ref().starts_with(b"xml") {
1010                // We ignore other xml attributes
1011            } else if cfg!(feature = "rdf-12")
1012                && attribute_namespace
1013                    == ResolveResult::Bound(Namespace(b"http://www.w3.org/2005/11/its"))
1014                && attribute.key.local_name().as_ref() == b"dir"
1015            {
1016                #[cfg(feature = "rdf-12")]
1017                {
1018                    base_direction_attr = Some(attribute);
1019                }
1020            } else if cfg!(feature = "rdf-12")
1021                && attribute_namespace
1022                    == ResolveResult::Bound(Namespace(b"http://www.w3.org/2005/11/its"))
1023                && attribute.key.local_name().as_ref() == b"version"
1024            {
1025                // We ignore its:version
1026            } else {
1027                let attribute_url =
1028                    self.resolve_ns_name(attribute_namespace.clone(), attribute_local_name)?;
1029                if *attribute_url == *RDF_ID {
1030                    let mut id = self.convert_attribute(&attribute)?.into_owned();
1031                    if !is_nc_name(&id) {
1032                        return Err(RdfXmlSyntaxError::msg(format!(
1033                            "{id} is not a valid rdf:ID value"
1034                        ))
1035                        .into());
1036                    }
1037                    id.insert(0, '#');
1038                    id_attr = Some(id);
1039                } else if *attribute_url == *RDF_BAG_ID {
1040                    let bag_id = self.convert_attribute(&attribute)?;
1041                    if !is_nc_name(&bag_id) {
1042                        return Err(RdfXmlSyntaxError::msg(format!(
1043                            "{bag_id} is not a valid rdf:bagID value"
1044                        ))
1045                        .into());
1046                    }
1047                } else if *attribute_url == *RDF_NODE_ID {
1048                    let id = self.convert_attribute(&attribute)?;
1049                    if !is_nc_name(&id) {
1050                        return Err(RdfXmlSyntaxError::msg(format!(
1051                            "{id} is not a valid rdf:nodeID value"
1052                        ))
1053                        .into());
1054                    }
1055                    node_id_attr = Some(BlankNode::new_unchecked(id));
1056                } else if *attribute_url == *RDF_ABOUT {
1057                    about_attr = Some(attribute);
1058                } else if *attribute_url == *RDF_RESOURCE {
1059                    resource_attr = Some(attribute);
1060                } else if *attribute_url == *RDF_DATATYPE {
1061                    datatype_attr = Some(attribute);
1062                } else if *attribute_url == *RDF_PARSE_TYPE {
1063                    parse_type = match self.convert_attribute(&attribute)?.as_ref() {
1064                        "Collection" => RdfXmlParseType::Collection,
1065                        "Literal" => RdfXmlParseType::Literal,
1066                        "Resource" => RdfXmlParseType::Resource,
1067                        #[cfg(feature = "rdf-12")]
1068                        "Triple" => RdfXmlParseType::Triple,
1069                        _ => RdfXmlParseType::Other,
1070                    };
1071                } else if cfg!(feature = "rdf-12") && *attribute_url == *RDF_VERSION {
1072                    #[cfg(feature = "rdf-12")]
1073                    {
1074                        rdf_version =
1075                            Some(RdfVersion::from_str(&self.convert_attribute(&attribute)?)?);
1076                    }
1077                } else if cfg!(feature = "rdf-12") && *attribute_url == *RDF_ANNOTATION {
1078                    #[cfg(feature = "rdf-12")]
1079                    {
1080                        annotation_attr = Some(attribute);
1081                    }
1082                } else if cfg!(feature = "rdf-12") && *attribute_url == *RDF_ANNOTATION_NODE_ID {
1083                    #[cfg(feature = "rdf-12")]
1084                    {
1085                        annotation_node_id_attr = Some(attribute);
1086                    }
1087                } else if attribute_url == rdf::TYPE.as_str() {
1088                    type_attr = Some(attribute);
1089                } else if RESERVED_RDF_ATTRIBUTES.contains(&&*attribute_url) {
1090                    return Err(RdfXmlSyntaxError::msg(format!(
1091                        "{attribute_url} is not a valid attribute"
1092                    ))
1093                    .into());
1094                } else {
1095                    property_attrs.push((
1096                        self.parse_iri(attribute_url)?,
1097                        self.convert_attribute(&attribute)?.into(),
1098                    ));
1099                }
1100            }
1101        }
1102
1103        // Parsing with the base URI
1104        let id_attr = if let Some(iri) = id_attr {
1105            let iri = self.resolve_iri(base_iri.as_ref(), iri.into())?;
1106            if !self.lenient {
1107                if self.known_rdf_id.contains(iri.as_str()) {
1108                    return Err(RdfXmlSyntaxError::msg(format!(
1109                        "{iri} has already been used as rdf:ID value"
1110                    ))
1111                    .into());
1112                }
1113                self.known_rdf_id.insert(iri.as_str().into());
1114            }
1115            Some(iri)
1116        } else {
1117            None
1118        };
1119        let about_attr = if let Some(attr) = about_attr {
1120            Some(self.convert_iri_attribute(base_iri.as_ref(), &attr)?)
1121        } else {
1122            None
1123        };
1124        let resource_attr = if let Some(attr) = resource_attr {
1125            Some(self.convert_iri_attribute(base_iri.as_ref(), &attr)?)
1126        } else {
1127            None
1128        };
1129        let datatype_attr = if let Some(attr) = datatype_attr {
1130            Some(self.convert_iri_attribute(base_iri.as_ref(), &attr)?)
1131        } else {
1132            None
1133        };
1134        let type_attr = if let Some(attr) = type_attr {
1135            Some(self.convert_iri_attribute(base_iri.as_ref(), &attr)?)
1136        } else {
1137            None
1138        };
1139        #[cfg(feature = "rdf-12")]
1140        let base_direction = if rdf_version
1141            .unwrap_or_else(|| self.current_rdf_version())
1142            .supports_its_dir()
1143        {
1144            if let Some(attr) = base_direction_attr {
1145                Some(match self.convert_attribute(&attr)?.as_ref() {
1146                    "ltr" => BaseDirection::Ltr,
1147                    "rtl" => BaseDirection::Rtl,
1148                    base => {
1149                        return Err(RdfXmlSyntaxError::msg(format!(
1150                            "Invalid base direction: '{base}'"
1151                        ))
1152                        .into());
1153                    }
1154                })
1155            } else {
1156                None
1157            }
1158        } else {
1159            None
1160        };
1161        #[cfg(feature = "rdf-12")]
1162        let annotation_attr = if let Some(attr) = annotation_attr {
1163            Some(self.convert_iri_attribute(base_iri.as_ref(), &attr)?)
1164        } else {
1165            None
1166        };
1167        #[cfg(feature = "rdf-12")]
1168        let annotation_node_id_attr = if let Some(attr) = annotation_node_id_attr {
1169            let id = self.convert_attribute(&attr)?;
1170            if !is_nc_name(&id) {
1171                return Err(RdfXmlSyntaxError::msg(format!(
1172                    "{id} is not a valid rdf:annotationNodeID value"
1173                ))
1174                .into());
1175            }
1176            Some(BlankNode::new_unchecked(id))
1177        } else {
1178            None
1179        };
1180
1181        let expected_production = match self.state.last() {
1182            Some(RdfXmlState::Doc { .. }) => RdfXmlNextProduction::Rdf,
1183            Some(
1184                RdfXmlState::Rdf { .. }
1185                | RdfXmlState::PropertyElt { .. }
1186                | RdfXmlState::ParseTypeCollectionPropertyElt { .. },
1187            ) => RdfXmlNextProduction::NodeElt,
1188            Some(RdfXmlState::NodeElt { subject, .. }) => RdfXmlNextProduction::PropertyElt {
1189                subject: subject.clone(),
1190            },
1191            Some(RdfXmlState::ParseTypeLiteralPropertyElt { .. }) => {
1192                return Err(
1193                    RdfXmlSyntaxError::msg("ParseTypeLiteralPropertyElt production children should never be considered as a RDF/XML content").into()
1194                );
1195            }
1196            #[cfg(feature = "rdf-12")]
1197            Some(RdfXmlState::ParseTypeTriplePropertyElt { .. }) => RdfXmlNextProduction::NodeElt,
1198            None => {
1199                return Err(RdfXmlSyntaxError::msg(
1200                    "No state in the stack: the XML is not balanced",
1201                )
1202                .into());
1203            }
1204        };
1205
1206        let new_state = match expected_production {
1207            RdfXmlNextProduction::Rdf => {
1208                if *tag_name == *RDF_RDF {
1209                    RdfXmlState::Rdf {
1210                        base_iri,
1211                        language,
1212                        #[cfg(feature = "rdf-12")]
1213                        base_direction,
1214                        #[cfg(feature = "rdf-12")]
1215                        rdf_version,
1216                    }
1217                } else if RESERVED_RDF_ELEMENTS.contains(&&*tag_name) {
1218                    return Err(RdfXmlSyntaxError::msg(format!(
1219                        "Invalid node element tag name: {tag_name}"
1220                    ))
1221                    .into());
1222                } else {
1223                    self.build_node_elt(
1224                        self.parse_iri(tag_name)?,
1225                        base_iri,
1226                        language,
1227                        #[cfg(feature = "rdf-12")]
1228                        base_direction,
1229                        id_attr,
1230                        node_id_attr,
1231                        about_attr,
1232                        type_attr,
1233                        property_attrs,
1234                        #[cfg(feature = "rdf-12")]
1235                        rdf_version,
1236                        results,
1237                    )?
1238                }
1239            }
1240            RdfXmlNextProduction::NodeElt => {
1241                if RESERVED_RDF_ELEMENTS.contains(&&*tag_name) {
1242                    return Err(RdfXmlSyntaxError::msg(format!(
1243                        "Invalid property element tag name: {tag_name}"
1244                    ))
1245                    .into());
1246                }
1247                self.build_node_elt(
1248                    self.parse_iri(tag_name)?,
1249                    base_iri,
1250                    language,
1251                    #[cfg(feature = "rdf-12")]
1252                    base_direction,
1253                    id_attr,
1254                    node_id_attr,
1255                    about_attr,
1256                    type_attr,
1257                    property_attrs,
1258                    #[cfg(feature = "rdf-12")]
1259                    rdf_version,
1260                    results,
1261                )?
1262            }
1263            RdfXmlNextProduction::PropertyElt { subject } => {
1264                let iri = if *tag_name == *RDF_LI {
1265                    let Some(RdfXmlState::NodeElt { li_counter, .. }) = self.state.last_mut()
1266                    else {
1267                        return Err(RdfXmlSyntaxError::msg(format!(
1268                            "Invalid property element tag name: {tag_name}"
1269                        ))
1270                        .into());
1271                    };
1272                    *li_counter += 1;
1273                    NamedNode::new_unchecked(format!(
1274                        "http://www.w3.org/1999/02/22-rdf-syntax-ns#_{li_counter}"
1275                    ))
1276                } else if RESERVED_RDF_ELEMENTS.contains(&&*tag_name)
1277                    || *tag_name == *RDF_DESCRIPTION
1278                {
1279                    return Err(RdfXmlSyntaxError::msg(format!(
1280                        "Invalid property element tag name: {tag_name}"
1281                    ))
1282                    .into());
1283                } else {
1284                    self.parse_iri(tag_name)?
1285                };
1286                match parse_type {
1287                    RdfXmlParseType::Default => {
1288                        if resource_attr.is_some()
1289                            || node_id_attr.is_some()
1290                            || !property_attrs.is_empty()
1291                        {
1292                            let object = match (resource_attr, node_id_attr)
1293                            {
1294                                (Some(resource_attr), None) => NamedOrBlankNode::from(resource_attr),
1295                                (None, Some(node_id_attr)) => node_id_attr.into(),
1296                                (None, None) => BlankNode::default().into(),
1297                                (Some(_), Some(_)) => return Err(RdfXmlSyntaxError::msg("Not both rdf:resource and rdf:nodeID could be set at the same time").into())
1298                            };
1299                            self.emit_property_attrs(
1300                                &object,
1301                                property_attrs,
1302                                language.as_deref(),
1303                                #[cfg(feature = "rdf-12")]
1304                                base_direction,
1305                                results,
1306                            );
1307                            if let Some(type_attr) = type_attr {
1308                                self.emit_triple(
1309                                    results,
1310                                    Triple::new(object.clone(), rdf::TYPE, type_attr),
1311                                );
1312                            }
1313                            RdfXmlState::PropertyElt {
1314                                iri,
1315                                base_iri,
1316                                language,
1317                                #[cfg(feature = "rdf-12")]
1318                                base_direction,
1319                                subject,
1320                                object: Some(NodeOrText::Node(object)),
1321                                id_attr,
1322                                #[cfg(feature = "rdf-12")]
1323                                annotation_attr,
1324                                #[cfg(feature = "rdf-12")]
1325                                annotation_node_id_attr,
1326                                datatype_attr,
1327                                #[cfg(feature = "rdf-12")]
1328                                rdf_version,
1329                            }
1330                        } else {
1331                            RdfXmlState::PropertyElt {
1332                                iri,
1333                                base_iri,
1334                                language,
1335                                #[cfg(feature = "rdf-12")]
1336                                base_direction,
1337                                subject,
1338                                object: None,
1339                                id_attr,
1340                                #[cfg(feature = "rdf-12")]
1341                                annotation_attr,
1342                                #[cfg(feature = "rdf-12")]
1343                                annotation_node_id_attr,
1344                                datatype_attr,
1345                                #[cfg(feature = "rdf-12")]
1346                                rdf_version,
1347                            }
1348                        }
1349                    }
1350                    RdfXmlParseType::Literal => RdfXmlState::ParseTypeLiteralPropertyElt {
1351                        iri,
1352                        base_iri,
1353                        language,
1354                        #[cfg(feature = "rdf-12")]
1355                        base_direction,
1356                        subject,
1357                        writer: Writer::new(Vec::default()),
1358                        id_attr,
1359                        #[cfg(feature = "rdf-12")]
1360                        annotation_attr,
1361                        #[cfg(feature = "rdf-12")]
1362                        annotation_node_id_attr,
1363                        emit: true,
1364                        #[cfg(feature = "rdf-12")]
1365                        rdf_version,
1366                    },
1367                    RdfXmlParseType::Resource => self.build_parse_type_resource_property_elt(
1368                        iri,
1369                        base_iri,
1370                        language,
1371                        #[cfg(feature = "rdf-12")]
1372                        base_direction,
1373                        #[cfg(feature = "rdf-12")]
1374                        rdf_version,
1375                        subject,
1376                        id_attr,
1377                        #[cfg(feature = "rdf-12")]
1378                        annotation_attr,
1379                        #[cfg(feature = "rdf-12")]
1380                        annotation_node_id_attr,
1381                        results,
1382                    ),
1383                    RdfXmlParseType::Collection => RdfXmlState::ParseTypeCollectionPropertyElt {
1384                        iri,
1385                        base_iri,
1386                        language,
1387                        #[cfg(feature = "rdf-12")]
1388                        base_direction,
1389                        subject,
1390                        objects: Vec::default(),
1391                        id_attr,
1392                        #[cfg(feature = "rdf-12")]
1393                        annotation_attr,
1394                        #[cfg(feature = "rdf-12")]
1395                        annotation_node_id_attr,
1396                        #[cfg(feature = "rdf-12")]
1397                        rdf_version,
1398                    },
1399                    #[cfg(feature = "rdf-12")]
1400                    RdfXmlParseType::Triple => RdfXmlState::ParseTypeTriplePropertyElt {
1401                        iri,
1402                        base_iri,
1403                        language,
1404                        base_direction,
1405                        subject,
1406                        id_attr,
1407                        #[cfg(feature = "rdf-12")]
1408                        annotation_attr,
1409                        #[cfg(feature = "rdf-12")]
1410                        annotation_node_id_attr,
1411                        #[cfg(feature = "rdf-12")]
1412                        rdf_version,
1413                        triples: Vec::new(),
1414                    },
1415                    RdfXmlParseType::Other => RdfXmlState::ParseTypeLiteralPropertyElt {
1416                        iri,
1417                        base_iri,
1418                        language,
1419                        #[cfg(feature = "rdf-12")]
1420                        base_direction,
1421                        subject,
1422                        writer: Writer::new(Vec::default()),
1423                        id_attr,
1424                        #[cfg(feature = "rdf-12")]
1425                        annotation_attr,
1426                        #[cfg(feature = "rdf-12")]
1427                        annotation_node_id_attr,
1428                        emit: false,
1429                        #[cfg(feature = "rdf-12")]
1430                        rdf_version,
1431                    },
1432                }
1433            }
1434        };
1435        self.state.push(new_state);
1436        Ok(())
1437    }
1438
1439    fn parse_end_event(
1440        &mut self,
1441        event: &BytesEnd<'_>,
1442        results: &mut Vec<Triple>,
1443    ) -> Result<(), RdfXmlParseError> {
1444        // Literal case
1445        if self.in_literal_depth > 0 {
1446            let Some(RdfXmlState::ParseTypeLiteralPropertyElt { writer, .. }) =
1447                self.state.last_mut()
1448            else {
1449                unreachable!()
1450            };
1451            writer.write_event(Event::End(BytesEnd::new(
1452                self.reader.decoder().decode(event.name().as_ref())?,
1453            )))?;
1454            self.in_literal_depth -= 1;
1455            return Ok(());
1456        }
1457
1458        if let Some(current_state) = self.state.pop() {
1459            self.end_state(current_state, results)?;
1460        }
1461        Ok(())
1462    }
1463
1464    fn parse_text_event(&mut self, event: &BytesText<'_>) -> Result<(), RdfXmlParseError> {
1465        let text = event.unescape_with(|e| self.resolve_entity(e))?.to_string();
1466        match self.state.last_mut() {
1467            Some(RdfXmlState::PropertyElt { object, .. }) => {
1468                if is_object_defined(object) {
1469                    if text.bytes().all(is_whitespace) {
1470                        Ok(()) // whitespace anyway, we ignore
1471                    } else {
1472                        Err(
1473                            RdfXmlSyntaxError::msg(format!("Unexpected text event: '{text}'"))
1474                                .into(),
1475                        )
1476                    }
1477                } else {
1478                    *object = Some(NodeOrText::Text(text));
1479                    Ok(())
1480                }
1481            }
1482            Some(RdfXmlState::ParseTypeLiteralPropertyElt { writer, .. }) => {
1483                writer.write_event(Event::Text(BytesText::new(&text)))?;
1484                Ok(())
1485            }
1486            _ => {
1487                if text.bytes().all(is_whitespace) {
1488                    Ok(())
1489                } else {
1490                    Err(RdfXmlSyntaxError::msg(format!("Unexpected text event: '{text}'")).into())
1491                }
1492            }
1493        }
1494    }
1495
1496    fn resolve_ns_name(
1497        &self,
1498        namespace: ResolveResult<'_>,
1499        local_name: LocalName<'_>,
1500    ) -> Result<String, RdfXmlParseError> {
1501        match namespace {
1502            ResolveResult::Bound(ns) => {
1503                let mut value = Vec::with_capacity(ns.as_ref().len() + local_name.as_ref().len());
1504                value.extend_from_slice(ns.as_ref());
1505                value.extend_from_slice(local_name.as_ref());
1506                Ok(unescape_with(&self.reader.decoder().decode(&value)?, |e| {
1507                    self.resolve_entity(e)
1508                })
1509                .map_err(Error::from)?
1510                .to_string())
1511            }
1512            ResolveResult::Unbound => {
1513                Err(RdfXmlSyntaxError::msg("XML namespaces are required in RDF/XML").into())
1514            }
1515            ResolveResult::Unknown(v) => Err(RdfXmlSyntaxError::msg(format!(
1516                "Unknown prefix {}:",
1517                self.reader.decoder().decode(&v)?
1518            ))
1519            .into()),
1520        }
1521    }
1522
1523    #[cfg_attr(feature = "rdf-12", expect(clippy::too_many_arguments))]
1524    fn build_node_elt(
1525        &mut self,
1526        iri: NamedNode,
1527        base_iri: Option<Iri<String>>,
1528        language: Option<String>,
1529        #[cfg(feature = "rdf-12")] base_direction: Option<BaseDirection>,
1530        id_attr: Option<NamedNode>,
1531        node_id_attr: Option<BlankNode>,
1532        about_attr: Option<NamedNode>,
1533        type_attr: Option<NamedNode>,
1534        property_attrs: Vec<(NamedNode, String)>,
1535        #[cfg(feature = "rdf-12")] rdf_version: Option<RdfVersion>,
1536        results: &mut Vec<Triple>,
1537    ) -> Result<RdfXmlState, RdfXmlSyntaxError> {
1538        let subject = match (id_attr, node_id_attr, about_attr) {
1539            (Some(id_attr), None, None) => NamedOrBlankNode::from(id_attr),
1540            (None, Some(node_id_attr), None) => node_id_attr.into(),
1541            (None, None, Some(about_attr)) => about_attr.into(),
1542            (None, None, None) => BlankNode::default().into(),
1543            (Some(_), Some(_), _) => {
1544                return Err(RdfXmlSyntaxError::msg(
1545                    "Not both rdf:ID and rdf:nodeID could be set at the same time",
1546                ));
1547            }
1548            (_, Some(_), Some(_)) => {
1549                return Err(RdfXmlSyntaxError::msg(
1550                    "Not both rdf:nodeID and rdf:resource could be set at the same time",
1551                ));
1552            }
1553            (Some(_), _, Some(_)) => {
1554                return Err(RdfXmlSyntaxError::msg(
1555                    "Not both rdf:ID and rdf:resource could be set at the same time",
1556                ));
1557            }
1558        };
1559
1560        self.emit_property_attrs(
1561            &subject,
1562            property_attrs,
1563            language.as_deref(),
1564            #[cfg(feature = "rdf-12")]
1565            base_direction,
1566            results,
1567        );
1568
1569        if let Some(type_attr) = type_attr {
1570            self.emit_triple(results, Triple::new(subject.clone(), rdf::TYPE, type_attr));
1571        }
1572
1573        if iri != *RDF_DESCRIPTION {
1574            self.emit_triple(results, Triple::new(subject.clone(), rdf::TYPE, iri));
1575        }
1576        Ok(RdfXmlState::NodeElt {
1577            base_iri,
1578            language,
1579            #[cfg(feature = "rdf-12")]
1580            base_direction,
1581            subject,
1582            li_counter: 0,
1583            #[cfg(feature = "rdf-12")]
1584            rdf_version,
1585        })
1586    }
1587
1588    #[cfg_attr(feature = "rdf-12", expect(clippy::too_many_arguments))]
1589    fn build_parse_type_resource_property_elt(
1590        &mut self,
1591        iri: NamedNode,
1592        base_iri: Option<Iri<String>>,
1593        language: Option<String>,
1594        #[cfg(feature = "rdf-12")] base_direction: Option<BaseDirection>,
1595        #[cfg(feature = "rdf-12")] rdf_version: Option<RdfVersion>,
1596        subject: NamedOrBlankNode,
1597        id_attr: Option<NamedNode>,
1598        #[cfg(feature = "rdf-12")] annotation_attr: Option<NamedNode>,
1599        #[cfg(feature = "rdf-12")] annotation_node_id_attr: Option<BlankNode>,
1600        results: &mut Vec<Triple>,
1601    ) -> RdfXmlState {
1602        let object = BlankNode::default();
1603        let triple = Triple::new(subject, iri, object.clone());
1604        self.reify_and_annotation(
1605            &triple,
1606            id_attr,
1607            #[cfg(feature = "rdf-12")]
1608            annotation_attr,
1609            #[cfg(feature = "rdf-12")]
1610            annotation_node_id_attr,
1611            results,
1612        );
1613        self.emit_triple(results, triple);
1614        RdfXmlState::NodeElt {
1615            base_iri,
1616            language,
1617            #[cfg(feature = "rdf-12")]
1618            base_direction,
1619            subject: object.into(),
1620            li_counter: 0,
1621            #[cfg(feature = "rdf-12")]
1622            rdf_version,
1623        }
1624    }
1625
1626    fn end_state(
1627        &mut self,
1628        state: RdfXmlState,
1629        results: &mut Vec<Triple>,
1630    ) -> Result<(), RdfXmlSyntaxError> {
1631        match state {
1632            RdfXmlState::PropertyElt {
1633                iri,
1634                language,
1635                #[cfg(feature = "rdf-12")]
1636                base_direction,
1637                subject,
1638                id_attr,
1639                #[cfg(feature = "rdf-12")]
1640                annotation_attr,
1641                #[cfg(feature = "rdf-12")]
1642                annotation_node_id_attr,
1643                datatype_attr,
1644                object,
1645                ..
1646            } => {
1647                let object = match object {
1648                    Some(NodeOrText::Node(node)) => Term::from(node),
1649                    Some(NodeOrText::Text(text)) => self
1650                        .new_literal(
1651                            text,
1652                            language,
1653                            #[cfg(feature = "rdf-12")]
1654                            base_direction,
1655                            datatype_attr,
1656                        )
1657                        .into(),
1658                    None => self
1659                        .new_literal(
1660                            String::new(),
1661                            language,
1662                            #[cfg(feature = "rdf-12")]
1663                            base_direction,
1664                            datatype_attr,
1665                        )
1666                        .into(),
1667                };
1668                let triple = Triple::new(subject, iri, object);
1669                self.reify_and_annotation(
1670                    &triple,
1671                    id_attr,
1672                    #[cfg(feature = "rdf-12")]
1673                    annotation_attr,
1674                    #[cfg(feature = "rdf-12")]
1675                    annotation_node_id_attr,
1676                    results,
1677                );
1678                self.emit_triple(results, triple);
1679            }
1680            RdfXmlState::ParseTypeCollectionPropertyElt {
1681                iri,
1682                subject,
1683                id_attr,
1684                #[cfg(feature = "rdf-12")]
1685                annotation_attr,
1686                #[cfg(feature = "rdf-12")]
1687                annotation_node_id_attr,
1688                objects,
1689                ..
1690            } => {
1691                let mut current_node = NamedOrBlankNode::from(rdf::NIL);
1692                for object in objects.into_iter().rev() {
1693                    let subject = NamedOrBlankNode::from(BlankNode::default());
1694                    self.emit_triple(results, Triple::new(subject.clone(), rdf::FIRST, object));
1695                    self.emit_triple(
1696                        results,
1697                        Triple::new(subject.clone(), rdf::REST, current_node),
1698                    );
1699                    current_node = subject;
1700                }
1701                let triple = Triple::new(subject, iri, current_node);
1702                self.reify_and_annotation(
1703                    &triple,
1704                    id_attr,
1705                    #[cfg(feature = "rdf-12")]
1706                    annotation_attr,
1707                    #[cfg(feature = "rdf-12")]
1708                    annotation_node_id_attr,
1709                    results,
1710                );
1711                self.emit_triple(results, triple);
1712            }
1713            RdfXmlState::ParseTypeLiteralPropertyElt {
1714                iri,
1715                subject,
1716                id_attr,
1717                #[cfg(feature = "rdf-12")]
1718                annotation_attr,
1719                #[cfg(feature = "rdf-12")]
1720                annotation_node_id_attr,
1721                writer,
1722                emit,
1723                ..
1724            } => {
1725                if emit {
1726                    let object = writer.into_inner();
1727                    if object.is_empty() {
1728                        return Err(RdfXmlSyntaxError::msg(format!(
1729                            "No value found for rdf:XMLLiteral value of property {iri}"
1730                        )));
1731                    }
1732                    let triple = Triple::new(
1733                        subject,
1734                        iri,
1735                        Literal::new_typed_literal(
1736                            str::from_utf8(&object).map_err(|_| {
1737                                RdfXmlSyntaxError::msg(
1738                                    "The XML literal is not in valid UTF-8".to_owned(),
1739                                )
1740                            })?,
1741                            rdf::XML_LITERAL,
1742                        ),
1743                    );
1744                    self.reify_and_annotation(
1745                        &triple,
1746                        id_attr,
1747                        #[cfg(feature = "rdf-12")]
1748                        annotation_attr,
1749                        #[cfg(feature = "rdf-12")]
1750                        annotation_node_id_attr,
1751                        results,
1752                    );
1753                    self.emit_triple(results, triple);
1754                }
1755            }
1756            RdfXmlState::NodeElt { subject, .. } => match self.state.last_mut() {
1757                Some(RdfXmlState::PropertyElt { object, .. }) => {
1758                    if is_object_defined(object) {
1759                        return Err(RdfXmlSyntaxError::msg(
1760                            "Unexpected node, a text value is already present",
1761                        ));
1762                    }
1763                    *object = Some(NodeOrText::Node(subject))
1764                }
1765                Some(RdfXmlState::ParseTypeCollectionPropertyElt { objects, .. }) => {
1766                    objects.push(subject)
1767                }
1768                _ => (),
1769            },
1770            RdfXmlState::Doc { .. } | RdfXmlState::Rdf { .. } => (),
1771            #[cfg(feature = "rdf-12")]
1772            RdfXmlState::ParseTypeTriplePropertyElt {
1773                iri,
1774                subject,
1775                id_attr,
1776                annotation_attr,
1777                annotation_node_id_attr,
1778                triples,
1779                rdf_version,
1780                ..
1781            } => {
1782                if rdf_version
1783                    .unwrap_or_else(|| self.current_rdf_version())
1784                    .supports_triple_term()
1785                {
1786                    if triples.len() != 1 {
1787                        return Err(RdfXmlSyntaxError::msg(
1788                            "rdf:parseType=\"Triple\" can only include a single triple",
1789                        ));
1790                    }
1791                    let triple = Triple::new(subject, iri, triples.into_iter().next().unwrap());
1792                    self.reify_and_annotation(
1793                        &triple,
1794                        id_attr,
1795                        annotation_attr,
1796                        annotation_node_id_attr,
1797                        results,
1798                    );
1799                    self.emit_triple(results, triple);
1800                }
1801            }
1802        }
1803        Ok(())
1804    }
1805
1806    fn new_literal(
1807        &self,
1808        value: String,
1809        language: Option<String>,
1810        #[cfg(feature = "rdf-12")] base_direction: Option<BaseDirection>,
1811        datatype: Option<NamedNode>,
1812    ) -> Literal {
1813        if let Some(datatype) = datatype {
1814            Literal::new_typed_literal(value, datatype)
1815        } else if let Some(language) =
1816            language.or_else(|| self.current_language().map(ToOwned::to_owned))
1817        {
1818            #[cfg(feature = "rdf-12")]
1819            if let Some(base_direction) = base_direction {
1820                return Literal::new_directional_language_tagged_literal_unchecked(
1821                    value,
1822                    language,
1823                    base_direction,
1824                );
1825            }
1826            Literal::new_language_tagged_literal_unchecked(value, language)
1827        } else {
1828            Literal::new_simple_literal(value)
1829        }
1830    }
1831
1832    fn reify_and_annotation(
1833        &mut self,
1834        triple: &Triple,
1835        statement_id: Option<NamedNode>,
1836        #[cfg(feature = "rdf-12")] annotation: Option<NamedNode>,
1837        #[cfg(feature = "rdf-12")] annotation_node_id: Option<BlankNode>,
1838        results: &mut Vec<Triple>,
1839    ) {
1840        if let Some(statement_id) = statement_id {
1841            self.emit_triple(
1842                results,
1843                Triple::new(statement_id.clone(), rdf::TYPE, rdf::STATEMENT),
1844            );
1845            self.emit_triple(
1846                results,
1847                Triple::new(statement_id.clone(), rdf::SUBJECT, triple.subject.clone()),
1848            );
1849            self.emit_triple(
1850                results,
1851                Triple::new(
1852                    statement_id.clone(),
1853                    rdf::PREDICATE,
1854                    triple.predicate.as_ref(),
1855                ),
1856            );
1857            self.emit_triple(
1858                results,
1859                Triple::new(statement_id, rdf::OBJECT, triple.object.clone()),
1860            );
1861        }
1862        #[cfg(feature = "rdf-12")]
1863        if let Some(annotation) = annotation {
1864            self.emit_triple(
1865                results,
1866                Triple::new(annotation, rdf::REIFIES, triple.clone()),
1867            );
1868        }
1869        #[cfg(feature = "rdf-12")]
1870        if let Some(annotation_node_id) = annotation_node_id {
1871            self.emit_triple(
1872                results,
1873                Triple::new(annotation_node_id, rdf::REIFIES, triple.clone()),
1874            );
1875        }
1876    }
1877
1878    fn emit_property_attrs(
1879        &mut self,
1880        subject: &NamedOrBlankNode,
1881        literal_attributes: Vec<(NamedNode, String)>,
1882        language: Option<&str>,
1883        #[cfg(feature = "rdf-12")] base_direction: Option<BaseDirection>,
1884        results: &mut Vec<Triple>,
1885    ) {
1886        for (literal_predicate, literal_value) in literal_attributes {
1887            self.emit_triple(
1888                results,
1889                Triple::new(
1890                    subject.clone(),
1891                    literal_predicate,
1892                    if let Some(language) = language.or_else(|| self.current_language()) {
1893                        #[cfg(feature = "rdf-12")]
1894                        if let Some(base_direction) =
1895                            base_direction.or_else(|| self.current_base_direction())
1896                        {
1897                            Literal::new_directional_language_tagged_literal_unchecked(
1898                                literal_value,
1899                                language,
1900                                base_direction,
1901                            )
1902                        } else {
1903                            Literal::new_language_tagged_literal_unchecked(literal_value, language)
1904                        }
1905                        #[cfg(not(feature = "rdf-12"))]
1906                        {
1907                            Literal::new_language_tagged_literal_unchecked(literal_value, language)
1908                        }
1909                    } else {
1910                        Literal::new_simple_literal(literal_value)
1911                    },
1912                ),
1913            );
1914        }
1915    }
1916
1917    #[cfg_attr(not(feature = "rdf-12"), expect(clippy::unused_self))]
1918    fn emit_triple(&mut self, results: &mut Vec<Triple>, triple: Triple) {
1919        #[cfg(feature = "rdf-12")]
1920        for state in self.state.iter_mut().rev() {
1921            if let RdfXmlState::ParseTypeTriplePropertyElt { triples, .. } = state {
1922                triples.push(triple);
1923                return;
1924            }
1925        }
1926        results.push(triple);
1927    }
1928
1929    fn convert_attribute<'a>(
1930        &self,
1931        attribute: &Attribute<'a>,
1932    ) -> Result<Cow<'a, str>, RdfXmlParseError> {
1933        Ok(attribute
1934            .decode_and_unescape_value_with(self.reader.decoder(), |e| self.resolve_entity(e))?)
1935    }
1936
1937    fn convert_iri_attribute(
1938        &self,
1939        base_iri: Option<&Iri<String>>,
1940        attribute: &Attribute<'_>,
1941    ) -> Result<NamedNode, RdfXmlParseError> {
1942        Ok(self.resolve_iri(base_iri, self.convert_attribute(attribute)?)?)
1943    }
1944
1945    fn resolve_iri(
1946        &self,
1947        base_iri: Option<&Iri<String>>,
1948        relative_iri: Cow<'_, str>,
1949    ) -> Result<NamedNode, RdfXmlSyntaxError> {
1950        if let Some(base_iri) = base_iri.or_else(|| self.current_base_iri()) {
1951            Ok(NamedNode::new_unchecked(
1952                if self.lenient {
1953                    base_iri.resolve_unchecked(&relative_iri)
1954                } else {
1955                    base_iri.resolve(&relative_iri).map_err(|error| {
1956                        RdfXmlSyntaxError::invalid_iri(relative_iri.into(), error)
1957                    })?
1958                }
1959                .into_inner(),
1960            ))
1961        } else {
1962            self.parse_iri(relative_iri.into())
1963        }
1964    }
1965
1966    fn parse_iri(&self, relative_iri: String) -> Result<NamedNode, RdfXmlSyntaxError> {
1967        Ok(NamedNode::new_unchecked(if self.lenient {
1968            relative_iri
1969        } else {
1970            Iri::parse(relative_iri.clone())
1971                .map_err(|error| RdfXmlSyntaxError::invalid_iri(relative_iri, error))?
1972                .into_inner()
1973        }))
1974    }
1975
1976    fn current_language(&self) -> Option<&str> {
1977        for state in self.state.iter().rev() {
1978            match state {
1979                RdfXmlState::Doc { .. } => (),
1980                RdfXmlState::Rdf { language, .. }
1981                | RdfXmlState::NodeElt { language, .. }
1982                | RdfXmlState::PropertyElt { language, .. }
1983                | RdfXmlState::ParseTypeCollectionPropertyElt { language, .. }
1984                | RdfXmlState::ParseTypeLiteralPropertyElt { language, .. } => {
1985                    if let Some(language) = language {
1986                        return Some(language);
1987                    }
1988                }
1989                #[cfg(feature = "rdf-12")]
1990                RdfXmlState::ParseTypeTriplePropertyElt { language, .. } => {
1991                    if let Some(language) = language {
1992                        return Some(language);
1993                    }
1994                }
1995            }
1996        }
1997        None
1998    }
1999
2000    #[cfg(feature = "rdf-12")]
2001    fn current_base_direction(&self) -> Option<BaseDirection> {
2002        for state in self.state.iter().rev() {
2003            match state {
2004                RdfXmlState::Doc { .. } => (),
2005                RdfXmlState::Rdf { base_direction, .. }
2006                | RdfXmlState::NodeElt { base_direction, .. }
2007                | RdfXmlState::PropertyElt { base_direction, .. }
2008                | RdfXmlState::ParseTypeCollectionPropertyElt { base_direction, .. }
2009                | RdfXmlState::ParseTypeLiteralPropertyElt { base_direction, .. } => {
2010                    if let Some(base_direction) = base_direction {
2011                        return Some(*base_direction);
2012                    }
2013                }
2014                #[cfg(feature = "rdf-12")]
2015                RdfXmlState::ParseTypeTriplePropertyElt { base_direction, .. } => {
2016                    if let Some(base_direction) = base_direction {
2017                        return Some(*base_direction);
2018                    }
2019                }
2020            }
2021        }
2022        None
2023    }
2024
2025    fn current_base_iri(&self) -> Option<&Iri<String>> {
2026        for state in self.state.iter().rev() {
2027            match state {
2028                RdfXmlState::Doc { base_iri }
2029                | RdfXmlState::Rdf { base_iri, .. }
2030                | RdfXmlState::NodeElt { base_iri, .. }
2031                | RdfXmlState::PropertyElt { base_iri, .. }
2032                | RdfXmlState::ParseTypeCollectionPropertyElt { base_iri, .. }
2033                | RdfXmlState::ParseTypeLiteralPropertyElt { base_iri, .. } => {
2034                    if let Some(base_iri) = base_iri {
2035                        return Some(base_iri);
2036                    }
2037                }
2038                #[cfg(feature = "rdf-12")]
2039                RdfXmlState::ParseTypeTriplePropertyElt { base_iri, .. } => {
2040                    if let Some(base_iri) = base_iri {
2041                        return Some(base_iri);
2042                    }
2043                }
2044            }
2045        }
2046        None
2047    }
2048
2049    #[cfg(feature = "rdf-12")]
2050    fn current_rdf_version(&self) -> RdfVersion {
2051        for state in self.state.iter().rev() {
2052            match state {
2053                RdfXmlState::Doc { .. } => (),
2054                RdfXmlState::Rdf { rdf_version, .. }
2055                | RdfXmlState::NodeElt { rdf_version, .. }
2056                | RdfXmlState::PropertyElt { rdf_version, .. }
2057                | RdfXmlState::ParseTypeCollectionPropertyElt { rdf_version, .. }
2058                | RdfXmlState::ParseTypeLiteralPropertyElt { rdf_version, .. } => {
2059                    if let Some(rdf_version) = rdf_version {
2060                        return *rdf_version;
2061                    }
2062                }
2063                #[cfg(feature = "rdf-12")]
2064                RdfXmlState::ParseTypeTriplePropertyElt { rdf_version, .. } => {
2065                    if let Some(rdf_version) = rdf_version {
2066                        return *rdf_version;
2067                    }
2068                }
2069            }
2070        }
2071        RdfVersion::V11
2072    }
2073
2074    fn resolve_entity(&self, e: &str) -> Option<&str> {
2075        resolve_xml_entity(e).or_else(|| self.custom_entities.get(e).map(String::as_str))
2076    }
2077}
2078
2079fn is_object_defined(object: &Option<NodeOrText>) -> bool {
2080    match object {
2081        Some(NodeOrText::Node(_)) => true,
2082        Some(NodeOrText::Text(t)) => !t.bytes().all(is_whitespace),
2083        None => false,
2084    }
2085}
2086
2087fn is_whitespace(c: u8) -> bool {
2088    matches!(c, b' ' | b'\t' | b'\n' | b'\r')
2089}
2090
2091fn is_utf8(encoding: &[u8]) -> bool {
2092    matches!(
2093        encoding.to_ascii_lowercase().as_slice(),
2094        b"unicode-1-1-utf-8"
2095            | b"unicode11utf8"
2096            | b"unicode20utf8"
2097            | b"utf-8"
2098            | b"utf8"
2099            | b"x-unicode20utf8"
2100    )
2101}
2102
2103#[cfg(feature = "rdf-12")]
2104#[derive(Copy, Clone)]
2105enum RdfVersion {
2106    V11,
2107    V12,
2108    V12Basic,
2109}
2110
2111#[cfg(feature = "rdf-12")]
2112impl RdfVersion {
2113    fn supports_its_dir(self) -> bool {
2114        matches!(self, Self::V12 | Self::V12Basic)
2115    }
2116
2117    fn supports_triple_term(self) -> bool {
2118        matches!(self, Self::V12)
2119    }
2120
2121    fn from_str(value: &str) -> Result<RdfVersion, RdfXmlSyntaxError> {
2122        match value {
2123            "1.1" => Ok(RdfVersion::V11),
2124            "1.2" => Ok(RdfVersion::V12),
2125            "1.2-basic" => Ok(RdfVersion::V12Basic),
2126            _ => Err(RdfXmlSyntaxError::msg(format!(
2127                "The rdf:version value '{value}' is not supported, allowed values are '1.1' and '1.2'"
2128            ))),
2129        }
2130    }
2131}