2024-11-20 15:10:36 +00:00
|
|
|
use std::{collections::HashSet, str::FromStr};
|
2024-11-19 14:52:14 +00:00
|
|
|
|
2024-11-20 16:43:34 +00:00
|
|
|
use async_recursion::async_recursion;
|
2024-11-19 14:52:14 +00:00
|
|
|
use futures::Sink;
|
2024-11-20 16:43:34 +00:00
|
|
|
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
2024-03-04 16:14:28 +00:00
|
|
|
|
|
|
|
use crate::{
|
2024-11-24 02:05:41 +00:00
|
|
|
declaration::{Declaration, VersionInfo},
|
|
|
|
element::{escape_str, Content, Element, IntoElement, Name, NamespaceDeclaration},
|
2024-03-04 16:14:28 +00:00
|
|
|
error::Error,
|
2024-11-24 02:05:41 +00:00
|
|
|
xml::{self, composers::Composer, parsers_complete::Parser, ETag, XMLDecl},
|
|
|
|
Result, XMLNS_NS, XML_NS,
|
2024-03-04 16:14:28 +00:00
|
|
|
};
|
|
|
|
|
2024-11-01 18:36:11 +00:00
|
|
|
// pub struct Writer<W, C = Composer> {
|
2024-03-04 16:14:28 +00:00
|
|
|
pub struct Writer<W> {
|
2024-11-19 14:52:14 +00:00
|
|
|
inner: W,
|
2024-03-04 16:14:28 +00:00
|
|
|
depth: Vec<Name>,
|
2024-11-19 16:46:51 +00:00
|
|
|
namespace_declarations: Vec<HashSet<NamespaceDeclaration>>,
|
2024-03-04 16:14:28 +00:00
|
|
|
}
|
|
|
|
|
2024-11-20 16:43:34 +00:00
|
|
|
impl<W> Writer<W> {
|
|
|
|
pub fn new(writer: W) -> Self {
|
2024-11-24 02:05:41 +00:00
|
|
|
let mut default_declarations = HashSet::new();
|
|
|
|
default_declarations.insert(NamespaceDeclaration {
|
|
|
|
prefix: Some("xml".to_string()),
|
|
|
|
namespace: XML_NS.to_string(),
|
|
|
|
});
|
|
|
|
default_declarations.insert(NamespaceDeclaration {
|
|
|
|
prefix: Some("xmlns".to_string()),
|
|
|
|
namespace: XMLNS_NS.to_string(),
|
|
|
|
});
|
2024-11-20 16:43:34 +00:00
|
|
|
Self {
|
|
|
|
inner: writer,
|
|
|
|
depth: Vec::new(),
|
2024-11-24 02:05:41 +00:00
|
|
|
namespace_declarations: vec![default_declarations],
|
2024-11-20 16:43:34 +00:00
|
|
|
}
|
2024-06-14 13:11:32 +01:00
|
|
|
}
|
2024-11-24 02:05:41 +00:00
|
|
|
|
|
|
|
pub fn into_inner(self) -> W {
|
|
|
|
self.inner
|
|
|
|
}
|
2024-11-20 16:43:34 +00:00
|
|
|
}
|
2024-11-19 14:52:14 +00:00
|
|
|
|
2024-11-20 16:43:34 +00:00
|
|
|
impl<W: AsyncWrite + Unpin + Send> Writer<W> {
|
2024-11-24 02:05:41 +00:00
|
|
|
pub async fn write_declaration(&mut self, version: VersionInfo) -> Result<()> {
|
|
|
|
let declaration = Declaration::version(version);
|
|
|
|
let version_info;
|
|
|
|
match declaration.version_info {
|
|
|
|
VersionInfo::One => version_info = xml::VersionInfo::SingleQuoted(xml::VersionNum::One),
|
|
|
|
VersionInfo::OneDotOne => {
|
|
|
|
version_info = xml::VersionInfo::SingleQuoted(xml::VersionNum::OneDotOne)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let declaration = xml::XMLDecl {
|
|
|
|
version_info,
|
|
|
|
encoding_decl: None,
|
|
|
|
sd_decl: None,
|
|
|
|
};
|
|
|
|
declaration.write(&mut self.inner).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn write_full(&mut self, into_element: &impl IntoElement) -> Result<()> {
|
|
|
|
let element = into_element.into_element();
|
|
|
|
Ok(self.write_element(&element).await?)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn write_start(&mut self, into_element: &impl IntoElement) -> Result<()> {
|
|
|
|
let element = into_element.into_element();
|
|
|
|
Ok(self.write_element_start(&element).await?)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn write_all_content(&mut self, into_element: &impl IntoElement) -> Result<()> {
|
|
|
|
for content in &into_element.get_content() {
|
|
|
|
self.write_content(content).await?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-11-20 16:43:34 +00:00
|
|
|
#[async_recursion]
|
|
|
|
pub async fn write_element(&mut self, element: &Element) -> Result<()> {
|
|
|
|
if element.content.is_empty() {
|
|
|
|
self.write_empty(element).await?;
|
|
|
|
} else {
|
2024-11-24 02:05:41 +00:00
|
|
|
self.write_element_start(element).await?;
|
2024-11-20 16:43:34 +00:00
|
|
|
for content in &element.content {
|
|
|
|
self.write_content(content).await?;
|
|
|
|
}
|
|
|
|
self.write_end().await?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn write_empty(&mut self, element: &Element) -> Result<()> {
|
2024-11-20 15:46:24 +00:00
|
|
|
let namespace_declarations_stack: Vec<_> = self
|
2024-11-20 15:10:36 +00:00
|
|
|
.namespace_declarations
|
|
|
|
.iter()
|
|
|
|
.flatten()
|
|
|
|
.chain(&element.namespace_declarations)
|
|
|
|
.collect();
|
2024-11-20 15:46:24 +00:00
|
|
|
|
|
|
|
let prefix;
|
|
|
|
if let Some(namespace) = &element.name.namespace {
|
|
|
|
let name_namespace_declaration = namespace_declarations_stack
|
|
|
|
.iter()
|
|
|
|
.rfind(|namespace_declaration| namespace_declaration.namespace == *namespace)
|
|
|
|
.ok_or(Error::UndeclaredNamespace(namespace.clone()))?;
|
|
|
|
prefix = name_namespace_declaration.prefix.as_ref();
|
|
|
|
} else {
|
|
|
|
prefix = None
|
|
|
|
}
|
|
|
|
|
2024-11-20 15:10:36 +00:00
|
|
|
let name;
|
|
|
|
if let Some(prefix) = &prefix {
|
|
|
|
name = xml::QName::PrefixedName(xml::PrefixedName {
|
|
|
|
prefix: xml::Prefix::parse_full(prefix)?,
|
|
|
|
local_part: xml::LocalPart::parse_full(&element.name.local_name)?,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
name = xml::QName::UnprefixedName(xml::UnprefixedName::parse_full(
|
|
|
|
&element.name.local_name,
|
|
|
|
)?)
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut attributes = Vec::new();
|
|
|
|
|
|
|
|
for namespace_declaration in &element.namespace_declarations {
|
|
|
|
let ns_name = namespace_declaration
|
|
|
|
.prefix
|
|
|
|
.as_ref()
|
|
|
|
.map(|prefix| -> Result<_> {
|
2024-11-20 16:43:34 +00:00
|
|
|
Ok(xml::NSAttName::PrefixedAttName(xml::PrefixedAttName(
|
|
|
|
xml::NCName::parse_full(&prefix)?,
|
|
|
|
)))
|
|
|
|
})
|
|
|
|
.unwrap_or(Ok(xml::NSAttName::DefaultAttName))?;
|
|
|
|
let value = xml::AttValue::from(namespace_declaration.namespace.as_str());
|
|
|
|
let xml_attribute = xml::Attribute::NamespaceDeclaration { ns_name, value };
|
|
|
|
attributes.push(xml_attribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (name, value) in &element.attributes {
|
|
|
|
let prefix;
|
|
|
|
if let Some(namespace) = &name.namespace {
|
|
|
|
let name_namespace_declaration = namespace_declarations_stack
|
|
|
|
.iter()
|
|
|
|
.rfind(|namespace_declaration| namespace_declaration.namespace == *namespace)
|
|
|
|
.ok_or(Error::UndeclaredNamespace(namespace.clone()))?;
|
|
|
|
prefix = name_namespace_declaration.prefix.as_ref();
|
|
|
|
} else {
|
|
|
|
prefix = None
|
|
|
|
}
|
|
|
|
|
|
|
|
let att_name;
|
|
|
|
if let Some(prefix) = &prefix {
|
|
|
|
att_name = xml::QName::PrefixedName(xml::PrefixedName {
|
|
|
|
prefix: xml::Prefix::parse_full(prefix)?,
|
2024-11-24 02:05:41 +00:00
|
|
|
local_part: xml::LocalPart::parse_full(&name.local_name)?,
|
2024-11-20 16:43:34 +00:00
|
|
|
})
|
|
|
|
} else {
|
2024-11-24 02:05:41 +00:00
|
|
|
att_name =
|
|
|
|
xml::QName::UnprefixedName(xml::UnprefixedName::parse_full(&name.local_name)?)
|
2024-11-20 16:43:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let value = xml::AttValue::from(value.as_str());
|
|
|
|
|
|
|
|
let xml_attribute = xml::Attribute::Attribute {
|
|
|
|
name: att_name,
|
|
|
|
value,
|
|
|
|
};
|
|
|
|
attributes.push(xml_attribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
let tag = xml::EmptyElemTag { name, attributes };
|
|
|
|
|
|
|
|
tag.write(&mut self.inner).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-11-24 02:05:41 +00:00
|
|
|
pub async fn write_element_start(&mut self, element: &Element) -> Result<()> {
|
2024-11-20 16:43:34 +00:00
|
|
|
let namespace_declarations_stack: Vec<_> = self
|
|
|
|
.namespace_declarations
|
|
|
|
.iter()
|
|
|
|
.flatten()
|
|
|
|
.chain(&element.namespace_declarations)
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let prefix;
|
|
|
|
if let Some(namespace) = &element.name.namespace {
|
|
|
|
let name_namespace_declaration = namespace_declarations_stack
|
|
|
|
.iter()
|
|
|
|
.rfind(|namespace_declaration| namespace_declaration.namespace == *namespace)
|
|
|
|
.ok_or(Error::UndeclaredNamespace(namespace.clone()))?;
|
|
|
|
prefix = name_namespace_declaration.prefix.as_ref();
|
|
|
|
} else {
|
|
|
|
prefix = None
|
|
|
|
}
|
|
|
|
|
|
|
|
let name;
|
|
|
|
if let Some(prefix) = &prefix {
|
|
|
|
name = xml::QName::PrefixedName(xml::PrefixedName {
|
|
|
|
prefix: xml::Prefix::parse_full(prefix)?,
|
|
|
|
local_part: xml::LocalPart::parse_full(&element.name.local_name)?,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
name = xml::QName::UnprefixedName(xml::UnprefixedName::parse_full(
|
|
|
|
&element.name.local_name,
|
|
|
|
)?)
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut attributes = Vec::new();
|
|
|
|
|
|
|
|
for namespace_declaration in &element.namespace_declarations {
|
|
|
|
let ns_name = namespace_declaration
|
|
|
|
.prefix
|
|
|
|
.as_ref()
|
|
|
|
.map(|prefix| -> Result<_> {
|
|
|
|
Ok(xml::NSAttName::PrefixedAttName(xml::PrefixedAttName(
|
|
|
|
xml::NCName::parse_full(&prefix)?,
|
|
|
|
)))
|
2024-11-20 15:10:36 +00:00
|
|
|
})
|
|
|
|
.unwrap_or(Ok(xml::NSAttName::DefaultAttName))?;
|
|
|
|
let value = xml::AttValue::from(namespace_declaration.namespace.as_str());
|
|
|
|
let xml_attribute = xml::Attribute::NamespaceDeclaration { ns_name, value };
|
|
|
|
attributes.push(xml_attribute);
|
|
|
|
}
|
|
|
|
|
2024-11-20 15:46:24 +00:00
|
|
|
for (name, value) in &element.attributes {
|
|
|
|
let prefix;
|
|
|
|
if let Some(namespace) = &name.namespace {
|
|
|
|
let name_namespace_declaration = namespace_declarations_stack
|
|
|
|
.iter()
|
|
|
|
.rfind(|namespace_declaration| namespace_declaration.namespace == *namespace)
|
|
|
|
.ok_or(Error::UndeclaredNamespace(namespace.clone()))?;
|
|
|
|
prefix = name_namespace_declaration.prefix.as_ref();
|
|
|
|
} else {
|
|
|
|
prefix = None
|
|
|
|
}
|
|
|
|
|
|
|
|
let att_name;
|
|
|
|
if let Some(prefix) = &prefix {
|
|
|
|
att_name = xml::QName::PrefixedName(xml::PrefixedName {
|
|
|
|
prefix: xml::Prefix::parse_full(prefix)?,
|
2024-11-24 02:05:41 +00:00
|
|
|
local_part: xml::LocalPart::parse_full(&name.local_name)?,
|
2024-11-20 15:46:24 +00:00
|
|
|
})
|
|
|
|
} else {
|
2024-11-24 02:05:41 +00:00
|
|
|
att_name =
|
|
|
|
xml::QName::UnprefixedName(xml::UnprefixedName::parse_full(&name.local_name)?)
|
2024-11-20 15:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let value = xml::AttValue::from(value.as_str());
|
|
|
|
|
|
|
|
let xml_attribute = xml::Attribute::Attribute {
|
|
|
|
name: att_name,
|
|
|
|
value,
|
|
|
|
};
|
|
|
|
attributes.push(xml_attribute);
|
|
|
|
}
|
|
|
|
|
2024-11-20 15:10:36 +00:00
|
|
|
let s_tag = xml::STag { name, attributes };
|
|
|
|
|
|
|
|
s_tag.write(&mut self.inner).await?;
|
|
|
|
|
2024-11-20 16:43:34 +00:00
|
|
|
self.depth.push(element.name.clone());
|
2024-11-20 15:10:36 +00:00
|
|
|
self.namespace_declarations
|
2024-11-20 16:43:34 +00:00
|
|
|
.push(element.namespace_declarations.clone());
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn write_content(&mut self, content: &Content) -> Result<()> {
|
|
|
|
match content {
|
|
|
|
Content::Element(element) => self.write_element(element).await?,
|
|
|
|
Content::Text(text) => self.inner.write_all(escape_str(text).as_bytes()).await?,
|
|
|
|
// TODO: comments and PI
|
|
|
|
Content::PI => {}
|
|
|
|
Content::Comment(_) => {}
|
|
|
|
}
|
2024-11-20 15:10:36 +00:00
|
|
|
Ok(())
|
2024-06-14 13:11:32 +01:00
|
|
|
}
|
2024-11-19 14:52:14 +00:00
|
|
|
|
2024-11-20 15:10:36 +00:00
|
|
|
pub async fn write_end(&mut self) -> Result<()> {
|
2024-11-19 16:46:51 +00:00
|
|
|
if let Some(name) = &self.depth.pop() {
|
2024-11-20 15:10:36 +00:00
|
|
|
let e_tag;
|
2024-11-19 16:46:51 +00:00
|
|
|
let namespace_declarations_stack: Vec<_> =
|
|
|
|
self.namespace_declarations.iter().flatten().collect();
|
2024-11-20 15:46:24 +00:00
|
|
|
|
|
|
|
let prefix;
|
|
|
|
if let Some(namespace) = &name.namespace {
|
|
|
|
let name_namespace_declaration = namespace_declarations_stack
|
|
|
|
.iter()
|
|
|
|
.rfind(|namespace_declaration| namespace_declaration.namespace == *namespace)
|
|
|
|
.ok_or(Error::UndeclaredNamespace(namespace.clone()))?;
|
|
|
|
prefix = name_namespace_declaration.prefix.as_ref();
|
|
|
|
} else {
|
|
|
|
prefix = None
|
|
|
|
}
|
|
|
|
|
2024-11-19 16:46:51 +00:00
|
|
|
if let Some(prefix) = &prefix {
|
|
|
|
e_tag = xml::ETag {
|
|
|
|
name: xml::QName::PrefixedName(xml::PrefixedName {
|
|
|
|
prefix: xml::Prefix::parse_full(prefix)?,
|
|
|
|
local_part: xml::LocalPart::parse_full(&name.local_name)?,
|
|
|
|
}),
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
e_tag = xml::ETag {
|
|
|
|
name: xml::QName::UnprefixedName(xml::UnprefixedName::parse_full(
|
|
|
|
&name.local_name,
|
|
|
|
)?),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
e_tag.write(&mut self.inner).await?;
|
|
|
|
self.namespace_declarations.pop();
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
return Err(Error::NotInElement("".to_string()));
|
|
|
|
}
|
2024-06-14 13:11:32 +01:00
|
|
|
}
|
2024-03-04 16:14:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<W: AsyncWrite, E: Into<Element>> Sink<E> for Writer<W> {
|
|
|
|
type Error = Error;
|
|
|
|
|
|
|
|
fn poll_ready(
|
|
|
|
self: std::pin::Pin<&mut Self>,
|
|
|
|
cx: &mut std::task::Context<'_>,
|
2024-11-20 15:10:36 +00:00
|
|
|
) -> std::task::Poll<Result<()>> {
|
2024-03-04 16:14:28 +00:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
2024-11-20 15:10:36 +00:00
|
|
|
fn start_send(self: std::pin::Pin<&mut Self>, item: E) -> Result<()> {
|
2024-03-04 16:14:28 +00:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll_flush(
|
|
|
|
self: std::pin::Pin<&mut Self>,
|
|
|
|
cx: &mut std::task::Context<'_>,
|
2024-11-20 15:10:36 +00:00
|
|
|
) -> std::task::Poll<Result<()>> {
|
2024-03-04 16:14:28 +00:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn poll_close(
|
|
|
|
self: std::pin::Pin<&mut Self>,
|
|
|
|
cx: &mut std::task::Context<'_>,
|
2024-11-20 15:10:36 +00:00
|
|
|
) -> std::task::Poll<Result<()>> {
|
2024-03-04 16:14:28 +00:00
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
}
|
2024-11-20 16:43:34 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use crate::{
|
|
|
|
reader::{test::*, Reader},
|
|
|
|
writer::Writer,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn test_element_write() {
|
|
|
|
let mock = MockAsyncReader::new(TEST_DOC);
|
|
|
|
let mut reader = Reader::new(mock);
|
|
|
|
let element = reader.read_element().await.unwrap();
|
|
|
|
let stdout = tokio::io::stdout();
|
|
|
|
let mut writer = Writer::new(stdout);
|
|
|
|
writer.write_element(&element).await.unwrap();
|
|
|
|
}
|
|
|
|
}
|