Skip to content

Commit d3aa38b

Browse files
authored
Merge pull request #56 from ModECI/test_xml3
Latest XML export/import changes
2 parents 04fe4cd + c47685f commit d3aa38b

File tree

8 files changed

+195
-53
lines changed

8 files changed

+195
-53
lines changed

examples/neuroml2/NeuroML2.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,21 @@ Some description...
1313
<tr>
1414
<td><b>xmlns</b></td>
1515
<td>str</td>
16-
<td><i>Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2</i></td>
16+
<td><i>Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2</i></td>
17+
</tr>
18+
19+
20+
<tr>
21+
<td><b>xmlns_xsi</b></td>
22+
<td>str</td>
23+
<td><i>Namespace for XMLSchema-instance</i></td>
24+
</tr>
25+
26+
27+
<tr>
28+
<td><b>xmlns_loc</b></td>
29+
<td>str</td>
30+
<td><i>Specifies location of the main namespace</i></td>
1731
</tr>
1832

1933

@@ -24,14 +38,14 @@ Some description...
2438
<tr>
2539
<td><b>izhikevich2007Cells</b></td>
2640
<td><a href="#izhikevich2007cell">izhikevich2007Cell</a></td>
27-
<td><i></i></td>
41+
<td><i>The izhikevich2007Cells</i></td>
2842
</tr>
2943

3044

3145
<tr>
3246
<td><b>pulseGenerators</b></td>
3347
<td><a href="#pulsegenerator">pulseGenerator</a></td>
34-
<td><i></i></td>
48+
<td><i>The pulse current generators</i></td>
3549
</tr>
3650

3751

examples/neuroml2/NeuroML2.rst

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,24 @@ Some description...
55

66
**Allowed parameters**
77

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

1517
**Allowed children**
1618

17-
======================= ============================================ ====================
19+
======================= ============================================ ============================
1820
Allowed child Data Type Description
19-
======================= ============================================ ====================
20-
**izhikevich2007Cells** `izhikevich2007Cell <#izhikevich2007cell>`__
21-
**pulseGenerators** `pulseGenerator <#pulsegenerator>`__
21+
======================= ============================================ ============================
22+
**izhikevich2007Cells** `izhikevich2007Cell <#izhikevich2007cell>`__ The izhikevich2007Cells
23+
**pulseGenerators** `pulseGenerator <#pulsegenerator>`__ The pulse current generators
2224
**networks** `network <#network>`__ The networks present
23-
======================= ============================================ ====================
25+
======================= ============================================ ============================
2426

2527
==================
2628
izhikevich2007Cell

examples/neuroml2/NeuroML2.specification.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,25 @@
88
},
99
"xmlns": {
1010
"type": "str",
11-
"description": "Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2"
11+
"description": "Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2"
12+
},
13+
"xmlns_xsi": {
14+
"type": "str",
15+
"description": "Namespace for XMLSchema-instance"
16+
},
17+
"xmlns_loc": {
18+
"type": "str",
19+
"description": "Specifies location of the main namespace"
1220
}
1321
},
1422
"allowed_children": {
1523
"izhikevich2007Cells": {
1624
"type": "izhikevich2007Cell",
17-
"description": ""
25+
"description": "The izhikevich2007Cells"
1826
},
1927
"pulseGenerators": {
2028
"type": "pulseGenerator",
21-
"description": ""
29+
"description": "The pulse current generators"
2230
},
2331
"networks": {
2432
"type": "network",

examples/neuroml2/NeuroML2.specification.yaml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,20 @@ neuroml:
66
description: The id of the NeuroML 2 document
77
xmlns:
88
type: str
9-
description: Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2
9+
description: Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2
10+
xmlns_xsi:
11+
type: str
12+
description: Namespace for XMLSchema-instance
13+
xmlns_loc:
14+
type: str
15+
description: Specifies location of the main namespace
1016
allowed_children:
1117
izhikevich2007Cells:
1218
type: izhikevich2007Cell
13-
description: ''
19+
description: The izhikevich2007Cells
1420
pulseGenerators:
1521
type: pulseGenerator
16-
description: ''
22+
description: The pulse current generators
1723
networks:
1824
type: network
1925
description: The networks present

examples/neuroml2/TestNeuroML.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" ?>
2-
<neuroml xmlns="http://www.neuroml.org/schema/neuroml2" id="TestNeuroML">
2+
<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">
33
<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"/>
44
<pulseGenerator id="pulseGen_0" delay="100ms" duration="800ms" amplitude="0.07 nA"/>
55
<network id="IzNet">

examples/neuroml2/neuroml2_spec.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,26 @@ class neuroml(Base):
101101
102102
Args:
103103
id: The id of the NeuroML 2 document
104-
xmlns: Schema for NeuroML 2, usually http://www.neuroml.org/schema/neuroml2
104+
xmlns: Default namespace for the NeuroML file, usually http://www.neuroml.org/schema/neuroml2
105+
xmlns_xsi: Namespace for XMLSchema-instance
106+
xmlns_loc: Specifies location of the main namespace
107+
izhikevich2007Cells: The izhikevich2007Cells
108+
pulseGenerators: The pulse current generators
105109
networks: The networks present
106110
"""
107111

108112
id: str = field(validator=instance_of(str))
113+
109114
xmlns: str = field(
110115
validator=instance_of(str), default="http://www.neuroml.org/schema/neuroml2"
111116
)
117+
xmlns_xsi: str = field(
118+
validator=instance_of(str), default="http://www.w3.org/2001/XMLSchema-instance"
119+
)
120+
xmlns_loc: str = field(
121+
validator=instance_of(str),
122+
default="http://www.neuroml.org/schema/neuroml2 https://raw.github.com/NeuroML/NeuroML2/development/Schemas/NeuroML2/NeuroML_v2.3.xsd",
123+
)
112124

113125
izhikevich2007Cells: List[izhikevich2007Cell] = field(factory=list)
114126
pulseGenerators: List[pulseGenerator] = field(factory=list)
@@ -187,3 +199,8 @@ class neuroml(Base):
187199
yy = yaml.dump(doc_dict, indent=4, sort_keys=False)
188200
print(yy)
189201
d.write(yy)
202+
203+
from modelspec.utils import load_xml
204+
205+
new_neuroml = load_xml("hello_world_neuroml.net.nml")
206+
print(new_neuroml)

src/modelspec/base_types.py

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ def to_xml(self) -> str:
125125
)
126126
from modelspec.utils import build_xml_element
127127

128-
# root = ET.Element("modelspec")
129128
root = build_xml_element(self)
130129

131130
xml_string = ET.tostring(
@@ -170,12 +169,38 @@ def from_bson(cls, bson_str: str) -> "Base":
170169
@classmethod
171170
def from_xml(cls, xml_str: str) -> "Base":
172171
"""Instantiate a Base object from an XML string"""
173-
from modelspec.utils import element_to_dict, handle_id, convert_values
172+
from modelspec.utils import (
173+
elementtree_element_to_dict,
174+
handle_xml_dict_id,
175+
convert_xml_dict_values,
176+
process_xml_namespace,
177+
)
178+
import re
179+
180+
# When the to_xml() method is used it messes up the string therefore,
181+
# it is necessary to convert it into an elementree object then decode into a string.
182+
xml_string_a = ET.fromstring(xml_str)
183+
xml_string_b = ET.tostring(xml_string_a).decode()
184+
185+
# while trying to obtain a useable xml structure, using the conversion above it acquires
186+
# some unusual string element that sometimes can be incremental from either :ns0 to :nsX or ns0: to nsX:.
187+
# Using the regex expression pattern catches it in any form and removes it from the xml string structure.
188+
ns_prefix_pattern = r"(ns\d+:|:ns\d+)"
189+
cleaned_xml = re.sub(ns_prefix_pattern, "", xml_string_b).strip()
190+
191+
# For the xml to be useable in modelspec unnecessary string elements which only serve as asthetics for the xml must
192+
# be removed when converting to a dict, the process_xml_namespaes function does just that.
193+
removed_namespaces = process_xml_namespace(cleaned_xml)
194+
195+
# process_xml_namespace function returns an elementtree object which can be directly worked upon by the elementtree_element_to_dict
196+
# function, this returns a python dictionary
197+
data_dict = elementtree_element_to_dict(removed_namespaces)
198+
199+
# This strips every instance of 'id' from the resulting dictionary structure
200+
removed_id = handle_xml_dict_id(data_dict)
174201

175-
root = ET.fromstring(xml_str)
176-
data_dict = element_to_dict(root)
177-
removed_id = handle_id(data_dict)
178-
converted_to_actual_val = convert_values(removed_id)
202+
# XML conversions do not returns exact values, instead all values are returned as a string, this reassigns their actual values
203+
converted_to_actual_val = convert_xml_dict_values(removed_id)
179204

180205
return cls.from_dict(converted_to_actual_val)
181206

@@ -377,15 +402,38 @@ def from_xml_file(cls, filename: str) -> "Base":
377402
Returns:
378403
A modelspec Base for this XML.
379404
"""
380-
from modelspec.utils import element_to_dict, handle_id, convert_values
405+
from modelspec.utils import (
406+
elementtree_element_to_dict,
407+
handle_xml_dict_id,
408+
convert_xml_dict_values,
409+
process_xml_namespace,
410+
)
411+
import re
381412

382413
with open(filename) as infile:
383-
tree = ET.parse(infile)
384-
root = tree.getroot()
414+
tree = ET.parse(infile) # Parse the XML file into an ElementTree object
415+
root = tree.getroot() # Get the root element
416+
417+
# This defines regular expressions to match the namespace patterns to be removed
418+
ns_prefix_pattern = r"(ns\d+:|:ns\d+)"
419+
420+
# Converts the loaded xml into a string and removes unwanted string values ':ns0' to :ns∞ and 'ns0:' to ns∞:
421+
# They prevent the xml from loading correctly
422+
xml_string = ET.tostring(root).decode()
423+
cleaned_xml = re.sub(ns_prefix_pattern, "", xml_string).strip()
424+
425+
# Removes xmlns, xmlns:xsi and xsi:schemaLocation from the xml structure for conversion
426+
# it passes an element tree object to the elementtree_element_to_dict function
427+
removed_namespaces = process_xml_namespace(cleaned_xml)
428+
429+
# Converts the resulting xml stripped of xmlns, xmlns:xsi and xsi:schemaLocation into a dict
430+
data_dict = elementtree_element_to_dict(removed_namespaces)
431+
432+
# Removes every key having 'id' and replaces it with it's value
433+
removed_id = handle_xml_dict_id(data_dict)
385434

386-
data_dict = element_to_dict(root)
387-
removed_id = handle_id(data_dict)
388-
converted_to_actual_val = convert_values(removed_id)
435+
# Values are returned as strings after conversion, this corrects them to their actual values
436+
converted_to_actual_val = convert_xml_dict_values(removed_id)
389437
return cls.from_dict(converted_to_actual_val)
390438

391439
def get_child(self, id: str, type_: str) -> Any:

0 commit comments

Comments
 (0)