Package advene :: Package model :: Package serializers :: Module advene_xml
[hide private]
[frames] | no frames]

Source Code for Module advene.model.serializers.advene_xml

  1  """ 
  2  Generic serializer implementation. 
  3   
  4  Note that the order chosen for XML elements (imports, tags, medias, resources, 
  5  annotations, relations, views, queries, lists) is designed to limit the number 
  6  of forward references, which makes the work of the parser more difficult. 
  7  Forward references are nevetheless still possible in meta-data, tag associated to another tag, list containing another list 
  8  """ 
  9   
 10  import base64 
 11  from itertools import chain 
 12  from xml.etree.cElementTree import Element, ElementTree, SubElement 
 13   
 14  from advene.model.consts import ADVENE_XML 
 15  from advene.model.serializers.unserialized import iter_unserialized_meta_prefix 
 16   
 17  NAME = "Generic Advene XML" 
 18   
 19  EXTENSION = ".bxp" # Advene-2 Xml Package 
 20   
 21  MIMETYPE = "application/x-advene-bxp" 
 22   
23 -def make_serializer(package, file_):
24 """Return a serializer that will serialize `package` to `file_`. 25 26 `file_` is a writable file-like object. It is the responsability of the 27 caller to close it. 28 29 The returned object must implement the interface for which 30 :class:`_Serializer` is the reference implementation. 31 """ 32 return _Serializer(package, file_)
33
34 -def serialize_to(package, file_):
35 """A shortcut for ``make_serializer(package, file_).serialize()``. 36 37 See also `make_serializer`. 38 """ 39 return _Serializer(package, file_).serialize()
40 41
42 -class _Serializer(object):
43
44 - def serialize(self):
45 """Perform the actual serialization.""" 46 namespaces = self.namespaces = {} 47 root = self.root = Element("package", xmlns=self.default_ns) 48 package = self.package 49 namespaces = package._get_namespaces_as_dict() 50 for uri, prefix in namespaces.iteritems(): 51 root.set("xmlns:%s" % prefix, uri) 52 if package.uri: 53 root.set("uri", package.uri) 54 # package meta-data 55 self._serialize_meta(package, self.root) 56 # imports 57 ximports = SubElement(self.root, "imports") 58 for i in package.own.imports: 59 self._serialize_import(i, ximports) 60 if len(ximports) == 0: 61 self.root.remove(ximports) 62 # tags 63 xtags = SubElement(self.root, "tags") 64 for t in package.own.tags: 65 self._serialize_tag(t, xtags) 66 if len(xtags) == 0: 67 self.root.remove(xtags) 68 # media 69 xmedias = SubElement(self.root, "medias") 70 for m in package.own.medias: 71 self._serialize_media(m, xmedias) 72 if len(xmedias) == 0: 73 self.root.remove(xmedias) 74 # resources 75 xresources = SubElement(self.root, "resources") 76 for r in package.own.resources: 77 self._serialize_resource(r, xresources) 78 if len(xresources) == 0: 79 self.root.remove(xresources) 80 # annotations 81 xannotations = SubElement(self.root, "annotations") 82 for a in package.own.annotations: 83 self._serialize_annotation(a, xannotations) 84 if len(xannotations) == 0: 85 self.root.remove(xannotations) 86 # relations 87 xrelations = SubElement(self.root, "relations") 88 for r in package.own.relations: 89 self._serialize_relation(r, xrelations) 90 if len(xrelations) == 0: 91 self.root.remove(xrelations) 92 # views 93 xviews = SubElement(self.root, "views") 94 for v in package.own.views: 95 self._serialize_view(v, xviews) 96 if len(xviews) == 0: 97 self.root.remove(xviews) 98 # queries 99 xqueries = SubElement(self.root, "queries") 100 for q in package.own.queries: 101 self._serialize_query(q, xqueries) 102 if len(xqueries) == 0: 103 self.root.remove(xqueries) 104 # lists 105 xlists = SubElement(self.root, "lists") 106 for L in package.own.lists: 107 self._serialize_list(L, xlists) 108 if len(xlists) == 0: 109 self.root.remove(xlists) 110 # external tag associations 111 self._serialize_external_tagging(self.root) 112 113 _indent(self.root) 114 ElementTree(self.root).write(self.file)
115 116 # end of the public interface 117
118 - def __init__(self, package, file_):
119 120 # this will be ugly, because ElementTree in python 2.5 does not handle 121 # custom namespace prefix, so we just handle them ourselves 122 123 self.package = package 124 self.file = file_ 125 self.unserialized_meta_prefixes = list(iter_unserialized_meta_prefix()) 126 self.default_ns = ADVENE_XML
127 128 # element serializers 129
130 - def _serialize_media(self, m, xmedias, tagname="media"):
131 xm = SubElement(xmedias, tagname, id=m.id, url=m.url, 132 **{"frame-of-reference": m.frame_of_reference}) 133 self._serialize_element_tags(m, xm) 134 self._serialize_meta(m, xm)
135
136 - def _serialize_annotation(self, a, xannotations, tagname="annotation"):
137 mid = a.media_id 138 xa = SubElement(xannotations, tagname, id=a.id, 139 media=mid, begin=str(a.begin), end=str(a.end)) 140 self._serialize_content(a, xa) 141 self._serialize_element_tags(a, xa) 142 self._serialize_meta(a, xa)
143
144 - def _serialize_relation(self, r, xrelations, tagname="relation"):
145 xr = SubElement(xrelations, tagname, id=r.id) 146 xmembers = SubElement(xr, "members") 147 for m in r.iter_member_ids(): 148 SubElement(xmembers, "member", {"id-ref":m}) 149 if len(xmembers) == 0: 150 xr.remove(xmembers) 151 self._serialize_content(r, xr) 152 self._serialize_element_tags(r, xr) 153 self._serialize_meta(r, xr)
154
155 - def _serialize_list(self, L, xlists, tagname="list"):
156 xL = SubElement(xlists, tagname, id=L.id) 157 xitems = SubElement(xL, "items") 158 for i in L.iter_item_ids(): 159 SubElement(xitems, "item", {"id-ref":i}) 160 if len(xitems) == 0: 161 xL.remove(xitems) 162 self._serialize_element_tags(L, xL) 163 self._serialize_meta(L, xL)
164
165 - def _serialize_tag(self, t, ximports, tagname="tag"):
166 xt = SubElement(ximports, tagname, id=t.id) 167 L = [ id for id in t.iter_element_ids(self.package, False) 168 if id.find(":") > 0 ] 169 if L: 170 ximp = SubElement(xt, "imported-elements") 171 for i in L: 172 SubElement(ximp, "element", {"id-ref":i}) 173 self._serialize_element_tags(t, xt) 174 self._serialize_meta(t, xt)
175
176 - def _serialize_view(self, v, xviews, tagname="view"):
177 xv = SubElement(xviews, tagname, id=v.id) 178 self._serialize_content(v, xv) 179 self._serialize_element_tags(v, xv) 180 self._serialize_meta(v, xv)
181
182 - def _serialize_query(self, q, xqueries, tagname="query"):
183 xq = SubElement(xqueries, tagname, id=q.id) 184 self._serialize_content(q, xq) 185 self._serialize_element_tags(q, xq) 186 self._serialize_meta(q, xq)
187
188 - def _serialize_resource(self, r, xresources, tagname="resource"):
189 xr = SubElement(xresources, tagname, id=r.id) 190 self._serialize_content(r, xr) 191 self._serialize_element_tags(r, xr) 192 self._serialize_meta(r, xr)
193
194 - def _serialize_import(self, i, ximports, tagname="import"):
195 xi = SubElement(ximports, tagname, id=i.id, url=i.url) 196 if i.uri: 197 xi.set("uri", i.uri) 198 self._serialize_element_tags(i, xi) 199 self._serialize_meta(i, xi)
200 201 # common methods 202
203 - def _serialize_content(self, elt, xelt):
204 if elt.content_mimetype != "x-advene/none": 205 xc = SubElement(xelt, "content", 206 mimetype=elt.content_mimetype) 207 if elt.content_model_id: 208 xc.set("model", elt.content_model_id) 209 if elt.content_url: 210 # TODO manage packaged: URLs 211 xc.set("url", elt.content_url) 212 else: 213 data = elt.content_data 214 if not elt.content_is_textual: 215 data = base64.encodestring(data) 216 xc.set("encoding", "base64") 217 xc.text = data
218
219 - def _serialize_meta(self, obj, xobj):
220 xm = SubElement(xobj, "meta") 221 umps = chain(self.unserialized_meta_prefixes, [None,]) 222 ump = umps.next() 223 for k,v in obj.iter_meta_ids(): 224 225 while ump and k > ump: 226 if k.startswith(ump): 227 k = None # used below to continue outer loop 228 break 229 else: 230 ump = umps.next() 231 if k is None: continue 232 233 ns, tag = _split_uri_ref(k) 234 if ns == self.default_ns: 235 xkeyval = SubElement(xm, tag) 236 else: 237 prefix = self.namespaces.get(ns) 238 if prefix is None: 239 xkeyval = SubElement(xm, tag, xmlns=ns) 240 else: 241 xkeyval = SubElement(xm, "%s:%s" % (prefix, tag)) 242 if v.is_id: 243 xkeyval.set("id-ref", v) 244 else: 245 xkeyval.text = v 246 if len(xm) == 0: 247 xobj.remove(xm)
248
249 - def _serialize_element_tags(self, elt, xelt):
250 xtags = SubElement(xelt, "tags") 251 for t in elt.iter_my_tag_ids(self.package, inherited=False): 252 SubElement(xtags, "tag", {"id-ref":t}) 253 if len(xtags) == 0: 254 xelt.remove(xtags)
255
256 - def _serialize_external_tagging(self, xpackage):
257 xx = SubElement(xpackage, "external-tag-associations") 258 pairs = self.package._backend.iter_external_tagging(self.package._id) 259 for e, t in pairs: 260 xxt = SubElement(xx, "association", element=e, tag=t) 261 if len(xx) == 0: 262 xpackage.remove(xx)
263 264
265 -def _indent(elem, level=0):
266 """from http://effbot.org/zone/element-lib.htm#prettyprint""" 267 i = "\n" + level*" " 268 if len(elem): 269 if not elem.text or not elem.text.strip(): 270 elem.text = i + " " 271 for child in elem: 272 _indent(child, level+1) 273 if not child.tail or not child.tail.strip(): 274 child.tail = i + " " 275 if not child.tail or not child.tail.strip(): 276 child.tail = i 277 else: 278 if level and (not elem.tail or not elem.tail.strip()): 279 elem.tail = i
280
281 -def _split_uri_ref(uriref):
282 sharp = uriref.rfind("#") 283 slash = uriref.rfind("/") 284 cut = max(sharp, slash) 285 return uriref[:cut+1], uriref[cut+1:]
286