1 """
2 Parse utype sets into ASTs.
3
4 The rough plan is to build an ElementTree from a sequence of
5 utype/value pairs (as returned by utypegen.getUtypes). This
6 ElementTree can then be used to build an AST using stcxast. The ElementTree
7 contains common.ColRefs and thus cannot be serialized to an XML string.
8
9 Most of the magic happens in utypeParseToTree, where the utypes are
10 dissected; it is important that the utypes sequence passed to this
11 is sorted such that utypes for things below an STC-X node are actually
12 immediately below the utype pair for their parent.
13 """
14
15
16
17
18
19
20
21 from gavo import utils
22 from gavo.stc import common
23 from gavo.stc import stcxast
24 from gavo.utils import ElementTree
25
26
28 if utype is None:
29 return None
30 return tuple(utype.split(":")[-1].split("."))
31
32
34 """a "value" for utypePairsToTree that causes an attribute to be set
35 on an element.
36
37 This is something a morph function would return.
38 """
41
42
44 """a "value" for utypesParisToTree that causes a child to be appended
45
46 This is for morph functions on substitution groups.
47 """
50
51
53 """returns a pair fromTail, toTail of tuples to bring fromTuple to toTuple.
54
55 This is done such that fromTuple-fromTuple+toTail=toTuple for "appending"
56 semantics.
57 """
58 if toTuple is None:
59 return (), ()
60 prefixLen = utils.commonPrefixLength(fromTuple, toTuple)
61 return fromTuple[prefixLen:], toTuple[prefixLen:]
62
63
66
68
69
70 for pair in _replaceLastWithValue(utype, value):
71 yield pair
72 yield None, _Attribute("coord_naxes", "2")
73
75 def makeAttribute(utype, value):
76 yield None, _Attribute(attName, value)
77 return makeAttribute
78
82 return makeAttribute
83
85 def makeChild(utype, value):
86 yield None, _Child(childName, value)
87 return makeChild
88
89
93 return replacer
94
96 def appender(orig, value):
97 yield "%s.%s"%(orig, frag), value
98 return appender
99
101 if False:
102 yield None
103
104
105 _utypeMorphers = {
106 'AstroCoordSystem.RedshiftFrame.ReferencePosition': _replaceLastWithValue,
107 'AstroCoordSystem.RedshiftFrame.value_type':
108 _makeParentAttributeMaker("value_type"),
109 'AstroCoordSystem.SpaceFrame.CoordFlavor': _makeCoordFlavor,
110 'AstroCoordSystem.SpaceFrame.CoordFlavor.coord_naxes':
111 _makeAttributeMaker("coord_naxes"),
112 'AstroCoordSystem.SpaceFrame.CoordRefFrame': _replaceLastWithValue,
113 'AstroCoordSystem.SpaceFrame.CoordRefFrame.Equinox':
114 _replaceUtype('AstroCoordSystem.SpaceFrame.Equinox'),
115 'AstroCoordSystem.SpaceFrame.ReferencePosition': _replaceLastWithValue,
116 'AstroCoordSystem.SpectralFrame.ReferencePosition': _replaceLastWithValue,
117 'AstroCoordSystem.TimeFrame.ReferencePosition': _replaceLastWithValue,
118 'AstroCoordSystem.href': _makeParentAttributeMaker(
119 utils.ElementTree.QName(common.XlinkNamespace, "href")),
120 'AstroCoordSystem.SpaceFrame.ReferencePosition.PlanetaryEphem':
121 _makeChildMaker("PlanetaryEphem"),
122 'AstroCoordSystem.TimeFrame.ReferencePosition.PlanetaryEphem':
123 _makeChildMaker("PlanetaryEphem"),
124 'AstroCoordSystem.SpectralFrame.ReferencePosition.PlanetaryEphem':
125 _makeChildMaker("PlanetaryEphem"),
126 'AstroCoordSystem.RedshiftFrame.ReferencePosition.PlanetaryEphem':
127 _makeChildMaker("PlanetaryEphem"),
128 'AstroCoords.Time.TimeInstant': _appendFragment('ISOTime'),
129 'AstroCoords.TimeInterval.StartTime': _appendFragment('ISOTime'),
130 'AstroCoords.TimeInterval.EndTime': _appendFragment('ISOTime'),
131 'AstroCoords.Position1D.Epoch.yearDef': _makeParentAttributeMaker("yearDef"),
132 'AstroCoords.Position2D.Epoch.yearDef': _makeParentAttributeMaker("yearDef"),
133 'AstroCoords.Position3D.Epoch.yearDef': _makeParentAttributeMaker("yearDef"),
134 'DataModel.Uri': _ignore,
135 'DataModel.Name': _ignore,
136 'DataModel.Version': _ignore,
137 }
138
140 """returns an ElementTree from a sequence of (utype, value) pairs.
141
142 nameQualifier(str) -> anything is a function producing element names.
143
144 The utypes are processed as they come in. In practice this means
145 you should sort them (or similar).
146
147 The utype can be none, meaning "Use last node".
148 """
149 utypes = list(utypes)
150 root = ElementTree.Element(nameQualifier("STCSpec"))
151 curParts, elementStack = (), [root]
152 for parts, val in ((parseUtype(u), v) for u, v in utypes):
153 toClose, toOpen = _unifyTuples(curParts, parts)
154 if toClose or toOpen:
155 curParts = parts
156
157 for elName in toClose:
158 elementStack.pop()
159 for elName in toOpen:
160 elementStack.append(
161 ElementTree.SubElement(elementStack[-1], nameQualifier(elName)))
162
163
164 if isinstance(val, _Attribute):
165 elementStack[-1].attrib[val.name] = val.value
166 elif isinstance(val, _Child):
167 ElementTree.SubElement(elementStack[-1],
168 nameQualifier(val.name)).text = val.value
169
170
171
172
173
174 else:
175 if not toClose and not toOpen:
176 elementStack.pop()
177 elementStack.append(ElementTree.SubElement(
178 elementStack[-1], nameQualifier(curParts[-1])))
179 elementStack[-1].text = val
180 return root
181
182
184 """returns a morphed sequence of utype/value pairs.
185
186 morphers is a dictionary of utypes to handling generators. Each of
187 those most take a utype and a value and generate utype/value pairs.
188
189 This is used here to fix the abominations where system elements become
190 values in utype representation.
191 """
192 for index, (k, v) in enumerate(utypeSeq):
193 if k in morphers:
194 for pair in morphers[k](k, v):
195 yield pair
196 else:
197 yield (k, v)
198
199
201 """returns a sorted sequence of utype, value pairs from utypeSeq
202
203 The result also has the abominable "stc:" cut off.
204 """
205 return sorted((key.split(":")[-1], value)
206 for key, value in utypeSeq)
207
208
217