first stab at an XSLT to convert the xml fieldmapper config into a pile of javascript
[OpenSRF.git] / examples / fieldmapper2javascript.xsl
1 <xsl:stylesheet
2         version='1.0'
3         xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
4         xmlns:opensrf="http://opensrf.org/xmlns/opensrf"
5         xmlns:cdbi="http://opensrf.org/xmlns/opensrf/cdbi"
6         xmlns:perl="http://opensrf.org/xmlns/opensrf/perl"
7         xmlns:javascript="http://opensrf.org/xmlns/opensrf/javascript"
8         xmlns:c="http://opensrf.org/xmlns/opensrf/c">
9         <xsl:output method="text" />
10         <xsl:strip-space elements="xsl:*"/>
11         <xsl:variable name="last_field_pos"/>
12
13         <xsl:template match="/">
14 // support functions
15  
16 var IE = false;
17 var unit_test = false;
18  
19 function instanceOf(object, constructorFunction) {
20         if(!IE) {
21                 while (object != null) {
22                         if (object == constructorFunction.prototype)
23                                 return true;
24                         object = object.__proto__;
25                 }
26         } else {
27                 while(object != null) {
28                         if( object instanceof constructorFunction )
29                                 return true;
30                         object = object.__proto__;
31                 }
32         }
33         return false;
34 }
35  
36 // Top level superclass
37 function Fieldmapper(array) {
38         this.array = [];
39         if(array) {
40                 if (array.constructor == Array) {
41                         this.array = array;
42                 } else if ( instanceOf( array, String ) || instanceOf( array, Number ) ) {
43
44                         var obj = null;
45                         if (this.cacheable) {
46                                 try {
47                                         obj = this.baseClass.obj_cache[this.classname][array];
48                                 } catch (E) {};
49                         }
50
51                         if (!obj) {
52                                 obj = user_request(
53                                         'open-ils.proxy',
54                                         'open-ils.proxy.proxy',
55                                         [
56                                                 mw.G.auth_ses[0],
57                                                 'open-ils.storage',
58                                                 'open-ils.storage.direct.' + this.db_type + '.retrieve',
59                                                 array
60                                         ]
61                                 )[0];
62
63                                 if (this.cacheable) {
64                                         if (this.baseClass.obj_cache[this.classname] == null)
65                                                 this.baseClass.obj_cache[this.classname] = {};
66
67                                         this.baseClass.obj_cache[this.classname][obj.id()] = obj;
68                                 }
69                         }
70                         this.array = obj.array;
71
72                 } else {
73                         throw new FieldmapperException( "Attempt to build fieldmapper object with something wierd");
74                 }
75         }
76 }
77 Fieldmapper.prototype.baseClass = Fieldmapper;
78 Fieldmapper.prototype.obj_cache = {};
79  
80 Fieldmapper.prototype.clone = function() {
81         var obj = new this.constructor();
82
83         for( var i in this.array ) {
84                 var thing = this.array[i];
85                 if(thing == null) continue;
86
87                 if( thing._isfieldmapper ) {
88                         obj.array[i] = thing.clone();
89                 } else {
90
91                         if(instanceOf(thing, Array)) {
92                                 obj.array[i] = new Array();
93
94                                 for( var j in thing ) {
95
96                                         if( thing[j]._isfieldmapper )
97                                                 obj.array[i][j] = thing[j].clone();
98                                         else
99                                                 obj.array[i][j] = thing[j];
100                                 }
101                         } else {
102                                 obj.array[i] = thing;
103                         }
104                 }
105         }
106         return obj;
107 }
108   
109 function FieldmapperException(message) {
110         this.message = message;
111 }
112
113 FieldmapperException.toString = function() {
114         return "FieldmapperException: " + this.message + "\n";
115
116 }
117
118         
119                 <xsl:apply-templates select="opensrf:fieldmapper/opensrf:classes"/>
120         </xsl:template>
121
122
123
124
125
126 <!-- sub-templates -->
127         <xsl:template match="opensrf:fieldmapper/opensrf:classes">
128                 <xsl:for-each select="opensrf:class">
129                         <xsl:apply-templates select="."/>
130                 </xsl:for-each>
131         </xsl:template>
132
133
134
135
136         <xsl:template match="opensrf:class">
137                 <xsl:apply-templates select="@javascript:class"/>
138                 <xsl:apply-templates select="opensrf:fields"/>
139                 <xsl:apply-templates select="opensrf:links/opensrf:link[@cdbi:type='has_many']"/>
140         </xsl:template>
141
142
143
144
145         <xsl:template match="opensrf:fields">
146                 <xsl:apply-templates select="opensrf:field"/>
147         </xsl:template>
148
149
150
151
152         <xsl:template match="opensrf:links/opensrf:link[@cdbi:type='has_many']">
153                 <xsl:variable name="num"><xsl:number/></xsl:variable>
154                 <xsl:variable name="source"><xsl:value-of select="@source"/></xsl:variable>
155                 <xsl:variable name="classname"><xsl:value-of select="../../@javascript:class"/></xsl:variable>
156
157 // accessor for <xsl:value-of select="$classname"/>:
158 <xsl:value-of select="$classname"/>.prototype.<xsl:value-of select="@field"/> = function () {
159  
160         var _pos = <xsl:value-of select="$classname"/>.last_real_field + <xsl:value-of select="$num"/>;
161  
162         if (!instanceOf(this.array[_pos], Array)) {
163                 this.array[_pos] = [];
164  
165         if (this.array[_pos].length == 0) {
166                 /* get the real thing.
167                  * search where <xsl:value-of select="$source"/>.<xsl:value-of select="//*[@id=$source]/opensrf:links/opensrf:link[@cdbi:type='has_a' and @source=$classname]/@field"/>()
168                  * equals this.<xsl:value-of select="../../opensrf:fields/opensrf:field[@cdbi:primary='true']/@name"/>();
169                  */
170         }
171  
172         return this.array[_pos];
173 }
174
175         </xsl:template>
176
177
178
179
180
181         <xsl:template match="@javascript:class">
182
183 // Class definition for "<xsl:value-of select="."/>"
184
185 function <xsl:value-of select="."/> (array) {
186
187         if (!instanceOf(this, <xsl:value-of select="."/>))
188                 return new <xsl:value-of select="."/>(array);
189
190         this.baseClass.call(this,array);
191         this.classname = "<xsl:value-of select="."/>";
192         this._isfieldmapper = true;
193         this.uber = <xsl:value-of select="."/>.baseClass.prototype;
194 }
195
196 <xsl:value-of select="."/>.prototype                    = new Fieldmapper();
197 <xsl:value-of select="."/>.prototype.constructor        = <xsl:value-of select="."/>;
198 <xsl:value-of select="."/>.baseClass                    = Fieldmapper;
199 <xsl:value-of select="."/>.prototype.cachable           = true;
200 <xsl:value-of select="."/>.prototype.fields             = [];
201 <xsl:value-of select="."/>.last_real_field              = 2;
202  
203 <!-- XXX This needs to come from somewhere else!!!! -->
204 <xsl:value-of select="."/>.prototype.db_type            = "<xsl:value-of select="../cdbi:table[@rdbms='Pg']/cdbi:name"/>";
205  
206 <xsl:value-of select="."/>.prototype.isnew = function(new_value) {
207         if(arguments.length == 1) { this.array[0] = new_value; }
208         return this.array[0];
209 }
210  
211 <xsl:value-of select="."/>.prototype.ischanged = function(new_value) {
212         if(arguments.length == 1) { this.array[1] = new_value; }
213         return this.array[1];
214 }
215  
216 <xsl:value-of select="."/>.prototype.isdeleted = function(new_value) {
217         if(arguments.length == 1) { this.array[2] = new_value; }
218         return this.array[2];
219 }
220  
221         </xsl:template>
222
223
224
225
226
227         <xsl:template match="opensrf:field">
228
229                 <xsl:variable name="num"><xsl:number/></xsl:variable>
230                 <xsl:variable name="field_pos" select="$num + 2"/>
231                 <xsl:variable name="last_field_pos" select="$field_pos + 1"/>
232                 <xsl:variable name="field_name" select="@name"/>
233
234 // Accessor/mutator for <xsl:value-of select="../../@javascript:class"/>.<xsl:value-of select="$field_name"/>:
235 <xsl:value-of select="../../@javascript:class"/>.last_real_field++;
236 <xsl:value-of select="../../@javascript:class"/>.prototype.fields.push("<xsl:value-of select="$field_name"/>");
237 <xsl:value-of select="../../@javascript:class"/>.prototype.<xsl:value-of select="$field_name"/> = function (new_value) {
238
239                 <xsl:choose>
240                         <xsl:when test="../../opensrf:links/opensrf:link[@field=$field_name and @cdbi:type='has_a']">
241                                 <xsl:variable
242                                         name="source"
243                                         select="../../opensrf:links/opensrf:link[@field=$field_name and @cdbi:type='has_a']/@source"/>
244
245         if(arguments.length == 1) { this.array[<xsl:value-of select="$field_pos"/>] = new_value; }
246         var val = this.array[<xsl:value-of select="$field_pos"/>];
247
248         if (!instanceOf(this.array[<xsl:value-of select="$field_pos"/>], <xsl:value-of select="$source"/>)) {
249                 if (this.array[<xsl:value-of select="$field_pos"/>] != null) {
250                         this.array[<xsl:value-of select="$field_pos"/>] = new <xsl:value-of select="$source"/>(val);
251                 }
252         }
253
254         return this.array[<xsl:value-of select="$field_pos"/>];
255                         </xsl:when>
256
257                         <xsl:otherwise>
258         if(arguments.length == 1) { this.array[<xsl:value-of select="$field_pos"/>] = new_value; }
259         return this.array[<xsl:value-of select="$field_pos"/>];
260                         </xsl:otherwise>
261                 </xsl:choose>
262 }
263         </xsl:template>
264
265 </xsl:stylesheet>
266