WIP: write start tag of element
This commit is contained in:
parent
0175a2d365
commit
a3dc4e1475
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
101
src/xml/mod.rs
101
src/xml/mod.rs
|
@ -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")))),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue