|
1 """base xml and rss views |
|
2 |
|
3 |
|
4 :organization: Logilab |
|
5 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
7 """ |
|
8 __docformat__ = "restructuredtext en" |
|
9 |
|
10 from time import timezone |
|
11 |
|
12 from logilab.mtconverter import xml_escape |
|
13 |
|
14 from cubicweb.view import EntityView, AnyRsetView |
|
15 from cubicweb.web.httpcache import MaxAgeHTTPCacheManager |
|
16 from cubicweb.common.uilib import simple_sgml_tag |
|
17 |
|
18 |
|
19 class XmlView(EntityView): |
|
20 """xml view for entities""" |
|
21 id = 'xml' |
|
22 title = _('xml') |
|
23 templatable = False |
|
24 content_type = 'text/xml' |
|
25 xml_root = 'rset' |
|
26 item_vid = 'xmlitem' |
|
27 |
|
28 def cell_call(self, row, col): |
|
29 self.wview(self.item_vid, self.rset, row=row, col=col) |
|
30 |
|
31 def call(self): |
|
32 """display a list of entities by calling their <item_vid> view""" |
|
33 self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding) |
|
34 self.w(u'<%s size="%s">\n' % (self.xml_root, len(self.rset))) |
|
35 for i in xrange(self.rset.rowcount): |
|
36 self.cell_call(i, 0) |
|
37 self.w(u'</%s>\n' % self.xml_root) |
|
38 |
|
39 |
|
40 class XmlItemView(EntityView): |
|
41 id = 'xmlitem' |
|
42 |
|
43 def cell_call(self, row, col): |
|
44 """ element as an item for an xml feed """ |
|
45 entity = self.complete_entity(row, col) |
|
46 self.w(u'<%s>\n' % (entity.e_schema)) |
|
47 for rschema, attrschema in entity.e_schema.attribute_definitions(): |
|
48 attr = rschema.type |
|
49 try: |
|
50 value = entity[attr] |
|
51 except KeyError: |
|
52 # Bytes |
|
53 continue |
|
54 if value is not None: |
|
55 if attrschema == 'Bytes': |
|
56 from base64 import b64encode |
|
57 value = '<![CDATA[%s]]>' % b64encode(value.getvalue()) |
|
58 elif isinstance(value, basestring): |
|
59 value = xml_escape(value) |
|
60 self.w(u' <%s>%s</%s>\n' % (attr, value, attr)) |
|
61 self.w(u'</%s>\n' % (entity.e_schema)) |
|
62 |
|
63 |
|
64 |
|
65 class XmlRsetView(AnyRsetView): |
|
66 """dumps raw rset as xml""" |
|
67 id = 'rsetxml' |
|
68 title = _('xml export') |
|
69 templatable = False |
|
70 content_type = 'text/xml' |
|
71 xml_root = 'rset' |
|
72 |
|
73 def call(self): |
|
74 w = self.w |
|
75 rset, descr = self.rset, self.rset.description |
|
76 eschema = self.schema.eschema |
|
77 labels = self.columns_labels(False) |
|
78 w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding) |
|
79 w(u'<%s query="%s">\n' % (self.xml_root, xml_escape(rset.printable_rql()))) |
|
80 for rowindex, row in enumerate(self.rset): |
|
81 w(u' <row>\n') |
|
82 for colindex, val in enumerate(row): |
|
83 etype = descr[rowindex][colindex] |
|
84 tag = labels[colindex] |
|
85 attrs = {} |
|
86 if '(' in tag: |
|
87 attrs['expr'] = tag |
|
88 tag = 'funccall' |
|
89 if val is not None and not eschema(etype).is_final(): |
|
90 attrs['eid'] = val |
|
91 # csvrow.append(val) # val is eid in that case |
|
92 val = self.view('textincontext', rset, |
|
93 row=rowindex, col=colindex) |
|
94 else: |
|
95 val = self.view('final', rset, displaytime=True, |
|
96 row=rowindex, col=colindex, format='text/plain') |
|
97 w(simple_sgml_tag(tag, val, **attrs)) |
|
98 w(u' </row>\n') |
|
99 w(u'</%s>\n' % self.xml_root) |
|
100 |
|
101 |
|
102 class RssView(XmlView): |
|
103 id = 'rss' |
|
104 title = _('rss') |
|
105 templatable = False |
|
106 content_type = 'text/xml' |
|
107 http_cache_manager = MaxAgeHTTPCacheManager |
|
108 cache_max_age = 60*60*2 # stay in http cache for 2 hours by default |
|
109 |
|
110 def cell_call(self, row, col): |
|
111 self.wview('rssitem', self.rset, row=row, col=col) |
|
112 |
|
113 def call(self): |
|
114 """display a list of entities by calling their <item_vid> view""" |
|
115 req = self.req |
|
116 self.w(u'<?xml version="1.0" encoding="%s"?>\n' % req.encoding) |
|
117 self.w(u'''<rdf:RDF |
|
118 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
|
119 xmlns:dc="http://purl.org/dc/elements/1.1/" |
|
120 xmlns="http://purl.org/rss/1.0/" |
|
121 >''') |
|
122 self.w(u' <channel rdf:about="%s">\n' % xml_escape(req.url())) |
|
123 self.w(u' <title>%s RSS Feed</title>\n' % xml_escape(self.page_title())) |
|
124 self.w(u' <description>%s</description>\n' % xml_escape(req.form.get('vtitle', ''))) |
|
125 params = req.form.copy() |
|
126 params.pop('vid', None) |
|
127 self.w(u' <link>%s</link>\n' % xml_escape(self.build_url(**params))) |
|
128 self.w(u' <items>\n') |
|
129 self.w(u' <rdf:Seq>\n') |
|
130 for entity in self.rset.entities(): |
|
131 self.w(u' <rdf:li resource="%s" />\n' % xml_escape(entity.absolute_url())) |
|
132 self.w(u' </rdf:Seq>\n') |
|
133 self.w(u' </items>\n') |
|
134 self.w(u' </channel>\n') |
|
135 for i in xrange(self.rset.rowcount): |
|
136 self.cell_call(i, 0) |
|
137 self.w(u'</rdf:RDF>') |
|
138 |
|
139 |
|
140 class RssItemView(EntityView): |
|
141 id = 'rssitem' |
|
142 date_format = '%%Y-%%m-%%dT%%H:%%M%+03i:00' % (timezone / 3600) |
|
143 |
|
144 def cell_call(self, row, col): |
|
145 entity = self.complete_entity(row, col) |
|
146 self.w(u'<item rdf:about="%s">\n' % xml_escape(entity.absolute_url())) |
|
147 self._marker('title', entity.dc_long_title()) |
|
148 self._marker('link', entity.absolute_url()) |
|
149 self._marker('description', entity.dc_description()) |
|
150 self._marker('dc:date', entity.dc_date(self.date_format)) |
|
151 if entity.creator: |
|
152 self.w(u'<author>') |
|
153 self._marker('name', entity.creator.name()) |
|
154 email = entity.creator.get_email() |
|
155 if email: |
|
156 self._marker('email', email) |
|
157 self.w(u'</author>') |
|
158 self.w(u'</item>\n') |
|
159 |
|
160 def _marker(self, marker, value): |
|
161 if value: |
|
162 self.w(u' <%s>%s</%s>\n' % (marker, xml_escape(value), marker)) |