1212
1313import numpy as np
1414
15+ from .. import xmlutils as xml
1516from ..nifti1 import data_type_codes , xform_codes , intent_codes
1617from .util import (array_index_order_codes , gifti_encoding_codes ,
1718 gifti_endian_codes , KIND2FMT )
2223import base64
2324
2425
25- class GiftiMetaData (object ):
26+ class GiftiMetaData (xml . XmlSerializable ):
2627 """ A list of GiftiNVPairs in stored in
2728 the list self.data """
2829 def __init__ (self , nvpair = None ):
@@ -50,18 +51,15 @@ def metadata(self):
5051 self .data_as_dict [ele .name ] = ele .value
5152 return self .data_as_dict
5253
53- def to_xml (self ):
54- if len (self .data ) == 0 :
55- return "<MetaData/>\n "
56- res = "<MetaData>\n "
54+ def _to_xml_element (self ):
55+ metadata = xml .Element ('MetaData' )
5756 for ele in self .data :
58- nvpair = """<MD>
59- \t <Name><![CDATA[%s]]></Name>
60- \t <Value><![CDATA[%s]]></Value>
61- </MD>\n """ % (ele .name , ele .value )
62- res = res + nvpair
63- res = res + "</MetaData>\n "
64- return res
57+ md = xml .SubElement (metadata , 'MD' )
58+ name = xml .SubElement (md , 'Name' )
59+ value = xml .SubElement (md , 'Value' )
60+ name .text = ele .name
61+ value .text = ele .value
62+ return metadata
6563
6664 def print_summary (self ):
6765 print (self .metadata )
@@ -77,7 +75,7 @@ def __init__(self, name='', value=''):
7775 self .value = value
7876
7977
80- class GiftiLabelTable (object ):
78+ class GiftiLabelTable (xml . XmlSerializable ):
8179
8280 def __init__ (self ):
8381 self .labels = []
@@ -88,31 +86,22 @@ def get_labels_as_dict(self):
8886 self .labels_as_dict [ele .key ] = ele .label
8987 return self .labels_as_dict
9088
91- def to_xml (self ):
92- if len (self .labels ) == 0 :
93- return "<LabelTable/>\n "
94- res = "<LabelTable>\n "
89+ def _to_xml_element (self ):
90+ labeltable = xml .Element ('LabelTable' )
9591 for ele in self .labels :
96- col = ''
97- if not ele .red is None :
98- col += ' Red="%s"' % str (ele .red )
99- if not ele .green is None :
100- col += ' Green="%s"' % str (ele .green )
101- if not ele .blue is None :
102- col += ' Blue="%s"' % str (ele .blue )
103- if not ele .alpha is None :
104- col += ' Alpha="%s"' % str (ele .alpha )
105- lab = """\t <Label Key="%s"%s><![CDATA[%s]]></Label>\n """ % \
106- (str (ele .key ), col , ele .label )
107- res = res + lab
108- res = res + "</LabelTable>\n "
109- return res
92+ label = xml .SubElement (labeltable , 'Label' )
93+ label .attrib ['Key' ] = str (ele .key )
94+ label .text = ele .label
95+ for attr in ['Red' , 'Green' , 'Blue' , 'Alpha' ]:
96+ if getattr (ele , attr .lower (), None ) is not None :
97+ label .attrib [attr ] = str (getattr (ele , attr .lower ()))
98+ return labeltable
11099
111100 def print_summary (self ):
112101 print (self .get_labels_as_dict ())
113102
114103
115- class GiftiLabel (object ):
104+ class GiftiLabel (xml . XmlSerializable ):
116105 key = int
117106 label = str
118107 # rgba
@@ -165,7 +154,7 @@ def _arr2txt(arr, elem_fmt):
165154 return '\n ' .join (fmt % tuple (row ) for row in arr )
166155
167156
168- class GiftiCoordSystem (object ):
157+ class GiftiCoordSystem (xml . XmlSerializable ):
169158 dataspace = int
170159 xformspace = int
171160 xform = np .ndarray # 4x4 numpy array
@@ -179,28 +168,37 @@ def __init__(self, dataspace=0, xformspace=0, xform=None):
179168 else :
180169 self .xform = xform
181170
182- def to_xml (self ):
183- if self .xform is None :
184- return "<CoordinateSystemTransformMatrix/>\n "
185- res = ("""<CoordinateSystemTransformMatrix>
186- \t <DataSpace><![CDATA[%s]]></DataSpace>
187- \t <TransformedSpace><![CDATA[%s]]></TransformedSpace>\n """
188- % (xform_codes .niistring [self .dataspace ],
189- xform_codes .niistring [self .xformspace ]))
190- res = res + "<MatrixData>\n "
191- res += _arr2txt (self .xform , '%10.6f' )
192- res = res + "</MatrixData>\n "
193- res = res + "</CoordinateSystemTransformMatrix>\n "
194- return res
171+ def _to_xml_element (self ):
172+ coord_xform = xml .Element ('CoordinateSystemTransformMatrix' )
173+ if self .xform is not None :
174+ dataspace = xml .SubElement (coord_xform , 'DataSpace' )
175+ dataspace .text = xform_codes .niistring [self .dataspace ]
176+ xformed_space = xml .SubElement (coord_xform , 'TransformedSpace' )
177+ xformed_space .text = xform_codes .niistring [self .xformspace ]
178+ matrix_data = xml .SubElement (coord_xform , 'MatrixData' )
179+ matrix_data .text = _arr2txt (self .xform , '%10.6f' )
180+ return coord_xform
195181
196182 def print_summary (self ):
197183 print ('Dataspace: ' , xform_codes .niistring [self .dataspace ])
198184 print ('XFormSpace: ' , xform_codes .niistring [self .xformspace ])
199185 print ('Affine Transformation Matrix: \n ' , self .xform )
200186
201187
188+ @np .deprecate_with_doc ("This is an internal API that will be discontinued." )
202189def data_tag (dataarray , encoding , datatype , ordering ):
203- """ Creates the data tag depending on the required encoding """
190+ class DataTag (xml .XmlSerializable ):
191+ def __init__ (self , * args ):
192+ self .args = args
193+ def _to_xml_element (self ):
194+ return _data_tag_element (* self .args )
195+
196+ return DataTag (dataarray , encoding , datatype , ordering ).to_xml ()
197+
198+
199+ def _data_tag_element (dataarray , encoding , datatype , ordering ):
200+ """ Creates the data tag depending on the required encoding,
201+ returns as XML element"""
204202 import zlib
205203 ord = array_index_order_codes .npcode [ordering ]
206204 enclabel = gifti_encoding_codes .label [encoding ]
@@ -215,10 +213,13 @@ def data_tag(dataarray, encoding, datatype, ordering):
215213 raise NotImplementedError ("In what format are the external files?" )
216214 else :
217215 da = ''
218- return "<Data>" + da + "</Data>\n "
216+
217+ data = xml .Element ('Data' )
218+ data .text = da
219+ return data
219220
220221
221- class GiftiDataArray (object ):
222+ class GiftiDataArray (xml . XmlSerializable ):
222223
223224 # These are for documentation only; we don't use these class variables
224225 intent = int
@@ -299,26 +300,37 @@ def from_array(klass,
299300 cda .meta = GiftiMetaData .from_dict (meta )
300301 return cda
301302
302- def to_xml (self ):
303+ def _to_xml_element (self ):
303304 # fix endianness to machine endianness
304305 self .endian = gifti_endian_codes .code [sys .byteorder ]
305- result = ""
306- result += self .to_xml_open ()
307- # write metadata
308- if not self .meta is None :
309- result += self .meta .to_xml ()
310- # write coord sys
311- if not self .coordsys is None :
312- result += self .coordsys .to_xml ()
306+
307+ data_array = xml .Element ('DataArray' , attrib = {
308+ 'Intent' : intent_codes .niistring [self .intent ],
309+ 'DataType' : data_type_codes .niistring [self .datatype ],
310+ 'ArrayIndexingOrder' : array_index_order_codes .label [self .ind_ord ],
311+ 'Dimensionality' : str (self .num_dim ),
312+ 'Encoding' : gifti_encoding_codes .specs [self .encoding ],
313+ 'Endian' : gifti_endian_codes .specs [self .endian ],
314+ 'ExternalFileName' : self .ext_fname ,
315+ 'ExternalFileOffset' : self .ext_offset })
316+ for di , dn in enumerate (self .dims ):
317+ data_array .attrib ['Dim%d' % di ] = str (dn )
318+
319+ if self .meta is not None :
320+ data_array .append (self .meta ._to_xml_element ())
321+ if self .coordsys is not None :
322+ data_array .append (self .coordsys ._to_xml_element ())
313323 # write data array depending on the encoding
314324 dt_kind = data_type_codes .dtype [self .datatype ].kind
315- result += data_tag (self .data ,
316- gifti_encoding_codes .specs [self .encoding ],
317- KIND2FMT [dt_kind ],
318- self .ind_ord )
319- result = result + self .to_xml_close ()
320- return result
325+ data_array .append (
326+ _data_tag_element (self .data ,
327+ gifti_encoding_codes .specs [self .encoding ],
328+ KIND2FMT [dt_kind ],
329+ self .ind_ord ))
321330
331+ return data_array
332+
333+ @np .deprecate_with_doc ("Use the to_xml() function instead." )
322334 def to_xml_open (self ):
323335 out = """<DataArray Intent="%s"
324336\t DataType="%s"
@@ -342,6 +354,7 @@ def to_xml_open(self):
342354 self .ext_offset ,
343355 )
344356
357+ @np .deprecate_with_doc ("Use the to_xml() function instead." )
345358 def to_xml_close (self ):
346359 return "</DataArray>\n "
347360
@@ -371,7 +384,8 @@ def metadata(self):
371384 return self .meta .metadata
372385
373386
374- class GiftiImage (object ):
387+ class GiftiImage (xml .XmlSerializable ):
388+
375389 def __init__ (self , meta = None , labeltable = None , darrays = None ,
376390 version = "1.0" ):
377391 if darrays is None :
@@ -497,17 +511,21 @@ def print_summary(self):
497511 print (da .print_summary ())
498512 print ('----end----' )
499513
500- def to_xml (self ):
514+
515+ def _to_xml_element (self ):
516+ GIFTI = xml .Element ('GIFTI' , attrib = {
517+ 'Version' : self .version ,
518+ 'NumberOfDataArrays' : str (self .numDA )})
519+ if self .meta is not None :
520+ GIFTI .append (self .meta ._to_xml_element ())
521+ if self .labeltable is not None :
522+ GIFTI .append (self .labeltable ._to_xml_element ())
523+ for dar in self .darrays :
524+ GIFTI .append (dar ._to_xml_element ())
525+ return GIFTI
526+
527+ def to_xml (self , enc = 'utf-8' ):
501528 """ Return XML corresponding to image content """
502- res = """<?xml version="1.0" encoding="UTF-8"?>
529+ return b """<?xml version="1.0" encoding="UTF-8"?>
503530<!DOCTYPE GIFTI SYSTEM "http://www.nitrc.org/frs/download.php/115/gifti.dtd">
504- <GIFTI Version="%s" NumberOfDataArrays="%s">\n """ % (self .version ,
505- str (self .numDA ))
506- if not self .meta is None :
507- res += self .meta .to_xml ()
508- if not self .labeltable is None :
509- res += self .labeltable .to_xml ()
510- for dar in self .darrays :
511- res += dar .to_xml ()
512- res += "</GIFTI>"
513- return res
531+ """ + xml .XmlSerializable .to_xml (self , enc )
0 commit comments