xmlgenerator 0.2.4

Generate XML instances from an XML Schema (XSD)
use crate::encoder::encode_html;
use crate::error::{XMLGeneratorError, unimplemented};
use crate::generator::Generator;
use crate::name::Name;
use crate::namespaces::Namespaces;
use crate::whitespace::WhiteSpace;
use crate::xsd::Xsd;
use crate::xsd_type::XSDType;
use std::cmp::PartialEq;
use xml_builder::XMLElement;
use xsd_parser::models::schema::SchemaInfo;
use xsd_parser::models::schema::xs::{AttributeType, AttributeUseType};

pub(crate) struct Attribute {
    name: Option<Name>,
    type_name: Option<String>,
    xsd_type: XSDType,
    use_type: AttributeUseType,
}

impl Attribute {
    pub(crate) fn new(
        attribute_type: &AttributeType,
        schema_info: &SchemaInfo,
        namespaces: &Namespaces,
    ) -> Result<Attribute, XMLGeneratorError> {
        let mut attribute = Attribute {
            name: None,
            type_name: None,
            xsd_type: XSDType::None,
            use_type: AttributeUseType::Required,
        };

        attribute.name = Name::from_name(schema_info, namespaces, &attribute_type.name)?;

        if let Some(attribute_type) = &attribute_type.type_ {
            let type_name = String::from_utf8(attribute_type.local_name().to_vec()).unwrap();
            attribute.xsd_type = XSDType::from_string(&type_name)?;
            if matches!(attribute.xsd_type, XSDType::None) {
                attribute.type_name = Some(type_name);
            }
        }

        attribute.use_type = attribute_type.use_;

        if attribute_type.ref_.is_some() {
            return unimplemented("Attribute references");
        }

        if attribute_type.default.is_some() {
            return unimplemented("Default attribute");
        }

        if attribute_type.fixed.is_some() {
            return unimplemented("Fixed attribute");
        }

        if attribute_type.form.is_some() {
            return unimplemented("Form attribute");
        }

        if attribute_type.target_namespace.is_some() {
            return unimplemented("Target namespace attribute");
        }

        if attribute_type.inheritable.is_some() {
            return unimplemented("Inheritable attribute");
        }

        if attribute_type.annotation.is_some() {
            return unimplemented("Annotation");
        }

        if attribute_type.simple_type.is_some() {
            return unimplemented("Simple type attribute");
        }

        Ok(attribute)
    }

    fn get_full_name(
        &self,
        generator: &mut Generator,
        name: &Name,
    ) -> Result<String, XMLGeneratorError> {
        let current_namespace = generator.get_current_namespace();

        match name.get_prefix() {
            None => name.get_name(),
            Some(prefix) => {
                if Some(&prefix) == current_namespace && !generator.attributes_qualified() {
                    name.get_suffix()
                } else {
                    generator.add_namespace(prefix);
                    name.get_name()
                }
            }
        }
    }

    fn get_name(&self, generator: &mut Generator) -> Result<String, XMLGeneratorError> {
        match &self.name {
            None => Err(XMLGeneratorError::DataTypesFormatError(
                "Attribute Name is empty".to_string(),
            )),
            Some(name) => self.get_full_name(generator, name),
        }
    }

    pub(crate) fn generate(
        &self,
        generator: &mut Generator,
        xml_element: &mut XMLElement,
        xsd: &Xsd,
    ) -> Result<(), XMLGeneratorError> {
        let mut generated = false;
        let n_namespaces = generator.n_namespaces();

        if self.use_type == AttributeUseType::Prohibited {
            return Ok(());
        }

        let name = self.get_name(generator)?;
        if let Some(attribute) = generator.generate_type(&self.xsd_type) {
            let value = encode_html(&attribute, &self.xsd_type.whitespace())?;
            xml_element.add_attribute(&name, &value);
            generated = true;
        }

        if let Some(type_name) = &self.type_name {
            for type_generator in xsd.types() {
                if type_generator.name_equals(type_name) {
                    generator.track_ref(type_name.as_str());
                    type_generator.generate_attribute(generator, xml_element, xsd, &name)?;
                    generator.untrack_ref(type_name.as_str())?;
                    generated = true;
                }
            }
        }

        if !generated {
            if self.type_name.is_none() {
                let xsd_type = XSDType::string("", &WhiteSpace::Collapse)?;
                let value = generator.generate_type(&xsd_type).unwrap();
                let attribute = encode_html(&value, &xsd_type.whitespace())?;
                xml_element.add_attribute(&name, &attribute);
            } else if self.use_type == AttributeUseType::Required {
                return Err(XMLGeneratorError::TypeGenerationError(
                    "Required attribute not generated".to_string(),
                ));
            }
        }

        generator.update_namespaces(n_namespaces);

        Ok(())
    }
}

impl PartialEq for Attribute {
    fn eq(&self, other: &Self) -> bool {
        if self.name != other.name {
            return false;
        }

        if !self.type_name.eq(&other.type_name) {
            return false;
        }

        if self.xsd_type != other.xsd_type {
            return false;
        }

        if self.use_type != other.use_type {
            return false;
        }

        true
    }
}