Compare commits
3 Commits
4c235b972e
...
caf8b7506e
Author | SHA1 | Date |
---|---|---|
cel 🌸 | caf8b7506e | |
cel 🌸 | c2a84072ac | |
cel 🌸 | c8ed16a2d1 |
|
@ -10,7 +10,7 @@ use crate::{
|
|||
// when are namespaces names chosen then if they are automatically calculated
|
||||
// namespaces are held by readers and writers.
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||
pub struct Namespace {
|
||||
pub struct NamespaceDeclaration {
|
||||
pub prefix: Option<String>,
|
||||
pub namespace: String,
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ pub struct Namespace {
|
|||
// names are qualified, they contain a reference to the namespace (held within the reader/writer)
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||
pub struct Name {
|
||||
pub namespace: Namespace,
|
||||
pub name: String,
|
||||
pub namespace: String,
|
||||
pub local_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -40,7 +40,7 @@ pub struct Element {
|
|||
// namespace: String,
|
||||
// hashmap of explicit namespace declarations on the element itself only
|
||||
// possibly not needed as can be calculated at write time depending on context and qualified namespace, and for reading, element validity and namespaces are kept track of by the reader.
|
||||
pub namespace_decl: HashSet<Namespace>,
|
||||
pub namespace_declarations: HashSet<NamespaceDeclaration>,
|
||||
// attributes can be in a different namespace than the element. how to make sure they are valid?
|
||||
// maybe include the namespace instead of or with the prefix
|
||||
// you can calculate the prefix from the namespaced name and the current writer context
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{num::ParseIntError, str::Utf8Error};
|
||||
|
||||
use crate::element::{Name, Namespace};
|
||||
use crate::element::{Name, NamespaceDeclaration};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
@ -10,11 +10,12 @@ pub enum Error {
|
|||
EntityProcessError(String),
|
||||
// TODO: better choice for failures than string
|
||||
InvalidCharRef(String),
|
||||
DuplicateNameSpace(Namespace),
|
||||
DuplicateNameSpaceDeclaration(NamespaceDeclaration),
|
||||
DuplicateAttribute(String),
|
||||
UnqualifiedNamespace(String),
|
||||
MismatchedEndTag(String, String),
|
||||
MismatchedEndTag(Name, Name),
|
||||
NotInElement(String),
|
||||
ExtraData(String),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
|
|
581
src/reader.rs
581
src/reader.rs
|
@ -13,7 +13,7 @@ use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt};
|
|||
static MAX_STANZA_SIZE: usize = 65536;
|
||||
|
||||
use crate::{
|
||||
element::{Content, Element, Name, Namespace},
|
||||
element::{Content, Element, Name, NamespaceDeclaration},
|
||||
error::Error,
|
||||
xml::{self, parsers::Parser},
|
||||
Result,
|
||||
|
@ -26,7 +26,7 @@ pub struct Reader<R> {
|
|||
// holds which tags we are in atm over depth
|
||||
// to have names reference namespaces could
|
||||
depth: Vec<Name>,
|
||||
namespaces: Vec<HashSet<Namespace>>,
|
||||
namespace_declarations: Vec<HashSet<NamespaceDeclaration>>,
|
||||
}
|
||||
|
||||
impl<R> Reader<R> {
|
||||
|
@ -35,7 +35,7 @@ impl<R> Reader<R> {
|
|||
inner: reader,
|
||||
buffer: Buffer::with_capacity(MAX_STANZA_SIZE),
|
||||
depth: Vec::new(),
|
||||
namespaces: Vec::new(),
|
||||
namespace_declarations: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,8 +75,11 @@ where
|
|||
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.namespaces, e)?;
|
||||
let element = Reader::<R>::start_tag_from_xml(
|
||||
&mut self.depth,
|
||||
&mut self.namespace_declarations,
|
||||
e,
|
||||
)?;
|
||||
self.buffer.consume(len);
|
||||
return Ok(element);
|
||||
}
|
||||
|
@ -97,7 +100,11 @@ where
|
|||
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.namespaces, e)?;
|
||||
Reader::<R>::end_tag_from_xml(
|
||||
&mut self.depth,
|
||||
&mut self.namespace_declarations,
|
||||
e,
|
||||
)?;
|
||||
self.buffer.consume(len);
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -118,7 +125,8 @@ where
|
|||
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.namespaces, e)?;
|
||||
let element =
|
||||
Reader::<R>::element_from_xml(&mut self.namespace_declarations, e)?;
|
||||
self.buffer.consume(len);
|
||||
return Ok(element);
|
||||
}
|
||||
|
@ -156,8 +164,10 @@ where
|
|||
} else {
|
||||
let len =
|
||||
self.buffer.available_data() - rest.as_bytes().len();
|
||||
let element =
|
||||
Self::element_from_xml(&mut self.namespaces, element)?;
|
||||
let element = Self::element_from_xml(
|
||||
&mut self.namespace_declarations,
|
||||
element,
|
||||
)?;
|
||||
self.buffer.consume(len);
|
||||
return Ok(Content::Element(element));
|
||||
}
|
||||
|
@ -209,12 +219,15 @@ where
|
|||
match xml::ContentItem::parse(input) {
|
||||
Ok((rest, content_item)) => match content_item {
|
||||
xml::ContentItem::Element(element) => {
|
||||
// text can still be empty
|
||||
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.namespaces, element)?;
|
||||
let element = Self::element_from_xml(
|
||||
&mut self.namespace_declarations,
|
||||
element,
|
||||
)?;
|
||||
self.buffer.consume(len);
|
||||
return Ok(Content::Element(element));
|
||||
}
|
||||
|
@ -264,10 +277,12 @@ where
|
|||
impl<R> Reader<R> {
|
||||
fn start_tag_from_xml(
|
||||
depth: &mut Vec<Name>,
|
||||
namespaces: &mut Vec<HashSet<Namespace>>,
|
||||
namespace_declarations: &mut Vec<HashSet<NamespaceDeclaration>>,
|
||||
s_tag: xml::STag,
|
||||
) -> Result<Element> {
|
||||
let mut namespace_declarations = HashSet::new();
|
||||
// namespace declarations on element
|
||||
|
||||
let mut element_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))
|
||||
|
@ -281,24 +296,53 @@ impl<R> Reader<R> {
|
|||
}
|
||||
xml::NSAttName::DefaultAttName => None,
|
||||
};
|
||||
let namespace = Namespace {
|
||||
let namespace = NamespaceDeclaration {
|
||||
prefix,
|
||||
namespace: namespace.process()?,
|
||||
};
|
||||
if !namespace_declarations.insert(namespace.clone()) {
|
||||
return Err(Error::DuplicateNameSpace(namespace));
|
||||
if !element_namespace_declarations.insert(namespace.clone()) {
|
||||
return Err(Error::DuplicateNameSpaceDeclaration(namespace));
|
||||
}
|
||||
}
|
||||
|
||||
// all namespaces available to the element (from both parent elements and element itself)
|
||||
let namespace_stack: Vec<&Namespace> = namespaces
|
||||
// all namespaces available in the element scope (from both parent elements and element itself)
|
||||
let namespace_declarations_stack: Vec<&NamespaceDeclaration> = namespace_declarations
|
||||
.iter()
|
||||
.flatten()
|
||||
.chain(namespace_declarations.iter())
|
||||
.chain(element_namespace_declarations.iter())
|
||||
.collect();
|
||||
|
||||
let mut attributes = HashMap::new();
|
||||
// element name and default attribute namespace
|
||||
|
||||
let element_namespace_declaration;
|
||||
let element_local_name = s_tag.name.local_part().to_string();
|
||||
|
||||
match s_tag.name.prefix() {
|
||||
Some(prefix) => {
|
||||
element_namespace_declaration = namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace| namespace.prefix.as_deref() == Some(prefix));
|
||||
}
|
||||
None => {
|
||||
element_namespace_declaration = namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace| namespace.prefix == None);
|
||||
}
|
||||
}
|
||||
|
||||
let element_default_namespace = element_namespace_declaration
|
||||
.ok_or_else(|| Error::UnqualifiedNamespace(s_tag.name.to_string()))?
|
||||
.namespace
|
||||
.clone();
|
||||
|
||||
let element_name = Name {
|
||||
namespace: element_default_namespace,
|
||||
local_name: element_local_name,
|
||||
};
|
||||
|
||||
// attributes
|
||||
|
||||
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))
|
||||
|
@ -306,29 +350,26 @@ impl<R> Reader<R> {
|
|||
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();
|
||||
let attribute_namespace_declaration;
|
||||
let attribute_local_name = q_name.local_part().to_string();
|
||||
match q_name.prefix() {
|
||||
Some(prefix) => {
|
||||
attribute_namespace_declaration =
|
||||
namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace_declaration| {
|
||||
namespace_declaration.prefix.as_deref() == Some(prefix)
|
||||
});
|
||||
}
|
||||
None => attribute_namespace_declaration = element_namespace_declaration,
|
||||
}
|
||||
if let Some(namespace) = namespace {
|
||||
let namespace = (*namespace).clone();
|
||||
if let Some(namespace_declaration) = attribute_namespace_declaration {
|
||||
let name = Name {
|
||||
namespace,
|
||||
name: attribute_name,
|
||||
namespace: namespace_declaration.namespace.clone(),
|
||||
local_name: attribute_local_name,
|
||||
};
|
||||
let value = value.process()?;
|
||||
// check for duplicate attribute
|
||||
if let Some(_value) = attributes.insert(name, value) {
|
||||
return Err(Error::DuplicateAttribute(q_name.to_string()));
|
||||
}
|
||||
|
@ -337,36 +378,13 @@ impl<R> Reader<R> {
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
depth.push(element_name.clone());
|
||||
|
||||
let namespace = (*namespace
|
||||
.ok_or_else(|| Error::UnqualifiedNamespace(s_tag.name.to_string()))?)
|
||||
.clone();
|
||||
|
||||
let name = Name { namespace, name };
|
||||
|
||||
depth.push(name.clone());
|
||||
|
||||
namespaces.push(namespace_declarations.clone());
|
||||
namespace_declarations.push(element_namespace_declarations.clone());
|
||||
|
||||
return Ok(Element {
|
||||
name,
|
||||
namespace_decl: namespace_declarations,
|
||||
name: element_name,
|
||||
namespace_declarations: element_namespace_declarations,
|
||||
attributes,
|
||||
content: Vec::new(),
|
||||
});
|
||||
|
@ -374,257 +392,234 @@ impl<R> Reader<R> {
|
|||
|
||||
fn end_tag_from_xml(
|
||||
depth: &mut Vec<Name>,
|
||||
namespaces: &mut Vec<HashSet<Namespace>>,
|
||||
e_tag: xml::ETag,
|
||||
namespace_declarations: &mut Vec<HashSet<NamespaceDeclaration>>,
|
||||
xml_e_tag: xml::ETag,
|
||||
) -> Result<()> {
|
||||
if let Some(s_tag_name) = depth.pop() {
|
||||
if s_tag_name.namespace.prefix.as_deref() == e_tag.name.prefix()
|
||||
&& s_tag_name.name == e_tag.name.local_part()
|
||||
{
|
||||
namespaces.pop();
|
||||
let e_tag_namespace_declaration;
|
||||
let e_tag_local_name = xml_e_tag.name.local_part().to_string();
|
||||
let namespace_declarations_stack: Vec<_> =
|
||||
namespace_declarations.iter().flatten().collect();
|
||||
|
||||
match xml_e_tag.name.prefix() {
|
||||
Some(prefix) => {
|
||||
e_tag_namespace_declaration = namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace| namespace.prefix.as_deref() == Some(prefix));
|
||||
}
|
||||
None => {
|
||||
e_tag_namespace_declaration = namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace| namespace.prefix == None);
|
||||
}
|
||||
}
|
||||
|
||||
let e_tag_namespace = e_tag_namespace_declaration
|
||||
.ok_or_else(|| Error::UnqualifiedNamespace(xml_e_tag.name.to_string()))?
|
||||
.namespace
|
||||
.clone();
|
||||
|
||||
let e_tag_name = Name {
|
||||
namespace: e_tag_namespace,
|
||||
local_name: e_tag_local_name,
|
||||
};
|
||||
|
||||
if e_tag_name != s_tag_name {
|
||||
return Err(Error::MismatchedEndTag(s_tag_name, e_tag_name));
|
||||
}
|
||||
if s_tag_name == e_tag_name {
|
||||
namespace_declarations.pop();
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(Error::MismatchedEndTag(
|
||||
s_tag_name.name,
|
||||
e_tag.name.to_string(),
|
||||
));
|
||||
return Err(Error::MismatchedEndTag(s_tag_name, e_tag_name));
|
||||
}
|
||||
} else {
|
||||
return Err(Error::NotInElement(e_tag.name.to_string()));
|
||||
return Err(Error::NotInElement(xml_e_tag.name.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
fn element_from_xml(
|
||||
namespaces: &mut Vec<HashSet<Namespace>>,
|
||||
namespace_declarations: &mut Vec<HashSet<NamespaceDeclaration>>,
|
||||
element: xml::Element,
|
||||
) -> Result<Element> {
|
||||
let xml_name;
|
||||
let xml_attributes;
|
||||
let xml_content;
|
||||
let xml_e_name;
|
||||
|
||||
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 = Namespace {
|
||||
prefix,
|
||||
namespace: namespace.process()?,
|
||||
};
|
||||
if !namespace_declarations.insert(namespace.clone()) {
|
||||
return Err(Error::DuplicateNameSpace(namespace));
|
||||
}
|
||||
}
|
||||
|
||||
// all namespaces available to the element (from both parent elements and element itself)
|
||||
let namespace_stack: Vec<&Namespace> = namespaces
|
||||
.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,
|
||||
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, name };
|
||||
|
||||
return Ok(Element {
|
||||
name,
|
||||
namespace_decl: namespace_declarations,
|
||||
attributes,
|
||||
content: Vec::new(),
|
||||
});
|
||||
xml_name = empty_elem_tag.name;
|
||||
xml_attributes = empty_elem_tag.attributes;
|
||||
xml_content = None;
|
||||
xml_e_name = None;
|
||||
}
|
||||
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 = Namespace {
|
||||
prefix,
|
||||
namespace: namespace.process()?,
|
||||
};
|
||||
if !namespace_declarations.insert(namespace.clone()) {
|
||||
return Err(Error::DuplicateNameSpace(namespace));
|
||||
}
|
||||
}
|
||||
|
||||
// all namespaces available to the element (from both parent elements and element itself)
|
||||
let namespace_stack: Vec<&Namespace> = namespaces
|
||||
.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,
|
||||
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, name };
|
||||
|
||||
namespaces.push(namespace_declarations.clone());
|
||||
|
||||
let content = Self::content_from_xml(namespaces, content)?;
|
||||
|
||||
namespaces.pop();
|
||||
|
||||
return Ok(Element {
|
||||
name,
|
||||
namespace_decl: namespace_declarations,
|
||||
attributes,
|
||||
content,
|
||||
});
|
||||
xml_name = s_tag.name;
|
||||
xml_attributes = s_tag.attributes;
|
||||
xml_content = Some(content);
|
||||
xml_e_name = Some(e_tag.name);
|
||||
}
|
||||
}
|
||||
|
||||
// namespace declarations on element
|
||||
|
||||
let mut element_namespace_declarations = HashSet::new();
|
||||
for (prefix, namespace) in xml_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 {
|
||||
prefix,
|
||||
namespace: namespace.process()?,
|
||||
};
|
||||
if !element_namespace_declarations.insert(namespace.clone()) {
|
||||
return Err(Error::DuplicateNameSpaceDeclaration(namespace));
|
||||
}
|
||||
}
|
||||
|
||||
// all namespaces available in the element scope (from both parent elements and element itself)
|
||||
let namespace_declarations_stack: Vec<&NamespaceDeclaration> = namespace_declarations
|
||||
.iter()
|
||||
.flatten()
|
||||
.chain(element_namespace_declarations.iter())
|
||||
.collect();
|
||||
|
||||
// element name and default attribute namespace
|
||||
|
||||
let element_namespace_declaration;
|
||||
let element_local_name = xml_name.local_part().to_string();
|
||||
|
||||
match xml_name.prefix() {
|
||||
Some(prefix) => {
|
||||
element_namespace_declaration = namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace| namespace.prefix.as_deref() == Some(prefix));
|
||||
}
|
||||
None => {
|
||||
element_namespace_declaration = namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace| namespace.prefix == None);
|
||||
}
|
||||
}
|
||||
|
||||
let element_default_namespace = element_namespace_declaration
|
||||
.ok_or_else(|| Error::UnqualifiedNamespace(xml_name.to_string()))?
|
||||
.namespace
|
||||
.clone();
|
||||
|
||||
let element_name = Name {
|
||||
namespace: element_default_namespace,
|
||||
local_name: element_local_name,
|
||||
};
|
||||
|
||||
// end tag name match check
|
||||
|
||||
if let Some(xml_e_name) = xml_e_name {
|
||||
let e_tag_namespace_declaration;
|
||||
let e_tag_local_name = xml_e_name.local_part().to_string();
|
||||
|
||||
match xml_e_name.prefix() {
|
||||
Some(prefix) => {
|
||||
e_tag_namespace_declaration = namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace| namespace.prefix.as_deref() == Some(prefix));
|
||||
}
|
||||
None => {
|
||||
e_tag_namespace_declaration = namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace| namespace.prefix == None);
|
||||
}
|
||||
}
|
||||
|
||||
let e_tag_namespace = e_tag_namespace_declaration
|
||||
.ok_or_else(|| Error::UnqualifiedNamespace(xml_name.to_string()))?
|
||||
.namespace
|
||||
.clone();
|
||||
|
||||
let e_tag_name = Name {
|
||||
namespace: e_tag_namespace,
|
||||
local_name: e_tag_local_name,
|
||||
};
|
||||
|
||||
if e_tag_name != element_name {
|
||||
return Err(Error::MismatchedEndTag(element_name, e_tag_name));
|
||||
}
|
||||
}
|
||||
|
||||
// attributes
|
||||
|
||||
let mut attributes = HashMap::new();
|
||||
for (q_name, value) in xml_attributes.iter().filter_map(|attribute| {
|
||||
if let xml::Attribute::Attribute { name, value } = attribute {
|
||||
Some((name, value))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
let attribute_namespace_declaration;
|
||||
let attribute_local_name = q_name.local_part().to_string();
|
||||
match q_name.prefix() {
|
||||
Some(prefix) => {
|
||||
attribute_namespace_declaration =
|
||||
namespace_declarations_stack
|
||||
.iter()
|
||||
.rfind(|namespace_declaration| {
|
||||
namespace_declaration.prefix.as_deref() == Some(prefix)
|
||||
});
|
||||
}
|
||||
None => attribute_namespace_declaration = element_namespace_declaration,
|
||||
}
|
||||
if let Some(namespace_declaration) = attribute_namespace_declaration {
|
||||
let name = Name {
|
||||
namespace: namespace_declaration.namespace.clone(),
|
||||
local_name: attribute_local_name,
|
||||
};
|
||||
let value = value.process()?;
|
||||
// check for duplicate attribute
|
||||
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 content;
|
||||
if let Some(xml_content) = xml_content {
|
||||
namespace_declarations.push(element_namespace_declarations.clone());
|
||||
|
||||
content = Self::content_from_xml(namespace_declarations, xml_content)?;
|
||||
|
||||
namespace_declarations.pop();
|
||||
} else {
|
||||
content = Vec::new();
|
||||
}
|
||||
|
||||
return Ok(Element {
|
||||
name: element_name,
|
||||
namespace_declarations: element_namespace_declarations,
|
||||
attributes,
|
||||
content,
|
||||
});
|
||||
}
|
||||
|
||||
fn content_from_xml(
|
||||
namespaces: &mut Vec<HashSet<Namespace>>,
|
||||
element: xml::Content,
|
||||
namespaces: &mut Vec<HashSet<NamespaceDeclaration>>,
|
||||
xml_content: 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 {
|
||||
let mut text = xml_content.char_data.map(|str| String::from(*str));
|
||||
for (content_item, char_data) in xml_content.content {
|
||||
match content_item {
|
||||
xml::ContentItem::Element(element) => {
|
||||
text.map(|text| content.push(Content::Text(text)));
|
||||
|
|
|
@ -1,26 +1,53 @@
|
|||
use futures::{AsyncWrite, Sink};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use futures::Sink;
|
||||
use tokio::io::AsyncWrite;
|
||||
|
||||
use crate::{
|
||||
element::{Element, Name, Namespace},
|
||||
element::{Element, Name, NamespaceDeclaration},
|
||||
error::Error,
|
||||
xml::{self, composers::Composer, parsers_complete::Parser, ETag},
|
||||
};
|
||||
|
||||
// pub struct Writer<W, C = Composer> {
|
||||
pub struct Writer<W> {
|
||||
writer: W,
|
||||
inner: W,
|
||||
depth: Vec<Name>,
|
||||
namespaces: Vec<(usize, Namespace)>,
|
||||
namespaces: Vec<HashSet<NamespaceDeclaration>>,
|
||||
}
|
||||
|
||||
impl<W: AsyncWrite> Writer<W> {
|
||||
pub async fn write(&self, element: impl Into<Element>) -> Result<(), Error> {
|
||||
impl<W: AsyncWrite + Unpin> Writer<W> {
|
||||
pub async fn write(&mut self, element: Element) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
pub async fn write_start(&self, element: impl Into<Element>) -> Result<(), Error> {
|
||||
|
||||
pub async fn write_start(&mut self, element: Element) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
pub async fn write_end(&self) -> Result<(), Error> {
|
||||
|
||||
pub async fn write_end(&mut self) -> Result<(), Error> {
|
||||
todo!()
|
||||
// let e_tag;
|
||||
// if let Some(name) = self.depth.pop() {
|
||||
// if let Some(prefix) = name.namespace.prefix {
|
||||
// e_tag = xml::ETag {
|
||||
// name: xml::QName::PrefixedName(xml::PrefixedName {
|
||||
// prefix: xml::Prefix::parse_full(&prefix)?,
|
||||
// local_part: xml::LocalPart::parse_full(&name.name)?,
|
||||
// }),
|
||||
// };
|
||||
// e_tag.write(&mut self.inner).await?;
|
||||
// Ok(())
|
||||
// } else {
|
||||
// e_tag = xml::ETag {
|
||||
// name: xml::QName::UnprefixedName(xml::UnprefixedName::parse_full(&name.name)?),
|
||||
// };
|
||||
// e_tag.write(&mut self.inner).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
// } else {
|
||||
// return Err(Error::NotInElement("".to_string()));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,19 @@ pub trait Parser<'s> {
|
|||
type Output;
|
||||
|
||||
fn parse(input: &'s str) -> IResult<&str, Self::Output>;
|
||||
|
||||
fn parse_full(input: &'s str) -> crate::Result<Self::Output> {
|
||||
match <Self as Parser>::parse(input) {
|
||||
Ok((rest, output)) => {
|
||||
if rest.is_empty() {
|
||||
return Ok(output);
|
||||
} else {
|
||||
return Err(crate::error::Error::ExtraData(rest.to_string()));
|
||||
}
|
||||
}
|
||||
Result::Err(e) => return Err(crate::error::Error::ParseError(e.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// [1] NSAttName ::= PrefixedAttName | DefaultAttName
|
||||
|
|
Loading…
Reference in New Issue