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