comparison xslt/model.xslt @ 0:cbdada054b4a

Basic schemas for generating csharp internal dom from model definition
author cin
date Wed, 21 Feb 2018 03:01:53 +0300
parents
children 7f803979305f
comparison
equal deleted inserted replaced
-1:000000000000 0:cbdada054b4a
1 <?xml version="1.0" encoding="utf-8"?>
2 <xsl:stylesheet version="1.0"
3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:m="http://implab.org/schemas/data-model.v1.xsd"
4 xmlns:clr="http://implab.org/schemas/data-model/dotnet.v1.xsd"
5 xmlns:cs="http://implab.org/schemas/code-dom/csharp.v1.xsd" xmlns:sql="http://implab.org/schemas/data-model/sql.v1.xsd"
6 xmlns:t="http://implab.org/schemas/temp" xmlns:exsl="http://exslt.org/common"
7 exclude-result-prefixes="clr m xsl exsl sql">
8 <xsl:output method="xml" indent="yes" />
9
10 <xsl:key name="type" match="m:package/m:*" use="@name" />
11
12 <xsl:variable name="fragment">
13 <t:fragment>
14 <xsl:call-template name="preprocess" />
15 </t:fragment>
16 </xsl:variable>
17
18 <xsl:template name="preprocess">
19 <xsl:param name="root" select="/" />
20 <xsl:param name="pending" select="$root/m:package/m:import[@href]" />
21 <xsl:param name="seen" select="/.." />
22 <xsl:param name="file" select="''" />
23 <xsl:param name="primary" select="true()" />
24
25 <xsl:if test="not($seen[generate-id() = generate-id($root)])">
26 <xsl:apply-templates select="$root" mode="preprocess">
27 <xsl:with-param name="primary" select="$primary" />
28 <xsl:with-param name="file" select="$file" />
29 </xsl:apply-templates>
30 <xsl:if test="$pending">
31 <xsl:variable name="doc" select="document($pending[1]/@href)" />
32 <xsl:call-template name="preprocess">
33 <xsl:with-param name="root" select="$doc" />
34 <xsl:with-param name="file" select="$pending[1]/@href" />
35 <xsl:with-param name="pending"
36 select="$pending[position() > 1] | $doc/m:package/m:import[@href]" />
37 <xsl:with-param name="seen" select="$root | $seen" />
38 <xsl:with-param name="primary" select="false()" />
39 </xsl:call-template>
40 </xsl:if>
41 </xsl:if>
42 </xsl:template>
43
44 <xsl:template match="m:package" mode="preprocess">
45 <xsl:param name="primary" />
46 <xsl:param name="file" />
47 <xsl:copy>
48 <xsl:copy-of select="@*" />
49 <xsl:if test="$primary">
50 <xsl:attribute name="primary"><xsl:value-of select="$primary" /></xsl:attribute>
51 </xsl:if>
52 <xsl:if test="$file">
53 <xsl:attribute name="file"><xsl:value-of select="$file" /></xsl:attribute>
54 </xsl:if>
55 <xsl:apply-templates mode="preprocess">
56 <xsl:with-param name="primary" select="$primary" />
57 <xsl:with-param name="file" select="$file" />
58 </xsl:apply-templates>
59 </xsl:copy>
60 </xsl:template>
61
62 <xsl:template match="*|/" mode="preprocess">
63 <xsl:param name="primary" />
64 <xsl:param name="file" />
65 <xsl:copy>
66 <xsl:copy-of select="@*" />
67 <xsl:apply-templates mode="preprocess">
68 <xsl:with-param name="primary" select="$primary" />
69 <xsl:with-param name="file" select="$file" />
70 </xsl:apply-templates>
71 </xsl:copy>
72 </xsl:template>
73
74 <xsl:template match="/">
75 <cs:document>
76 <xsl:apply-templates select="exsl:node-set($fragment)"
77 mode="generate-document" />
78 </cs:document>
79 </xsl:template>
80
81 <!-- code generation -->
82
83 <!-- disable default template -->
84 <xsl:template match="*|text()" mode="generate-document" />
85
86 <xsl:template match="t:fragment" mode="generate-document">
87 <xsl:apply-templates mode="generate-document" />
88 </xsl:template>
89
90 <!-- generate code for primary package -->
91 <xsl:template match="m:package[@primary='true' and @clr:namespace]"
92 mode="generate-document" priority="1">
93 <cs:namespace name="{@clr:namespace}">
94 <xsl:apply-templates mode="generate-document" />
95 </cs:namespace>
96 </xsl:template>
97
98 <xsl:template match="m:package[@primary='true']" mode="generate-document">
99 <xsl:apply-templates mode="generate-document" />
100 </xsl:template>
101
102 <xsl:template match="m:entity" mode="generate-document">
103 <cs:class name="{@name}" modifiers="partial ">
104 <xsl:apply-templates mode="attributes" />
105 <xsl:apply-templates mode="members" />
106 </cs:class>
107 </xsl:template>
108
109 <xsl:template match="*|text()" mode="attributes" />
110
111 <xsl:template match="sql:table" mode="attributes">
112 <cs:attribute>
113 <cs:type name="Table" namespace="Linq2Db" />
114 <cs:parameter><cs:string text="{@name}"/></cs:parameter>
115 </cs:attribute>
116 </xsl:template>
117
118 <!-- class-name -->
119 <xsl:template match="*[@name]" mode="type-name">
120 <xsl:value-of select="@name"/>
121 </xsl:template>
122
123 <xsl:template match="*[@clr:name]" mode="type-name">
124 <xsl:value-of select="@clr:name"/>
125 </xsl:template>
126
127 <!-- generate members -->
128
129 <xsl:template match="*|text()" mode="members" />
130
131 <xsl:template match="m:primaryKey | m:property | m:thisKey | clr:association" mode="members">
132 <t:trace msg="{name()} {@name}"/>
133 <xsl:apply-templates select="." mode="property"/>
134 </xsl:template>
135
136 <!-- hasA and hasMany doesn't generate members itself, they delegate this work to inner members -->
137 <xsl:template match="m:hasA | m:hasMany" mode="members">
138 <t:trace msg="{name()} {@name}" />
139 <xsl:apply-templates mode="members" />
140 </xsl:template>
141
142 <xsl:template match="m:hasA/clr:lazy" mode="members">
143 <xsl:apply-templates select="." mode="field"/>
144 </xsl:template>
145
146 <!-- member-name -->
147 <xsl:template match="*|text()|@*" mode="member-name" />
148
149 <xsl:template match="*[@name]" mode="member-name">
150 <xsl:value-of select="@name"/>
151 </xsl:template>
152 <xsl:template match="*[@clr:name]" mode="member-name">
153 <xsl:value-of select="@clr:name"/>
154 </xsl:template>
155
156 <!-- member-type -->
157 <xsl:template match="*|text()|@*" mode="member-type" />
158
159 <xsl:template match="*[@type]" mode="member-type">
160 <xsl:call-template name="getClrType">
161 <xsl:with-param name="type" select="@type" />
162 </xsl:call-template>
163 </xsl:template>
164
165 <xsl:template match="*[clr:type]" mode="member-type">
166 <xsl:apply-templates select="clr:type" mode="clr-type" />
167 </xsl:template>
168
169 <!-- member-attributes -->
170 <xsl:template match="*|text()" mode="member-attributes"/>
171
172 <!-- member-extension -->
173 <xsl:template match="*|text()" mode="member-extension"/>
174 <xsl:template match="*" mode="member-extension">
175 <xsl:apply-templates mode="member-extension-comments"/>
176 </xsl:template>
177
178 <xsl:template match="m:hasA/* | m:hasMany/*" mode="member-extension">
179 <xsl:variable name="comments" select="../m:description | m:description"/>
180 <xsl:apply-templates select="$comments[position() = count($comments)]" mode="member-extension-comments"/>
181 </xsl:template>
182
183 <!-- member-extension-comments -->
184 <xsl:template match="*|text()" mode="member-extension-comments"/>
185
186 <xsl:template match="m:description" mode="member-extension-comments">
187 <cs:comments>
188 <xsl:apply-templates mode="comments" />
189 </cs:comments>
190 </xsl:template>
191
192
193
194 <!-- property -->
195
196 <xsl:template match="*" mode="property">
197 <cs:property modifiers="public">
198 <xsl:attribute name="name"><xsl:apply-templates select="." mode="property-name"/></xsl:attribute>
199 <xsl:apply-templates select="." mode="property-type"/>
200 <xsl:apply-templates select="." mode="property-attributes"/>
201 <xsl:apply-templates select="." mode="property-extension" />
202 <xsl:apply-templates select="." mode="property-accessors"/>
203 </cs:property>
204 </xsl:template>
205
206 <!-- property-name -->
207
208 <xsl:template match="m:hasA/clr:association[not(@name|@clr:name)]" mode="property-name">
209 <!-- if the association doesn't define a name, use it from the parent node -->
210 <xsl:apply-templates select=".." mode="property-name"/>
211 </xsl:template>
212 <xsl:template match="m:hasMany/clr:association[not(@name|@clr:name)]" mode="property-name">
213 <!-- if the association doesn't define a name, use it from the parent node -->
214 <xsl:apply-templates select=".." mode="property-name"/>
215 </xsl:template>
216
217 <xsl:template match="*" mode="property-name">
218 <xsl:apply-templates select="." mode="member-name"/>
219 </xsl:template>
220
221 <!-- property-type -->
222 <xsl:template match="m:hasA[@type]/clr:association[not(clr:type)]" mode="property-type">
223 <xsl:apply-templates select=".." mode="property-type"/>
224 </xsl:template>
225
226 <xsl:template match="m:hasMany[@type]/clr:association[not(clr:type)]" mode="property-type">
227 <cs:array>
228 <xsl:apply-templates select=".." mode="property-type"/>
229 </cs:array>
230 </xsl:template>
231
232 <xsl:template match="m:hasA[@type]/m:thisKey" mode="property-type">
233 <xsl:call-template name="getKeyType">
234 <xsl:with-param name="type" select="../@type"/>
235 </xsl:call-template>
236 </xsl:template>
237
238 <xsl:template match="m:hasA[@type and boolean(@optional)]/m:thisKey" mode="property-type">
239 <cs:nullable>
240 <xsl:call-template name="getKeyType">
241 <xsl:with-param name="type" select="../@type"/>
242 </xsl:call-template>
243 </cs:nullable>
244 </xsl:template>
245
246 <xsl:template match="*" mode="property-type">
247 <xsl:apply-templates select="." mode="member-type"/>
248 </xsl:template>
249
250 <!-- property-attributes -->
251 <xsl:template match="m:primaryKey" mode="property-attributes">
252 <cs:attribute>
253 <cs:type name="PrimaryKey" namespace="Linq2Db" />
254 </cs:attribute>
255 </xsl:template>
256
257 <xsl:template match="m:hasA/clr:association" mode="property-attributes">
258 <cs:attribute>
259 <cs:type name="Association" namespace="Linq2Db"/>
260 <cs:parameter name="thisKey">nameof(<xsl:apply-templates select="../m:thisKey" mode="property-name"/>)</cs:parameter>
261 <cs:parameter name="otherKey">nameof(<cs:typeName>
262 <xsl:apply-templates select="." mode="property-type"/>
263 </cs:typeName>.<xsl:call-template name="getKeyName">
264 <xsl:with-param name="type" select="../@type"/>
265 </xsl:call-template>)</cs:parameter>
266 </cs:attribute>
267 </xsl:template>
268
269 <xsl:template match="m:hasMany/clr:association" mode="property-attributes">
270 <cs:attribute>
271 <cs:type name="Association" namespace="Linq2Db"/>
272 <!-- thisKey points to own primaryKey which may be inherited, using getKeyName to address such cases -->
273 <cs:parameter name="thisKey">nameof(<xsl:call-template name="getKeyName">
274 <xsl:with-param name="type" select="../../@name"/>
275 </xsl:call-template>)</cs:parameter>
276 <cs:parameter name="otherKey">nameof(<cs:typeName>
277 <xsl:call-template name="getClrType">
278 <xsl:with-param name="type" select="../@type"/>
279 </xsl:call-template>
280 </cs:typeName>.<xsl:call-template name="getClrPropertyName">
281 <xsl:with-param name="member" select="../m:otherKey/@name"/>
282 <xsl:with-param name="type" select="../@type"/>
283 </xsl:call-template>)</cs:parameter>
284 </cs:attribute>
285 </xsl:template>
286
287 <xsl:template match="*" mode="property-attributes">
288 <xsl:apply-templates select="." mode="member-attributes"/>
289 </xsl:template>
290
291 <!-- property-extension -->
292 <xsl:template match="*" mode="property-extension">
293 <xsl:apply-templates select="." mode="member-extension"/>
294 </xsl:template>
295
296 <!-- property-accessors -->
297 <xsl:template match="*" mode="property-accessors">
298 <cs:get/>
299 <cs:set/>
300 </xsl:template>
301
302 <xsl:template match="m:hasA[clr:lazy]/m:thisKey" mode="property-accessors">
303 <cs:get>
304 <xsl:text>return </xsl:text>
305 <xsl:apply-templates select="../clr:lazy" mode="field-name"/>
306 <xsl:text>.Key;</xsl:text>
307 </cs:get>
308 <cs:set>
309 <xsl:apply-templates select="../clr:lazy" mode="field-name"/>
310 <xsl:text>.Key = value;</xsl:text>
311 </cs:set>
312 </xsl:template>
313
314 <xsl:template match="m:hasA[clr:lazy]/clr:association" mode="property-accessors">
315 <cs:get>
316 <xsl:text>return </xsl:text>
317 <xsl:apply-templates select="../clr:lazy" mode="field-name"/>
318 <xsl:text>.Instance;</xsl:text>
319 </cs:get>
320 <cs:set>
321 <xsl:apply-templates select="../clr:lazy" mode="field-name"/>
322 <xsl:text>.Instance = value;</xsl:text>
323 </cs:set>
324 </xsl:template>
325
326 <!-- fields -->
327 <xsl:template match="*" mode="field">
328 <cs:field>
329 <xsl:attribute name="name"><xsl:apply-templates select="." mode="field-name"/></xsl:attribute>
330 <xsl:apply-templates select="." mode="field-type"/>
331 <xsl:apply-templates select="." mode="field-initializer"/>
332 </cs:field>
333 </xsl:template>
334
335 <!-- field-name -->
336 <xsl:template match="m:hasA/clr:lazy" mode="field-name">
337 <xsl:text>m_lazy</xsl:text>
338 <xsl:apply-templates select=".." mode="property-name"/>
339 </xsl:template>
340
341 <xsl:template match="clr:lazy[@field]" mode="field-name">
342 <xsl:value-of select="@field"/>
343 </xsl:template>
344
345 <xsl:template match="*" mode="field-name">
346 <xsl:apply-templates select="." mode="member-name"/>
347 </xsl:template>
348
349 <!-- field-type -->
350 <xsl:template match="m:hasA[@optional='true']/clr:lazy" mode="field-type">
351 <cs:type name="NullableReference" namespace="Pallada.Data">
352 <xsl:call-template name="getKeyType">
353 <xsl:with-param name="type" select="../@type"/>
354 </xsl:call-template>
355 <xsl:apply-templates select=".." mode="property-type"/>
356 </cs:type>
357 </xsl:template>
358 <xsl:template match="m:hasA[@optional!='true']/clr:lazy" mode="field-type">
359 <cs:type name="Reference" namespace="Pallada.Data">
360 <xsl:apply-templates select="../m:thisKey" mode="property-type"/>
361 <xsl:apply-templates select=".." mode="property-type"/>
362 </cs:type>
363 </xsl:template>
364
365 <xsl:template match="*" mode="field-type">
366 <xsl:apply-templates select="." mode="member-type"/>
367 </xsl:template>
368 <!-- field-initializer -->
369 <xsl:template match="*|text()" mode="field-initializer"/>
370
371 <!-- primary key -->
372
373 <!-- Resolves primaryKey information for the given type name.
374 @returns m:primaryKey node copy with additional attribute
375 @declaringType which points to the type where this primaryKey
376 was defined.
377 -->
378 <xsl:template name="getKey">
379 <xsl:param name="type" />
380 <xsl:for-each select="exsl:node-set($fragment)">
381 <xsl:apply-templates select="key('type', $type)"
382 mode="resolvePK" />
383 </xsl:for-each>
384 </xsl:template>
385
386 <!-- -->
387 <xsl:template name="getKeyType">
388 <xsl:param name="type" />
389 <xsl:variable name="otherKey">
390 <xsl:call-template name="getKey">
391 <xsl:with-param name="type" select="$type" />
392 </xsl:call-template>
393 </xsl:variable>
394 <xsl:apply-templates select="exsl:node-set($otherKey)/m:primaryKey" mode="property-type"/>
395 </xsl:template>
396
397 <xsl:template name="getKeyName">
398 <xsl:param name="type" />
399 <xsl:variable name="otherKey">
400 <xsl:call-template name="getKey">
401 <xsl:with-param name="type" select="$type" />
402 </xsl:call-template>
403 </xsl:variable>
404 <xsl:apply-templates select="exsl:node-set($otherKey)/m:primaryKey" mode="property-name"/>
405 </xsl:template>
406
407 <!-- internal. applied to the entity with a primaryKey node -->
408 <xsl:template match="m:entity[m:primaryKey]" mode="resolvePK">
409 <xsl:apply-templates select="m:primaryKey" mode="resolvePK" />
410 </xsl:template>
411
412 <!--
413 This template formats the result of 'resolvePk' template,
414 override this template to extend returned metadata, beware that
415 other templates rely on the resulting format of this template.
416 -->
417 <xsl:template match="m:primaryKey" mode="resolvePK">
418 <xsl:copy>
419 <xsl:copy-of select="@*" />
420 <xsl:attribute name="declaringType"><xsl:value-of select="../@name" /></xsl:attribute>
421 <xsl:copy-of select="*" />
422 </xsl:copy>
423 </xsl:template>
424
425 <!-- internal, used to traverse the hierarchy -->
426 <xsl:template match="m:entity" mode="resolvePK">
427 <xsl:apply-templates select="m:extends" mode="resolvePK" />
428 </xsl:template>
429
430 <!-- internal, used to traverse the hierarchy -->
431 <xsl:template match="m:extends" mode="resolvePK">
432 <xsl:apply-templates select="key('type', @type)"
433 mode="resolvePK" />
434 </xsl:template>
435
436 <!-- resolves CLR type for the given type -->
437 <xsl:template name="getClrType">
438 <xsl:param name="type" />
439 <xsl:param name="typeArgs" select="/.." />
440 <!-- <t:trace msg="resolveClrType {$type}"/> -->
441 <xsl:for-each select="exsl:node-set($fragment)">
442 <xsl:apply-templates select="key('type', $type)"
443 mode="clr-type">
444 <xsl:with-param name="typeArgs" select="$typeArgs"/>
445 </xsl:apply-templates>
446 </xsl:for-each>
447 </xsl:template>
448
449 <!-- CLR type construction -->
450 <xsl:template match="*" mode="clr-type" />
451
452 <xsl:template match="m:type[clr:type]" mode="clr-type">
453 <xsl:param name="typeArgs" select="clr:type/*" />
454 <xsl:apply-templates select="clr:type" mode="clr-type">
455 <xsl:with-param name="typeArgs" select="$typeArgs" />
456 </xsl:apply-templates>
457 </xsl:template>
458
459 <xsl:template match="m:entity" mode="clr-type">
460 <cs:type name="{@clr:name | @name[not(../@clr:name)]}" namespace="{ancestor::*[@clr:namespace]/@clr:namespace}" />
461 </xsl:template>
462
463 <xsl:template match="clr:type" mode="clr-type">
464 <xsl:apply-templates mode="clr-type"/>
465 </xsl:template>
466
467 <xsl:template match="clr:type[@ref]" mode="clr-type">
468 <xsl:param name="typeArgs" select="*" />
469 <xsl:call-template name="getClrType">
470 <xsl:with-param name="type" select="@ref" />
471 <xsl:with-param name="typeArgs" select="$typeArgs" />
472 </xsl:call-template>
473 </xsl:template>
474
475 <xsl:template match="clr:type[@cs:name or @name]" mode="clr-type">
476 <xsl:param name="typeArgs" select="*" />
477 <xsl:variable name="ns"
478 select="@cs:namespace | @namespace[not(../@cs:namespace)]" />
479 <cs:type name="{@cs:name | @name[not(../@cs:name)]}">
480 <xsl:if test="$ns">
481 <xsl:attribute name="namespace"><xsl:value-of select="$ns" /></xsl:attribute>
482 </xsl:if>
483 <xsl:copy-of select="@struct"/>
484
485 <xsl:apply-templates select="$typeArgs | *[not($typeArgs)]"
486 mode="clr-type" />
487 </cs:type>
488 </xsl:template>
489
490 <xsl:template match="clr:arrayOf[@type]" mode="clr-type">
491 <xsl:param name="typeArgs" select="*" />
492 <cs:array>
493 <xsl:call-template name="getClrType">
494 <xsl:with-param name="type" select="@type" />
495 <xsl:with-param name="typeArgs" select="$typeArgs" />
496 </xsl:call-template>
497 </cs:array>
498 </xsl:template>
499
500 <xsl:template match="clr:arrayOf[@cs:name or @name]" mode="clr-type">
501 <xsl:param name="typeArgs" select="*" />
502 <xsl:variable name="ns"
503 select="@cs:namespace | @namespace[not(../@cs:namespace)]" />
504 <cs:array>
505 <cs:type name="{@cs:name | @name[not(../@cs:name)]}">
506 <xsl:if test="$ns">
507 <xsl:attribute name="namespace"><xsl:value-of
508 select="$ns" /></xsl:attribute>
509 </xsl:if>
510 <xsl:apply-templates select="$typeArgs | *[not($typeArgs)]"
511 mode="clr-type" />
512 </cs:type>
513 </cs:array>
514 </xsl:template>
515
516 <!-- member resolution traits -->
517
518 <!-- lookups for the specified member for the specified type
519 and returns the CLR property name -->
520 <xsl:template name="getClrPropertyName">
521 <xsl:param name="type"/>
522 <xsl:param name="member"/>
523 <trace msg="getClrPropertyName {$type}.{$member}"/>
524 <xsl:for-each select="exsl:node-set($fragment)">
525 <xsl:apply-templates select="key('type', $type)"
526 mode="member-lookup">
527 <xsl:with-param name="member" select="$member"/>
528 </xsl:apply-templates>
529 </xsl:for-each>
530 </xsl:template>
531
532 <xsl:template match="*" mode="member-lookup"/>
533
534 <xsl:template match="m:entity" mode="member-lookup">
535 <xsl:param name="member"/>
536 <xsl:variable name="match" select="*[@name=$member]"/>
537 <xsl:choose>
538 <xsl:when test="$match">
539 <xsl:apply-templates select="$match" mode="member-lookup"/>
540 </xsl:when>
541 <xsl:when test="m:extends">
542 <xsl:call-template name="getClrPropertyName">
543 <xsl:with-param name="type" select="m:extends/@type"/>
544 <xsl:with-param name="member" select="$member"/>
545 </xsl:call-template>
546 </xsl:when>
547 </xsl:choose>
548 </xsl:template>
549
550 <xsl:template match="m:property | m:primaryKey" mode="member-lookup">
551 <xsl:apply-templates select="." mode="property-name" />
552 </xsl:template>
553
554 <xsl:template match="m:hasA" mode="member-lookup">
555 <xsl:apply-templates select="m:thisKey" mode="property-name"/>
556 </xsl:template>
557
558 </xsl:stylesheet>