peanuts/src/reader.rs

865 lines
35 KiB
Rust
Raw Normal View History

2024-11-10 14:31:43 +00:00
use circular::Buffer;
2024-11-10 22:28:55 +00:00
use futures::{FutureExt, Stream};
2024-06-27 20:22:16 +01:00
use nom::Err;
2024-11-10 14:31:43 +00:00
use std::{
collections::{BTreeMap, HashMap, HashSet},
2024-11-10 22:28:55 +00:00
future::Future,
2024-11-10 14:31:43 +00:00
path::Prefix,
2024-11-10 22:28:55 +00:00
pin::{pin, Pin},
2024-11-10 14:31:43 +00:00
str::{self, FromStr},
};
use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt};
static MAX_STANZA_SIZE: usize = 65536;
2024-03-04 16:14:28 +00:00
use crate::{
element::{Content, Element, Name, NamespaceDeclaration},
2024-03-04 16:14:28 +00:00
error::Error,
2024-11-10 14:31:43 +00:00
xml::{self, parsers::Parser},
Result,
2024-03-04 16:14:28 +00:00
};
/// streaming reader that tracks depth and available namespaces at current depth
pub struct Reader<R> {
2024-06-27 20:22:16 +01:00
inner: R,
2024-11-10 14:31:43 +00:00
buffer: Buffer,
2024-03-04 16:14:28 +00:00
// holds which tags we are in atm over depth
2024-11-10 14:31:43 +00:00
// to have names reference namespaces could
2024-03-04 16:14:28 +00:00
depth: Vec<Name>,
namespace_declarations: Vec<HashSet<NamespaceDeclaration>>,
2024-03-04 16:14:28 +00:00
}
2024-06-27 20:22:16 +01:00
impl<R> Reader<R> {
pub fn new(reader: R) -> Self {
Self {
inner: reader,
2024-11-10 14:31:43 +00:00
buffer: Buffer::with_capacity(MAX_STANZA_SIZE),
2024-06-27 20:22:16 +01:00
depth: Vec::new(),
namespace_declarations: Vec::new(),
2024-06-27 20:22:16 +01:00
}
}
}
2024-11-10 14:31:43 +00:00
impl<R> Reader<R>
where
R: AsyncRead + Unpin,
{
2024-11-10 22:28:55 +00:00
async fn read_buf<'s>(&mut self) -> Result<usize> {
2024-11-10 14:31:43 +00:00
Ok(self.inner.read_buf(&mut self.buffer).await?)
}
2024-11-10 22:28:55 +00:00
async fn read_prolog<'s>(&'s mut self) -> Result<()> {
loop {
self.read_buf().await?;
let input = str::from_utf8(self.buffer.data())?;
match xml::Prolog::parse(input) {
Ok((rest, _prolog)) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
self.buffer.consume(len);
return Ok(());
}
std::result::Result::Err(e) => match e {
Err::Incomplete(_) => {}
// TODO: better error
Err::Error(e) => return Err(Error::ParseError(e.to_string())),
Err::Failure(e) => return Err(Error::ParseError(e.to_string())),
},
}
}
}
async fn read_start_tag<'s>(&'s mut self) -> Result<Element> {
loop {
self.read_buf().await?;
let input = str::from_utf8(self.buffer.data())?;
match xml::STag::parse(input) {
Ok((rest, e)) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
let element = Reader::<R>::start_tag_from_xml(
&mut self.depth,
&mut self.namespace_declarations,
e,
)?;
2024-11-10 22:28:55 +00:00
self.buffer.consume(len);
return Ok(element);
}
std::result::Result::Err(e) => match e {
Err::Incomplete(_) => {}
// TODO: better error
Err::Error(e) => return Err(Error::ParseError(e.to_string())),
Err::Failure(e) => return Err(Error::ParseError(e.to_string())),
},
}
}
}
async fn read_end_tag<'s>(&'s mut self) -> Result<()> {
loop {
self.read_buf().await?;
let input = str::from_utf8(self.buffer.data())?;
match xml::ETag::parse(input) {
Ok((rest, e)) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
Reader::<R>::end_tag_from_xml(
&mut self.depth,
&mut self.namespace_declarations,
e,
)?;
2024-11-10 22:28:55 +00:00
self.buffer.consume(len);
return Ok(());
}
std::result::Result::Err(e) => match e {
Err::Incomplete(_) => {}
// TODO: better error
Err::Error(e) => return Err(Error::ParseError(e.to_string())),
Err::Failure(e) => return Err(Error::ParseError(e.to_string())),
},
}
}
}
2024-11-10 14:31:43 +00:00
async fn read_element<'s>(&'s mut self) -> Result<Element> {
loop {
2024-11-10 22:28:55 +00:00
self.read_buf().await?;
let input = str::from_utf8(self.buffer.data())?;
2024-11-10 14:31:43 +00:00
match xml::Element::parse(input) {
Ok((rest, e)) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
let element =
Reader::<R>::element_from_xml(&mut self.namespace_declarations, e)?;
2024-11-10 14:31:43 +00:00
self.buffer.consume(len);
return Ok(element);
}
std::result::Result::Err(e) => match e {
2024-11-10 22:28:55 +00:00
Err::Incomplete(_) => {}
// TODO: better error
Err::Error(e) => return Err(Error::ParseError(e.to_string())),
Err::Failure(e) => return Err(Error::ParseError(e.to_string())),
},
}
}
}
async fn read_content<'s>(&'s mut self) -> Result<Content> {
2024-11-11 12:15:13 +00:00
let mut last_char = false;
let mut text = String::new();
2024-11-10 22:28:55 +00:00
loop {
self.read_buf().await?;
let input = str::from_utf8(self.buffer.data())?;
2024-11-11 12:15:13 +00:00
if last_char == false {
match xml::CharData::parse(input) {
Ok((rest, char_data)) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
text.push_str(*char_data);
self.buffer.consume(len);
last_char = true;
2024-11-10 14:31:43 +00:00
}
2024-11-11 12:15:13 +00:00
std::result::Result::Err(e) => match e {
Err::Incomplete(_needed) => continue,
_ => match xml::ContentItem::parse(input) {
Ok((rest, content_item)) => match content_item {
xml::ContentItem::Element(element) => {
if !text.is_empty() {
return Ok(Content::Text(text));
} else {
let len =
self.buffer.available_data() - rest.as_bytes().len();
let element = Self::element_from_xml(
&mut self.namespace_declarations,
element,
)?;
2024-11-11 12:15:13 +00:00
self.buffer.consume(len);
return Ok(Content::Element(element));
}
}
xml::ContentItem::Reference(reference) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
text.push(reference.process()?);
self.buffer.consume(len);
continue;
}
xml::ContentItem::CDSect(cd_sect) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
text.push_str(**cd_sect);
self.buffer.consume(len);
continue;
}
xml::ContentItem::PI(_pi) => {
if !text.is_empty() {
return Ok(Content::Text(text));
} else {
let len =
self.buffer.available_data() - rest.as_bytes().len();
self.buffer.consume(len);
return Ok(Content::PI);
}
}
xml::ContentItem::Comment(comment) => {
if !text.is_empty() {
return Ok(Content::Text(text));
} else {
let len =
self.buffer.available_data() - rest.as_bytes().len();
let comment = comment.to_string();
self.buffer.consume(len);
return Ok(Content::Comment(comment));
}
}
},
std::result::Result::Err(e) => match e {
Err::Incomplete(_) => continue,
// TODO: better error
Err::Error(e) => return Err(Error::ParseError(e.to_string())),
Err::Failure(e) => return Err(Error::ParseError(e.to_string())),
},
},
},
}
} else {
match xml::ContentItem::parse(input) {
Ok((rest, content_item)) => match content_item {
xml::ContentItem::Element(element) => {
// text can still be empty
2024-11-11 12:15:13 +00:00
if !text.is_empty() {
return Ok(Content::Text(text));
} else {
let len = self.buffer.available_data() - rest.as_bytes().len();
let element = Self::element_from_xml(
&mut self.namespace_declarations,
element,
)?;
2024-11-11 12:15:13 +00:00
self.buffer.consume(len);
return Ok(Content::Element(element));
}
}
xml::ContentItem::Reference(reference) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
text.push(reference.process()?);
self.buffer.consume(len);
last_char = false;
continue;
}
xml::ContentItem::CDSect(cd_sect) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
text.push_str(**cd_sect);
self.buffer.consume(len);
last_char = false;
continue;
}
xml::ContentItem::PI(_pi) => {
if !text.is_empty() {
return Ok(Content::Text(text));
} else {
let len = self.buffer.available_data() - rest.as_bytes().len();
self.buffer.consume(len);
return Ok(Content::PI);
}
}
xml::ContentItem::Comment(comment) => {
let len = self.buffer.available_data() - rest.as_bytes().len();
let comment = comment.to_string();
self.buffer.consume(len);
return Ok(Content::Comment(comment));
}
},
std::result::Result::Err(e) => match e {
Err::Incomplete(_) => continue,
// TODO: better error
Err::Error(e) => return Err(Error::ParseError(e.to_string())),
Err::Failure(e) => return Err(Error::ParseError(e.to_string())),
},
2024-11-10 22:28:55 +00:00
}
2024-11-10 14:31:43 +00:00
}
}
}
}
impl<R> Reader<R> {
2024-11-10 22:28:55 +00:00
fn start_tag_from_xml(
depth: &mut Vec<Name>,
namespaces: &mut Vec<HashSet<NamespaceDeclaration>>,
2024-11-10 22:28:55 +00:00
s_tag: xml::STag,
) -> Result<Element> {
let mut namespace_declarations = HashSet::new();
for (prefix, namespace) in s_tag.attributes.iter().filter_map(|attribute| {
if let xml::Attribute::NamespaceDeclaration { ns_name, value } = attribute {
Some((ns_name, value))
} else {
None
}
}) {
let prefix = match prefix {
xml::NSAttName::PrefixedAttName(prefixed_att_name) => {
Some(prefixed_att_name.to_string())
}
xml::NSAttName::DefaultAttName => None,
};
let namespace = NamespaceDeclaration {
2024-11-10 22:28:55 +00:00
prefix,
namespace: namespace.process()?,
};
if !namespace_declarations.insert(namespace.clone()) {
return Err(Error::DuplicateNameSpaceDeclaration(namespace));
2024-11-10 22:28:55 +00:00
}
}
// all namespaces available to the element (from both parent elements and element itself)
let namespace_stack: Vec<&NamespaceDeclaration> = namespaces
2024-11-10 22:28:55 +00:00
.iter()
.flatten()
.chain(namespace_declarations.iter())
.collect();
let mut attributes = HashMap::new();
for (q_name, value) in s_tag.attributes.iter().filter_map(|attribute| {
if let xml::Attribute::Attribute { name, value } = attribute {
Some((name, value))
} else {
None
}
}) {
let namespace;
let attribute_name;
match q_name {
xml::QName::PrefixedName(prefixed_name) => {
namespace = namespace_stack.iter().rfind(|namespace| {
namespace.prefix.as_deref() == Some(**prefixed_name.prefix)
});
attribute_name = prefixed_name.local_part.to_string();
}
xml::QName::UnprefixedName(unprefixed_name) => {
namespace = namespace_stack
.iter()
.rfind(|namespace| namespace.prefix == None);
attribute_name = unprefixed_name.to_string();
}
}
if let Some(namespace_declaration) = namespace {
2024-11-10 22:28:55 +00:00
let name = Name {
namespace: namespace_declaration.namespace.clone(),
2024-11-10 22:28:55 +00:00
name: attribute_name,
};
let value = value.process()?;
if let Some(_value) = attributes.insert(name, value) {
return Err(Error::DuplicateAttribute(q_name.to_string()));
}
} else {
return Err(Error::UnqualifiedNamespace(q_name.to_string()));
}
}
let name;
let namespace;
match &s_tag.name {
xml::QName::PrefixedName(prefixed_name) => {
namespace = namespace_stack
.iter()
.rfind(|namespace| namespace.prefix.as_deref() == Some(**prefixed_name.prefix));
name = prefixed_name.local_part.to_string();
}
xml::QName::UnprefixedName(unprefixed_name) => {
namespace = namespace_stack
.iter()
.rfind(|namespace| namespace.prefix == None);
name = unprefixed_name.to_string();
}
}
let namespace_declaration = (*namespace
2024-11-10 22:28:55 +00:00
.ok_or_else(|| Error::UnqualifiedNamespace(s_tag.name.to_string()))?)
.clone();
let name = Name {
namespace: namespace_declaration.namespace,
name,
};
2024-11-10 22:28:55 +00:00
depth.push(name.clone());
namespaces.push(namespace_declarations.clone());
return Ok(Element {
name,
attributes,
content: Vec::new(),
});
}
fn end_tag_from_xml(
depth: &mut Vec<Name>,
namespaces: &mut Vec<HashSet<NamespaceDeclaration>>,
2024-11-10 22:28:55 +00:00
e_tag: xml::ETag,
) -> Result<()> {
if let Some(s_tag_name) = depth.pop() {
let (namespace, name);
let namespace_declarations: Vec<_> = namespaces.iter().flatten().collect();
match e_tag.name {
xml::QName::PrefixedName(ref prefixed_name) => {
namespace = namespace_declarations
.iter()
.rfind(|namespace| {
namespace.prefix.as_deref() == Some(**prefixed_name.prefix)
})
.map(|namespace_decl| namespace_decl.namespace.clone())
.ok_or_else(|| {
return Error::UnqualifiedNamespace((&e_tag.name).to_string());
})?;
name = prefixed_name.local_part.to_string();
}
xml::QName::UnprefixedName(ref unprefixed_name) => {
namespace = namespace_declarations
.iter()
.rfind(|namespace| namespace.prefix.as_deref() == None)
.map(|namespace_decl| namespace_decl.namespace.clone())
.ok_or_else(|| {
return Error::UnqualifiedNamespace(e_tag.name.to_string());
})?;
name = unprefixed_name.to_string();
}
}
let e_tag_name = Name { namespace, name };
if s_tag_name == e_tag_name {
2024-11-10 22:28:55 +00:00
namespaces.pop();
return Ok(());
} else {
return Err(Error::MismatchedEndTag(
s_tag_name.name,
e_tag.name.to_string(),
));
}
} else {
return Err(Error::NotInElement(e_tag.name.to_string()));
}
}
2024-11-10 14:31:43 +00:00
fn element_from_xml(
namespaces: &mut Vec<HashSet<NamespaceDeclaration>>,
2024-11-10 14:31:43 +00:00
element: xml::Element,
) -> Result<Element> {
match element {
xml::Element::Empty(empty_elem_tag) => {
let mut namespace_declarations = HashSet::new();
for (prefix, namespace) in
empty_elem_tag.attributes.iter().filter_map(|attribute| {
if let xml::Attribute::NamespaceDeclaration { ns_name, value } = attribute {
Some((ns_name, value))
} else {
None
}
})
{
let prefix = match prefix {
xml::NSAttName::PrefixedAttName(prefixed_att_name) => {
Some(prefixed_att_name.to_string())
}
xml::NSAttName::DefaultAttName => None,
};
let namespace = NamespaceDeclaration {
2024-11-10 14:31:43 +00:00
prefix,
namespace: namespace.process()?,
};
if !namespace_declarations.insert(namespace.clone()) {
return Err(Error::DuplicateNameSpaceDeclaration(namespace));
2024-11-10 14:31:43 +00:00
}
}
// all namespaces available to the element (from both parent elements and element itself)
let namespace_stack: Vec<&NamespaceDeclaration> = namespaces
2024-11-10 14:31:43 +00:00
.iter()
.flatten()
.chain(namespace_declarations.iter())
.collect();
let mut attributes = HashMap::new();
for (q_name, value) in empty_elem_tag.attributes.iter().filter_map(|attribute| {
if let xml::Attribute::Attribute { name, value } = attribute {
Some((name, value))
} else {
None
}
}) {
let namespace;
let attribute_name;
match q_name {
xml::QName::PrefixedName(prefixed_name) => {
namespace = namespace_stack.iter().rfind(|namespace| {
namespace.prefix.as_deref() == Some(**prefixed_name.prefix)
});
attribute_name = prefixed_name.local_part.to_string();
}
xml::QName::UnprefixedName(unprefixed_name) => {
namespace = namespace_stack
.iter()
.rfind(|namespace| namespace.prefix == None);
attribute_name = unprefixed_name.to_string();
}
}
if let Some(namespace) = namespace {
let namespace = (*namespace).clone();
let name = Name {
namespace: namespace.namespace,
2024-11-10 14:31:43 +00:00
name: attribute_name,
};
let value = value.process()?;
if let Some(_value) = attributes.insert(name, value) {
return Err(Error::DuplicateAttribute(q_name.to_string()));
}
} else {
return Err(Error::UnqualifiedNamespace(q_name.to_string()));
}
}
let name;
let namespace;
match &empty_elem_tag.name {
xml::QName::PrefixedName(prefixed_name) => {
namespace = namespace_stack.iter().rfind(|namespace| {
namespace.prefix.as_deref() == Some(**prefixed_name.prefix)
});
name = prefixed_name.local_part.to_string();
}
xml::QName::UnprefixedName(unprefixed_name) => {
namespace = namespace_stack
.iter()
.rfind(|namespace| namespace.prefix == None);
name = unprefixed_name.to_string();
}
}
let namespace = (*namespace
.ok_or_else(|| Error::UnqualifiedNamespace(empty_elem_tag.name.to_string()))?)
.clone();
let name = Name {
namespace: namespace.namespace,
name,
};
2024-11-10 14:31:43 +00:00
return Ok(Element {
name,
attributes,
content: Vec::new(),
});
}
xml::Element::NotEmpty(s_tag, content, e_tag) => {
if s_tag.name != e_tag.name {
return Err(Error::MismatchedEndTag(
s_tag.name.to_string(),
e_tag.name.to_string(),
));
}
let mut namespace_declarations = HashSet::new();
for (prefix, namespace) in s_tag.attributes.iter().filter_map(|attribute| {
if let xml::Attribute::NamespaceDeclaration { ns_name, value } = attribute {
Some((ns_name, value))
} else {
None
}
}) {
let prefix = match prefix {
xml::NSAttName::PrefixedAttName(prefixed_att_name) => {
Some(prefixed_att_name.to_string())
}
xml::NSAttName::DefaultAttName => None,
};
let namespace = NamespaceDeclaration {
2024-11-10 14:31:43 +00:00
prefix,
namespace: namespace.process()?,
};
if !namespace_declarations.insert(namespace.clone()) {
return Err(Error::DuplicateNameSpaceDeclaration(namespace));
2024-11-10 14:31:43 +00:00
}
}
// all namespaces available to the element (from both parent elements and element itself)
let namespace_stack: Vec<&NamespaceDeclaration> = namespaces
2024-11-10 14:31:43 +00:00
.iter()
.flatten()
.chain(namespace_declarations.iter())
.collect();
let mut attributes = HashMap::new();
for (q_name, value) in s_tag.attributes.iter().filter_map(|attribute| {
if let xml::Attribute::Attribute { name, value } = attribute {
Some((name, value))
} else {
None
}
}) {
let namespace;
let attribute_name;
match q_name {
xml::QName::PrefixedName(prefixed_name) => {
namespace = namespace_stack.iter().rfind(|namespace| {
namespace.prefix.as_deref() == Some(**prefixed_name.prefix)
});
attribute_name = prefixed_name.local_part.to_string();
}
xml::QName::UnprefixedName(unprefixed_name) => {
namespace = namespace_stack
.iter()
.rfind(|namespace| namespace.prefix == None);
attribute_name = unprefixed_name.to_string();
}
}
if let Some(namespace) = namespace {
let namespace = (*namespace).clone();
let name = Name {
namespace: namespace.namespace,
2024-11-10 14:31:43 +00:00
name: attribute_name,
};
let value = value.process()?;
if let Some(_value) = attributes.insert(name, value) {
return Err(Error::DuplicateAttribute(q_name.to_string()));
}
} else {
return Err(Error::UnqualifiedNamespace(q_name.to_string()));
}
}
let name;
let namespace;
match &s_tag.name {
xml::QName::PrefixedName(prefixed_name) => {
namespace = namespace_stack.iter().rfind(|namespace| {
namespace.prefix.as_deref() == Some(**prefixed_name.prefix)
});
name = prefixed_name.local_part.to_string();
}
xml::QName::UnprefixedName(unprefixed_name) => {
namespace = namespace_stack
.iter()
.rfind(|namespace| namespace.prefix == None);
name = unprefixed_name.to_string();
}
}
let namespace = (*namespace
.ok_or_else(|| Error::UnqualifiedNamespace(s_tag.name.to_string()))?)
.clone();
let name = Name {
namespace: namespace.namespace,
name,
};
2024-11-10 14:31:43 +00:00
namespaces.push(namespace_declarations.clone());
let content = Self::content_from_xml(namespaces, content)?;
namespaces.pop();
return Ok(Element {
name,
attributes,
content,
});
}
}
}
fn content_from_xml(
namespaces: &mut Vec<HashSet<NamespaceDeclaration>>,
2024-11-10 14:31:43 +00:00
element: xml::Content,
) -> Result<Vec<Content>> {
let mut content = Vec::new();
let mut text = element.char_data.map(|str| String::from(*str));
for (content_item, char_data) in element.content {
match content_item {
xml::ContentItem::Element(element) => {
text.map(|text| content.push(Content::Text(text)));
content.push(Content::Element(Self::element_from_xml(
namespaces, element,
)?));
text = char_data.map(|str| String::from(*str));
}
xml::ContentItem::Reference(reference) => {
let data = reference.process()?;
if let Some(text) = &mut text {
text.push(data)
} else {
text = Some(String::from(data))
}
char_data.map(|char_data| text.as_mut().map(|s| s.push_str(*char_data)));
}
xml::ContentItem::CDSect(cd_sect) => {
if let Some(text) = &mut text {
text.push_str(**cd_sect)
} else {
text = Some(String::from(**cd_sect))
}
char_data.map(|char_data| text.as_mut().map(|s| s.push_str(*char_data)));
}
// TODO: is this important?
xml::ContentItem::PI(pi) => {
char_data.map(|char_data| text.as_mut().map(|s| s.push_str(*char_data)));
}
// TODO: comments?
xml::ContentItem::Comment(comment) => {
char_data.map(|char_data| text.as_mut().map(|s| s.push_str(*char_data)));
}
}
}
text.map(|text| content.push(Content::Text(text)));
2024-11-10 17:57:05 +00:00
Ok(content)
2024-11-10 14:31:43 +00:00
}
}
2024-11-10 22:28:55 +00:00
impl<R: AsyncRead + Unpin> Stream for Reader<R> {
type Item = Result<Content>;
fn poll_next(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Self::Item>> {
let mut e = self;
let mut pinned = pin!(e.read_content());
pinned.as_mut().poll(cx).map(|result| Some(result))
}
}
2024-11-10 17:57:05 +00:00
#[cfg(test)]
mod test {
2024-11-10 22:28:55 +00:00
use futures::{sink::Buffer, StreamExt};
2024-11-10 17:57:05 +00:00
use tokio::io::AsyncRead;
use super::Reader;
2024-11-11 12:15:13 +00:00
struct MockAsyncReader<'s> {
put: bool,
data: &'s str,
}
2024-11-10 17:57:05 +00:00
impl<'s> MockAsyncReader<'s> {
fn new(data: &'s str) -> Self {
2024-11-11 12:15:13 +00:00
Self { put: false, data }
2024-11-10 17:57:05 +00:00
}
}
impl<'s> AsyncRead for MockAsyncReader<'s> {
fn poll_read(
self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> std::task::Poll<std::io::Result<()>> {
2024-11-11 12:15:13 +00:00
if !self.put {
buf.put_slice(self.data.as_bytes());
self.get_mut().put = true
};
2024-11-10 17:57:05 +00:00
std::task::Poll::Ready(Ok(()))
}
}
2024-11-10 22:28:55 +00:00
const TEST_DOC: &'static str = "<xs:schema
2024-11-10 17:57:05 +00:00
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://etherx.jabber.org/streams'
xmlns='http://etherx.jabber.org/streams'
elementFormDefault='unqualified'>
<xs:import namespace='jabber:client'/>
<xs:import namespace='jabber:server'/>
<xs:import namespace='urn:ietf:params:xml:ns:xmpp-sasl'/>
<xs:import namespace='urn:ietf:params:xml:ns:xmpp-streams'/>
<xs:import namespace='urn:ietf:params:xml:ns:xmpp-tls'/>
<xs:element name='stream'>
<xs:complexType>
<xs:sequence xmlns:client='jabber:client'
xmlns:server='jabber:server'>
<xs:element ref='features'
minOccurs='0'
maxOccurs='1'/>
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'
minOccurs='0'
maxOccurs='1'/>
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'
minOccurs='0'
maxOccurs='1'/>
<xs:any namespace='##other'
minOccurs='0'
maxOccurs='unbounded'
processContents='lax'/>
<xs:choice minOccurs='0' maxOccurs='1'>
<xs:choice minOccurs='0' maxOccurs='unbounded'>
<xs:element ref='client:message'/>
<xs:element ref='client:presence'/>
<xs:element ref='client:iq'/>
</xs:choice>
<xs:choice minOccurs='0' maxOccurs='unbounded'>
<xs:element ref='server:message'/>
<xs:element ref='server:presence'/>
<xs:element ref='server:iq'/>
</xs:choice>
</xs:choice>
<xs:element ref='error' minOccurs='0' maxOccurs='1'/>
</xs:sequence>
<xs:attribute name='from' type='xs:string' use='optional'/>
<xs:attribute name='id' type='xs:string' use='optional'/>
<xs:attribute name='to' type='xs:string' use='optional'/>
<xs:attribute name='version' type='xs:decimal' use='optional'/>
<xs:attribute ref='xml:lang' use='optional'/>
<xs:anyAttribute namespace='##other' processContents='lax'/>
</xs:complexType>
</xs:element>
<xs:element name='features'>
<xs:complexType>
<xs:sequence>
<xs:any namespace='##other'
minOccurs='0'
maxOccurs='unbounded'
processContents='lax'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='error'>
<xs:complexType>
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'>
<xs:group ref='err:streamErrorGroup'/>
<xs:element ref='err:text'
minOccurs='0'
maxOccurs='1'/>
<xs:any namespace='##other'
minOccurs='0'
maxOccurs='1'
processContents='lax'/>
</xs:sequence>
</xs:complexType>
</xs:element>
2024-11-10 22:28:55 +00:00
</xs:schema>asdf";
#[tokio::test]
async fn test_element_read() {
let mock = MockAsyncReader::new(TEST_DOC);
2024-11-10 17:57:05 +00:00
let mut reader = Reader::new(mock);
let element = reader.read_element().await.unwrap();
println!("{:#?}", element);
}
2024-11-10 22:28:55 +00:00
#[tokio::test]
async fn test_element_stream() {
let mock = MockAsyncReader::new(TEST_DOC);
let mut reader = Reader::new(mock);
let element = reader.read_start_tag().await.unwrap();
2024-11-11 12:15:13 +00:00
println!("start element: {:#?}", element);
let mut content_count = 0;
2024-11-10 22:28:55 +00:00
loop {
2024-11-11 12:15:13 +00:00
if let Some(content) = reader.next().await {
match content {
Ok(content) => {
content_count += 1;
println!("content {}: {:#?}", content_count, content)
}
Err(_) => break,
}
}
2024-11-10 22:28:55 +00:00
}
2024-11-11 12:15:13 +00:00
reader.read_end_tag().await.unwrap()
2024-11-10 22:28:55 +00:00
}
2024-11-10 17:57:05 +00:00
}