source: products/quintagroup.transmogrifier/branches/plone-2.1/quintagroup.transmogrifier/quintagroup/transmogrifier/manifest.py @ 1413

Last change on this file since 1413 was 1389, checked in by piv, 14 years ago

fix manifest and binary export sections to generate valid xml

File size: 5.1 KB
Line 
1import os.path
2from xml.dom import minidom
3
4from zope.interface import classProvides, implements
5from zope.app.annotation.interfaces import IAnnotations
6
7from collective.transmogrifier.interfaces import ISection, ISectionBlueprint
8from collective.transmogrifier.utils import defaultMatcher
9
10from quintagroup.transmogrifier.logger import VALIDATIONKEY
11
12class ManifestExporterSection(object):
13    classProvides(ISectionBlueprint)
14    implements(ISection)
15
16    def __init__(self, transmogrifier, name, options, previous):
17        self.previous = previous
18        self.context = transmogrifier.context
19
20        self.entrieskey = defaultMatcher(options, 'entries-key', name, 'entries')
21        self.fileskey = options.get('files-key', '_files').strip()
22
23        self.doc = minidom.Document()
24
25    def __iter__(self):
26        for item in self.previous:
27            entrieskey = self.entrieskey(*item.keys())[0]
28            if not entrieskey:
29                yield item; continue
30
31            manifest = self.createManifest(item[entrieskey])
32
33            if manifest:
34                files = item.setdefault('_files', {})
35                item[self.fileskey]['manifest'] = {
36                    'name': '.objects.xml',
37                    'data': manifest,
38                }
39
40            yield item
41
42    def createManifest(self, entries):
43        if not entries:
44            return None
45
46        doc = self.doc
47        root = doc.createElement('manifest')
48
49        for obj_id, obj_type in entries:
50            # create record
51            record = doc.createElement('record')
52
53            # set type attribute
54            attr = doc.createAttribute('type')
55            attr.value = obj_type
56            record.setAttributeNode(attr)
57
58            # add object id
59            text = doc.createTextNode(obj_id)
60            record.appendChild(text)
61
62            root.appendChild(record)
63
64        doc.appendChild(root)
65
66        try:
67            data = doc.toprettyxml(indent='  ', encoding='utf-8')
68        except UnicodeDecodeError, e:
69            # all comments are strings encoded in 'utf-8' and they will properly
70            # saved in xml file, but if we explicitly give 'utf-8' encoding
71            # UnicodeDecodeError will be raised when they have non-ascii chars
72            data = doc.toprettyxml(indent='  ')
73
74        doc.unlink()
75        return data
76
77class ManifestImporterSection(object):
78    classProvides(ISectionBlueprint)
79    implements(ISection)
80
81    def __init__(self, transmogrifier, name, options, previous):
82        self.previous = previous
83        self.context = transmogrifier.context
84
85        self.pathkey = defaultMatcher(options, 'path-key', name, 'path')
86        self.fileskey = defaultMatcher(options, 'files-key', name, 'files')
87        self.typekey = options.get('type-key', '_type').strip()
88
89        # communication with logger
90        self.anno = IAnnotations(transmogrifier)
91        self.storage = self.anno.setdefault(VALIDATIONKEY, [])
92
93        # we need this dictionary to store manifest data, because reader section
94        # uses recursion when walking through content folders
95        self.manifests = {}
96
97    def __iter__(self):
98        for item in self.previous:
99            pathkey = self.pathkey(*item.keys())[0]
100            fileskey = self.fileskey(*item.keys())[0]
101
102            # skip items without path
103            if not pathkey: continue
104
105            path  = item[pathkey]
106
107            if path != '':
108                parent, item_id = os.path.split(path)
109                manifest = self.manifests.get(parent, {})
110
111                # skip that are not listed in their parent's manifest
112                if item_id not in manifest: continue
113
114                item[self.typekey] = manifest.pop(item_id)
115                # remove empty manifest dict
116                if not manifest:
117                    del self.manifests[parent]
118
119            # this item is folderish - parse manifest
120            if fileskey and 'manifest' in item[fileskey]:
121                self.extractManifest(path, item[fileskey]['manifest']['data'])
122
123            yield item
124
125        # now we yield items that were defined in manifests but not generated by
126        # previous sections - it is posible
127        if self.manifests:
128            containers = self.manifests.keys()
129            containers.sort()
130            for i in containers:
131                manifest = self.manifests[i]
132                ids = manifest.keys()
133                ids.sort()
134                for id_ in ids:
135                    if i == '':
136                        path = id_
137                    else:
138                        path = '/'.join([i, id_])
139                    self.storage.append(path)
140                    yield {pathkey: path, self.typekey: manifest[id_]}
141       
142        # cleanup
143        if VALIDATIONKEY in self.anno:
144            del self.anno[VALIDATIONKEY]
145
146    def extractManifest(self, path, data):
147        doc = minidom.parseString(data)
148        objects = {}
149        for record in doc.getElementsByTagName('record'):
150            type_ = str(record.getAttribute('type'))
151            object_id = str(record.firstChild.nodeValue.strip())
152            objects[object_id] = type_
153        self.manifests[path] = objects
Note: See TracBrowser for help on using the repository browser.