使用 JSON 和 XML 保存与恢复参数
19765 为本文评分:
1.5
使用 JSON 和 XML 保存与恢复参数
匿名作者 2014年3月6日 星期四
编写 IDL 代码时,能够保存和恢复代码中使用的参数通常非常方便。这些参数可能是用于执行计算的算法常量或阈值,也可能是用户界面上复选框的状态。在 IDL 的早期版本中,常使用静态结构来存储此类信息。在 IDL 8.3 中,有序哈希(ordered hash)可能是实现此目的的最佳选择。
有序哈希对象是动态的,并且可以嵌套。以下是一个示例:
IDL> param = OrderedHash()
IDL> param['sigma'] = !dpi/4
IDL> param['xsize'] = 512
IDL> param['name'] = 'Exelis'
IDL> param
{ "sigma": 0.78539816339744828, "xsize": 512, "name": "Exelis" }
以及嵌套示例:
IDL> tmp = OrderedHash('alpha', 1, 'beta', [255,240,190]) IDL> param['subparam'] = tmp IDL> param
{ "sigma": 0.78539816339744828, "xsize": 512, "name": "Exelis", "subparam": { "alpha": 1, "beta": [255, 240, 190] } }
保存此类数据的最简单方法是使用 IDL 的 SAVE 过程。然而,生成的文件将是二进制格式,除非使用 IDL 的 RESTORE 过程,否则无法访问。如果你希望配置参数能在文本编辑器中编辑或能被其他编程语言访问,最好使用 JSON 或 XML 等可读格式。以下是使用 JSON 的示例:
IDL> json = JSON_SERIALIZE(param) IDL> json {"sigma":0.785398163397448,"xsize":512,"name":"Exelis","subparam":{"alpha":1,"beta":[255,240,190]}}
在此示例中,"json" 是 OrderedHash 对象的字符串表示形式。
要在以后恢复参数,请使用:
IDL> newparam = JSON_PARSE(string(read_binary(filename)))
这将从文件中读取的字符串创建一个新的有序哈希。JSON 格式支持的内部类型有限,因此 IDL 变量在通过 JSON_SERIALIZE 和 JSON_PARSE 处理后,不一定能保留完全相同的类型。例如,在此情况下,数组被转换为列表,因为 JSON 数组更接近于 IDL 的列表而不是 IDL 数组。数字总是以双精度浮点数或 long64 整数形式返回。
最后,我将提供一个简单的示例,演示如何为有序哈希添加 XML 序列化和反序列化功能。由于 OrderedHash 继承自 Hash,因此这些方法被添加到 Hash 中。第一个方法是 hash__toxml.pro
function hash::ToXml,_ref_extra=extra compile_opt idl2,logical_predicate nl = string(10b) formats = hash(4,'(g0.9)',5,'(g0.17)',6,'("(",g0.9,",",g0.9,")")',9,'("(",g0.17,",",g0.17,")")') oXml = IDLffXmlDomDocument() oTop = oXml.CreateElement('TOP') parent = oXml.AppendChild(oTop) keys = self->Keys() foreach k, keys do begin val = self[k] type = size(val, /type) node = oXml.CreateElement(k) node.SetAttribute, 'TYPE', strtrim(type, 2) if isa(val, /array) then node.SetAttribute,'ARRAY', $ strjoin(string(size(val, /dimension),format='(i0)'), ' ') format = formats.HasKey(type) ? formats[type] : '(i0)' str = (type eq 7)?strjoin(val, nl):strjoin(string(val, format=format), ' ') txt = oXml.CreateTextNode(str) _ = node.AppendChild(txt) _ = parent.AppendChild(oXml.CreateTextNode(nl)) _ = parent.AppendChild(node) endforeach _ = parent.AppendChild(oXml.CreateTextNode(nl)) if n_elements(extra) then oXml.Save, _strict_extra=extra return, oXml end
使用此方法,可以通过以下代码将有序哈希转换为 XML:
IDL> param = OrderedHash() IDL> param['sigma'] = !dpi/4 IDL> param['xsize'] = 512 IDL> param['name'] = 'Exelis' IDL> param['theta'] = [[23, 334, 4.0, 41.0], [1.0, 2, 3, 4]] IDL> !null = param.ToXml(string=str) % Loaded DLM: XML. % Compiled module: HASH::TOXML. IDL> str
然后,要将结果字符串转换回 OrderedHash,请使用:
pro hash::FromXml_,_ref_extra=extra compile_opt idl2,logical_predicate, static oXml = IDLffXmlDomDocument() oXml.Load, _strict_extra=extra top = oXml.GetDocumentElement() nodes = top.GetChildNodes() for i=0, nodes.GetLength()-1 do begin n = nodes.Item(i) if isa(n, 'IDLffXmlDomElement') then begin array = [] key = n.GetTagName() txt = n.GetFirstChild() if isa(txt, 'IDLffXmlDomText') then str = txt.GetData() type = n.GetAttribute('TYPE') array = n.GetAttribute('ARRAY') if type eq 7 && ~keyword_set(array) then val = str $ else if type eq 7 then begin val = reform(strsplit(str, string(10b), /extract), $ long64(strsplit(array, /extract))) endif else begin if keyword_set(array) then begin val = make_array(long64(strsplit(array, /extract)),type=type) endif else val = (make_array(1, type=type))[0] reads, str, val endelse self[key] = val endif endfor end
使用静态方法有助于简化语法:
function OrderedHash::FromXML,_ref_extra=extra compile_opt static objref = OrderedHash() objref.FromXML_, _strict_extra=extra return, objref end
以下是将字符串变量 "str" 转换回 OrderedHash 的示例:
IDL> newparam = OrderedHash.FromXML(string=str) IDL> newparam { "sigma": 0.78539816339744828, "xsize": 512, "name": "Exelis", "theta": [[23.000000, 334.00000, 4.0000000, 41.000000],[1.0000000, 2.0000000, 3.0000000, 4.0000000]] }
这个简单示例不支持嵌套的哈希对象、列表,并且处理包含换行符的字符串数组时存在问题。