aboutsummaryrefslogblamecommitdiffstats
path: root/src/element.rs
blob: 1c04c98659a9712a691b3c3d142075627b6c379a (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                                                            




                                    


                 
                                                     
           
  
 












                                                      

                                                                             
                                            
                                 

                               

 
                                                                                                 
                                            
                 
                                  
                           

 
                       
                  

                     
       
                    


                          
                       
                    
                   
                       




                                                                                                                                                                                             

                                                                                                                      




                                                                                                                                                          
                                          
                                                                                          
                              

 


























                                                                        


















                                                                                                    


                                  
                                                                                                            









                                                                                                                                                                                                       
// elements resemble a final tree, including inherited namespace information

use std::{
    collections::{HashMap, HashSet},
    convert::Infallible,
    str::FromStr,
};

use crate::{
    error::Error,
    xml::{self, parsers_complete::Parser, Attribute},
    Result,
};

pub trait FromElement: Sized {
    fn from_element(element: Element) -> Result<Self>;
}

pub trait IntoElement {
    fn into_element(&self) -> Element;

    fn get_content(&self) -> Vec<Content> {
        let element = self.into_element();
        element.content
    }
}

// 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 NamespaceDeclaration {
    pub prefix: Option<String>,
    pub namespace: String,
}

// 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: Option<String>,
    pub local_name: String,
}

#[derive(Debug, Clone)]
pub enum Content {
    Element(Element),
    Text(String),
    PI,
    Comment(String),
}

// should this be a trait?
#[derive(Debug, Clone)]
pub struct Element {
    pub 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
    // 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.
    // change this to custom namespace declarations only, so you can override the definition of namespaces if you wish
    pub namespace_declaration_overrides: 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
    // 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<Name, String>,
    // TODO: make a hashmap maybe? to be able to address parts of the content individually
    pub content: Vec<Content>,
}

pub fn escape_str(s: &str) -> String {
    let mut string = String::new();
    for str in s.split_inclusive(|c| c == '<' || c == '&' || c == '>') {
        if let Some(str) = str.strip_suffix('<') {
            if !str.is_empty() {
                string.push_str(str)
            }
            string.push_str("&lt;");
        } else if let Some(str) = str.strip_suffix('&') {
            if !str.is_empty() {
                string.push_str(str)
            }
            string.push_str("&amp;");
        } else if let Some(str) = str.strip_suffix('>') {
            if !str.is_empty() {
                string.push_str(str)
            }
            string.push_str("&gt;");
        } else {
            if !str.is_empty() {
                string.push_str(str)
            }
        }
    }
    string
}

// impl<'s> TryFrom<xml::Element<'s>> for Element<'s> {
//     type Error = Error;

//     fn try_from(xml_element: xml::Element) -> Result<Self, Self::Error> {
//         match &xml_element {
//             xml::Element::Empty(empty_elem_tag) => {
//                 let namespace_decl;
//                 let attributes;
//                 empty_elem_tag
//                     .attributes
//                     .into_iter()
//                     .filter(|attribute| matches!(attribute, Attribute::NamespaceDeclaration(_)));
//                 todo!()
//             }
//             xml::Element::NotEmpty(stag, content, etag) => todo!(),
//         }
//     }
// }

// example of deriving an element:

// #[derive(XMLWrite, XMLRead)]
// #[peanuts(xmlns = "jabber:client", xmlns:stream = "http://etherx.jabber.org/streams", prefix = "stream")]
// pub struct Stream {
//     from: JID,
//     id: String,
//     to: JID,
//     version: String,
//     #[peanuts(namespace = "http://www.w3.org/XML/1998/namespace")]
//     lang: Lang,
// }

// note: if an element name has a prefix all unprefixed attributes are qualified by the namespace of the prefix, so in this example from's Name's namespace would be "http://etherx.jabber.org/streams"