From 6d1f28eb79c6c70b058fcbae5047dbd744764149 Mon Sep 17 00:00:00 2001 From: cel 🌸 Date: Fri, 30 May 2025 13:29:02 +0100 Subject: doc: everything --- src/element.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 4 deletions(-) (limited to 'src/element.rs') diff --git a/src/element.rs b/src/element.rs index 1c1366a..b6b3c15 100644 --- a/src/element.rs +++ b/src/element.rs @@ -11,12 +11,15 @@ use crate::{ Result, }; +/// Result type for the `FromElement` trait. pub type DeserializeResult = std::result::Result; +/// Trait for conversion from an `Element` into another type, for deserialisation from a `Reader`. pub trait FromElement: Sized { fn from_element(element: Element) -> DeserializeResult; } +/// Trait for conversion from a type into an `Element`, for serialisation into a `Writer`. pub trait IntoElement { fn builder(&self) -> ElementBuilder; @@ -45,18 +48,24 @@ pub struct Name { pub local_name: String, } +/// `Content` represents anything that can be the content of an XML element. #[derive(Debug, Clone)] pub enum Content { + /// A child element. Element(Element), + /// A text value. Text(String), + /// A processing instruction. PI, + /// A comment. Comment(String), } // should this be a trait? +/// `Element` represents an XML element that can be written to a `Writer` or read from a `Reader`. #[derive(Debug, Clone)] pub struct Element { - pub name: Name, + pub(crate) name: Name, // namespace: Name, // each element once created contains the qualified namespace information for that element // the name contains the qualified namespace so this is unnecessary @@ -64,15 +73,15 @@ pub struct Element { // 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. // change this to custom namespace declarations only, so you can override the definition of namespaces if you wish - pub namespace_declaration_overrides: HashSet, + pub(crate) namespace_declaration_overrides: HashSet, // 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 // you can validate the prefix and calculate the namespace from the current reader context // this results in readers and writers being able to return qualification errors as they aren't able to create elements until every part is qualified. - pub attributes: HashMap, + pub(crate) attributes: HashMap, // TODO: make a hashmap maybe? to be able to address parts of the content individually - pub content: VecDeque, + pub(crate) content: VecDeque, } impl FromElement for Element { @@ -82,10 +91,12 @@ impl FromElement for Element { } impl Element { + /// Return the namespace the xml element is qualified by, and the localname, for matching on the element when you don't know which kind of element to expect. pub fn identify(&self) -> (Option<&str>, &str) { (self.name.namespace.as_deref(), &self.name.local_name) } + /// Check the localname of the element. pub fn check_name(&self, name: &str) -> DeserializeResult<()> { if self.name.local_name == name { Ok(()) @@ -97,6 +108,7 @@ impl Element { } } + /// Check the element is qualified by a namespace. pub fn check_namespace(&self, namespace: &str) -> DeserializeResult<()> { if self.name.namespace.as_deref() == Some(namespace) { return Ok(()); @@ -114,6 +126,7 @@ impl Element { } } + /// Optionally extract an attribute from the element. pub fn attribute_opt(&mut self, att_name: &str) -> DeserializeResult> { if let Some(att_value) = self.attributes.remove(&Name { namespace: None, @@ -127,6 +140,7 @@ impl Element { } } + /// Optionally extract a namespaced attribute from the elmeent. pub fn attribute_opt_namespaced( &mut self, att_name: &str, @@ -144,6 +158,7 @@ impl Element { } } + /// Extract an attribute from the element. pub fn attribute(&mut self, att_name: &str) -> DeserializeResult { let name = Name { namespace: None, @@ -158,6 +173,7 @@ impl Element { } } + /// Extract a namespaced attribute from the element. pub fn attribute_namespaced( &mut self, att_name: &str, @@ -176,6 +192,7 @@ impl Element { } } + /// Ensure there are no more attributes on the element. pub fn no_more_attributes(self) -> DeserializeResult { if self.attributes.is_empty() { Ok(self) @@ -186,6 +203,8 @@ impl Element { // for xs:any + /// Extract a child of type `T` from the element. + /// E.g. when there is an xs:any. pub fn child_one(&mut self) -> DeserializeResult { if let Some(position) = self.content.iter().position(|content| match content { Content::Element(element) => ::from_element(element.clone()).is_ok(), @@ -204,6 +223,8 @@ impl Element { } } + /// Optionally extract a child of type `T` from the element. + /// E.g. when there is an xs:any. pub fn child_opt(&mut self) -> DeserializeResult> { if let Some(position) = self.content.iter().position(|content| match content { Content::Element(element) => ::from_element(element.clone()).is_ok(), @@ -222,6 +243,7 @@ impl Element { } } + /// Extract several children of type `T` from the element. pub fn children(&mut self) -> DeserializeResult> { let (children, rest): (VecDeque<_>, VecDeque<_>) = self .content @@ -252,6 +274,7 @@ impl Element { Ok(children) } + /// Extract a text value from the element. pub fn value(&mut self) -> DeserializeResult { if let Some(position) = self.content.iter().position(|content| match content { Content::Element(_) => false, @@ -270,6 +293,7 @@ impl Element { } } + /// Optionally extract a text value from the element. pub fn value_opt(&mut self) -> DeserializeResult> { if let Some(position) = self.content.iter().position(|content| match content { Content::Element(_) => false, @@ -290,6 +314,8 @@ impl Element { // for xs:sequence + /// Pop a child element of type `T` from the element. + /// E.g. when there is an xs:sequence. pub fn pop_child_one(&mut self) -> DeserializeResult { loop { let child = self @@ -307,6 +333,8 @@ impl Element { } } + /// Optionally pop a child element of type `T` from the element. + /// E.g. when there is an xs:sequence. pub fn pop_child_opt(&mut self) -> DeserializeResult> { loop { let child = self.content.pop_front(); @@ -327,6 +355,8 @@ impl Element { } } + /// Pop several children of type `T` from the element. + /// E.g. when there is an xs:sequence. pub fn pop_children(&mut self) -> DeserializeResult> { let mut children = Vec::new(); loop { @@ -360,6 +390,8 @@ impl Element { } } + /// Pop a text value from the element. + /// E.g. when there is an xs:sequence. pub fn pop_value(&mut self) -> DeserializeResult { loop { let child = self @@ -381,6 +413,8 @@ impl Element { } } + /// Optionally pop a text value from the element. + /// E.g. when there is an xs:sequence. pub fn pop_value_opt(&mut self) -> DeserializeResult> { loop { let child = self.content.pop_front(); @@ -404,6 +438,7 @@ impl Element { } } + /// Ensure there is no more element content left. pub fn no_more_content(self) -> DeserializeResult { if self .content @@ -423,11 +458,13 @@ impl Element { } } + /// Create a new `ElementBuilder`. pub fn builder(name: impl ToString, namespace: Option) -> ElementBuilder { ElementBuilder::new(name, namespace) } } +/// Builder for the `Element` type. pub struct ElementBuilder { name: Name, namespace_declaration_overrides: Vec, @@ -436,6 +473,7 @@ pub struct ElementBuilder { } impl ElementBuilder { + /// Create a new `ElementBuilder`. pub fn new(name: impl ToString, namespace: Option) -> Self { Self { name: Name { @@ -448,6 +486,7 @@ impl ElementBuilder { } } + /// Push a namespace declaration override onto the element builder. pub fn push_namespace_declaration_override( mut self, prefix: Option, @@ -461,6 +500,7 @@ impl ElementBuilder { self } + /// Push an attribute onto the element builder. pub fn push_attribute(mut self, name: N, value: V) -> Self { self.attributes.push(( // TODO: make sure name is a valid name, same for prefixes @@ -473,6 +513,7 @@ impl ElementBuilder { self } + /// Push a namespaced attribute onto the element builder. pub fn push_attribute_namespaced( mut self, namespace: impl ToString, @@ -490,17 +531,20 @@ impl ElementBuilder { } // TODO: use references for everything to avoid cloning + /// Push a child element onto the element builder. pub fn push_child(mut self, child: impl IntoElement) -> Self { self.content.push(ContentBuilder::Element(child.builder())); self } // TODO: better way for push_text to work, empty string should be empty element no matter what + /// Push a text value onto the element builder. pub fn push_text(mut self, text: impl ToString) -> Self { self.content.push(ContentBuilder::Text(text.to_string())); self } + /// Optionally push an attribute onto the element builder. pub fn push_attribute_opt(self, name: impl ToString, value: Option) -> Self { if let Some(value) = value { self.push_attribute(name, value) @@ -509,6 +553,7 @@ impl ElementBuilder { } } + /// Optionally push a namespaced attribute onto the element builder. pub fn push_attribute_opt_namespaced( self, namespace: impl ToString, @@ -522,6 +567,7 @@ impl ElementBuilder { } } + /// Optionally push a child onto the element builder. pub fn push_child_opt(self, child: Option) -> Self { if let Some(child) = child { self.push_child(child) @@ -530,6 +576,7 @@ impl ElementBuilder { } } + /// Optionally push a text value onto the element builder. pub fn push_text_opt(self, text: Option) -> Self { if let Some(text) = text { self.push_text(text) @@ -538,11 +585,13 @@ impl ElementBuilder { } } + /// Optionally push a content item onto the element builder. pub fn push_content(mut self, content: ContentBuilder) -> Self { self.content.push(content); self } + /// Optionally push content items onto the element builder. pub fn push_children(self, children: Vec) -> Self { let mut element_builder = self; for child in children { @@ -551,6 +600,7 @@ impl ElementBuilder { element_builder } + /// Build an `Element` from the `ElementBuilder`. pub fn build(&self) -> Result { let mut namespace_declaration_overrides = HashSet::new(); for namespace_declaration in &self.namespace_declaration_overrides { @@ -588,6 +638,7 @@ impl ElementBuilder { } } +/// Trait for conversion from a type into an (`Element`) `Content` item. pub trait IntoContent { fn into_content(&self) -> Content { self.builder().build().unwrap() @@ -605,17 +656,23 @@ where } } +/// Trait for conversion from some `Element` `Content` into another type. pub trait FromContent: Sized { fn from_content(content: Content) -> DeserializeResult; } +/// Builder for `Content`. pub enum ContentBuilder { + /// A child element. Element(ElementBuilder), + /// A text value. Text(String), + /// A comment. Comment(String), } impl ContentBuilder { + /// Build a `Content` item from the builder. pub fn build(&self) -> Result { match self { ContentBuilder::Element(element_builder) => { @@ -627,6 +684,7 @@ impl ContentBuilder { } } +/// Escape a str into an XML escaped string. pub fn escape_str(s: &str) -> String { let mut string = String::new(); for str in s.split_inclusive(|c| c == '<' || c == '&' || c == '>') { -- cgit