Skip to content

Commit

Permalink
Merge pull request #56 from ModECI/test_xml3
Browse files Browse the repository at this point in the history
Latest XML export/import changes
  • Loading branch information
pgleeson authored Aug 21, 2023
2 parents 04fe4cd + c47685f commit d3aa38b
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 53 deletions.
20 changes: 17 additions & 3 deletions examples/neuroml2/NeuroML2.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,21 @@ Some description...
<tr>
<td><b>xmlns</b></td>
<td>str</td>
<td><i>Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2</i></td>
<td><i>Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2</i></td>
</tr>


<tr>
<td><b>xmlns_xsi</b></td>
<td>str</td>
<td><i>Namespace for XMLSchema-instance</i></td>
</tr>


<tr>
<td><b>xmlns_loc</b></td>
<td>str</td>
<td><i>Specifies location of the main namespace</i></td>
</tr>


Expand All @@ -24,14 +38,14 @@ Some description...
<tr>
<td><b>izhikevich2007Cells</b></td>
<td><a href="#izhikevich2007cell">izhikevich2007Cell</a></td>
<td><i></i></td>
<td><i>The izhikevich2007Cells</i></td>
</tr>


<tr>
<td><b>pulseGenerators</b></td>
<td><a href="#pulsegenerator">pulseGenerator</a></td>
<td><i></i></td>
<td><i>The pulse current generators</i></td>
</tr>


Expand Down
20 changes: 11 additions & 9 deletions examples/neuroml2/NeuroML2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@ Some description...

**Allowed parameters**

=============== =========== ====================================================================
=============== =========== ======================================================================================
Allowed field Data Type Description
=============== =========== ====================================================================
=============== =========== ======================================================================================
**id** str The id of the NeuroML 2 document
**xmlns** str Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2
=============== =========== ====================================================================
**xmlns** str Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2
**xmlns_xsi** str Namespace for XMLSchema-instance
**xmlns_loc** str Specifies location of the main namespace
=============== =========== ======================================================================================

**Allowed children**

======================= ============================================ ====================
======================= ============================================ ============================
Allowed child Data Type Description
======================= ============================================ ====================
**izhikevich2007Cells** `izhikevich2007Cell <#izhikevich2007cell>`__
**pulseGenerators** `pulseGenerator <#pulsegenerator>`__
======================= ============================================ ============================
**izhikevich2007Cells** `izhikevich2007Cell <#izhikevich2007cell>`__ The izhikevich2007Cells
**pulseGenerators** `pulseGenerator <#pulsegenerator>`__ The pulse current generators
**networks** `network <#network>`__ The networks present
======================= ============================================ ====================
======================= ============================================ ============================

==================
izhikevich2007Cell
Expand Down
14 changes: 11 additions & 3 deletions examples/neuroml2/NeuroML2.specification.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@
},
"xmlns": {
"type": "str",
"description": "Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2"
"description": "Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2"
},
"xmlns_xsi": {
"type": "str",
"description": "Namespace for XMLSchema-instance"
},
"xmlns_loc": {
"type": "str",
"description": "Specifies location of the main namespace"
}
},
"allowed_children": {
"izhikevich2007Cells": {
"type": "izhikevich2007Cell",
"description": ""
"description": "The izhikevich2007Cells"
},
"pulseGenerators": {
"type": "pulseGenerator",
"description": ""
"description": "The pulse current generators"
},
"networks": {
"type": "network",
Expand Down
12 changes: 9 additions & 3 deletions examples/neuroml2/NeuroML2.specification.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ neuroml:
description: The id of the NeuroML 2 document
xmlns:
type: str
description: Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2
description: Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2
xmlns_xsi:
type: str
description: Namespace for XMLSchema-instance
xmlns_loc:
type: str
description: Specifies location of the main namespace
allowed_children:
izhikevich2007Cells:
type: izhikevich2007Cell
description: ''
description: The izhikevich2007Cells
pulseGenerators:
type: pulseGenerator
description: ''
description: The pulse current generators
networks:
type: network
description: The networks present
Expand Down
2 changes: 1 addition & 1 deletion examples/neuroml2/TestNeuroML.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" ?>
<neuroml xmlns="http://www.neuroml.org/schema/neuroml2" id="TestNeuroML">
<neuroml xmlns="http://www.neuroml.org/schema/neuroml2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="TestNeuroML" xsi:schemaLocation="http://www.neuroml.org/schema/neuroml2 https://raw.github.com/NeuroML/NeuroML2/development/Schemas/NeuroML2/NeuroML_v2.3.xsd">
<izhikevich2007Cell id="izh2007RS0" C="100pF" v0="-60mV" k="0.7nS_per_mV" vr="-60mV" vt="-40mV" vpeak="35mV" a="0.03per_ms" b="-2nS" c="-50.0mV" d="100pA"/>
<pulseGenerator id="pulseGen_0" delay="100ms" duration="800ms" amplitude="0.07 nA"/>
<network id="IzNet">
Expand Down
19 changes: 18 additions & 1 deletion examples/neuroml2/neuroml2_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,26 @@ class neuroml(Base):
Args:
id: The id of the NeuroML 2 document
xmlns: Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2
xmlns: Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2
xmlns_xsi: Namespace for XMLSchema-instance
xmlns_loc: Specifies location of the main namespace
izhikevich2007Cells: The izhikevich2007Cells
pulseGenerators: The pulse current generators
networks: The networks present
"""

id: str = field(validator=instance_of(str))

xmlns: str = field(
validator=instance_of(str), default="http://www.neuroml.org/schema/neuroml2"
)
xmlns_xsi: str = field(
validator=instance_of(str), default="http://www.w3.org/2001/XMLSchema-instance"
)
xmlns_loc: str = field(
validator=instance_of(str),
default="http://www.neuroml.org/schema/neuroml2 https://raw.github.com/NeuroML/NeuroML2/development/Schemas/NeuroML2/NeuroML_v2.3.xsd",
)

izhikevich2007Cells: List[izhikevich2007Cell] = field(factory=list)
pulseGenerators: List[pulseGenerator] = field(factory=list)
Expand Down Expand Up @@ -187,3 +199,8 @@ class neuroml(Base):
yy = yaml.dump(doc_dict, indent=4, sort_keys=False)
print(yy)
d.write(yy)

from modelspec.utils import load_xml

new_neuroml = load_xml("hello_world_neuroml.net.nml")
print(new_neuroml)
72 changes: 60 additions & 12 deletions src/modelspec/base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ def to_xml(self) -> str:
)
from modelspec.utils import build_xml_element

# root = ET.Element("modelspec")
root = build_xml_element(self)

xml_string = ET.tostring(
Expand Down Expand Up @@ -170,12 +169,38 @@ def from_bson(cls, bson_str: str) -> "Base":
@classmethod
def from_xml(cls, xml_str: str) -> "Base":
"""Instantiate a Base object from an XML string"""
from modelspec.utils import element_to_dict, handle_id, convert_values
from modelspec.utils import (
elementtree_element_to_dict,
handle_xml_dict_id,
convert_xml_dict_values,
process_xml_namespace,
)
import re

# When the to_xml() method is used it messes up the string therefore,
# it is necessary to convert it into an elementree object then decode into a string.
xml_string_a = ET.fromstring(xml_str)
xml_string_b = ET.tostring(xml_string_a).decode()

# while trying to obtain a useable xml structure, using the conversion above it acquires
# some unusual string element that sometimes can be incremental from either :ns0 to :nsX or ns0: to nsX:.
# Using the regex expression pattern catches it in any form and removes it from the xml string structure.
ns_prefix_pattern = r"(ns\d+:|:ns\d+)"
cleaned_xml = re.sub(ns_prefix_pattern, "", xml_string_b).strip()

# For the xml to be useable in modelspec unnecessary string elements which only serve as asthetics for the xml must
# be removed when converting to a dict, the process_xml_namespaes function does just that.
removed_namespaces = process_xml_namespace(cleaned_xml)

# process_xml_namespace function returns an elementtree object which can be directly worked upon by the elementtree_element_to_dict
# function, this returns a python dictionary
data_dict = elementtree_element_to_dict(removed_namespaces)

# This strips every instance of 'id' from the resulting dictionary structure
removed_id = handle_xml_dict_id(data_dict)

root = ET.fromstring(xml_str)
data_dict = element_to_dict(root)
removed_id = handle_id(data_dict)
converted_to_actual_val = convert_values(removed_id)
# XML conversions do not returns exact values, instead all values are returned as a string, this reassigns their actual values
converted_to_actual_val = convert_xml_dict_values(removed_id)

return cls.from_dict(converted_to_actual_val)

Expand Down Expand Up @@ -377,15 +402,38 @@ def from_xml_file(cls, filename: str) -> "Base":
Returns:
A modelspec Base for this XML.
"""
from modelspec.utils import element_to_dict, handle_id, convert_values
from modelspec.utils import (
elementtree_element_to_dict,
handle_xml_dict_id,
convert_xml_dict_values,
process_xml_namespace,
)
import re

with open(filename) as infile:
tree = ET.parse(infile)
root = tree.getroot()
tree = ET.parse(infile) # Parse the XML file into an ElementTree object
root = tree.getroot() # Get the root element

# This defines regular expressions to match the namespace patterns to be removed
ns_prefix_pattern = r"(ns\d+:|:ns\d+)"

# Converts the loaded xml into a string and removes unwanted string values ':ns0' to :ns∞ and 'ns0:' to ns∞:
# They prevent the xml from loading correctly
xml_string = ET.tostring(root).decode()
cleaned_xml = re.sub(ns_prefix_pattern, "", xml_string).strip()

# Removes xmlns, xmlns:xsi and xsi:schemaLocation from the xml structure for conversion
# it passes an element tree object to the elementtree_element_to_dict function
removed_namespaces = process_xml_namespace(cleaned_xml)

# Converts the resulting xml stripped of xmlns, xmlns:xsi and xsi:schemaLocation into a dict
data_dict = elementtree_element_to_dict(removed_namespaces)

# Removes every key having 'id' and replaces it with it's value
removed_id = handle_xml_dict_id(data_dict)

data_dict = element_to_dict(root)
removed_id = handle_id(data_dict)
converted_to_actual_val = convert_values(removed_id)
# Values are returned as strings after conversion, this corrects them to their actual values
converted_to_actual_val = convert_xml_dict_values(removed_id)
return cls.from_dict(converted_to_actual_val)

def get_child(self, id: str, type_: str) -> Any:
Expand Down
Loading

0 comments on commit d3aa38b

Please sign in to comment.