WIP: write start tag of element

This commit is contained in:
cel 🌸 2024-11-20 15:10:36 +00:00
parent 0175a2d365
commit a3dc4e1475
4 changed files with 163 additions and 19 deletions

View File

@ -1,10 +1,14 @@
// elements resemble a final tree, including inherited namespace information // elements resemble a final tree, including inherited namespace information
use std::collections::{HashMap, HashSet}; use std::{
collections::{HashMap, HashSet},
convert::Infallible,
str::FromStr,
};
use crate::{ use crate::{
error::Error, error::Error,
xml::{self, Attribute}, xml::{self, parsers_complete::Parser, Attribute},
}; };
// when are namespaces names chosen then if they are automatically calculated // when are namespaces names chosen then if they are automatically calculated

View File

@ -16,6 +16,7 @@ pub enum Error {
MismatchedEndTag(Name, Name), MismatchedEndTag(Name, Name),
NotInElement(String), NotInElement(String),
ExtraData(String), ExtraData(String),
UndeclaredNamespace(String),
} }
impl From<std::io::Error> for Error { impl From<std::io::Error> for Error {

View File

@ -1,4 +1,4 @@
use std::collections::HashSet; use std::{collections::HashSet, str::FromStr};
use futures::Sink; use futures::Sink;
use tokio::io::AsyncWrite; use tokio::io::AsyncWrite;
@ -7,6 +7,7 @@ use crate::{
element::{Element, Name, NamespaceDeclaration}, element::{Element, Name, NamespaceDeclaration},
error::Error, error::Error,
xml::{self, composers::Composer, parsers_complete::Parser, ETag}, xml::{self, composers::Composer, parsers_complete::Parser, ETag},
Result,
}; };
// pub struct Writer<W, C = Composer> { // pub struct Writer<W, C = Composer> {
@ -17,17 +18,68 @@ pub struct Writer<W> {
} }
impl<W: AsyncWrite + Unpin> Writer<W> { impl<W: AsyncWrite + Unpin> Writer<W> {
pub async fn write(&mut self, element: Element) -> Result<(), Error> { pub async fn write(&mut self, element: Element) -> Result<()> {
todo!() todo!()
} }
pub async fn write_start(&mut self, element: Element) -> Result<(), Error> { pub async fn write_start(&mut self, element: Element) -> Result<()> {
todo!() let mut namespace_declarations_stack: Vec<_> = self
.namespace_declarations
.iter()
.flatten()
.chain(&element.namespace_declarations)
.collect();
let name_namespace_declaration = namespace_declarations_stack
.iter()
.rfind(|namespace_declaration| {
namespace_declaration.namespace == element.name.namespace
})
.ok_or(Error::UndeclaredNamespace(element.name.namespace.clone()))?;
let prefix = &name_namespace_declaration.prefix;
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,
)?)
} }
pub async fn write_end(&mut self) -> Result<(), Error> { namespace_declarations_stack.push(name_namespace_declaration);
let e_tag;
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::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);
}
let s_tag = xml::STag { name, attributes };
s_tag.write(&mut self.inner).await?;
self.depth.push(element.name);
self.namespace_declarations
.push(element.namespace_declarations);
Ok(())
}
pub async fn write_end(&mut self) -> Result<()> {
if let Some(name) = &self.depth.pop() { if let Some(name) = &self.depth.pop() {
let e_tag;
let namespace_declarations_stack: Vec<_> = let namespace_declarations_stack: Vec<_> =
self.namespace_declarations.iter().flatten().collect(); self.namespace_declarations.iter().flatten().collect();
let namespace_declaration = namespace_declarations_stack let namespace_declaration = namespace_declarations_stack
@ -65,25 +117,25 @@ impl<W: AsyncWrite, E: Into<Element>> Sink<E> for Writer<W> {
fn poll_ready( fn poll_ready(
self: std::pin::Pin<&mut Self>, self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> { ) -> std::task::Poll<Result<()>> {
todo!() todo!()
} }
fn start_send(self: std::pin::Pin<&mut Self>, item: E) -> Result<(), Self::Error> { fn start_send(self: std::pin::Pin<&mut Self>, item: E) -> Result<()> {
todo!() todo!()
} }
fn poll_flush( fn poll_flush(
self: std::pin::Pin<&mut Self>, self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> { ) -> std::task::Poll<Result<()>> {
todo!() todo!()
} }
fn poll_close( fn poll_close(
self: std::pin::Pin<&mut Self>, self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> { ) -> std::task::Poll<Result<()>> {
todo!() todo!()
} }
} }

View File

@ -1,4 +1,6 @@
use std::{char, ops::Deref}; use std::{char, convert::Infallible, ops::Deref, str::FromStr};
use parsers_complete::Parser;
use crate::error::Error; use crate::error::Error;
@ -228,14 +230,14 @@ pub enum EntityValue<'s> {
SingleQuoted(Vec<EntityValueData<'s>>), SingleQuoted(Vec<EntityValueData<'s>>),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum AttValueData<'s> { pub enum AttValueData<'s> {
String(&'s str), String(&'s str),
Reference(Reference<'s>), Reference(Reference<'s>),
} }
/// [10] AttValue ::= '"' ([^<&"] | Reference)* '"' /// [10] AttValue ::= '"' ([^<&"] | Reference)* '"'
/// | "'" ([^<&'] | Reference)* "'" /// | "'" ([^<&'] | Reference)* "'"
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum AttValue<'s> { pub enum AttValue<'s> {
DoubleQuoted(Vec<AttValueData<'s>>), DoubleQuoted(Vec<AttValueData<'s>>),
SingleQuoted(Vec<AttValueData<'s>>), SingleQuoted(Vec<AttValueData<'s>>),
@ -259,6 +261,34 @@ impl<'s> AttValue<'s> {
} }
} }
impl<'s> From<&'s str> for AttValue<'s> {
fn from(s: &'s str) -> AttValue<'s> {
let mut data = Vec::new();
for str in s.split_inclusive(|c| c == '<' || c == '"') {
if let Some(str) = str.strip_suffix('<') {
if !str.is_empty() {
data.push(AttValueData::String(str))
}
data.push(AttValueData::Reference(Reference::EntityRef(EntityRef(
Name::parse_full("lt").unwrap(),
))))
} else if let Some(str) = str.strip_suffix('"') {
if !str.is_empty() {
data.push(AttValueData::String(str))
}
data.push(AttValueData::Reference(Reference::EntityRef(EntityRef(
Name::parse_full("quot").unwrap(),
))))
} else {
if !str.is_empty() {
data.push(AttValueData::String(str))
}
}
}
AttValue::DoubleQuoted(data)
}
}
/// [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") /// [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
#[derive(Debug)] #[derive(Debug)]
pub enum SystemLiteral<'s> { pub enum SystemLiteral<'s> {
@ -673,7 +703,7 @@ pub struct IgnoreSectContents<'s> {
pub struct Ignore<'s>(&'s str); pub struct Ignore<'s>(&'s str);
/// [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';' /// [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum CharRef<'s> { pub enum CharRef<'s> {
Decimal(&'s str), Decimal(&'s str),
Hexadecimal(&'s str), Hexadecimal(&'s str),
@ -706,7 +736,7 @@ impl<'s> CharRef<'s> {
} }
/// [67] Reference ::= EntityRef | CharRef /// [67] Reference ::= EntityRef | CharRef
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Reference<'s> { pub enum Reference<'s> {
EntityRef(EntityRef<'s>), EntityRef(EntityRef<'s>),
CharRef(CharRef<'s>), CharRef(CharRef<'s>),
@ -729,8 +759,8 @@ impl<'s> Reference<'s> {
} }
/// [68] EntityRef ::= '&' Name ';' /// [68] EntityRef ::= '&' Name ';'
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct EntityRef<'s>(Name<'s>); pub struct EntityRef<'s>(pub(crate) Name<'s>);
impl<'s> Deref for EntityRef<'s> { impl<'s> Deref for EntityRef<'s> {
type Target = Name<'s>; type Target = Name<'s>;
@ -835,3 +865,60 @@ pub struct NotationDecl<'s> {
/// [83] PublicID ::= 'PUBLIC' S PubidLiteral /// [83] PublicID ::= 'PUBLIC' S PubidLiteral
#[derive(Debug)] #[derive(Debug)]
pub struct PublicID<'s>(PubidLiteral<'s>); pub struct PublicID<'s>(PubidLiteral<'s>);
#[cfg(test)]
mod test {
use super::{AttValue, AttValueData, EntityRef, Name, Reference};
#[test]
fn att_value_from_str() {
assert_eq!(
AttValue::from("hsdaflaskdf<laksdf<abdsf"),
AttValue::DoubleQuoted(vec![
AttValueData::String("hsdaflaskdf"),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("lt")))),
AttValueData::String("laksdf"),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("lt")))),
AttValueData::String("abdsf"),
])
);
assert_eq!(
AttValue::from("hsdaflaskdf<laksdf\"abdsf"),
AttValue::DoubleQuoted(vec![
AttValueData::String("hsdaflaskdf"),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("lt")))),
AttValueData::String("laksdf"),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("quot")))),
AttValueData::String("abdsf"),
])
);
assert_eq!(
AttValue::from("hsdaflaskdf<laksdf\""),
AttValue::DoubleQuoted(vec![
AttValueData::String("hsdaflaskdf"),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("lt")))),
AttValueData::String("laksdf"),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("quot")))),
])
);
assert_eq!(
AttValue::from("hsdaflaskdf\"<<laksdf\""),
AttValue::DoubleQuoted(vec![
AttValueData::String("hsdaflaskdf"),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("quot")))),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("lt")))),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("lt")))),
AttValueData::String("laksdf"),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("quot")))),
])
);
assert_eq!(
AttValue::from("<<\""),
AttValue::DoubleQuoted(vec![
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("lt")))),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("lt")))),
AttValueData::Reference(Reference::EntityRef(EntityRef(Name("quot")))),
])
);
}
}