1 """
2 The renderer for VOSI examples, plus the docutils extensions provided for
3 them.
4
5 If you have a renderer that needs custom text roles or directives, read the
6 docstring of misctricks.RSTExtensions and add whatever roles you need below,
7 more or less like this::
8
9 misctricks.RSTExtensions.makeTextRole("niceRole")
10
11 Only go through RSTExtensions, as these will make sure HTML postprocessing
12 happens as required.
13
14 The reason we keep the roles here and not in the renderer modules where they'd
15 logically belong (and where they should be documented in the renderer
16 docstrings) is that we don't want docutils imports all over the place.
17 """
18
19
20
21
22
23
24
25 import re
26
27 from docutils import nodes
28 from docutils import utils as rstutils
29 from docutils.parsers import rst
30
31 from lxml import etree
32
33 from nevow import rend
34
35 from gavo import utils
36 from gavo.utils import misctricks
37 from .. import base
38 from .. import svcs
39 from . import grend
40
41
42 -class _Example(rend.DataFactory, base.MetaMixin):
43 """A formatted example.
44
45 These get constructed with example meta items and glue these
46 together with the nevow rendering system.
47
48 An important role of this is the translation from the HTML class
49 attribute values we use in ReStructuredText to the RDFa properties
50 in the output. The first class that has a matching property wins.
51
52 There's the special exmeta render function that works like metahtml,
53 except it's using the example's meta.
54 """
61
64
66 rawHTML = self.original.getContent("html")
67 parsed = etree.fromstring(
68 '<div typeof="example" id="%s" resource="#%s">\n'
69 '<h2 property="name">%s</h2>\n'
70 '%s\n</div>'%(
71 self.htmlId,
72 self.htmlId,
73 utils.escapePCDATA(self.title),
74 rawHTML))
75 actOnClasses = set(misctricks.RSTExtensions.classToProperty)
76
77 for node in parsed.iterfind(".//*[@class]"):
78 nodeClasses = set(node.attrib["class"].split())
79 properties = " ".join(misctricks.RSTExtensions.classToProperty[c]
80 for c in actOnClasses & nodeClasses)
81 if properties:
82 node.set("property", properties)
83
84
85
86
87 if "href" in node.attrib or "src" in node.attrib:
88 node.set("content", node.text)
89
90 return etree.tostring(parsed, encoding="utf-8").decode("utf-8")
91
93 if not hasattr(self.original, "renderedDescription"):
94 self.original.renderedDescription = self._getTranslatedHTML()
95 return self.original.renderedDescription
96
97
98 -class Examples(grend.CustomTemplateMixin, grend.ServiceBasedPage):
99 r"""A renderer for examples for service usage.
100
101 This renderer formats _example meta items in its service. Its output
102 is XHTML compliant to VOSI examples; clients can parse it to,
103 for instance, fill forms for service operation or display examples
104 to users.
105
106 The examples make use of RDFa to convey semantic markup. To see
107 what kind of semantics is contained, try
108 http://www.w3.org/2012/pyRdfa/Overview.html and feed it the
109 example URL of your service.
110
111 The default content of _example is ReStructuredText, and really, not much
112 else makes sense. An example for such a meta item can be viewed by
113 executing ``gavo admin dumpDF //userconfig``, in the tapexamples STREAM.
114
115 To support annotation of things within the example text, DaCHS
116 defines several RST extensions, both interpreted text roles (used like
117 ``:role-name:`content with blanks```) and custom directives (used
118 to mark up blocks introduced by a single line like
119 ``.. directive-name ::`` (the blanks before and after the
120 directive name are significant).
121
122 Here's the custom interpreted text roles:
123
124 * *dl-id*: An publisher DID a service returns data for (used in
125 datalink examples)
126 * *taptable*: A (fully qualified) table name a TAP example query is
127 (particularly) relevant for; in HTML, this is also a link
128 to the table description.
129 * *genparam*: A "generic parameter" as defined by DALI. The values
130 of these have the form param(value), e.g., :genparam:\`POS(32,4)\`.
131 Right now, not parantheses are allowed in the value. Complain
132 if this bites you.
133
134 These are the custom directives:
135
136 * *tapquery*: The query discussed in a TAP example.
137
138 Examples for how to write TAP examples are in the userconfig.rd
139 distributed with DaCHS. Examples for Datalink examples can
140 be found in the GAVO RDs feros/q and califa/q3.
141 """
142 name = "examples"
143 checkedRenderer = False
144 customTemplate = svcs.loadSystemTemplate("examples.html")
145
146 @classmethod
149
153
155 """returns _Example instances from the service metadata.
156 """
157 for ex in self.service.iterMeta("_example"):
158 yield _Example(ex)
159
160
161
162
163
164
165
166
167
168 -def _taptableRoleFunc(name, rawText, text, lineno, inliner,
169 options={}, content=[]):
170 tablename = nodes.emphasis(rawText, text)
171 tablename["classes"] = ["dachs-ex-taptable"]
172 descr = nodes.reference(u"\u2197", u"\u2197",
173 refuri="/tableinfo/%s"%text)
174 descr["classes"] = ["taptable-link"]
175 return [descr, tablename], []
176
177 misctricks.RSTExtensions.makeTextRole("taptable", _taptableRoleFunc,
178 propertyName="table")
179 del _taptableRoleFunc
182 has_content = True
183
185 body = "\n".join(self.content)
186 res = nodes.literal_block(body, body)
187 res["classes"] = ["dachs-ex-tapquery"]
188 return [res]
189
190 misctricks.RSTExtensions.addDirective("tapquery", _TAPQuery,
191 propertyName="query")
192 del _TAPQuery
193
194
195
196
197 misctricks.RSTExtensions.makeTextRole("dl-id")
198
199
200
201 -def _genparamRoleFunc(name, rawText, text, lineno, inliner,
202 options={}, content=[]):
203 mat = re.match(r"([^(]+)\(([^)]*)\)$", text)
204 if not mat:
205 msg = inliner.reporter.error(
206 "genparam content must have the form key(value); %s does not."%text)
207 return [inliner.problematic(rawText, rawText, msg)], [msg]
208
209 key, value = mat.groups()
210
211 formatted = """<span property="generic-parameter" typeof="keyval"
212 class="generic-parameter">
213 <span property="key" class="genparam-key">%s</span> =
214 <span property="value" class="genparam-value">%s</span>
215 </span>"""%(
216 utils.escapePCDATA(rstutils.unescape(key, 1)),
217 utils.escapePCDATA(rstutils.unescape(value, 1)))
218 res = nodes.raw(
219 rawsource=rawText,
220 text=formatted,
221 format='html')
222 return [res], []
223
224 misctricks.RSTExtensions.makeTextRole("genparam", _genparamRoleFunc)
225 del _genparamRoleFunc
226