1 """ XML tools; so far just conversion between object attributes and xml.
2
3 Copyright 2007-2011 Research Foundation State University of New York
4 This file is part of QUB Express.
5
6 QUB Express is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 QUB Express is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License,
17 named LICENSE.txt, in the QUB Express program directory. If not, see
18 <http://www.gnu.org/licenses/>.
19
20 """
21
22 import xml.dom.minidom
23 from qubx.util_types import *
24 import sys
25
26 try:
27 import xml.dom.ext
28 XMLPrettyPrint = xml.dom.ext.PrettyPrint
29 except:
33
35 """
36 Field(name, default, accept=str, format=str): an attribute for <properties>.
37
38 - name: the object attribute of interest, e.g. name="foo" selects obj.foo
39 - default: default value, of whatever type
40 - accept: function which parses a string and returns the appropriate type, or raises an exception
41 in this case the exception means to fall back to the default
42 - format: function which converts your type to string; or a %-style format string, e.g. "%.8g"
43 """
44
46 """
47 Returns a DOM element representing specified fields of obj.
48
49 - obj: any python object
50 - doc: the destination xml.dom Document
51 - ns: doc's xml.dom namespace
52 - fields: a list of qubx.xmlt.Field(name, default, accept=str, format=str)
53
54 example:
55 >>> obj = object()
56 >>> obj.name = 'x'
57 >>> obj.length = obj.volume = 0.0
58
59 >>> fields = [Field(name='name', accept=str, default='untitled'),
60 ... Field(name='length', accept=float, format=str, default=2.3),
61 ... Field(name='volume', accept=float, format='%9g', default=2.3)]
62
63 >>> print PropertiesToXML(obj, doc, ns, fields)
64 <properties>
65 <property name='name'>x</property>
66 <property name='length'>0.0</property>
67 <property name='volume'>0.0</property>
68 </properties>
69 """
70
71 properties = doc.createElementNS(ns, 'properties')
72 for field in fields:
73 prop = properties.appendChild( doc.createElementNS(ns, 'property') )
74 prop.setAttribute('name', field.name)
75 val = obj.__getattr__(field.name)
76 data = None
77 if field.format:
78 try:
79 if callable(field.format):
80 data = field.format(val)
81 else:
82 data = field.format % val
83 except:
84 traceback.print_exc()
85 if data is None:
86 data = str(val)
87 prop.appendChild( doc.createTextNode(data) )
88 return properties
89
91 """
92 Sets attributes of obj from xml.dom element <properties>.
93
94 @param properties: an xml.dom element with children <property name=''>value</property>
95 @param obj: the receiver of obj.name = value
96 @param fields: optional list of qubx.xmlt.Field(name, default, accept=str, format=str)::
97 if fields is None:
98 obj.name = string value for all <property> elements
99 else:
100 only <property>s listed in fields are copied;
101 obj.name = default if no <property> or failed "accept" conversion
102
103 example:
104
105 >>> obj = object()
106 >>> fields = [Field(name='name', accept=str, default='untitled'),
107 ... Field(name='length', accept=float, format=str, default=2.3),
108 ... Field(name='volume', accept=float, format='%9g', default=2.3)]
109 >>> XMLToProperties(properties_element, obj, fields)
110 >>> print obj.name, obj.length, obj.volume
111 x, 0.0, 0.0
112 """
113
114 if fields is None:
115 strs = obj
116 else:
117 strs = Anon()
118 for node in properties.childNodes:
119 try:
120 if node.nodeName == 'property':
121 name = node.getAttribute('name')
122 data = node.childNodes[0]
123 strs.__setattr__(name, data.nodeValue)
124 except:
125 traceback.print_exc()
126 if not (fields is None):
127 for field in fields:
128 accept = field.accept or str
129 sval = strs.__getattr__(field.name)
130 if not (sval is None):
131 try:
132 obj.__setattr__(field.name, accept(sval))
133 except:
134 traceback.print_exc()
135 if obj.__getattr__(field.name) is None:
136 obj.__setattr__(field.name, field.default)
137