use std::io::BufRead;
use bytes::Bytes;
use countio::Counter;
use quick_xml::{events, Reader};
use time::format_description::well_known::Iso8601;
use time::OffsetDateTime;
use url::Url;
use crate::{
attribute as attr,
attribute::{Frequency, Priority},
parse::Parser,
record::{EntryRecord, IndexRecord, BYTE_LIMIT, RECORD_LIMIT},
Error,
};
/// Sitemap parser for the versatile XML file with an optional support of extensions.
///
/// For example:
///
/// ```xml
///
///
///
/// https://www.example.com/foo.html
/// 2022-06-04
///
///
/// ```
/// Enforces [total written/read bytes](BYTE_LIMIT) and [total records](RECORD_LIMIT) limits.
/// See [Error].
///
/// ```rust
/// use sitemapo::{
/// parse::{Parser, XmlParser},
/// record::EntryRecord,
/// Error,
/// };
///
/// fn main() -> Result<(), Error> {
/// let buf = // "...".as_bytes();
/// # r#"
/// #
/// # https://www.example.com/file1.html
/// # 2022-09-08T10:43:13.000-04:00
/// # daily
/// # 0.6
/// #
/// #
/// # "#.as_bytes();
///
/// let mut parser = XmlParser::new(buf)?;
/// let _rec: Option = parser.read()?;
/// let _buf = parser.close()?;
/// Ok(())
/// }
/// ```
pub struct XmlParser {
record: Option,
pub(crate) reader: Reader>,
pub(crate) records: usize,
path: Vec,
}
impl XmlParser {
/// Creates a new instance with a provided reader.
pub(crate) fn from_reader(reader: R) -> Self {
Self {
record: None,
reader: Reader::from_reader(Counter::new(reader)),
records: 0,
path: Vec::default(),
}
}
/// Creates a new instance with a provided reader.
pub(crate) fn from_wrapper(wrapped: Reader>, path: &str) -> Self {
let bytes = Bytes::from(path.as_bytes().to_vec());
Self {
record: None,
reader: wrapped,
records: 0,
path: Vec::from([bytes]),
}
}
/// Returns a reference to the underlying reader.
pub fn get_ref(&self) -> &R {
self.reader.get_ref().get_ref()
}
/// Returns a mutable reference to the underlying reader.
pub fn get_mut(&mut self) -> &mut R {
self.reader.get_mut().get_mut()
}
/// Returns an underlying reader.
pub fn into_inner(self) -> R {
self.reader.into_inner().into_inner()
}
pub(crate) fn try_if_readable(&mut self) -> Result<(), Error> {
if self.records + 1 > RECORD_LIMIT {
return Err(Error::EntryLimit { over: 1 });
}
if self.reader.get_ref().reader_bytes() > BYTE_LIMIT {
let over = self.reader.get_ref().reader_bytes() - BYTE_LIMIT;
return Err(Error::ByteLimit { over });
}
Ok(())
}
pub(crate) fn write_event(
&mut self,
event: events::Event,
tag: &[u8],
create: impl FnOnce() -> D,
handle: impl FnOnce(&mut Self, &str),
check: impl FnOnce(Option) -> Option,
) -> Result