Skip to content

Commit

Permalink
Merge pull request #24 from sybila/validation
Browse files Browse the repository at this point in the history
Validation: General rules for `annotation` elements
  • Loading branch information
daemontus authored Mar 6, 2024
2 parents 29cdfa6 + e2b2b5d commit 3a0b9c8
Show file tree
Hide file tree
Showing 15 changed files with 237 additions and 51 deletions.
14 changes: 11 additions & 3 deletions src/core/validation/compartment.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::core::validation::{
apply_rule_10102, apply_rule_10301, apply_rule_10307, apply_rule_10308, apply_rule_10309,
apply_rule_10310, apply_rule_10311, apply_rule_10312, apply_rule_10313, SanityCheckable,
SbmlValidable,
apply_rule_10310, apply_rule_10311, apply_rule_10312, apply_rule_10313, apply_rule_10401,
apply_rule_10402, apply_rule_10404, SanityCheckable, SbmlValidable,
};
use crate::core::{Compartment, SBase};
use crate::xml::{OptionalXmlProperty, RequiredXmlProperty, XmlProperty, XmlWrapper};
use crate::xml::{
OptionalXmlChild, OptionalXmlProperty, RequiredXmlProperty, XmlProperty, XmlWrapper,
};
use crate::SbmlIssue;
use std::collections::HashSet;

Expand All @@ -29,6 +31,12 @@ impl SbmlValidable for Compartment {
apply_rule_10311(units.name(), units.get(), xml_element, issues);
apply_rule_10312(self.name().get(), xml_element, issues);
apply_rule_10313(units.name(), units.get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/core/validation/constraint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::core::validation::{
apply_rule_10102, apply_rule_10301, apply_rule_10307, apply_rule_10308, apply_rule_10309,
apply_rule_10310, apply_rule_10312, SanityCheckable, SbmlValidable,
apply_rule_10310, apply_rule_10312, apply_rule_10401, apply_rule_10402, apply_rule_10404,
SanityCheckable, SbmlValidable,
};
use crate::core::{Constraint, SBase};
use crate::xml::{OptionalXmlChild, OptionalXmlProperty, XmlWrapper};
Expand All @@ -26,6 +27,11 @@ impl SbmlValidable for Constraint {
apply_rule_10310(id.get(), xml_element, issues);
apply_rule_10312(self.name().get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(math) = self.math().get() {
math.validate(issues);
}
Expand Down
29 changes: 27 additions & 2 deletions src/core/validation/event.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::core::validation::{
apply_rule_10102, apply_rule_10301, apply_rule_10307, apply_rule_10308, apply_rule_10309,
apply_rule_10310, apply_rule_10312, sanity_check, sanity_check_of_list,
validate_list_of_objects, SanityCheckable, SbmlValidable,
apply_rule_10310, apply_rule_10312, apply_rule_10401, apply_rule_10402, apply_rule_10404,
sanity_check, sanity_check_of_list, validate_list_of_objects, SanityCheckable, SbmlValidable,
};
use crate::core::{Delay, Event, EventAssignment, Model, Priority, SBase, Trigger};
use crate::xml::{OptionalXmlChild, OptionalXmlProperty, RequiredXmlProperty, XmlList, XmlWrapper};
Expand All @@ -24,6 +24,11 @@ impl SbmlValidable for Event {
apply_rule_10309(self.meta_id().get(), xml_element, issues);
apply_rule_10310(self.id().get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(trigger) = self.trigger().get() {
trigger.validate(issues, identifiers, meta_ids);
}
Expand Down Expand Up @@ -127,6 +132,11 @@ impl SbmlValidable for Trigger {
apply_rule_10309(self.meta_id().get(), xml_element, issues);
apply_rule_10310(self.id().get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(math) = self.math().get() {
math.validate(issues);
}
Expand All @@ -151,6 +161,11 @@ impl SbmlValidable for Priority {
apply_rule_10309(self.meta_id().get(), xml_element, issues);
apply_rule_10310(self.id().get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(math) = self.math().get() {
math.validate(issues);
}
Expand All @@ -175,6 +190,11 @@ impl SbmlValidable for Delay {
apply_rule_10309(self.meta_id().get(), xml_element, issues);
apply_rule_10310(self.id().get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(math) = self.math().get() {
math.validate(issues);
}
Expand Down Expand Up @@ -202,6 +222,11 @@ impl SbmlValidable for EventAssignment {
apply_rule_10310(id.get(), xml_element, issues);
apply_rule_10312(self.name().get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(math) = self.math().get() {
math.validate(issues);
}
Expand Down
8 changes: 7 additions & 1 deletion src/core/validation/function_definition.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::core::validation::{
apply_rule_10102, apply_rule_10301, apply_rule_10307, apply_rule_10308, apply_rule_10309,
apply_rule_10310, apply_rule_10312, SanityCheckable, SbmlValidable,
apply_rule_10310, apply_rule_10312, apply_rule_10401, apply_rule_10402, apply_rule_10404,
SanityCheckable, SbmlValidable,
};
use crate::core::{FunctionDefinition, SBase};
use crate::xml::{OptionalXmlChild, OptionalXmlProperty, XmlWrapper};
Expand All @@ -26,6 +27,11 @@ impl SbmlValidable for FunctionDefinition {
apply_rule_10310(id.get(), xml_element, issues);
apply_rule_10312(self.name().get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(math) = self.math().get() {
math.validate(issues);
}
Expand Down
8 changes: 7 additions & 1 deletion src/core/validation/initial_assignment.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::core::validation::{
apply_rule_10102, apply_rule_10301, apply_rule_10307, apply_rule_10308, apply_rule_10309,
apply_rule_10310, apply_rule_10312, SanityCheckable, SbmlValidable,
apply_rule_10310, apply_rule_10312, apply_rule_10401, apply_rule_10402, apply_rule_10404,
SanityCheckable, SbmlValidable,
};
use crate::core::{InitialAssignment, SBase};
use crate::xml::{OptionalXmlChild, OptionalXmlProperty, XmlWrapper};
Expand All @@ -26,6 +27,11 @@ impl SbmlValidable for InitialAssignment {
apply_rule_10310(id.get(), xml_element, issues);
apply_rule_10312(self.name().get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(math) = self.math().get() {
math.validate(issues);
}
Expand Down
88 changes: 76 additions & 12 deletions src/core/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,20 +345,20 @@ pub(crate) fn apply_rule_10102(xml_element: &XmlElement, issues: &mut Vec<SbmlIs
/// [Event](event::Event), [EventAssignment](event::EventAssignment),
/// [FunctionDefinition](function_definition::FunctionDefinition),
/// [InitialAssignment](initial_assignment::InitialAssignment), [KineticLaw](reaction::KineticLaw),
/// [ListOfCompartments](model::Model::compartments), [ListOfConstraints](model::Model::constraints),
/// [ListOfEventAssignments](event::Event::event_assignments), [ListOfEvents](model::Model::events),
/// [ListOfFunctionDefinitions](model::Model::function_definitions),
/// [ListOfInitialAssignments](model::Model::initial_assignments),
/// [ListOfCompartments](Model::compartments), [ListOfConstraints](Model::constraints),
/// [ListOfEventAssignments](event::Event::event_assignments), [ListOfEvents](Model::events),
/// [ListOfFunctionDefinitions](Model::function_definitions),
/// [ListOfInitialAssignments](Model::initial_assignments),
/// [ListOfLocalParameters](reaction::KineticLaw::local_parameters),
/// [ListOfModifierSpeciesReferences](reaction::Reaction::modifiers), [ListOfParameters](model::Model::parameters),
/// [ListOfReactions](model::Model::reactions), [ListOfRules](model::Model::rules),
/// [ListOfSpecies](model::Model::species), [ListOfSpeciesReferences](reaction::Reaction::reactants),
/// [ListOfUnitDefinitions](model::Model::unit_definitions), [ListOfUnits](unit_definition::UnitDefinition::units),
/// [Model](model::Model), [ModifierSpeciesReference](reaction::ModifierSpeciesReference),
/// [ListOfModifierSpeciesReferences](reaction::Reaction::modifiers), [ListOfParameters](Model::parameters),
/// [ListOfReactions](Model::reactions), [ListOfRules](Model::rules),
/// [ListOfSpecies](Model::species), [ListOfSpeciesReferences](reaction::Reaction::reactants),
/// [ListOfUnitDefinitions](Model::unit_definitions), [ListOfUnits](unit_definition::UnitDefinition::units),
/// [Model](Model), [ModifierSpeciesReference](reaction::ModifierSpeciesReference),
/// [Parameter](parameter::Parameter), [Priority](event::Priority), [RateRule](rule::RateRule),
/// [Reaction](reaction::Reaction), [Species](species::Species), [SpeciesReference](reaction::SpeciesReference),
/// [Trigger](event::Trigger), and [Unit](unit::Unit), plus the *id* attribute values of any SBML Level 3 package
/// element defined to be in the *SId* namespace of the [Model](model::Model).
/// element defined to be in the *SId* namespace of the [Model](Model).
pub(crate) fn apply_rule_10301(
id: Option<String>,
xml_element: &XmlElement,
Expand All @@ -370,6 +370,7 @@ pub(crate) fn apply_rule_10301(

/// ### Rule 10307
/// Every *metaid* attribute value must be unique across the set of all *metaid* values in a model.
// TODO: might be placed inside SBASE validation method
pub(crate) fn apply_rule_10307(
meta_id: Option<String>,
xml_element: &XmlElement,
Expand All @@ -379,6 +380,7 @@ pub(crate) fn apply_rule_10307(
check_identifier_uniqueness("10307", "meta_id", meta_id, xml_element, issues, meta_ids);
}

// TODO: might be placed inside SBASE validation method
/// ### Rule 10308
/// The value of the attribute *sboTerm* must always conform to the syntax of the SBML data type
/// **SBOTerm**, which is a string consisting of the characters `S', `B', `O', ':', followed by
Expand All @@ -397,6 +399,7 @@ pub(crate) fn apply_rule_10308(
}
}

// TODO: might be placed inside SBASE validation method
/// ### Rule 10309
/// The value of a *metaid* attribute must always conform to the syntax of the *XML* data type **ID**.
pub(crate) fn apply_rule_10309(
Expand Down Expand Up @@ -437,7 +440,7 @@ pub(crate) fn apply_rule_10310(
/// [LocalParameter](reaction::LocalParameter), the **substanceUnits** attribute on
/// [Species](species::Species), the SBML **units** attribute on MathML **cn** elements, and the
/// **substanceUnits**, **volumeUnits**, **areaUnits**, **lengthUnits**, **timeUnits** and
/// **extentUnits** on [Model](model::Model)) must always conform to the syntax of the SBML
/// **extentUnits** on [Model]) must always conform to the syntax of the SBML
/// data type **UnitSId**.
pub(crate) fn apply_rule_10311(
attr_name: &str,
Expand All @@ -454,6 +457,7 @@ pub(crate) fn apply_rule_10311(
}
}

// TODO: might be placed inside SBASE validation method
/// ### Rule 10312
/// The value of a **name** attribute must always conform to the syntax of type **string**.
pub(crate) fn apply_rule_10312(
Expand Down Expand Up @@ -491,7 +495,7 @@ pub(crate) fn apply_rule_10313(
let Some(unit_ref) = unit_ref else {
return;
};
// TODO: could be optimized - make efficient passing of the vector of unit definition identifiers or global variable or something
// TODO: could be optimized - make efficient passing of the vector of unit definition identifiers or use global variable or something else
let unit_definition_ids = Model::for_child_element(xml_element)
.unwrap()
.unit_definition_identifiers();
Expand All @@ -504,3 +508,63 @@ pub(crate) fn apply_rule_10313(
issues.push(SbmlIssue::new_error("10313", xml_element, message));
}
}

// TODO: might be placed inside SBASE validation method
/// ### Rule 10401
/// Every top-level XML element within an **Annotation** object must have an XML namespace declared.
pub(crate) fn apply_rule_10401(annotation: &XmlElement, issues: &mut Vec<SbmlIssue>) {
let top_level_elements = annotation.child_elements();

for element in top_level_elements {
// TODO: is this correct and sufficient?
if element.namespace_url().is_empty() {
let message = format!(
"XML namespace not declared for '{0}' in annotation.",
element.full_name()
);
issues.push(SbmlIssue::new_error(
"10401",
element.xml_element(),
message,
))
}
}
}

// TODO: might be placed inside SBASE validation method
/// ### Rule 10402
/// A given XML namespace cannot be the namespace of more than *one* top-level element within a
// given **Annotation** object.
pub(crate) fn apply_rule_10402(annotation: &XmlElement, issues: &mut Vec<SbmlIssue>) {
let top_level_elements =
annotation.child_elements_filtered(|el| !el.namespace_url().is_empty());
let mut unique_namespaces: HashSet<String> = HashSet::new();

for element in top_level_elements {
let namespace = element.namespace_url();

if unique_namespaces.contains(&namespace) {
let message = format!(
"XML namespace '{namespace}' found in multiple top-level elements of <annotation>."
);
issues.push(SbmlIssue::new_error("10402", &element, message));
} else {
unique_namespaces.insert(namespace);
}
}
}

// TODO: might be placed inside SBASE validation method
/// ### Rule 10404
/// A given SBML element may contain at most *one* **Annotation** subobject.
pub(crate) fn apply_rule_10404(element: &XmlElement, issues: &mut Vec<SbmlIssue>) {
let annotation_elements = element.child_elements_filtered(|el| el.tag_name() == "annotation");

if annotation_elements.len() > 1 {
let message = format!(
"Multiple annotation elements found in <{0}>.",
element.tag_name()
);
issues.push(SbmlIssue::new_error("10404", element, message));
}
}
10 changes: 8 additions & 2 deletions src/core/validation/model.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::core::validation::{
apply_rule_10102, apply_rule_10301, apply_rule_10307, apply_rule_10308, apply_rule_10309,
apply_rule_10310, apply_rule_10311, apply_rule_10312, apply_rule_10313, sanity_check,
sanity_check_of_list, validate_list_of_objects, SanityCheckable, SbmlValidable,
apply_rule_10310, apply_rule_10311, apply_rule_10312, apply_rule_10313, apply_rule_10401,
apply_rule_10402, apply_rule_10404, sanity_check, sanity_check_of_list,
validate_list_of_objects, SanityCheckable, SbmlValidable,
};
use crate::core::{AbstractRule, Model, SBase, UnitDefinition};
use crate::xml::{OptionalXmlChild, OptionalXmlProperty, XmlElement, XmlProperty, XmlWrapper};
Expand Down Expand Up @@ -29,6 +30,11 @@ impl SbmlValidable for Model {
apply_rule_10312(self.name().get(), xml_element, issues);
self.apply_rule_10313(xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
if let Some(list_of_function_definition) = self.function_definitions().get() {
validate_list_of_objects(&list_of_function_definition, issues, identifiers, meta_ids);
}
Expand Down
14 changes: 11 additions & 3 deletions src/core/validation/parameter.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::core::validation::{
apply_rule_10102, apply_rule_10301, apply_rule_10307, apply_rule_10308, apply_rule_10309,
apply_rule_10310, apply_rule_10311, apply_rule_10312, apply_rule_10313, SanityCheckable,
SbmlValidable,
apply_rule_10310, apply_rule_10311, apply_rule_10312, apply_rule_10313, apply_rule_10401,
apply_rule_10402, apply_rule_10404, SanityCheckable, SbmlValidable,
};
use crate::core::{Parameter, SBase};
use crate::xml::{OptionalXmlProperty, RequiredXmlProperty, XmlProperty, XmlWrapper};
use crate::xml::{
OptionalXmlChild, OptionalXmlProperty, RequiredXmlProperty, XmlProperty, XmlWrapper,
};
use crate::SbmlIssue;
use std::collections::HashSet;

Expand All @@ -29,6 +31,12 @@ impl SbmlValidable for Parameter {
apply_rule_10311(units.name(), units.get(), xml_element, issues);
apply_rule_10312(self.name().get(), xml_element, issues);
apply_rule_10313(units.name(), units.get(), xml_element, issues);

if let Some(annotation) = self.annotation().get() {
apply_rule_10401(&annotation, issues);
apply_rule_10402(&annotation, issues);
apply_rule_10404(xml_element, issues);
}
}
}

Expand Down
Loading

0 comments on commit 3a0b9c8

Please sign in to comment.