Project

Profile

Help

How to connect?
Download (29.8 KB) Statistics
| Branch: | Tag: | Revision:

he / tools / dotnet / merge.xsl @ 5d25f10d

1
<xsl:stylesheet version="3.0" 
2
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
4
   xmlns:f="http://local-functions/"
5
   xmlns:map="http://www.w3.org/2005/xpath-functions/map"
6
   xmlns:functx="http://www.functx.com"
7
   exclude-result-prefixes="xs f map functx">
8
  
9
  <xsl:output method="xml" indent="yes"/>
10
  
11
  <xsl:param name="names-file" select="'names.xml'"/>
12
  <xsl:param name="api-doc-file" select="'apidoc.xml'"/>
13
  
14
  <xsl:variable name="names-doc" select="doc($names-file)"/> 
15
  <xsl:variable name="api-doc" select="doc($api-doc-file)"/>
16
  
17
  <xsl:key name="class-by-name" match="class | interface | enum" 
18
    use="if (contains(@name,'.')) then tokenize(@name, '\.')[last()] else @name"/>
19
  
20
  <xsl:template name="main">
21
    <xsl:apply-templates select="$names-doc/package"/>
22
  </xsl:template>
23
  
24
  <xsl:template match="package">
25
    <xsl:copy>
26
      <xsl:copy-of select="@*"/>
27
      <xsl:apply-templates select="*"/>
28
    </xsl:copy>
29
  </xsl:template>
30
  
31
  <!-- Do not include internal classes, interfaces, or enums -->
32
  <xsl:template match="(class|interface|enum)[@internal='true']"/>
33
  
34
  <!-- class, interface, enum all begin 'T:' (enum followed by 'F:' classes) -->
35

    
36
  <xsl:template match="class | interface | enum">
37
    <xsl:param name="process-nested-class" select="false()"/>
38
    
39
    <!-- Generic class e.g. Feature<T> corresponding apiclass name is 
40
      T:Saxon.Api.Feature`1 -->
41
    <!-- Generic method e.g. SetProperty<T> corresponding apiclass name is 
42
      M:Saxon.Api.Processor.SetProperty``1(Saxon.Api.Feature{``0},``0) -->
43
    
44
    <xsl:variable name="shortname" select="@name"/>
45
    <xsl:variable name="apiclass" select="$api-doc//member[starts-with(@name, 'T:') and
46
      ((tokenize(@name, '\.')[last()] eq $shortname)
47
      or (substring-before(tokenize(@name, '\.')[last()], '`') eq $shortname))]"/>
48
    <!--<xsl:message>processing class <xsl:value-of select="$apiclass/@name, $shortname"/></xsl:message>-->
49
    <xsl:if test="empty($apiclass)">
50
      <xsl:message>--- Missing documentation for <xsl:value-of select="$shortname"/></xsl:message>
51
    </xsl:if>
52
    <xsl:if test="self::interface[empty(*)]">
53
      <xsl:message>---- <xsl:value-of select="@name"/> interface has no methods or properties;
54
        the cs code lines should begin '/**public**/' so that they are included</xsl:message>
55
    </xsl:if>
56
    
57
    
58
    <xsl:variable name="fullname" select="substring-after($apiclass/@name, ':')"/>
59
    <xsl:variable name="fullname" select="if (contains($fullname,'`')) then
60
      substring-before($fullname, '`') else $fullname"/>
61
    <xsl:variable name="nestedname" select="substring-after($fullname, 'Saxon.Api.')"/>
62
    <xsl:variable name="is-nested" select="not($shortname eq $nestedname)"/>
63
    <!--<xsl:if test="$is-nested">
64
      <xsl:message>nested class <xsl:value-of select="$nestedname, $shortname"/> 
65
        process nested class <xsl:value-of select="$process-nested-class"/></xsl:message>
66
    </xsl:if>-->
67
    
68
    <!-- Check that $api-doc contains comments for all fields, constructors, properties, and methods -->
69
    <xsl:variable name="field-count" select="count($api-doc//member[starts-with(@name, concat('F:Saxon.Api.',
70
      $nestedname, '.')) or starts-with(@name, concat('F:Saxon.Api.', $nestedname, '`'))])"/>
71
    <xsl:if test="count(field[@public ne 'false']) - $field-count gt 0">
72
      <xsl:message>Missing <xsl:value-of 
73
        select="count(field[@public ne 'false']) - $field-count"/> field comments in <xsl:value-of 
74
          select="@name"/></xsl:message>
75
    </xsl:if>
76
    
77
    <xsl:variable name="constructor-count" select="count($api-doc//member[starts-with(@name, concat('M:Saxon.Api.',
78
      $nestedname, '.')) and contains(@name, '.#ctor')])"/>
79
    <xsl:if test="count(constructor[@public ne 'false']) - $constructor-count gt 0">
80
      <xsl:message>Missing <xsl:value-of 
81
        select="count(constructor[@public ne 'false']) - $constructor-count"/> constructor comments in <xsl:value-of 
82
          select="@name"/></xsl:message>
83
    </xsl:if>
84
    
85
    <xsl:variable name="property-count" select="count($api-doc//member[starts-with(@name, concat('P:Saxon.Api.', 
86
      $nestedname, '.')) or starts-with(@name, concat('P:Saxon.Api.', $nestedname, '`'))])"/>
87
    <xsl:if test="count(property[@public ne 'false']) - $property-count gt 0">
88
      <xsl:message>Missing <xsl:value-of 
89
        select="count(property[@public ne 'false']) - $property-count"/> property comments in <xsl:value-of 
90
          select="@name"/></xsl:message>
91
    </xsl:if>
92
    
93
    <xsl:variable name="method-count" select="count($api-doc//member[(starts-with(@name, concat('M:Saxon.Api.',
94
      $nestedname, '.')) or starts-with(@name, concat('M:Saxon.Api.', $nestedname, '`'))) 
95
      and not(contains(@name, '.#ctor'))])"/>
96
    <xsl:if test="count(method[@public ne 'false']) - $method-count gt 0">
97
      <xsl:message>Missing <xsl:value-of 
98
        select="count(method[@public ne 'false']) - $method-count"/> method comments in <xsl:value-of 
99
          select="@name"/></xsl:message>
100
    </xsl:if>
101
    
102
    <xsl:variable name="apisubclasses" select="$api-doc//member[starts-with(@name, concat('T:',
103
      $fullname, '.'))]"/>
104
    <xsl:variable name="has-subclasses" select="exists($apisubclasses)"/>
105
    <!--<xsl:if test="$has-subclasses">
106
      <xsl:message>subclasses of <xsl:value-of select="$fullname"/> : <xsl:value-of
107
        select="$apisubclasses/@name"/></xsl:message>
108
    </xsl:if>-->
109
    
110
    <xsl:if test="not($is-nested) or $process-nested-class">
111
      <xsl:copy>
112
        <xsl:copy-of select="@* except (@base|@name)"/>
113
        <xsl:attribute name="name" select="if ($process-nested-class) then $nestedname else @name"/>
114
        <xsl:attribute name="fulltype" select="$fullname"/>
115
        <xsl:if test="@base">
116
          <xsl:variable name="superclasses" select="tokenize(@base, ', ', 'q')"/>
117
          <!-- For generic superclasses, can just remove type parameters in @base -->
118
          <xsl:variable name="superclassesMain" select="$superclasses!(if (contains(., '&lt;')) then (substring-before(.,
119
            '&lt;')) else .)"/>
120
          <xsl:attribute name="base" select="string-join($superclassesMain!f:getKnownFullType(.), ', ')"/>
121
          <!-- If $base is a class, then this is a subclass which extends the base class; 
122
                if $base is an interface, then this is a class which implements the base interface. -->
123
          <xsl:call-template name="process-base">
124
            <xsl:with-param name="derived-class" select="." as="element()" tunnel="yes"/>
125
            <xsl:with-param name="base-attr-value" select="string(@base)"/>
126
          </xsl:call-template>
127
        </xsl:if>
128
        <xsl:apply-templates select="type"/><!-- for classes and interfaces which are generic types -->
129
        <comments>
130
          <xsl:variable name="obsolete" select="reverse(preceding-sibling::*)[1]/self::obsolete"/>
131
          <xsl:apply-templates select="$obsolete" mode="comment"/>
132
          <xsl:apply-templates select="$apiclass/*" mode="comment"/>
133
        </comments>
134
        <xsl:apply-templates select="*[not(@public='false')] except (type)"/><!-- Go process methods etc. -->
135
        <xsl:if test="self::enum">
136
          <xsl:variable name="fields" select="$api-doc//member[starts-with(@name, concat('F:', $fullname, '.'))]"/>
137
          <xsl:for-each select="$fields">
138
            <field name="{tokenize(@name, '\.')[last()]}"
139
              public="true">
140
              <comments>
141
                <xsl:apply-templates select="*" mode="comment"/>
142
              </comments>
143
            </field>
144
          </xsl:for-each>
145
        </xsl:if>
146
        
147
        <!-- If class has nested subclasses, process them now. -->
148
        <xsl:if test="$has-subclasses">
149
          <xsl:variable name="subclass-shortnames" select="$apisubclasses/@name/tokenize(., '\.')[last()]"/>
150
          <xsl:apply-templates select="//class[@name = $subclass-shortnames]">
151
            <xsl:with-param name="process-nested-class" select="true()"/>
152
          </xsl:apply-templates>
153
        </xsl:if>
154
      </xsl:copy>
155
    </xsl:if>
156
    
157
  </xsl:template>
158
  
159
  <xsl:template name="process-base">
160
    <xsl:param name="derived-class" as="element()" tunnel="yes"/>
161
    <xsl:param name="base-attr-value" as="xs:string"/>
162
    <xsl:variable name="superclasses" select="tokenize($base-attr-value, ', ', 'q')"/>
163
    
164
    <!--<xsl:message>process-base of <xsl:value-of select="$derived-class/@name"/>: <xsl:value-of
165
      select="$base-attr-value"/></xsl:message>-->
166
    
167
    <xsl:call-template name="base-class">
168
      <xsl:with-param name="superclasses" select="$superclasses"/>
169
    </xsl:call-template>
170
    <xsl:call-template name="base-interfaces">
171
      <xsl:with-param name="superclasses" select="$superclasses"/>
172
    </xsl:call-template>
173
    
174
  </xsl:template>
175
  
176
  <xsl:template name="base-class">
177
    <xsl:param name="derived-class" as="element()" tunnel="yes"/>
178
    <xsl:param name="superclasses" as="xs:string*"/>
179
    <xsl:variable name="bClass" as="element(interface)*">
180
      <xsl:for-each select="$superclasses">
181
        <xsl:variable name="superclass" select="if (contains(., '&lt;')) then substring-before(., '&lt;') else ."/>
182
        <xsl:variable name="basei" select="key('class-by-name', $superclass, $names-doc)"/>
183
        <xsl:choose>
184
          <xsl:when test="$superclass = $knownInterfaces"/>
185
          <xsl:when test="$superclass = 'object'"/><!-- Don't include extends child if the base is 'System.Object' -->
186
          <xsl:when test="exists($basei) and (local-name($basei) ne 'interface')">
187
            <xsl:sequence select="f:getBase(., f:saxonFullName($basei), $basei)"/>
188
          </xsl:when>
189
          <xsl:when test="empty($basei)">
190
            <!-- If non-local super is not known to be an interface, then assume it is a class.
191
                  ($knownInterfaces must be maintained.) -->
192
            <xsl:if test="contains($superclass, '.')">
193
              <xsl:message>-- Unhandled nested superclass: <xsl:value-of select="$superclass"/></xsl:message>
194
            </xsl:if>
195
            <xsl:variable name="knownType" select="f:getKnownFullType($superclass)"/>
196
            <xsl:sequence select="f:getBase(., $knownType, ())"/>
197
          </xsl:when>
198
        </xsl:choose>
199
      </xsl:for-each>
200
    </xsl:variable>
201
    <xsl:if test="count($bClass) gt 1">
202
      <!-- Only really possible to extend one class. Warning means $knownInterfaces may need updating. -->
203
      <xsl:message>Warning: update $knownInterfaces. Class with multiple base classes - <xsl:value-of select="$derived-class/@name"/></xsl:message>
204
    </xsl:if>
205
    <xsl:if test="exists($bClass)">
206
      <extends>
207
        <xsl:sequence select="$bClass"/>
208
      </extends>
209
    </xsl:if>
210
  </xsl:template>
211
  
212
  <xsl:template name="base-interfaces">
213
    <xsl:param name="superclasses" as="xs:string*"/>
214
    <xsl:variable name="bInterfaces" as="element(interface)*">
215
      <xsl:for-each select="$superclasses">
216
        <xsl:variable name="superclass" select="if (contains(., '&lt;')) then substring-before(., '&lt;') else ."/>
217
        <xsl:variable name="basei" select="key('class-by-name', $superclass, $names-doc)"/>
218
        <xsl:choose>
219
          <xsl:when test="exists($basei) and (local-name($basei) eq 'interface')">
220
            <xsl:sequence select="f:getBase(., f:saxonFullName($basei), $basei)"/>
221
          </xsl:when>
222
          <xsl:when test="$superclass = $knownInterfaces">
223
            <xsl:variable name="base-is-nested" select="contains($superclass, '.')"/>
224
            <xsl:variable name="base-top-class" select="if ($base-is-nested) then
225
              substring-before($superclass, '.') else $superclass"/>
226
            <xsl:variable name="nested-name" select="if ($base-is-nested) then substring-after($superclass,
227
              $base-top-class) else ''"/>
228
            <xsl:variable name="knownType" select="f:getKnownFullType($base-top-class)"/>
229
            <xsl:sequence select="f:getBase(., concat($knownType, $nested-name), ())"/>
230
          </xsl:when>
231
          <!-- Otherwise the superclass is assumed to be a class not an interface; and processed by base-class. -->
232
        </xsl:choose>
233
      </xsl:for-each>
234
    </xsl:variable>
235
    <xsl:if test="exists($bInterfaces)">
236
      <implements>
237
        <xsl:sequence select="$bInterfaces"/>
238
      </implements>
239
    </xsl:if>
240
  </xsl:template>
241
  
242
  <xsl:function name="f:getBase" as="element(interface)">
243
    <xsl:param name="superclass" as="xs:string"/>
244
    <xsl:param name="fulltype" as="xs:string"/>
245
    <xsl:param name="base" as="element()?"/>
246
    <interface type="{$fulltype}">
247
      <!-- Iterate to construct full type hierarchy -->
248
      <xsl:if test="exists($base) and $base/@base">
249
        <xsl:call-template name="process-base">
250
          <xsl:with-param name="derived-class" select="$base" as="element()" tunnel="yes"/>
251
          <xsl:with-param name="base-attr-value" select="string($base/@base)"/>
252
        </xsl:call-template>
253
      </xsl:if>
254
      <xsl:if test="contains($superclass, '&lt;')">
255
        <!-- Cannot just copy $basei/type directly, as type parameters may be different 
256
            (e.g. when base interface has covariant type parameter) -->
257
        <xsl:variable name="typeParams"  as="xs:string*"
258
          select="substring-after($superclass, '&lt;') => substring-before('&gt;') => tokenize(',', 'q')"/>
259
        <xsl:for-each select="$typeParams">
260
          <type type="{.}"/>
261
        </xsl:for-each>
262
      </xsl:if>
263
    </interface>
264
  </xsl:function>
265
  
266
  <xsl:function name="f:getTypeParamTypes" as="element(type)*">
267
    <xsl:param name="typeParamString" as="xs:string"/>
268
    <xsl:variable name="typeParams"  as="xs:string*"
269
      select="substring-after($typeParamString, '&lt;') => substring-before('&gt;') => tokenize(',', 'q')"/>
270
    <xsl:for-each select="$typeParams">
271
      <type type="{.}"/>
272
    </xsl:for-each>
273
  </xsl:function>
274

    
275
  <xsl:template match="constructor">
276
    <!--<xsl:message>processing <xsl:value-of select="@name"/> : with param <xsl:value-of
277
    select="param/@name"/></xsl:message>-->
278
    <xsl:copy>
279
      <xsl:copy-of select="@* except @type"/>
280
      <xsl:variable name="position" select="count(preceding-sibling::constructor[@public='true'])+1"/>
281
      <xsl:variable name="apimember" select="$api-doc//member[starts-with(@name, 'M:Saxon.Api.') and
282
        contains(@name, concat(current()/@name,'.#ctor'))][$position]"/>
283
      <!--<xsl:message>position <xsl:value-of select="$position"/></xsl:message>
284
      <xsl:message>apimember <xsl:value-of select="$apimember/@name"/> : with param <xsl:value-of
285
        select="param/@name"/></xsl:message>-->
286
      <xsl:if test="empty($apimember)">
287
        <xsl:message>*** apimember not found for <xsl:value-of select="@name"/> constructor</xsl:message>
288
      </xsl:if>
289
      <xsl:sequence select="f:extract-params($apimember/@name)"/>
290
      <xsl:if test="count(f:extract-params($apimember/@name)) = 0">
291
        <xsl:sequence select="f:params-from-names-doc(param)"/>
292
      </xsl:if>
293
      <comments>
294
        <xsl:variable name="obsolete" select="reverse(preceding-sibling::*)[1]/self::obsolete"/>
295
        <xsl:apply-templates select="$obsolete" mode="comment"/>
296
        <xsl:apply-templates select="$apimember/*" mode="comment"/>
297
      </comments>
298
    </xsl:copy>
299
  </xsl:template>
300
  
301
  <xsl:template match="node()|@*" mode="comment">
302
    <xsl:copy>
303
      <xsl:apply-templates mode="comment" select="node()|@*"/>
304
    </xsl:copy>
305
  </xsl:template>
306
  
307
  <xsl:template match="exception" mode="comment">
308
    <xsl:copy>
309
      <xsl:attribute name="name" select="if (@name) then @name else (substring-after(@cref,':'))"/>
310
      <xsl:apply-templates mode="comment"/>
311
    </xsl:copy>
312
  </xsl:template>
313
  
314
  <xsl:template match="see" mode="comment">
315
    <xsl:variable name="cref" select="substring-after(@cref,':')"/>
316
    
317
    <xsl:variable name="preArgs" select="if (contains($cref,'(')) then substring-before($cref,'(') else $cref"/>
318
    <xsl:variable name="args" select="substring-before(substring-after($cref,'('), ')')"/>
319
    
320
    <!-- Handle generics: if class contains '{ ... }' then chop out this part -->
321
    <xsl:variable name="preArgs" select="if (contains($preArgs,'{')) then 
322
      concat(substring-before($preArgs,'{'), substring-after($preArgs,'}')) else $preArgs"/>
323
    
324
    <!-- First convert separator '.' to '#' for methods, properties, etc on Class -->
325
    <xsl:variable name="class" as="xs:string">
326
      <xsl:choose>
327
        <xsl:when test="starts-with($preArgs, 'Saxon.Api.')">
328
          <xsl:value-of select="concat('Saxon.Api.', translate(substring-after($preArgs, 'Saxon.Api.'), '.', '#'))"/>
329
        </xsl:when>
330
        <xsl:otherwise>
331
          <xsl:value-of select="$preArgs"/>
332
        </xsl:otherwise>
333
      </xsl:choose>
334
    </xsl:variable>
335
    
336
    <xsl:variable name="argStr" as="xs:string">
337
      <!-- For methods with arguments, remove all package names (not just 'Saxon.Api.') for arg types.
338
          Otherwise fully qualified names appear in documentation app unnecessarily. 
339
          Also, for arguments of generic type, drop type parameters i.e. {...} -->
340
      <!-- e.g. for Saxon.Api.Xslt30Transformer.SetInitialTemplateParameters
341
            (System.Collections.Generic.Dictionary{Saxon.Api.QName,Saxon.Api.XdmValue},System.Boolean) 
342
            $argStr becomes (Dictionary,Boolean) -->
343
      <xsl:variable name="argsMain" as="xs:string">
344
        <xsl:choose>
345
          <xsl:when test="contains($args, '{')">
346
            <xsl:variable name="main-args" as="xs:string*">
347
              <xsl:analyze-string select="$args" regex="{'\{.*\}'}">
348
                <xsl:non-matching-substring>
349
                  <xsl:value-of select="."/>
350
                </xsl:non-matching-substring>
351
              </xsl:analyze-string>
352
            </xsl:variable>
353
            <xsl:value-of select="string-join($main-args)"/>
354
          </xsl:when>
355
          <xsl:otherwise>
356
            <xsl:value-of select="$args"/>
357
          </xsl:otherwise>
358
        </xsl:choose>
359
      </xsl:variable>
360
      
361
      <xsl:choose>
362
        <xsl:when test="$argsMain ne ''">
363
          <xsl:variable name="argLocal" select="tokenize($argsMain, ',', 'q')!(tokenize(., '.', 'q')[last()])" as="xs:string*"/>
364
          <xsl:value-of select="concat('(', string-join($argLocal, ','), ')')"/>
365
        </xsl:when>
366
        <xsl:otherwise>
367
          <xsl:value-of select="''"/>
368
        </xsl:otherwise>
369
      </xsl:choose>
370
    </xsl:variable>
371
    
372
    <!-- Second convert separator '+' to '.' for nested classes -->
373
    <tag kind="see">
374
      <xsl:value-of select="concat(translate($class, '+', '.'), $argStr)"/>
375
    </tag>
376
    
377
  </xsl:template>
378
  
379
  <xsl:function name="functx:substring-before-if-contains" as="xs:string?"
380
    xmlns:functx="http://www.functx.com">
381
    <xsl:param name="arg" as="xs:string?"/>
382
    <xsl:param name="delim" as="xs:string"/>
383
    
384
    <xsl:sequence select="
385
      if (contains($arg,$delim))
386
      then substring-before($arg,$delim)
387
      else $arg
388
      "/>
389
    
390
  </xsl:function>
391

    
392
  <xsl:template match="method">
393
    <xsl:copy>
394
      <xsl:copy-of select="@* except @type"/>
395
      <xsl:if test="@type">
396
        <xsl:attribute name="type" select="f:getKnownFullType(@type)"/>
397
      </xsl:if>
398
      <xsl:apply-templates select="type"/><!-- for methods which return generic types -->
399
      <xsl:apply-templates select="paramtypes"/><!-- for generic methods -->
400
      <xsl:variable name="position" select="count(preceding-sibling::method[@public='true' and @name=current()/@name])+1"/>
401
      <xsl:variable name="apimember" select="$api-doc//member[starts-with(@name,'M:Saxon.Api.') and 
402
        (
403
        ends-with(functx:substring-before-if-contains(@name, '('), concat(current()/../@name, '.', current()/@name)) or 
404
        (contains(functx:substring-before-if-contains(@name, '('), concat(current()/../@name, '`')) and
405
        ends-with(functx:substring-before-if-contains(@name, '('), concat('.', current()/@name))) or
406
        contains(functx:substring-before-if-contains(@name, '('), concat(current()/../@name,  '.',
407
        current()/@name, '`'))
408
        )][$position]"/>
409
      
410
      <xsl:if test="empty($apimember)">
411
        <xsl:message>*** apimember not found for <xsl:value-of select="../@name"/>.<xsl:value-of select="@name"/></xsl:message>
412
      </xsl:if>
413
      
414
      <!-- Usually get params from apidoc.xml - in this case all types have been fully resolved.
415
          When there are parameters with generic types, or this is a generic method, or generic class,
416
          it is easier to get the parameters from names.xml, than try to extract them from apidoc.xml.
417
          Types of parameters will be resolved in the next step of the pipeline as required.
418
          For generic methods, the information in apidoc.xml may not be good enough for
419
          parameters with types which use the method's type parameters
420
          e.g. "M:Saxon.Api.Processor.SetProperty``1(Saxon.Api.Feature{``0},``0)"
421
          or for methods of classes of generic type, with parameters with types which use the
422
          class's type parameters e.g. "M:Saxon.Api.Predicate`1.matches(`0)" -->
423
      <xsl:variable name="is-generic-method" select="exists(paramtypes)"/>
424
      <xsl:variable name="apidoc-params" select="f:extract-params($apimember/@name)"/>
425
      <xsl:sequence select="if ($is-generic-method or count($apidoc-params) = 0) 
426
        then f:params-from-names-doc(param) else $apidoc-params"/>
427
      <comments>
428
        <xsl:variable name="obsolete" select="reverse(preceding-sibling::*)[1]/self::obsolete"/>
429
        <xsl:apply-templates select="$obsolete" mode="comment"/>
430
        <xsl:apply-templates select="$apimember/*" mode="comment"/>
431
      </comments>
432
    </xsl:copy>
433
  </xsl:template>   
434

    
435
  <xsl:template match="property">
436
    <xsl:copy>
437
      <xsl:copy-of select="@* except @type"/>
438
      <xsl:if test="@type">
439
        <xsl:attribute name="type" select="f:getKnownFullType(@type)"/>
440
      </xsl:if>
441
      <xsl:variable name="position" select="count(preceding-sibling::property[@name=current()/@name])+1"/>
442
      <xsl:variable name="apimember" select="$api-doc//member[starts-with(@name,'P:Saxon.Api.') and 
443
        (ends-with(@name, concat(current()/../@name, '.', current()/@name)) or 
444
        (contains(@name, concat(current()/../@name, '`')) and ends-with(@name, concat('.', current()/@name))))][$position]"/>
445
      <xsl:if test="empty($apimember)">
446
        <xsl:message>*** apimember not found for <xsl:value-of select="../@name"/>.<xsl:value-of select="@name"/></xsl:message>
447
      </xsl:if>
448
      <xsl:if test="subsequence(following-sibling::*, 1, 2)/self::get">
449
        <xsl:attribute name="get">true</xsl:attribute>
450
      </xsl:if>
451
      <xsl:if test="subsequence(following-sibling::*, 1, 2)/self::set">
452
        <xsl:attribute name="set">true</xsl:attribute>
453
      </xsl:if>
454
      <xsl:apply-templates select="type"/><!-- for properties which are generic types -->
455
      <comments>
456
        <xsl:variable name="obsolete" select="reverse(preceding-sibling::*)[1]/self::obsolete"/>
457
        <xsl:apply-templates select="$obsolete" mode="comment"/>
458
        <xsl:apply-templates select="$apimember/*" mode="comment"/>
459
      </comments>
460
    </xsl:copy>
461
  </xsl:template>
462
  
463
  <xsl:template match="field">
464
    <xsl:copy>
465
      <xsl:copy-of select="@* except @type"/>
466
      <xsl:if test="@type">
467
        <xsl:attribute name="type" select="f:getKnownFullType(@type)"/>
468
      </xsl:if>
469
      <xsl:apply-templates select="type"/><!-- for fields which are generic types -->
470
      <xsl:variable name="apimember" select="$api-doc//member[starts-with(@name,'F:Saxon.Api.') and 
471
        (ends-with(@name, concat(current()/../@name, '.', current()/@name)) or 
472
        (contains(@name, concat(current()/../@name, '`')) and ends-with(@name, concat('.', current()/@name))))]"/>
473
      <xsl:if test="empty($apimember)">
474
        <xsl:message>*** apimember not found for <xsl:value-of select="../@name"/>.<xsl:value-of select="@name"/></xsl:message>
475
      </xsl:if>
476
      <comments>
477
        <xsl:variable name="obsolete" select="reverse(preceding-sibling::*)[1]/self::obsolete"/>
478
        <xsl:apply-templates select="$obsolete" mode="comment"/>
479
        <xsl:apply-templates select="$apimember/*" mode="comment"/>
480
      </comments>
481
    </xsl:copy>
482
  </xsl:template>
483
  
484
  <xsl:template match="using"/> 
485
  
486
  <xsl:template match="get|set"/> 
487
  
488
  <xsl:template match="obsolete"/>
489
  
490
  <xsl:template match="paramtypes">
491
    <xsl:copy-of select="."/>
492
  </xsl:template>
493
  
494
  <xsl:template match="type">
495
    <xsl:copy>
496
      <xsl:copy-of select="@* except @type"/>
497
      <xsl:if test="@type">
498
        <xsl:attribute name="type" select="f:getKnownFullType(@type)"/>
499
      </xsl:if>
500
    </xsl:copy>
501
  </xsl:template>
502
  
503
  <xsl:template match="*">
504
    <xsl:message>*** No template found for <xsl:value-of select="name()"/></xsl:message>
505
  </xsl:template>
506
  
507
  <!-- If apidoc.xml does not have (good enough) param information, then get it from names.xml -->
508
  <xsl:function name="f:params-from-names-doc" as="element()*">
509
    <xsl:param name="params" as="element()*"/>
510
    <xsl:for-each select="$params">
511
      <xsl:copy>
512
        <xsl:copy-of select="@* except @type"/>
513
        <xsl:if test="@type">
514
          <xsl:attribute name="type" select="f:getKnownFullType(@type)"/>
515
        </xsl:if>
516
        <xsl:apply-templates select="type"/><!-- for parameters which are generic types -->
517
      </xsl:copy>
518
    </xsl:for-each>
519
  </xsl:function>
520

    
521
  <xsl:function name="f:extract-params" as="element()*">
522
    <!-- Returns empty sequence if this is a generic method, or any params have generic type (i.e.
523
      $in contains '{'), or any param is the generic param of the class (e.g. M:Saxon.Api.Predicate`1.matches(`0)) -->
524
    <xsl:param name="in" as="xs:string?"/>
525
    <xsl:variable name="paramTypes" select="substring-after($in, '(') => substring-before(')') => tokenize(',')"/>
526
    <!--<xsl:if test="exists($paramTypes[not(matches(., '[A-Za-z]'))])">
527
      <xsl:message>$paramTypes[not(matches(., '[A-Za-z]'))] <xsl:value-of select="$paramTypes[not(matches(., '[A-Za-z]'))]"/></xsl:message>
528
      <xsl:message>$in <xsl:value-of select="$in"/></xsl:message>
529
    </xsl:if>-->
530
    <!--<xsl:if test="contains($in, '(') and contains($in, '{')">
531
      <xsl:message>f:extract-params $in contains { <xsl:value-of select="$in"/></xsl:message>
532
    </xsl:if>-->
533
    <xsl:if test="contains($in, '(') and not(contains($in, '{')) and empty($paramTypes[not(matches(., '[A-Za-z]'))])">
534
      <xsl:for-each select="$paramTypes">
535
        <param type="{f:getKnownFullType(.)}"/>
536
      </xsl:for-each>
537
    </xsl:if>
538
  </xsl:function>
539
  
540
  <!-- Get the full type name for classes, interfaces, and enums in the Saxon.Api namespace.
541
      Note that this also works for nested classes (i.e. don't just prepend 'Saxon.Api'). -->
542
  <xsl:function name="f:saxonFullName" as="xs:string">
543
    <xsl:param name="class" as="element()"/><!-- class, interface, or enum element from names.xml -->
544
    <xsl:variable name="shortname" select="$class/@name"/>
545
    <xsl:variable name="apiclass" select="$api-doc//member[starts-with(@name, 'T:') and
546
      ((tokenize(@name, '\.')[last()] eq $shortname)
547
      or (substring-before(tokenize(@name, '\.')[last()], '`') eq $shortname))]"/>
548
    <!--<xsl:message>processing class <xsl:value-of select="$apiclass/@name, $shortname"/></xsl:message>-->
549
    <xsl:variable name="fullname" select="substring-after($apiclass/@name, ':')"/>
550
    <xsl:variable name="fullname" select="if (contains($fullname,'`')) then
551
      substring-before($fullname, '`') else $fullname"/>
552
    <xsl:sequence select="$fullname"/>
553
  </xsl:function>
554
  
555
  <xsl:key name="known-classes" match="using" use="@class"/>
556
  
557
  <!-- Resolve types for known Java types (as obtained from 'using' elements in names.xml), 
558
    and known .NET System types (maintained in $knownSystemClassesMap).
559
    Note that the types for Saxon.Api members are not resolved (use f:saxonFullName instead).
560
    Check the names.xml document 'using' elements for full type names from aliases (e.g. 'J' names); 
561
    be careful for lists (i.e. when the type ends with '[]') -->
562
  <xsl:function name="f:getKnownFullType" as="xs:string">
563
    <xsl:param name="in" as="xs:string"/><!-- $in might already be full type -->
564
    <xsl:variable name="in2" select="normalize-space($in)"/>
565
    <xsl:variable name="is-list" select="contains($in2, '[]')"/>
566
    <xsl:variable name="in3" select="if ($is-list) then translate($in2, '[]', '') else $in2"/>
567
    <xsl:variable name="known-class" select="key('known-classes', $in3, $names-doc)"/>
568
    <xsl:variable name="out" select="if ($known-class) then
569
      string($known-class/@fulltype) else if (map:contains($knownSystemClassesMap, $in3)) then
570
      map:get($knownSystemClassesMap, $in3) else $in3"/>
571
    <xsl:sequence select="if ($is-list) then concat($out,'[]') else $out"/>
572
  </xsl:function>
573
  
574
  <!-- Types which are known to be interfaces, rather than classes -->
575
  <xsl:variable name="knownInterfaces" select="('IEnumerable', 'JInvalidityHandler', 'JConfiguration.ApiProvider')"/>
576
  
577
  <!-- Resolve all known System types. Map from short name to resolved type. 
578
      This map requires maintenance. -->
579
  <xsl:variable name="knownSystemClassesMap" as="map(xs:string,xs:string)"
580
    select="map{
581
    'bool':'System.Boolean',
582
    'char':'System.Char',
583
    'decimal':'System.Decimal',
584
    'double':'System.Double',
585
    'float':'System.Single',
586
    'int':'System.Int32',
587
    'long':'System.Int64',
588
    'object':'System.Object',
589
    'string':'System.String',
590
    'ArgumentException':'System.ArgumentException',
591
    'Boolean':'System.Boolean',
592
    'Char':'System.Char',
593
    'Decimal':'System.Decimal',
594
    'Double':'System.Double',
595
    'Exception':'System.Exception',
596
    'Object':'System.Object',
597
    'String':'System.String',
598
    'Uri':'System.Uri',
599
    'DictionaryEntry':'System.Collections.DictionaryEntry',
600
    'ICollection':'System.Collections.ICollection',
601
    'IEnumerator':'System.Collections.IEnumerator',
602
    'IEnumerable':'System.Collections.IEnumerable',
603
    'IList':'System.Collections.IList',
604
    'Dictionary':'System.Collections.Generic.Dictionary',
605
    'HashSet':'System.Collections.Generic.HashSet',
606
    'List':'System.Collections.Generic.List',
607
    'XmlDocument':'System.Xml.XmlDocument',
608
    'XmlNode':'System.Xml.XmlNode',
609
    'XmlNodeType':'System.Xml.XmlNodeType',
610
    'XmlQualifiedName':'System.Xml.XmlQualifiedName',
611
    'XmlResolver':'System.Xml.XmlResolver',
612
    'TextWriter':'System.IO.TextWriter'
613
    }"/>
614
  
615
  
616
    
617
</xsl:stylesheet>  
618
 
(2-2/7)