Project

General

Profile

Download (94 KB) Statistics
| Branch: | Tag: | Revision:
1
<!--
2

    
3
 ********************************
4
 The FunctX XSLT Function Library
5
 ********************************
6

    
7
 Copyright (C) 2007 Datypic
8

    
9
 This library is free software; you can redistribute it and/or
10
 modify it under the terms of the GNU Lesser General Public
11
 License as published by the Free Software Foundation; either
12
 version 2.1 of the License.
13

    
14
 This library is distributed in the hope that it will be useful,
15
 but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 Lesser General Public License for more details.
18

    
19
 You should have received a copy of the GNU Lesser General Public
20
 License along with this library; if not, write to the Free Software
21
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22

    
23
 For more information on the FunctX XSLT library, contact contrib@functx.com.
24

    
25
 @version 1.0
26
 @see     http://www.xsltfunctions.com
27
-->
28
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dxmlf="http://www.datypic.com/xmlf" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:local="http://www.datypic.com/local" xmlns:functx="http://www.functx.com" exclude-result-prefixes="dxmlf xs" version="2.0">
29
 
30
<!--
31
  Adds attributes to XML elements 
32

    
33
 @author  Priscilla Walmsley, Datypic 
34
 @version 1.0 
35
 @see     http://www.xsltfunctions.com/xsl/functx_add-attributes.html 
36
 @param   $elements the element(s) to which you wish to add the attribute 
37
 @param   $attrNames the name(s) of the attribute(s) to add 
38
 @param   $attrValues the value(s) of the attribute(s) to add 
39
--> 
40
<xsl:function name="functx:add-attributes" as="element()?" xmlns:functx="http://www.functx.com">
41
  <xsl:param name="elements" as="element()*"/> 
42
  <xsl:param name="attrNames" as="xs:QName*"/> 
43
  <xsl:param name="attrValues" as="xs:anyAtomicType*"/> 
44
 
45
  <xsl:for-each select="$elements">
46
    <xsl:variable name="element" select="."/>
47
    <xsl:copy>
48
      <xsl:for-each select="$attrNames">
49
        <xsl:variable name="seq" select="position()"/>
50
        <xsl:if test="not($element/@*[node-name(.) = current()])">
51
          <xsl:attribute name="{.}" namespace="{namespace-uri-from-QName(.)}" select="$attrValues[$seq]"/>
52
        </xsl:if>
53
      </xsl:for-each>
54
      <xsl:copy-of select="@*|node()"/>
55
    </xsl:copy>
56
  </xsl:for-each>
57
 
58
</xsl:function>
59

    
60

    
61
<!--
62
  Adds months to a date 
63

    
64
 @author  Priscilla Walmsley, Datypic 
65
 @version 1.0 
66
 @see     http://www.xsltfunctions.com/xsl/functx_add-months.html 
67
 @param   $date the date 
68
 @param   $months the number of months to add 
69
--> 
70
<xsl:function name="functx:add-months" as="xs:date?" xmlns:functx="http://www.functx.com">
71
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
72
  <xsl:param name="months" as="xs:integer"/> 
73
 
74
  <xsl:sequence select="     xs:date($date) + functx:yearMonthDuration(0,$months)  "/>
75
   
76
</xsl:function>
77

    
78

    
79
<!--
80
  Adds attributes to XML elements 
81

    
82
 @author  Priscilla Walmsley, Datypic 
83
 @version 1.0 
84
 @see     http://www.xsltfunctions.com/xsl/functx_add-or-update-attributes.html 
85
 @param   $elements the element(s) to which you wish to add the attribute 
86
 @param   $attrNames the name(s) of the attribute(s) to add 
87
 @param   $attrValues the value(s) of the attribute(s) to add 
88
--> 
89
<xsl:function name="functx:add-or-update-attributes" as="element()?" xmlns:functx="http://www.functx.com">
90
  <xsl:param name="elements" as="element()*"/> 
91
  <xsl:param name="attrNames" as="xs:QName*"/> 
92
  <xsl:param name="attrValues" as="xs:anyAtomicType*"/> 
93
 
94
  <xsl:for-each select="$elements">
95
    <xsl:copy>
96
      <xsl:for-each select="$attrNames">
97
        <xsl:variable name="seq" select="position()"/>
98
        <xsl:attribute name="{.}" namespace="{namespace-uri-from-QName(.)}" select="$attrValues[$seq]"/>
99
      </xsl:for-each>
100
      <xsl:copy-of select="@*[not(node-name(.) = $attrNames)]|node()"/>
101
    </xsl:copy>
102
  </xsl:for-each>
103
 
104
</xsl:function>
105

    
106

    
107
<!--
108
  Whether a value is all whitespace or a zero-length string 
109

    
110
 @author  Priscilla Walmsley, Datypic 
111
 @version 1.0 
112
 @see     http://www.xsltfunctions.com/xsl/functx_all-whitespace.html 
113
 @param   $arg the string (or node) to test 
114
--> 
115
<xsl:function name="functx:all-whitespace" as="xs:boolean" xmlns:functx="http://www.functx.com">
116
  <xsl:param name="arg" as="xs:string?"/> 
117
 
118
  <xsl:sequence select="     normalize-space($arg) = ''  "/>
119
   
120
</xsl:function>
121

    
122

    
123
<!--
124
  Whether all the values in a sequence are distinct 
125

    
126
 @author  Priscilla Walmsley, Datypic 
127
 @version 1.0 
128
 @see     http://www.xsltfunctions.com/xsl/functx_are-distinct-values.html 
129
 @param   $seq the sequence of values 
130
--> 
131
<xsl:function name="functx:are-distinct-values" as="xs:boolean" xmlns:functx="http://www.functx.com">
132
  <xsl:param name="seq" as="xs:anyAtomicType*"/> 
133
 
134
  <xsl:sequence select="     count(distinct-values($seq)) = count($seq)  "/>
135
   
136
</xsl:function>
137

    
138

    
139
<!--
140
  The built-in type of an atomic value 
141

    
142
 @author  Priscilla Walmsley, Datypic 
143
 @version 1.0 
144
 @see     http://www.xsltfunctions.com/xsl/functx_atomic-type.html 
145
 @param   $values the value(s) whose type you want to determine 
146
--> 
147
<xsl:function name="functx:atomic-type" as="xs:string*" xmlns:functx="http://www.functx.com">
148
  <xsl:param name="values" as="xs:anyAtomicType*"/> 
149
 
150
  <xsl:sequence select="   for $val in $values  return  (if ($val instance of xs:untypedAtomic) then 'xs:untypedAtomic'  else if ($val instance of xs:anyURI) then 'xs:anyURI'  else if ($val instance of xs:string) then 'xs:string'  else if ($val instance of xs:QName) then 'xs:QName'  else if ($val instance of xs:boolean) then 'xs:boolean'  else if ($val instance of xs:base64Binary) then 'xs:base64Binary'  else if ($val instance of xs:hexBinary) then 'xs:hexBinary'  else if ($val instance of xs:integer) then 'xs:integer'  else if ($val instance of xs:decimal) then 'xs:decimal'  else if ($val instance of xs:float) then 'xs:float'  else if ($val instance of xs:double) then 'xs:double'  else if ($val instance of xs:date) then 'xs:date'  else if ($val instance of xs:time) then 'xs:time'  else if ($val instance of xs:dateTime) then 'xs:dateTime'  else if ($val instance of xs:dayTimeDuration)          then 'xs:dayTimeDuration'  else if ($val instance of xs:yearMonthDuration)          then 'xs:yearMonthDuration'  else if ($val instance of xs:duration) then 'xs:duration'  else if ($val instance of xs:gMonth) then 'xs:gMonth'  else if ($val instance of xs:gYear) then 'xs:gYear'  else if ($val instance of xs:gYearMonth) then 'xs:gYearMonth'  else if ($val instance of xs:gDay) then 'xs:gDay'  else if ($val instance of xs:gMonthDay) then 'xs:gMonthDay'  else 'unknown')  "/>
151
   
152
</xsl:function>
153

    
154

    
155
<!--
156
  The average, counting "empty" values as zero 
157

    
158
 @author  Priscilla Walmsley, Datypic 
159
 @version 1.0 
160
 @see     http://www.xsltfunctions.com/xsl/functx_avg-empty-is-zero.html 
161
 @param   $values the values to be averaged 
162
 @param   $allNodes the sequence of all nodes to find the average over 
163
--> 
164
<xsl:function name="functx:avg-empty-is-zero" as="xs:double" xmlns:functx="http://www.functx.com">
165
  <xsl:param name="values" as="xs:anyAtomicType*"/> 
166
  <xsl:param name="allNodes" as="node()*"/> 
167
 
168
  <xsl:sequence select="     if (empty($allNodes))    then 0    else sum($values[string(.) != '']) div count($allNodes)  "/>
169
   
170
</xsl:function>
171

    
172

    
173
<!--
174
  Whether a value is between two provided values 
175

    
176
 @author  Priscilla Walmsley, Datypic 
177
 @version 1.0 
178
 @see     http://www.xsltfunctions.com/xsl/functx_between-exclusive.html 
179
 @param   $value the value to be tested 
180
 @param   $minValue the minimum value 
181
 @param   $maxValue the maximum value 
182
--> 
183
<xsl:function name="functx:between-exclusive" as="xs:boolean" xmlns:functx="http://www.functx.com">
184
  <xsl:param name="value" as="xs:anyAtomicType?"/> 
185
  <xsl:param name="minValue" as="xs:anyAtomicType"/> 
186
  <xsl:param name="maxValue" as="xs:anyAtomicType"/> 
187
 
188
  <xsl:sequence select="     $value &gt; $minValue and $value &lt; $maxValue  "/>
189
   
190
</xsl:function>
191

    
192

    
193
<!--
194
  Whether a value is between two provided values, or equal to one of them 
195

    
196
 @author  Priscilla Walmsley, Datypic 
197
 @version 1.0 
198
 @see     http://www.xsltfunctions.com/xsl/functx_between-inclusive.html 
199
 @param   $value the value to be tested 
200
 @param   $minValue the minimum value 
201
 @param   $maxValue the maximum value 
202
--> 
203
<xsl:function name="functx:between-inclusive" as="xs:boolean" xmlns:functx="http://www.functx.com">
204
  <xsl:param name="value" as="xs:anyAtomicType?"/> 
205
  <xsl:param name="minValue" as="xs:anyAtomicType"/> 
206
  <xsl:param name="maxValue" as="xs:anyAtomicType"/> 
207
 
208
  <xsl:sequence select="     $value &gt;= $minValue and $value &lt;= $maxValue  "/>
209
   
210
</xsl:function>
211

    
212

    
213
<!--
214
  Turns a camelCase string into space-separated words 
215

    
216
 @author  Priscilla Walmsley, Datypic 
217
 @version 1.0 
218
 @see     http://www.xsltfunctions.com/xsl/functx_camel-case-to-words.html 
219
 @param   $arg the string to modify 
220
 @param   $delim the delimiter for the words (e.g. a space) 
221
--> 
222
<xsl:function name="functx:camel-case-to-words" as="xs:string" xmlns:functx="http://www.functx.com">
223
  <xsl:param name="arg" as="xs:string?"/> 
224
  <xsl:param name="delim" as="xs:string"/> 
225
 
226
  <xsl:sequence select="     concat(substring($arg,1,1),              replace(substring($arg,2),'(\p{Lu})',                         concat($delim, '$1')))  "/>
227
   
228
</xsl:function>
229

    
230

    
231
<!--
232
  Capitalizes the first character of a string 
233

    
234
 @author  Priscilla Walmsley, Datypic 
235
 @version 1.0 
236
 @see     http://www.xsltfunctions.com/xsl/functx_capitalize-first.html 
237
 @param   $arg the word or phrase to capitalize 
238
--> 
239
<xsl:function name="functx:capitalize-first" as="xs:string?" xmlns:functx="http://www.functx.com">
240
  <xsl:param name="arg" as="xs:string?"/> 
241
 
242
  <xsl:sequence select="     concat(upper-case(substring($arg,1,1)),              substring($arg,2))  "/>
243
   
244
</xsl:function>
245

    
246

    
247
<!--
248
  Changes the names of elements in an XML fragment 
249

    
250
 @author  Priscilla Walmsley, Datypic 
251
 @version 1.0 
252
 @see     http://www.xsltfunctions.com/xsl/functx_change-element-names-deep.html 
253
 @param   $nodes the element(s) to change 
254
 @param   $oldNames the sequence of names to change from 
255
 @param   $newNames the sequence of names to change to 
256
--> 
257
<xsl:function name="functx:change-element-names-deep" as="node()*" xmlns:functx="http://www.functx.com">
258
  <xsl:param name="nodes" as="node()*"/> 
259
  <xsl:param name="oldNames" as="xs:QName*"/> 
260
  <xsl:param name="newNames" as="xs:QName*"/> 
261
 
262
  <xsl:if test="count($oldNames) != count($newNames)">
263
    <xsl:sequence select="error(          xs:QName('functx:Different_number_of_names'))"/>
264
  </xsl:if>
265
  <xsl:for-each select="$nodes">
266
    <xsl:variable name="node" select="."/>
267
    <xsl:choose>
268
      <xsl:when test="$node instance of element()">
269
        <xsl:variable name="theName" select="functx:if-empty                     ($newNames[index-of($oldNames, node-name($node))],                      node-name($node))"/>
270
        <xsl:element name="{$theName}" namespace="{namespace-uri-from-QName($theName)}">
271
           <xsl:sequence select="($node/@*,                   functx:change-element-names-deep($node/node(),                                            $oldNames, $newNames))"/>
272
        </xsl:element>
273
      </xsl:when>
274
      <xsl:when test="$node instance of document-node()">
275
        <xsl:document>
276
           <xsl:sequence select="functx:change-element-names-deep(                 $node/node(), $oldNames, $newNames)"/>
277
        </xsl:document>
278
      </xsl:when>
279
      <xsl:otherwise>
280
        <xsl:sequence select="$node"/>
281
      </xsl:otherwise>
282
    </xsl:choose>
283
  </xsl:for-each>
284
 
285
</xsl:function>
286

    
287

    
288
<!--
289
  Changes the namespace of XML elements and its descendants 
290

    
291
 @author  Priscilla Walmsley, Datypic 
292
 @version 1.0 
293
 @see     http://www.xsltfunctions.com/xsl/functx_change-element-ns-deep.html 
294
 @param   $nodes the nodes to change 
295
 @param   $newns the new namespace 
296
 @param   $prefix the prefix to use for the new namespace 
297
--> 
298
<xsl:function name="functx:change-element-ns-deep" as="node()*" xmlns:functx="http://www.functx.com">
299
  <xsl:param name="nodes" as="node()*"/> 
300
  <xsl:param name="newns" as="xs:string"/> 
301
  <xsl:param name="prefix" as="xs:string"/> 
302
 
303
  <xsl:for-each select="$nodes">
304
    <xsl:variable name="node" select="."/>
305
    <xsl:choose>
306
      <xsl:when test="$node instance of element()">
307
        <xsl:element name="{concat($prefix,                                     if ($prefix = '')                                     then ''                                     else ':',                                     local-name($node))}" namespace="{$newns}">
308
          <xsl:sequence select="($node/@*,                 functx:change-element-ns-deep($node/node(),                                            $newns, $prefix))"/>
309
        </xsl:element>
310
      </xsl:when>
311
      <xsl:when test="$node instance of document-node()">
312
        <xsl:document>
313
          <xsl:sequence select="functx:change-element-ns-deep(                 $node/node(), $newns, $prefix)"/>
314
        </xsl:document>
315
      </xsl:when>
316
      <xsl:otherwise>
317
        <xsl:sequence select="$node"/>
318
      </xsl:otherwise>
319
   </xsl:choose>
320
  </xsl:for-each>
321
 
322
</xsl:function>
323

    
324

    
325
<!--
326
  Changes the namespace of XML elements 
327

    
328
 @author  Priscilla Walmsley, Datypic 
329
 @version 1.0 
330
 @see     http://www.xsltfunctions.com/xsl/functx_change-element-ns.html 
331
 @param   $elements the elements to change 
332
 @param   $newns the new namespace 
333
 @param   $prefix the prefix to use for the new namespace 
334
--> 
335
<xsl:function name="functx:change-element-ns" as="element()?" xmlns:functx="http://www.functx.com">
336
  <xsl:param name="elements" as="element()*"/> 
337
  <xsl:param name="newns" as="xs:string"/> 
338
  <xsl:param name="prefix" as="xs:string"/> 
339
 
340
   <xsl:for-each select="$elements">
341
     <xsl:variable name="element" select="."/>
342
     <xsl:element name="{concat($prefix,                                     if ($prefix = '')                                     then ''                                     else ':',                                     local-name($element))}" namespace="{$newns}">
343
       <xsl:sequence select="$element/@*, $element/node()"/>
344
     </xsl:element>
345
   </xsl:for-each>
346
 
347
</xsl:function>
348

    
349

    
350
<!--
351
  Converts a string to a sequence of characters 
352

    
353
 @author  Priscilla Walmsley, Datypic 
354
 @version 1.0 
355
 @see     http://www.xsltfunctions.com/xsl/functx_chars.html 
356
 @param   $arg the string to split 
357
--> 
358
<xsl:function name="functx:chars" as="xs:string*" xmlns:functx="http://www.functx.com">
359
  <xsl:param name="arg" as="xs:string?"/> 
360
 
361
  <xsl:sequence select="     for $ch in string-to-codepoints($arg)    return codepoints-to-string($ch)  "/>
362
   
363
</xsl:function>
364

    
365

    
366
<!--
367
  Whether a string contains any of a sequence of strings 
368

    
369
 @author  Priscilla Walmsley, Datypic 
370
 @version 1.0 
371
 @see     http://www.xsltfunctions.com/xsl/functx_contains-any-of.html 
372
 @param   $arg the string to test 
373
 @param   $searchStrings the strings to look for 
374
--> 
375
<xsl:function name="functx:contains-any-of" as="xs:boolean" xmlns:functx="http://www.functx.com">
376
  <xsl:param name="arg" as="xs:string?"/> 
377
  <xsl:param name="searchStrings" as="xs:string*"/> 
378
 
379
  <xsl:sequence select="     some $searchString in $searchStrings    satisfies contains($arg,$searchString)  "/>
380
   
381
</xsl:function>
382

    
383

    
384
<!--
385
  Whether one string contains another, without regard to case 
386

    
387
 @author  Priscilla Walmsley, Datypic 
388
 @version 1.0 
389
 @see     http://www.xsltfunctions.com/xsl/functx_contains-case-insensitive.html 
390
 @param   $arg the string to search 
391
 @param   $substring the substring to find 
392
--> 
393
<xsl:function name="functx:contains-case-insensitive" as="xs:boolean?" xmlns:functx="http://www.functx.com">
394
  <xsl:param name="arg" as="xs:string?"/> 
395
  <xsl:param name="substring" as="xs:string"/> 
396
 
397
  <xsl:sequence select="     contains(upper-case($arg), upper-case($substring))  "/>
398
   
399
</xsl:function>
400

    
401

    
402
<!--
403
  Whether one string contains another, as a separate word 
404

    
405
 @author  Priscilla Walmsley, Datypic 
406
 @version 1.0 
407
 @see     http://www.xsltfunctions.com/xsl/functx_contains-word.html 
408
 @param   $arg the string to search 
409
 @param   $word the word to find 
410
--> 
411
<xsl:function name="functx:contains-word" as="xs:boolean" xmlns:functx="http://www.functx.com">
412
  <xsl:param name="arg" as="xs:string?"/> 
413
  <xsl:param name="word" as="xs:string"/> 
414
 
415
  <xsl:sequence select="     matches(upper-case($arg),            concat('^(.*\W)?',                      upper-case(functx:escape-for-regex($word)),                      '(\W.*)?$'))  "/>
416
   
417
</xsl:function>
418

    
419

    
420
<!--
421
  Copies attributes from one element to another 
422

    
423
 @author  Priscilla Walmsley, Datypic 
424
 @version 1.0 
425
 @see     http://www.xsltfunctions.com/xsl/functx_copy-attributes.html 
426
 @param   $copyTo the element to copy attributes to 
427
 @param   $copyFrom the element to copy attributes from 
428
--> 
429
<xsl:function name="functx:copy-attributes" as="element()" xmlns:functx="http://www.functx.com">
430
  <xsl:param name="copyTo" as="element()"/> 
431
  <xsl:param name="copyFrom" as="element()"/> 
432
 
433
  <xsl:element name="{node-name($copyTo)}">
434
    <xsl:sequence select="        ($copyTo/@*[not(node-name(.) = $copyFrom/@*/node-name(.))],         $copyFrom/@*,         $copyTo/node())"/>
435
  </xsl:element>
436
 
437
</xsl:function>
438

    
439

    
440
<!--
441
  Construct a date from a year, month and day 
442

    
443
 @author  Priscilla Walmsley, Datypic 
444
 @version 1.0 
445
 @see     http://www.xsltfunctions.com/xsl/functx_date.html 
446
 @param   $year the year 
447
 @param   $month the month 
448
 @param   $day the day 
449
--> 
450
<xsl:function name="functx:date" as="xs:date" xmlns:functx="http://www.functx.com">
451
  <xsl:param name="year" as="xs:anyAtomicType"/> 
452
  <xsl:param name="month" as="xs:anyAtomicType"/> 
453
  <xsl:param name="day" as="xs:anyAtomicType"/> 
454
 
455
  <xsl:sequence select="     xs:date(      concat(        functx:pad-integer-to-length(xs:integer($year),4),'-',        functx:pad-integer-to-length(xs:integer($month),2),'-',        functx:pad-integer-to-length(xs:integer($day),2)))  "/>
456
   
457
</xsl:function>
458

    
459

    
460
<!--
461
  Construct a date/time from individual components 
462

    
463
 @author  Priscilla Walmsley, Datypic 
464
 @version 1.0 
465
 @see     http://www.xsltfunctions.com/xsl/functx_datetime.html 
466
 @param   $year the year 
467
 @param   $month the month 
468
 @param   $day the day 
469
 @param   $hour the hour 
470
 @param   $minute the minute 
471
 @param   $second the second 
472
--> 
473
<xsl:function name="functx:dateTime" as="xs:dateTime" xmlns:functx="http://www.functx.com">
474
  <xsl:param name="year" as="xs:anyAtomicType"/> 
475
  <xsl:param name="month" as="xs:anyAtomicType"/> 
476
  <xsl:param name="day" as="xs:anyAtomicType"/> 
477
  <xsl:param name="hour" as="xs:anyAtomicType"/> 
478
  <xsl:param name="minute" as="xs:anyAtomicType"/> 
479
  <xsl:param name="second" as="xs:anyAtomicType"/> 
480
 
481
  <xsl:sequence select="     xs:dateTime(      concat(functx:date($year,$month,$day),'T',              functx:time($hour,$minute,$second)))  "/>
482
   
483
</xsl:function>
484

    
485

    
486
<!--
487
  The day of the year (a number between 1 and 366) 
488

    
489
 @author  Priscilla Walmsley, Datypic 
490
 @version 1.0 
491
 @see     http://www.xsltfunctions.com/xsl/functx_day-in-year.html 
492
 @param   $date the date 
493
--> 
494
<xsl:function name="functx:day-in-year" as="xs:integer?" xmlns:functx="http://www.functx.com">
495
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
496
 
497
  <xsl:sequence select="    days-from-duration(       xs:date($date) - functx:first-day-of-year($date)) + 1  "/>
498
   
499
</xsl:function>
500

    
501

    
502
<!--
503
  The abbreviated day of the week, from a date, in English 
504

    
505
 @author  Priscilla Walmsley, Datypic 
506
 @version 1.0 
507
 @see     http://www.xsltfunctions.com/xsl/functx_day-of-week-abbrev-en.html 
508
 @param   $date the date 
509
--> 
510
<xsl:function name="functx:day-of-week-abbrev-en" as="xs:string?" xmlns:functx="http://www.functx.com">
511
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
512
 
513
  <xsl:sequence select="     ('Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat')    [functx:day-of-week($date) + 1]  "/>
514
   
515
</xsl:function>
516

    
517

    
518
<!--
519
  The name of the day of the week, from a date, in English 
520

    
521
 @author  Priscilla Walmsley, Datypic 
522
 @version 1.0 
523
 @see     http://www.xsltfunctions.com/xsl/functx_day-of-week-name-en.html 
524
 @param   $date the date 
525
--> 
526
<xsl:function name="functx:day-of-week-name-en" as="xs:string?" xmlns:functx="http://www.functx.com">
527
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
528
 
529
  <xsl:sequence select="     ('Sunday', 'Monday', 'Tuesday', 'Wednesday',     'Thursday', 'Friday', 'Saturday')       [functx:day-of-week($date) + 1]  "/>
530
   
531
</xsl:function>
532

    
533

    
534
<!--
535
  The day of the week, from a date 
536

    
537
 @author  Priscilla Walmsley, Datypic 
538
 @version 1.0 
539
 @see     http://www.xsltfunctions.com/xsl/functx_day-of-week.html 
540
 @param   $date the date 
541
--> 
542
<xsl:function name="functx:day-of-week" as="xs:integer?" xmlns:functx="http://www.functx.com">
543
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
544
 
545
  <xsl:sequence select="    if (empty($date))   then ()   else xs:integer((xs:date($date) - xs:date('1901-01-06'))           div xs:dayTimeDuration('P1D')) mod 7  "/>
546
   
547
</xsl:function>
548

    
549

    
550
<!--
551
  Construct a dayTimeDuration from a number of days, hours, etc. 
552

    
553
 @author  Priscilla Walmsley, Datypic 
554
 @version 1.0 
555
 @see     http://www.xsltfunctions.com/xsl/functx_daytimeduration.html 
556
 @param   $days the number of days 
557
 @param   $hours the number of hours 
558
 @param   $minutes the number of minutes 
559
 @param   $seconds the number of seconds 
560
--> 
561
<xsl:function name="functx:dayTimeDuration" as="xs:dayTimeDuration" xmlns:functx="http://www.functx.com">
562
  <xsl:param name="days" as="xs:decimal?"/> 
563
  <xsl:param name="hours" as="xs:decimal?"/> 
564
  <xsl:param name="minutes" as="xs:decimal?"/> 
565
  <xsl:param name="seconds" as="xs:decimal?"/> 
566
 
567
  <xsl:sequence select="      (xs:dayTimeDuration('P1D') * functx:if-empty($days,0)) +     (xs:dayTimeDuration('PT1H') * functx:if-empty($hours,0)) +     (xs:dayTimeDuration('PT1M') * functx:if-empty($minutes,0)) +     (xs:dayTimeDuration('PT1S') * functx:if-empty($seconds,0))  "/>
568
   
569
</xsl:function>
570

    
571

    
572
<!--
573
  Number of days in the month 
574

    
575
 @author  Priscilla Walmsley, Datypic 
576
 @version 1.0 
577
 @see     http://www.xsltfunctions.com/xsl/functx_days-in-month.html 
578
 @param   $date the date 
579
--> 
580
<xsl:function name="functx:days-in-month" as="xs:integer?" xmlns:functx="http://www.functx.com">
581
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
582
 
583
  <xsl:sequence select="     if (month-from-date(xs:date($date)) = 2 and        functx:is-leap-year($date))    then 29    else    (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)     [month-from-date(xs:date($date))]  "/>
584
   
585
</xsl:function>
586

    
587

    
588
<!--
589
  The depth (level) of a node in an XML tree 
590

    
591
 @author  Priscilla Walmsley, Datypic 
592
 @version 1.0 
593
 @see     http://www.xsltfunctions.com/xsl/functx_depth-of-node.html 
594
 @param   $node the node to check 
595
--> 
596
<xsl:function name="functx:depth-of-node" as="xs:integer" xmlns:functx="http://www.functx.com">
597
  <xsl:param name="node" as="node()?"/> 
598
 
599
  <xsl:sequence select="     count($node/ancestor-or-self::node())  "/>
600
   
601
</xsl:function>
602

    
603

    
604
<!--
605
  The distinct names of all attributes in an XML fragment 
606

    
607
 @author  Priscilla Walmsley, Datypic 
608
 @version 1.0 
609
 @see     http://www.xsltfunctions.com/xsl/functx_distinct-attribute-names.html 
610
 @param   $nodes the root to start from 
611
--> 
612
<xsl:function name="functx:distinct-attribute-names" as="xs:string*" xmlns:functx="http://www.functx.com">
613
  <xsl:param name="nodes" as="node()*"/> 
614
 
615
  <xsl:sequence select="     distinct-values($nodes//@*/name(.))  "/>
616
   
617
</xsl:function>
618

    
619

    
620
<!--
621
  The XML nodes with distinct values, taking into account attributes and descendants 
622

    
623
 @author  Priscilla Walmsley, Datypic 
624
 @version 1.0 
625
 @see     http://www.xsltfunctions.com/xsl/functx_distinct-deep.html 
626
 @param   $nodes the sequence of nodes to test 
627
--> 
628
<xsl:function name="functx:distinct-deep" as="node()*" xmlns:functx="http://www.functx.com">
629
  <xsl:param name="nodes" as="node()*"/> 
630
 
631
  <xsl:sequence select="      for $seq in (1 to count($nodes))     return $nodes[$seq][not(functx:is-node-in-sequence-deep-equal(                           .,$nodes[position() &lt; $seq]))]  "/>
632
   
633
</xsl:function>
634

    
635

    
636
<!--
637
  The distinct names of all elements in an XML fragment 
638

    
639
 @author  Priscilla Walmsley, Datypic 
640
 @version 1.0 
641
 @see     http://www.xsltfunctions.com/xsl/functx_distinct-element-names.html 
642
 @param   $nodes the root(s) to start from 
643
--> 
644
<xsl:function name="functx:distinct-element-names" as="xs:string*" xmlns:functx="http://www.functx.com">
645
  <xsl:param name="nodes" as="node()*"/> 
646
 
647
  <xsl:sequence select="     distinct-values($nodes/descendant-or-self::*/name(.))  "/>
648
   
649
</xsl:function>
650

    
651

    
652
<!--
653
  The distinct paths of all descendant elements in an XML fragment 
654

    
655
 @author  Priscilla Walmsley, Datypic 
656
 @version 1.0 
657
 @see     http://www.xsltfunctions.com/xsl/functx_distinct-element-paths.html 
658
 @param   $nodes the root(s) to start from 
659
--> 
660
<xsl:function name="functx:distinct-element-paths" as="xs:string*" xmlns:functx="http://www.functx.com">
661
  <xsl:param name="nodes" as="node()*"/> 
662
 
663
  <xsl:sequence select="     distinct-values(functx:path-to-node($nodes/descendant-or-self::*))  "/>
664
   
665
</xsl:function>
666

    
667

    
668
<!--
669
  The distinct XML nodes in a sequence (by node identity) 
670

    
671
 @author  Priscilla Walmsley, Datypic 
672
 @version 1.0 
673
 @see     http://www.xsltfunctions.com/xsl/functx_distinct-nodes.html 
674
 @param   $nodes the node sequence 
675
--> 
676
<xsl:function name="functx:distinct-nodes" as="node()*" xmlns:functx="http://www.functx.com">
677
  <xsl:param name="nodes" as="node()*"/> 
678
 
679
  <xsl:sequence select="      for $seq in (1 to count($nodes))     return $nodes[$seq][not(functx:is-node-in-sequence(                                 .,$nodes[position() &lt; $seq]))]  "/>
680
   
681
</xsl:function>
682

    
683

    
684
<!--
685
  Converts a timezone like "-05:00" or "Z" into xs:dayTimeDuration 
686

    
687
 @author  Priscilla Walmsley, Datypic 
688
 @version 1.0 
689
 @see     http://www.xsltfunctions.com/xsl/functx_duration-from-timezone.html 
690
 @param   $timezone the time zone, in (+|-)HH:MM format 
691
--> 
692
<xsl:function name="functx:duration-from-timezone" as="xs:dayTimeDuration" xmlns:functx="http://www.functx.com">
693
  <xsl:param name="timezone" as="xs:string"/> 
694
 
695
  <xsl:sequence select="     xs:dayTimeDuration(      if (not(matches($timezone,'Z|[\+\-]\d{2}:\d{2}')))      then error(xs:QName('functx:Invalid_Timezone_Value'))      else if ($timezone = 'Z')      then 'PT0S'      else replace($timezone,'\+?(\d{2}):\d{2}','PT$1H')         )  "/>
696
   
697
</xsl:function>
698

    
699

    
700
<!--
701
  Dynamically evaluates a simple XPath path 
702

    
703
 @author  Priscilla Walmsley, Datypic 
704
 @version 1.0 
705
 @see     http://www.xsltfunctions.com/xsl/functx_dynamic-path.html 
706
 @param   $parent the root to start from 
707
 @param   $path the path expression 
708
--> 
709
<xsl:function name="functx:dynamic-path" as="item()*" xmlns:functx="http://www.functx.com">
710
  <xsl:param name="parent" as="node()"/> 
711
  <xsl:param name="path" as="xs:string"/> 
712
 
713
  <xsl:variable name="nextStep" select="functx:substring-before-if-contains($path,'/')"/>
714
  <xsl:variable name="restOfSteps" select="substring-after($path,'/')"/>
715
  <xsl:for-each select="     ($parent/*[functx:name-test(name(),$nextStep)],      $parent/@*[functx:name-test(name(),                               substring-after($nextStep,'@'))])">
716
    <xsl:variable name="child" select="."/>
717
    <xsl:sequence select="if ($restOfSteps)          then functx:dynamic-path($child, $restOfSteps)          else $child"/>
718
  </xsl:for-each>
719
 
720
</xsl:function>
721

    
722

    
723
<!--
724
  Escapes regex special characters 
725

    
726
 @author  Priscilla Walmsley, Datypic 
727
 @version 1.0 
728
 @see     http://www.xsltfunctions.com/xsl/functx_escape-for-regex.html 
729
 @param   $arg the string to escape 
730
--> 
731
<xsl:function name="functx:escape-for-regex" as="xs:string" xmlns:functx="http://www.functx.com">
732
  <xsl:param name="arg" as="xs:string?"/> 
733
 
734
  <xsl:sequence select="     replace($arg,            '(\.|\[|\]|\\|\||\-|\^|\$|\?|\*|\+|\{|\}|\(|\))','\\$1')  "/>
735
   
736
</xsl:function>
737

    
738

    
739
<!--
740
  Whether one (and only one) of two boolean values is true 
741

    
742
 @author  Priscilla Walmsley, Datypic 
743
 @version 1.0 
744
 @see     http://www.xsltfunctions.com/xsl/functx_exclusive-or.html 
745
 @param   $arg1 the first boolean value 
746
 @param   $arg2 the second boolean value 
747
--> 
748
<xsl:function name="functx:exclusive-or" as="xs:boolean?" xmlns:functx="http://www.functx.com">
749
  <xsl:param name="arg1" as="xs:boolean?"/> 
750
  <xsl:param name="arg2" as="xs:boolean?"/> 
751
 
752
  <xsl:sequence select="     $arg1 != $arg2  "/>
753
   
754
</xsl:function>
755

    
756

    
757
<!--
758
  The first day of the month of a date 
759

    
760
 @author  Priscilla Walmsley, Datypic 
761
 @version 1.0 
762
 @see     http://www.xsltfunctions.com/xsl/functx_first-day-of-month.html 
763
 @param   $date the date 
764
--> 
765
<xsl:function name="functx:first-day-of-month" as="xs:date?" xmlns:functx="http://www.functx.com">
766
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
767
 
768
  <xsl:sequence select="     functx:date(year-from-date(xs:date($date)),             month-from-date(xs:date($date)),             1)  "/>
769
   
770
</xsl:function>
771

    
772

    
773
<!--
774
  The first day of the year of a date 
775

    
776
 @author  Priscilla Walmsley, Datypic 
777
 @version 1.0 
778
 @see     http://www.xsltfunctions.com/xsl/functx_first-day-of-year.html 
779
 @param   $date the date 
780
--> 
781
<xsl:function name="functx:first-day-of-year" as="xs:date?" xmlns:functx="http://www.functx.com">
782
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
783
 
784
  <xsl:sequence select="     functx:date(year-from-date(xs:date($date)), 1, 1)  "/>
785
   
786
</xsl:function>
787

    
788

    
789
<!--
790
  The XML node in a sequence that appears first in document order 
791

    
792
 @author  Priscilla Walmsley, Datypic 
793
 @version 1.0 
794
 @see     http://www.xsltfunctions.com/xsl/functx_first-node.html 
795
 @param   $nodes the sequence of nodes 
796
--> 
797
<xsl:function name="functx:first-node" as="node()?" xmlns:functx="http://www.functx.com">
798
  <xsl:param name="nodes" as="node()*"/> 
799
 
800
  <xsl:sequence select="     ($nodes/.)[1]  "/>
801
   
802
</xsl:function>
803

    
804

    
805
<!--
806
  Whether an XML node follows another without being its descendant 
807

    
808
 @author  W3C XML Query Working Group 
809
 @version 1.0 
810
 @see     http://www.xsltfunctions.com/xsl/functx_follows-not-descendant.html 
811
 @param   $a the first node 
812
 @param   $b the second node 
813
--> 
814
<xsl:function name="functx:follows-not-descendant" as="xs:boolean" xmlns:functx="http://www.functx.com">
815
  <xsl:param name="a" as="node()?"/> 
816
  <xsl:param name="b" as="node()?"/> 
817
 
818
  <xsl:sequence select="     $a &gt;&gt; $b and empty($b intersect $a/ancestor::node())  "/>
819
   
820
</xsl:function>
821

    
822

    
823
<!--
824
  Moves title words like "the" and "a" to the end of strings 
825

    
826
 @author  Priscilla Walmsley, Datypic 
827
 @version 1.0 
828
 @see     http://www.xsltfunctions.com/xsl/functx_format-as-title-en.html 
829
 @param   $titles the titles to format 
830
--> 
831
<xsl:function name="functx:format-as-title-en" as="xs:string*" xmlns:functx="http://www.functx.com">
832
  <xsl:param name="titles" as="xs:string*"/> 
833
 
834
   <xsl:variable name="wordsToMoveToEnd" select="('A', 'An', 'The')"/>
835
   <xsl:for-each select="$titles">
836
     <xsl:variable name="title" select="."/>
837
     <xsl:variable name="firstWord" select="functx:substring-before-match($title,'\W')"/>
838
     <xsl:sequence select="if ($firstWord = $wordsToMoveToEnd)           then replace($title,'(.*?)\W(.*)', '$2, $1')           else $title"/>
839
   </xsl:for-each>
840
 
841
</xsl:function>
842

    
843

    
844
<!--
845
  Returns the fragment from a URI 
846

    
847
 @author  Priscilla Walmsley, Datypic 
848
 @version 1.0 
849
 @see     http://www.xsltfunctions.com/xsl/functx_fragment-from-uri.html 
850
 @param   $uri the URI 
851
--> 
852
<xsl:function name="functx:fragment-from-uri" as="xs:string?" xmlns:functx="http://www.functx.com">
853
  <xsl:param name="uri" as="xs:string?"/> 
854
 
855
  <xsl:sequence select="     substring-after($uri,'#')  "/>
856
   
857
</xsl:function>
858

    
859

    
860
<!--
861
  Whether an element has element-only content 
862

    
863
 @author  Priscilla Walmsley, Datypic 
864
 @version 1.0 
865
 @see     http://www.xsltfunctions.com/xsl/functx_has-element-only-content.html 
866
 @param   $element the XML element to test 
867
--> 
868
<xsl:function name="functx:has-element-only-content" as="xs:boolean" xmlns:functx="http://www.functx.com">
869
  <xsl:param name="element" as="element()"/> 
870
 
871
  <xsl:sequence select="     not($element/text()[normalize-space(.) != '']) and $element/*  "/>
872
   
873
</xsl:function>
874

    
875

    
876
<!--
877
  Whether an element has empty content 
878

    
879
 @author  Priscilla Walmsley, Datypic 
880
 @version 1.0 
881
 @see     http://www.xsltfunctions.com/xsl/functx_has-empty-content.html 
882
 @param   $element the XML element to test 
883
--> 
884
<xsl:function name="functx:has-empty-content" as="xs:boolean" xmlns:functx="http://www.functx.com">
885
  <xsl:param name="element" as="element()"/> 
886
 
887
  <xsl:sequence select="     not($element/node())  "/>
888
   
889
</xsl:function>
890

    
891

    
892
<!--
893
  Whether an element has mixed content 
894

    
895
 @author  Priscilla Walmsley, Datypic 
896
 @version 1.0 
897
 @see     http://www.xsltfunctions.com/xsl/functx_has-mixed-content.html 
898
 @param   $element the XML element to test 
899
--> 
900
<xsl:function name="functx:has-mixed-content" as="xs:boolean" xmlns:functx="http://www.functx.com">
901
  <xsl:param name="element" as="element()"/> 
902
 
903
  <xsl:sequence select="     $element/text()[normalize-space(.) != ''] and $element/*  "/>
904
   
905
</xsl:function>
906

    
907

    
908
<!--
909
  Whether an element has simple content 
910

    
911
 @author  Priscilla Walmsley, Datypic 
912
 @version 1.0 
913
 @see     http://www.xsltfunctions.com/xsl/functx_has-simple-content.html 
914
 @param   $element the XML element to test 
915
--> 
916
<xsl:function name="functx:has-simple-content" as="xs:boolean" xmlns:functx="http://www.functx.com">
917
  <xsl:param name="element" as="element()"/> 
918
 
919
  <xsl:sequence select="     $element/text() and not($element/*)  "/>
920
   
921
</xsl:function>
922

    
923

    
924
<!--
925
  Gets the ID of an XML element 
926

    
927
 @author  Priscilla Walmsley, Datypic 
928
 @version 1.0 
929
 @see     http://www.xsltfunctions.com/xsl/functx_id-from-element.html 
930
 @param   $element the element 
931
--> 
932
<xsl:function name="functx:id-from-element" as="xs:string?" xmlns:functx="http://www.functx.com">
933
  <xsl:param name="element" as="element()?"/> 
934
 
935
  <xsl:sequence select="    data(($element/@*[id(.) is ..])[1])  "/>
936
   
937
</xsl:function>
938

    
939

    
940
<!--
941
  Gets XML element(s) that have an attribute with a particular value 
942

    
943
 @author  Priscilla Walmsley, Datypic 
944
 @version 1.0 
945
 @see     http://www.xsltfunctions.com/xsl/functx_id-untyped.html 
946
 @param   $node the root node(s) to start from 
947
 @param   $id the "id" to find 
948
--> 
949
<xsl:function name="functx:id-untyped" as="element()*" xmlns:functx="http://www.functx.com">
950
  <xsl:param name="node" as="node()*"/> 
951
  <xsl:param name="id" as="xs:anyAtomicType"/> 
952
 
953
  <xsl:sequence select="    $node//*[@* = $id]  "/>
954
   
955
</xsl:function>
956

    
957

    
958
<!--
959
  The first argument if it is not empty, otherwise the second argument 
960

    
961
 @author  W3C XML Query WG 
962
 @version 1.0 
963
 @see     http://www.xsltfunctions.com/xsl/functx_if-absent.html 
964
 @param   $arg the item(s) that may be absent 
965
 @param   $value the item(s) to use if the item is absent 
966
--> 
967
<xsl:function name="functx:if-absent" as="item()*" xmlns:functx="http://www.functx.com">
968
  <xsl:param name="arg" as="item()*"/> 
969
  <xsl:param name="value" as="item()*"/> 
970
 
971
  <xsl:sequence select="      if (exists($arg))     then $arg     else $value  "/>
972
   
973
</xsl:function>
974

    
975

    
976
<!--
977
  The first argument if it is not blank, otherwise the second argument 
978

    
979
 @author  Priscilla Walmsley, Datypic 
980
 @version 1.0 
981
 @see     http://www.xsltfunctions.com/xsl/functx_if-empty.html 
982
 @param   $arg the node that may be empty 
983
 @param   $value the item(s) to use if the node is empty 
984
--> 
985
<xsl:function name="functx:if-empty" as="item()*" xmlns:functx="http://www.functx.com">
986
  <xsl:param name="arg" as="item()?"/> 
987
  <xsl:param name="value" as="item()*"/> 
988
 
989
  <xsl:sequence select="    if (string($arg) != '')   then data($arg)   else $value  "/>
990
   
991
</xsl:function>
992

    
993

    
994
<!--
995
  The position of a node in a sequence, based on contents and attributes 
996

    
997
 @author  Priscilla Walmsley, Datypic 
998
 @version 1.0 
999
 @see     http://www.xsltfunctions.com/xsl/functx_index-of-deep-equal-node.html 
1000
 @param   $nodes the node sequence 
1001
 @param   $nodeToFind the node to find in the sequence 
1002
--> 
1003
<xsl:function name="functx:index-of-deep-equal-node" as="xs:integer*" xmlns:functx="http://www.functx.com">
1004
  <xsl:param name="nodes" as="node()*"/> 
1005
  <xsl:param name="nodeToFind" as="node()"/> 
1006
 
1007
  <xsl:sequence select="    for $seq in (1 to count($nodes))   return $seq[deep-equal($nodes[$seq],$nodeToFind)]  "/>
1008
   
1009
</xsl:function>
1010

    
1011

    
1012
<!--
1013
  The first position of a matching substring 
1014

    
1015
 @author  Priscilla Walmsley, Datypic 
1016
 @version 1.0 
1017
 @see     http://www.xsltfunctions.com/xsl/functx_index-of-match-first.html 
1018
 @param   $arg the string 
1019
 @param   $pattern the pattern to match 
1020
--> 
1021
<xsl:function name="functx:index-of-match-first" as="xs:integer?" xmlns:functx="http://www.functx.com">
1022
  <xsl:param name="arg" as="xs:string?"/> 
1023
  <xsl:param name="pattern" as="xs:string"/> 
1024
 
1025
  <xsl:sequence select="    if (matches($arg,$pattern))   then string-length(tokenize($arg, $pattern)[1]) + 1   else ()  "/>
1026
   
1027
</xsl:function>
1028

    
1029

    
1030
<!--
1031
  The position of a node in a sequence, based on node identity 
1032

    
1033
 @author  W3C XML Query Working Group 
1034
 @version 1.0 
1035
 @see     http://www.xsltfunctions.com/xsl/functx_index-of-node.html 
1036
 @param   $nodes the node sequence 
1037
 @param   $nodeToFind the node to find in the sequence 
1038
--> 
1039
<xsl:function name="functx:index-of-node" as="xs:integer*" xmlns:functx="http://www.functx.com">
1040
  <xsl:param name="nodes" as="node()*"/> 
1041
  <xsl:param name="nodeToFind" as="node()"/> 
1042
 
1043
  <xsl:sequence select="    for $seq in (1 to count($nodes))   return $seq[$nodes[$seq] is $nodeToFind]  "/>
1044
   
1045
</xsl:function>
1046

    
1047

    
1048
<!--
1049
  The first position of a substring 
1050

    
1051
 @author  Priscilla Walmsley, Datypic 
1052
 @version 1.0 
1053
 @see     http://www.xsltfunctions.com/xsl/functx_index-of-string-first.html 
1054
 @param   $arg the string 
1055
 @param   $substring the substring to find 
1056
--> 
1057
<xsl:function name="functx:index-of-string-first" as="xs:integer?" xmlns:functx="http://www.functx.com">
1058
  <xsl:param name="arg" as="xs:string?"/> 
1059
  <xsl:param name="substring" as="xs:string"/> 
1060
 
1061
  <xsl:sequence select="    if (contains($arg, $substring))   then string-length(substring-before($arg, $substring))+1   else ()  "/>
1062
   
1063
</xsl:function>
1064

    
1065

    
1066
<!--
1067
  The last position of a substring 
1068

    
1069
 @author  Priscilla Walmsley, Datypic 
1070
 @version 1.0 
1071
 @see     http://www.xsltfunctions.com/xsl/functx_index-of-string-last.html 
1072
 @param   $arg the string 
1073
 @param   $substring the substring to find 
1074
--> 
1075
<xsl:function name="functx:index-of-string-last" as="xs:integer?" xmlns:functx="http://www.functx.com">
1076
  <xsl:param name="arg" as="xs:string?"/> 
1077
  <xsl:param name="substring" as="xs:string"/> 
1078
 
1079
  <xsl:sequence select="    functx:index-of-string($arg, $substring)[last()]  "/>
1080
   
1081
</xsl:function>
1082

    
1083

    
1084
<!--
1085
  The position(s) of a substring 
1086

    
1087
 @author  Priscilla Walmsley, Datypic 
1088
 @version 1.0 
1089
 @see     http://www.xsltfunctions.com/xsl/functx_index-of-string.html 
1090
 @param   $arg the string 
1091
 @param   $substring the substring to find 
1092
--> 
1093
<xsl:function name="functx:index-of-string" as="xs:integer*" xmlns:functx="http://www.functx.com">
1094
  <xsl:param name="arg" as="xs:string?"/> 
1095
  <xsl:param name="substring" as="xs:string"/> 
1096
 
1097
  <xsl:sequence select="    if (contains($arg, $substring))   then (string-length(substring-before($arg, $substring))+1,         for $other in            functx:index-of-string(substring-after($arg, $substring),                                $substring)         return           $other +           string-length(substring-before($arg, $substring)) +           string-length($substring))   else ()  "/>
1098
   
1099
</xsl:function>
1100

    
1101

    
1102
<!--
1103
  Inserts a string at a specified position 
1104

    
1105
 @author  Priscilla Walmsley, Datypic 
1106
 @version 1.0 
1107
 @see     http://www.xsltfunctions.com/xsl/functx_insert-string.html 
1108
 @param   $originalString the original string to insert into 
1109
 @param   $stringToInsert the string to insert 
1110
 @param   $pos the position 
1111
--> 
1112
<xsl:function name="functx:insert-string" as="xs:string" xmlns:functx="http://www.functx.com">
1113
  <xsl:param name="originalString" as="xs:string?"/> 
1114
  <xsl:param name="stringToInsert" as="xs:string?"/> 
1115
  <xsl:param name="pos" as="xs:integer"/> 
1116
 
1117
  <xsl:sequence select="     concat(substring($originalString,1,$pos - 1),              $stringToInsert,              substring($originalString,$pos))  "/>
1118
   
1119
</xsl:function>
1120

    
1121

    
1122
<!--
1123
  Whether a value is numeric 
1124

    
1125
 @author  Priscilla Walmsley, Datypic 
1126
 @version 1.0 
1127
 @see     http://www.xsltfunctions.com/xsl/functx_is-a-number.html 
1128
 @param   $value the value to test 
1129
--> 
1130
<xsl:function name="functx:is-a-number" as="xs:boolean" xmlns:functx="http://www.functx.com">
1131
  <xsl:param name="value" as="xs:anyAtomicType?"/> 
1132
 
1133
  <xsl:sequence select="     string(number($value)) != 'NaN'  "/>
1134
   
1135
</xsl:function>
1136

    
1137

    
1138
<!--
1139
  Whether a URI is absolute 
1140

    
1141
 @author  Priscilla Walmsley, Datypic 
1142
 @version 1.0 
1143
 @see     http://www.xsltfunctions.com/xsl/functx_is-absolute-uri.html 
1144
 @param   $uri the URI to test 
1145
--> 
1146
<xsl:function name="functx:is-absolute-uri" as="xs:boolean" xmlns:functx="http://www.functx.com">
1147
  <xsl:param name="uri" as="xs:string?"/> 
1148
 
1149
  <xsl:sequence select="     matches($uri,'^[a-z]+:')  "/>
1150
   
1151
</xsl:function>
1152

    
1153

    
1154
<!--
1155
  Whether an XML node is an ancestor of another node 
1156

    
1157
 @author  Priscilla Walmsley, Datypic 
1158
 @version 1.0 
1159
 @see     http://www.xsltfunctions.com/xsl/functx_is-ancestor.html 
1160
 @param   $node1 the first node 
1161
 @param   $node2 the second node 
1162
--> 
1163
<xsl:function name="functx:is-ancestor" as="xs:boolean" xmlns:functx="http://www.functx.com">
1164
  <xsl:param name="node1" as="node()"/> 
1165
  <xsl:param name="node2" as="node()"/> 
1166
 
1167
  <xsl:sequence select="     exists($node1 intersect $node2/ancestor::node())  "/>
1168
   
1169
</xsl:function>
1170

    
1171

    
1172
<!--
1173
  Whether an XML node is a descendant of another node 
1174

    
1175
 @author  Priscilla Walmsley, Datypic 
1176
 @version 1.0 
1177
 @see     http://www.xsltfunctions.com/xsl/functx_is-descendant.html 
1178
 @param   $node1 the first node 
1179
 @param   $node2 the second node 
1180
--> 
1181
<xsl:function name="functx:is-descendant" as="xs:boolean" xmlns:functx="http://www.functx.com">
1182
  <xsl:param name="node1" as="node()"/> 
1183
  <xsl:param name="node2" as="node()"/> 
1184
 
1185
  <xsl:sequence select="     boolean($node2 intersect $node1/ancestor::node())  "/>
1186
   
1187
</xsl:function>
1188

    
1189

    
1190
<!--
1191
  Whether a date falls in a leap year 
1192

    
1193
 @author  Priscilla Walmsley, Datypic 
1194
 @version 1.0 
1195
 @see     http://www.xsltfunctions.com/xsl/functx_is-leap-year.html 
1196
 @param   $date the date or year 
1197
--> 
1198
<xsl:function name="functx:is-leap-year" as="xs:boolean" xmlns:functx="http://www.functx.com">
1199
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
1200
 
1201
  <xsl:sequence select="      for $year in xs:integer(substring(string($date),1,4))     return ($year mod 4 = 0 and             $year mod 100 != 0) or             $year mod 400 = 0  "/>
1202
   
1203
</xsl:function>
1204

    
1205

    
1206
<!--
1207
  Whether an XML node is among the descendants of a sequence, based on contents and attributes 
1208

    
1209
 @author  Priscilla Walmsley, Datypic 
1210
 @version 1.0 
1211
 @see     http://www.xsltfunctions.com/xsl/functx_is-node-among-descendants-deep-equal.html 
1212
 @param   $node the node to test 
1213
 @param   $seq the sequence of nodes to search 
1214
--> 
1215
<xsl:function name="functx:is-node-among-descendants-deep-equal" as="xs:boolean" xmlns:functx="http://www.functx.com">
1216
  <xsl:param name="node" as="node()?"/> 
1217
  <xsl:param name="seq" as="node()*"/> 
1218
 
1219
  <xsl:sequence select="     some $nodeInSeq in $seq/descendant-or-self::*/(.|@*)    satisfies deep-equal($nodeInSeq,$node)  "/>
1220
   
1221
</xsl:function>
1222

    
1223

    
1224
<!--
1225
  Whether an XML node is among the descendants of a sequence, based on node identity 
1226

    
1227
 @author  Priscilla Walmsley, Datypic 
1228
 @version 1.0 
1229
 @see     http://www.xsltfunctions.com/xsl/functx_is-node-among-descendants.html 
1230
 @param   $node the node to test 
1231
 @param   $seq the sequence of nodes to search 
1232
--> 
1233
<xsl:function name="functx:is-node-among-descendants" as="xs:boolean" xmlns:functx="http://www.functx.com">
1234
  <xsl:param name="node" as="node()?"/> 
1235
  <xsl:param name="seq" as="node()*"/> 
1236
 
1237
  <xsl:sequence select="     some $nodeInSeq in $seq/descendant-or-self::*/(.|@*)    satisfies $nodeInSeq is $node  "/>
1238
   
1239
</xsl:function>
1240

    
1241

    
1242
<!--
1243
  Whether an XML node is in a sequence, based on contents and attributes 
1244

    
1245
 @author  Priscilla Walmsley, Datypic 
1246
 @version 1.0 
1247
 @see     http://www.xsltfunctions.com/xsl/functx_is-node-in-sequence-deep-equal.html 
1248
 @param   $node the node to test 
1249
 @param   $seq the sequence of nodes to search 
1250
--> 
1251
<xsl:function name="functx:is-node-in-sequence-deep-equal" as="xs:boolean" xmlns:functx="http://www.functx.com">
1252
  <xsl:param name="node" as="node()?"/> 
1253
  <xsl:param name="seq" as="node()*"/> 
1254
 
1255
  <xsl:sequence select="     some $nodeInSeq in $seq satisfies deep-equal($nodeInSeq,$node)  "/>
1256
   
1257
</xsl:function>
1258

    
1259

    
1260
<!--
1261
  Whether an XML node is in a sequence, based on node identity 
1262

    
1263
 @author  Priscilla Walmsley, Datypic 
1264
 @version 1.0 
1265
 @see     http://www.xsltfunctions.com/xsl/functx_is-node-in-sequence.html 
1266
 @param   $node the node to test 
1267
 @param   $seq the sequence of nodes to search 
1268
--> 
1269
<xsl:function name="functx:is-node-in-sequence" as="xs:boolean" xmlns:functx="http://www.functx.com">
1270
  <xsl:param name="node" as="node()?"/> 
1271
  <xsl:param name="seq" as="node()*"/> 
1272
 
1273
  <xsl:sequence select="     some $nodeInSeq in $seq satisfies $nodeInSeq is $node  "/>
1274
   
1275
</xsl:function>
1276

    
1277

    
1278
<!--
1279
  Whether an atomic value appears in a sequence  
1280

    
1281
 @author  Priscilla Walmsley, Datypic 
1282
 @version 1.0 
1283
 @see     http://www.xsltfunctions.com/xsl/functx_is-value-in-sequence.html 
1284
 @param   $value the atomic value to test 
1285
 @param   $seq the sequence of values to search 
1286
--> 
1287
<xsl:function name="functx:is-value-in-sequence" as="xs:boolean" xmlns:functx="http://www.functx.com">
1288
  <xsl:param name="value" as="xs:anyAtomicType?"/> 
1289
  <xsl:param name="seq" as="xs:anyAtomicType*"/> 
1290
 
1291
  <xsl:sequence select="     $value = $seq  "/>
1292
   
1293
</xsl:function>
1294

    
1295

    
1296
<!--
1297
  The last day of the month of a date 
1298

    
1299
 @author  Priscilla Walmsley, Datypic 
1300
 @version 1.0 
1301
 @see     http://www.xsltfunctions.com/xsl/functx_last-day-of-month.html 
1302
 @param   $date the date 
1303
--> 
1304
<xsl:function name="functx:last-day-of-month" as="xs:date?" xmlns:functx="http://www.functx.com">
1305
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
1306
 
1307
  <xsl:sequence select="     functx:date(year-from-date(xs:date($date)),             month-from-date(xs:date($date)),             functx:days-in-month($date))  "/>
1308
   
1309
</xsl:function>
1310

    
1311

    
1312
<!--
1313
  The last day of the month of a date 
1314

    
1315
 @author  Priscilla Walmsley, Datypic 
1316
 @version 1.0 
1317
 @see     http://www.xsltfunctions.com/xsl/functx_last-day-of-year.html 
1318
 @param   $date the date 
1319
--> 
1320
<xsl:function name="functx:last-day-of-year" as="xs:date?" xmlns:functx="http://www.functx.com">
1321
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
1322
 
1323
  <xsl:sequence select="     functx:date(year-from-date(xs:date($date)), 12, 31)  "/>
1324
   
1325
</xsl:function>
1326

    
1327

    
1328
<!--
1329
  The XML node in a sequence that is last in document order 
1330

    
1331
 @author  Priscilla Walmsley, Datypic 
1332
 @version 1.0 
1333
 @see     http://www.xsltfunctions.com/xsl/functx_last-node.html 
1334
 @param   $nodes the sequence of nodes 
1335
--> 
1336
<xsl:function name="functx:last-node" as="node()?" xmlns:functx="http://www.functx.com">
1337
  <xsl:param name="nodes" as="node()*"/> 
1338
 
1339
  <xsl:sequence select="     ($nodes/.)[last()]  "/>
1340
   
1341
</xsl:function>
1342

    
1343

    
1344
<!--
1345
  All XML elements that don't have any child elements 
1346

    
1347
 @author  Priscilla Walmsley, Datypic 
1348
 @version 1.0 
1349
 @see     http://www.xsltfunctions.com/xsl/functx_leaf-elements.html 
1350
 @param   $root the root 
1351
--> 
1352
<xsl:function name="functx:leaf-elements" as="element()*" xmlns:functx="http://www.functx.com">
1353
  <xsl:param name="root" as="node()?"/> 
1354
 
1355
  <xsl:sequence select="     $root/descendant-or-self::*[not(*)]  "/>
1356
   
1357
</xsl:function>
1358

    
1359

    
1360
<!--
1361
  Trims leading whitespace 
1362

    
1363
 @author  Priscilla Walmsley, Datypic 
1364
 @version 1.0 
1365
 @see     http://www.xsltfunctions.com/xsl/functx_left-trim.html 
1366
 @param   $arg the string to trim 
1367
--> 
1368
<xsl:function name="functx:left-trim" as="xs:string" xmlns:functx="http://www.functx.com">
1369
  <xsl:param name="arg" as="xs:string?"/> 
1370
 
1371
  <xsl:sequence select="     replace($arg,'^\s+','')  "/>
1372
   
1373
</xsl:function>
1374

    
1375

    
1376
<!--
1377
  The number of lines 
1378

    
1379
 @author  Priscilla Walmsley, Datypic 
1380
 @version 1.0 
1381
 @see     http://www.xsltfunctions.com/xsl/functx_line-count.html 
1382
 @param   $arg the string to test 
1383
--> 
1384
<xsl:function name="functx:line-count" as="xs:integer" xmlns:functx="http://www.functx.com">
1385
  <xsl:param name="arg" as="xs:string?"/> 
1386
 
1387
  <xsl:sequence select="     count(functx:lines($arg))  "/>
1388
   
1389
</xsl:function>
1390

    
1391

    
1392
<!--
1393
  Split a string into separate lines 
1394

    
1395
 @author  Priscilla Walmsley, Datypic 
1396
 @version 1.0 
1397
 @see     http://www.xsltfunctions.com/xsl/functx_lines.html 
1398
 @param   $arg the string to split 
1399
--> 
1400
<xsl:function name="functx:lines" as="xs:string*" xmlns:functx="http://www.functx.com">
1401
  <xsl:param name="arg" as="xs:string?"/> 
1402
 
1403
  <xsl:sequence select="     tokenize($arg, '(\r\n?|\n\r?)')  "/>
1404
   
1405
</xsl:function>
1406

    
1407

    
1408
<!--
1409
  The maximum depth of elements in an XML tree 
1410

    
1411
 @author  Priscilla Walmsley, Datypic 
1412
 @version 1.0 
1413
 @see     http://www.xsltfunctions.com/xsl/functx_max-depth.html 
1414
 @param   $root the root to start from 
1415
--> 
1416
<xsl:function name="functx:max-depth" as="xs:integer?" xmlns:functx="http://www.functx.com">
1417
  <xsl:param name="root" as="node()?"/> 
1418
 
1419
  <xsl:sequence select="     if ($root/*)    then max($root/*/functx:max-depth(.)) + 1    else 1  "/>
1420
   
1421
</xsl:function>
1422

    
1423

    
1424
<!--
1425
  The maximum value in a sequence, figuring out its type (numeric or string) 
1426

    
1427
 @author  Priscilla Walmsley, Datypic 
1428
 @version 1.0 
1429
 @see     http://www.xsltfunctions.com/xsl/functx_max-determine-type.html 
1430
 @param   $seq the sequence of values to test 
1431
--> 
1432
<xsl:function name="functx:max-determine-type" as="xs:anyAtomicType?" xmlns:functx="http://www.functx.com">
1433
  <xsl:param name="seq" as="xs:anyAtomicType*"/> 
1434
 
1435
  <xsl:sequence select="     if (every $value in $seq satisfies ($value castable as xs:double))    then max(for $value in $seq return xs:double($value))    else max(for $value in $seq return xs:string($value))  "/>
1436
   
1437
</xsl:function>
1438

    
1439

    
1440
<!--
1441
  The maximum line length 
1442

    
1443
 @author  Priscilla Walmsley, Datypic 
1444
 @version 1.0 
1445
 @see     http://www.xsltfunctions.com/xsl/functx_max-line-length.html 
1446
 @param   $arg the string to test 
1447
--> 
1448
<xsl:function name="functx:max-line-length" as="xs:integer" xmlns:functx="http://www.functx.com">
1449
  <xsl:param name="arg" as="xs:string?"/> 
1450
 
1451
  <xsl:sequence select="     max(      for $line in functx:lines($arg)      return string-length($line))  "/>
1452
   
1453
</xsl:function>
1454

    
1455

    
1456
<!--
1457
  The XML node whose typed value is the maximum 
1458

    
1459
 @author  Priscilla Walmsley, Datypic 
1460
 @version 1.0 
1461
 @see     http://www.xsltfunctions.com/xsl/functx_max-node.html 
1462
 @param   $nodes the sequence of nodes to test 
1463
--> 
1464
<xsl:function name="functx:max-node" as="node()*" xmlns:functx="http://www.functx.com">
1465
  <xsl:param name="nodes" as="node()*"/> 
1466
 
1467
  <xsl:sequence select="     $nodes[. = max($nodes)]  "/>
1468
   
1469
</xsl:function>
1470

    
1471

    
1472
<!--
1473
  The maximum of a sequence of values, treating them like strings 
1474

    
1475
 @author  Priscilla Walmsley, Datypic 
1476
 @version 1.0 
1477
 @see     http://www.xsltfunctions.com/xsl/functx_max-string.html 
1478
 @param   $strings the sequence of values 
1479
--> 
1480
<xsl:function name="functx:max-string" as="xs:string?" xmlns:functx="http://www.functx.com">
1481
  <xsl:param name="strings" as="xs:anyAtomicType*"/> 
1482
 
1483
  <xsl:sequence select="     max(for $string in $strings return string($string))  "/>
1484
   
1485
</xsl:function>
1486

    
1487

    
1488
<!--
1489
  The minimum value in a sequence, figuring out its type (numeric or string) 
1490

    
1491
 @author  Priscilla Walmsley, Datypic 
1492
 @version 1.0 
1493
 @see     http://www.xsltfunctions.com/xsl/functx_min-determine-type.html 
1494
 @param   $seq the sequence of values to test 
1495
--> 
1496
<xsl:function name="functx:min-determine-type" as="xs:anyAtomicType?" xmlns:functx="http://www.functx.com">
1497
  <xsl:param name="seq" as="xs:anyAtomicType*"/> 
1498
 
1499
  <xsl:sequence select="     if (every $value in $seq satisfies ($value castable as xs:double))    then min(for $value in $seq return xs:double($value))    else min(for $value in $seq return xs:string($value))  "/>
1500
   
1501
</xsl:function>
1502

    
1503

    
1504
<!--
1505
  The XML node whose typed value is the minimum 
1506

    
1507
 @author  Priscilla Walmsley, Datypic 
1508
 @version 1.0 
1509
 @see     http://www.xsltfunctions.com/xsl/functx_min-node.html 
1510
 @param   $nodes the sequence of nodes to test 
1511
--> 
1512
<xsl:function name="functx:min-node" as="node()*" xmlns:functx="http://www.functx.com">
1513
  <xsl:param name="nodes" as="node()*"/> 
1514
 
1515
  <xsl:sequence select="     $nodes[. = min($nodes)]  "/>
1516
   
1517
</xsl:function>
1518

    
1519

    
1520
<!--
1521
  The minimum of a sequence of strings, ignoring "empty" values 
1522

    
1523
 @author  Priscilla Walmsley, Datypic 
1524
 @version 1.0 
1525
 @see     http://www.xsltfunctions.com/xsl/functx_min-non-empty-string.html 
1526
 @param   $strings the sequence of strings to search 
1527
--> 
1528
<xsl:function name="functx:min-non-empty-string" as="xs:string?" xmlns:functx="http://www.functx.com">
1529
  <xsl:param name="strings" as="xs:string*"/> 
1530
 
1531
  <xsl:sequence select="     min($strings[. != ''])  "/>
1532
   
1533
</xsl:function>
1534

    
1535

    
1536
<!--
1537
  The minimum of a sequence of values, treating them like strings 
1538

    
1539
 @author  Priscilla Walmsley, Datypic 
1540
 @version 1.0 
1541
 @see     http://www.xsltfunctions.com/xsl/functx_min-string.html 
1542
 @param   $strings the sequence of strings 
1543
--> 
1544
<xsl:function name="functx:min-string" as="xs:string?" xmlns:functx="http://www.functx.com">
1545
  <xsl:param name="strings" as="xs:anyAtomicType*"/> 
1546
 
1547
  <xsl:sequence select="     min(for $string in $strings return string($string))  "/>
1548
   
1549
</xsl:function>
1550

    
1551

    
1552
<!--
1553
  Converts a string with format MMDDYYYY (with any delimiters) to a date 
1554

    
1555
 @author  Priscilla Walmsley, Datypic 
1556
 @version 1.0 
1557
 @see     http://www.xsltfunctions.com/xsl/functx_mmddyyyy-to-date.html 
1558
 @param   $dateString the MMDDYYYY string 
1559
--> 
1560
<xsl:function name="functx:mmddyyyy-to-date" as="xs:date?" xmlns:functx="http://www.functx.com">
1561
  <xsl:param name="dateString" as="xs:string?"/> 
1562
 
1563
  <xsl:sequence select="     if (empty($dateString))    then ()    else if (not(matches($dateString,                         '^\D*(\d{2})\D*(\d{2})\D*(\d{4})\D*$')))    then error(xs:QName('functx:Invalid_Date_Format'))    else xs:date(replace($dateString,                         '^\D*(\d{2})\D*(\d{2})\D*(\d{4})\D*$',                         '$3-$1-$2'))  "/>
1564
   
1565
</xsl:function>
1566

    
1567

    
1568
<!--
1569
  The month of a date as an abbreviated word (Jan, Feb, etc.) 
1570

    
1571
 @author  Priscilla Walmsley, Datypic 
1572
 @version 1.0 
1573
 @see     http://www.xsltfunctions.com/xsl/functx_month-abbrev-en.html 
1574
 @param   $date the date 
1575
--> 
1576
<xsl:function name="functx:month-abbrev-en" as="xs:string?" xmlns:functx="http://www.functx.com">
1577
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
1578
 
1579
  <xsl:sequence select="     ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',     'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')     [month-from-date(xs:date($date))]  "/>
1580
   
1581
</xsl:function>
1582

    
1583

    
1584
<!--
1585
  The month of a date as a word (January, February, etc.) 
1586

    
1587
 @author  Priscilla Walmsley, Datypic 
1588
 @version 1.0 
1589
 @see     http://www.xsltfunctions.com/xsl/functx_month-name-en.html 
1590
 @param   $date the date 
1591
--> 
1592
<xsl:function name="functx:month-name-en" as="xs:string?" xmlns:functx="http://www.functx.com">
1593
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
1594
 
1595
  <xsl:sequence select="     ('January', 'February', 'March', 'April', 'May', 'June',     'July', 'August', 'September', 'October', 'November', 'December')    [month-from-date(xs:date($date))]  "/>
1596
   
1597
</xsl:function>
1598

    
1599

    
1600
<!--
1601
  Whether a name matches a list of names or name wildcards 
1602

    
1603
 @author  Priscilla Walmsley, Datypic 
1604
 @version 1.0 
1605
 @see     http://www.xsltfunctions.com/xsl/functx_name-test.html 
1606
 @param   $testname the name to test 
1607
 @param   $names the list of names or name wildcards 
1608
--> 
1609
<xsl:function name="functx:name-test" as="xs:boolean" xmlns:functx="http://www.functx.com">
1610
  <xsl:param name="testname" as="xs:string?"/> 
1611
  <xsl:param name="names" as="xs:string*"/> 
1612
 
1613
  <xsl:sequence select="  $testname = $names or $names = '*' or functx:substring-after-if-contains($testname,':') =    (for $name in $names    return substring-after($name,'*:')) or substring-before($testname,':') =    (for $name in $names[contains(.,':*')]    return substring-before($name,':*'))  "/>
1614
   
1615
</xsl:function>
1616

    
1617

    
1618
<!--
1619
  A list of namespaces used in element/attribute names in an XML fragment 
1620

    
1621
 @author  Priscilla Walmsley, Datypic 
1622
 @version 1.0 
1623
 @see     http://www.xsltfunctions.com/xsl/functx_namespaces-in-use.html 
1624
 @param   $root the root node to start from 
1625
--> 
1626
<xsl:function name="functx:namespaces-in-use" as="xs:anyURI*" xmlns:functx="http://www.functx.com">
1627
  <xsl:param name="root" as="node()?"/> 
1628
 
1629
  <xsl:sequence select="     distinct-values(       $root/descendant-or-self::*/(.|@*)/namespace-uri(.))  "/>
1630
   
1631
</xsl:function>
1632

    
1633

    
1634
<!--
1635
  The next day 
1636

    
1637
 @author  Priscilla Walmsley, Datypic 
1638
 @version 1.0 
1639
 @see     http://www.xsltfunctions.com/xsl/functx_next-day.html 
1640
 @param   $date the date 
1641
--> 
1642
<xsl:function name="functx:next-day" as="xs:date?" xmlns:functx="http://www.functx.com">
1643
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
1644
 
1645
  <xsl:sequence select="     xs:date($date) + xs:dayTimeDuration('P1D')  "/>
1646
   
1647
</xsl:function>
1648

    
1649

    
1650
<!--
1651
  The XML node kind (element, attribute, text, etc.) 
1652

    
1653
 @author  Priscilla Walmsley, Datypic 
1654
 @version 1.0 
1655
 @see     http://www.xsltfunctions.com/xsl/functx_node-kind.html 
1656
 @param   $nodes the node(s) whose kind you want to determine 
1657
--> 
1658
<xsl:function name="functx:node-kind" as="xs:string*" xmlns:functx="http://www.functx.com">
1659
  <xsl:param name="nodes" as="node()*"/> 
1660
 
1661
  <xsl:sequence select="   for $node in $nodes  return  if ($node instance of element()) then 'element'  else if ($node instance of attribute()) then 'attribute'  else if ($node instance of text()) then 'text'  else if ($node instance of document-node()) then 'document-node'  else if ($node instance of comment()) then 'comment'  else if ($node instance of processing-instruction())          then 'processing-instruction'  else 'unknown'  "/>
1662
   
1663
</xsl:function>
1664

    
1665

    
1666
<!--
1667
  Returns any values that appear more than once in a sequence 
1668

    
1669
 @author  Priscilla Walmsley, Datypic 
1670
 @version 1.0 
1671
 @see     http://www.xsltfunctions.com/xsl/functx_non-distinct-values.html 
1672
 @param   $seq the sequence of values 
1673
--> 
1674
<xsl:function name="functx:non-distinct-values" as="xs:anyAtomicType*" xmlns:functx="http://www.functx.com">
1675
  <xsl:param name="seq" as="xs:anyAtomicType*"/> 
1676
 
1677
  <xsl:sequence select="     for $val in distinct-values($seq)    return $val[count($seq[. = $val]) &gt; 1]  "/>
1678
   
1679
</xsl:function>
1680

    
1681

    
1682
<!--
1683
  The number of regions that match a pattern 
1684

    
1685
 @author  Priscilla Walmsley, Datypic 
1686
 @version 1.0 
1687
 @see     http://www.xsltfunctions.com/xsl/functx_number-of-matches.html 
1688
 @param   $arg the string to test 
1689
 @param   $pattern the regular expression 
1690
--> 
1691
<xsl:function name="functx:number-of-matches" as="xs:integer" xmlns:functx="http://www.functx.com">
1692
  <xsl:param name="arg" as="xs:string?"/> 
1693
  <xsl:param name="pattern" as="xs:string"/> 
1694
 
1695
  <xsl:sequence select="     count(tokenize($arg,$pattern)) - 1  "/>
1696
   
1697
</xsl:function>
1698

    
1699

    
1700
<!--
1701
  Resolves a relative URI and references it, returning an XML document 
1702

    
1703
 @author  Priscilla Walmsley, Datypic 
1704
 @version 1.0 
1705
 @see     http://www.xsltfunctions.com/xsl/functx_open-ref-document.html 
1706
 @param   $refNode a node whose value is a relative URI reference 
1707
--> 
1708
<xsl:function name="functx:open-ref-document" as="document-node()" xmlns:functx="http://www.functx.com">
1709
  <xsl:param name="refNode" as="node()"/> 
1710
 
1711
  <xsl:sequence select="     if (base-uri($refNode))    then doc(resolve-uri($refNode, base-uri($refNode)))    else doc(resolve-uri($refNode))  "/>
1712
   
1713
</xsl:function>
1714

    
1715

    
1716
<!--
1717
  Reformats a number as an ordinal number, e.g. 1st, 2nd, 3rd. 
1718

    
1719
 @author  Priscilla Walmsley, Datypic 
1720
 @version 1.0 
1721
 @see     http://www.xsltfunctions.com/xsl/functx_ordinal-number-en.html 
1722
 @param   $num the number 
1723
--> 
1724
<xsl:function name="functx:ordinal-number-en" as="xs:string" xmlns:functx="http://www.functx.com">
1725
  <xsl:param name="num" as="xs:integer?"/> 
1726
 
1727
  <xsl:sequence select="     concat(xs:string($num),          if (matches(xs:string($num),'[04-9]$|1[1-3]$')) then 'th'          else if (ends-with(xs:string($num),'1')) then 'st'          else if (ends-with(xs:string($num),'2')) then 'nd'          else if (ends-with(xs:string($num),'3')) then 'rd'          else '')  "/>
1728
   
1729
</xsl:function>
1730

    
1731

    
1732
<!--
1733
  Pads an integer to a desired length by adding leading zeros 
1734

    
1735
 @author  Priscilla Walmsley, Datypic 
1736
 @version 1.0 
1737
 @see     http://www.xsltfunctions.com/xsl/functx_pad-integer-to-length.html 
1738
 @param   $integerToPad the integer to pad 
1739
 @param   $length the desired length 
1740
--> 
1741
<xsl:function name="functx:pad-integer-to-length" as="xs:string" xmlns:functx="http://www.functx.com">
1742
  <xsl:param name="integerToPad" as="xs:anyAtomicType?"/> 
1743
  <xsl:param name="length" as="xs:integer"/> 
1744
 
1745
  <xsl:sequence select="     if ($length &lt; string-length(string($integerToPad)))    then error(xs:QName('functx:Integer_Longer_Than_Length'))    else concat          (functx:repeat-string(             '0',$length - string-length(string($integerToPad))),           string($integerToPad))  "/>
1746
   
1747
</xsl:function>
1748

    
1749

    
1750
<!--
1751
  Pads a string to a desired length 
1752

    
1753
 @author  Priscilla Walmsley, Datypic 
1754
 @version 1.0 
1755
 @see     http://www.xsltfunctions.com/xsl/functx_pad-string-to-length.html 
1756
 @param   $stringToPad the string to pad 
1757
 @param   $padChar the character(s) to use as padding 
1758
 @param   $length the desired length 
1759
--> 
1760
<xsl:function name="functx:pad-string-to-length" as="xs:string" xmlns:functx="http://www.functx.com">
1761
  <xsl:param name="stringToPad" as="xs:string?"/> 
1762
  <xsl:param name="padChar" as="xs:string"/> 
1763
  <xsl:param name="length" as="xs:integer"/> 
1764
 
1765
  <xsl:sequence select="     substring(      string-join (        ($stringToPad, for $i in (1 to $length) return $padChar)        ,'')     ,1,$length)  "/>
1766
   
1767
</xsl:function>
1768

    
1769

    
1770
<!--
1771
  A unique path to an XML node (or sequence of nodes) 
1772

    
1773
 @author  Priscilla Walmsley, Datypic 
1774
 @version 1.0 
1775
 @see     http://www.xsltfunctions.com/xsl/functx_path-to-node-with-pos.html 
1776
 @param   $node the node sequence 
1777
--> 
1778
<xsl:function name="functx:path-to-node-with-pos" as="xs:string" xmlns:functx="http://www.functx.com">
1779
  <xsl:param name="node" as="node()?"/> 
1780
 
1781
 <xsl:variable name="names" as="xs:string*">
1782
   <xsl:for-each select="$node/ancestor-or-self::*">
1783
     <xsl:variable name="ancestor" select="."/>
1784
     <xsl:variable name="sibsOfSameName" select="$ancestor/../*[name() = name($ancestor)]"/>
1785
     <xsl:sequence select="concat(name($ancestor),          if (count($sibsOfSameName) &lt;= 1)          then ''          else concat(         '[',functx:index-of-node($sibsOfSameName,$ancestor),']'))"/>
1786
   </xsl:for-each>
1787
 </xsl:variable>
1788
 <xsl:sequence select="string-join($names,'/')"/>
1789
 
1790
</xsl:function>
1791

    
1792

    
1793
<!--
1794
  A path to an XML node (or sequence of nodes) 
1795

    
1796
 @author  Priscilla Walmsley, Datypic 
1797
 @version 1.0 
1798
 @see     http://www.xsltfunctions.com/xsl/functx_path-to-node.html 
1799
 @param   $nodes the node sequence 
1800
--> 
1801
<xsl:function name="functx:path-to-node" as="xs:string*" xmlns:functx="http://www.functx.com">
1802
  <xsl:param name="nodes" as="node()*"/> 
1803
 
1804
  <xsl:sequence select="  $nodes/string-join(ancestor-or-self::*/name(.), '/')  "/>
1805
   
1806
</xsl:function>
1807

    
1808

    
1809
<!--
1810
  Whether an XML node precedes another without being its ancestor 
1811

    
1812
 @author  W3C XML Query Working Group 
1813
 @version 1.0 
1814
 @see     http://www.xsltfunctions.com/xsl/functx_precedes-not-ancestor.html 
1815
 @param   $a the first node 
1816
 @param   $b the second node 
1817
--> 
1818
<xsl:function name="functx:precedes-not-ancestor" as="xs:boolean" xmlns:functx="http://www.functx.com">
1819
  <xsl:param name="a" as="node()?"/> 
1820
  <xsl:param name="b" as="node()?"/> 
1821
 
1822
  <xsl:sequence select="     $a &lt;&lt; $b and empty($a intersect $b/ancestor::node())  "/>
1823
   
1824
</xsl:function>
1825

    
1826

    
1827
<!--
1828
  The previous day 
1829

    
1830
 @author  Priscilla Walmsley, Datypic 
1831
 @version 1.0 
1832
 @see     http://www.xsltfunctions.com/xsl/functx_previous-day.html 
1833
 @param   $date the date 
1834
--> 
1835
<xsl:function name="functx:previous-day" as="xs:date?" xmlns:functx="http://www.functx.com">
1836
  <xsl:param name="date" as="xs:anyAtomicType?"/> 
1837
 
1838
  <xsl:sequence select="     xs:date($date) - xs:dayTimeDuration('P1D')  "/>
1839
   
1840
</xsl:function>
1841

    
1842

    
1843
<!--
1844
  Removes attributes from an XML fragment, based on name 
1845

    
1846
 @author  Priscilla Walmsley, Datypic 
1847
 @version 1.0 
1848
 @see     http://www.xsltfunctions.com/xsl/functx_remove-attributes-deep.html 
1849
 @param   $nodes the root(s) to start from 
1850
 @param   $names the names of the attributes to remove, or * for all attributes 
1851
--> 
1852
<xsl:function name="functx:remove-attributes-deep" as="node()*" xmlns:functx="http://www.functx.com">
1853
  <xsl:param name="nodes" as="node()*"/> 
1854
  <xsl:param name="names" as="xs:string*"/> 
1855
 
1856
   <xsl:for-each select="$nodes">
1857
     <xsl:choose>
1858
       <xsl:when test=". instance of element()">
1859
         <xsl:element name="{node-name(.)}">
1860
           <xsl:sequence select="               (@*[not(functx:name-test(name(),$names))],                functx:remove-attributes-deep(node(), $names))"/>
1861
         </xsl:element>
1862
       </xsl:when>
1863
       <xsl:when test=". instance of document-node()">
1864
         <xsl:document>
1865
           <xsl:sequence select="                 functx:remove-attributes-deep(node(), $names)"/>
1866
         </xsl:document>
1867
       </xsl:when>
1868
       <xsl:otherwise>
1869
         <xsl:sequence select="."/>
1870
       </xsl:otherwise>
1871
     </xsl:choose>
1872
   </xsl:for-each>
1873
 
1874
</xsl:function>
1875

    
1876

    
1877
<!--
1878
  Removes attributes from an XML element, based on name 
1879

    
1880
 @author  Priscilla Walmsley, Datypic 
1881
 @version 1.0 
1882
 @see     http://www.xsltfunctions.com/xsl/functx_remove-attributes.html 
1883
 @param   $elements the element(s) from which to remove the attributes 
1884
 @param   $names the names of the attributes to remove, or * for all attributes 
1885
--> 
1886
<xsl:function name="functx:remove-attributes" as="element()" xmlns:functx="http://www.functx.com">
1887
  <xsl:param name="elements" as="element()*"/> 
1888
  <xsl:param name="names" as="xs:string*"/> 
1889
 
1890
   <xsl:for-each select="$elements">
1891
     <xsl:element name="{node-name(.)}">
1892
       <xsl:sequence select="(@*[not(functx:name-test(name(),$names))],                  node())"/>
1893
     </xsl:element>
1894
   </xsl:for-each>
1895
 
1896
</xsl:function>
1897

    
1898

    
1899
<!--
1900
  Removes descendant elements from an XML node, based on name 
1901

    
1902
 @author  Priscilla Walmsley, Datypic 
1903
 @version 1.0 
1904
 @see     http://www.xsltfunctions.com/xsl/functx_remove-elements-deep.html 
1905
 @param   $nodes root(s) to start from 
1906
 @param   $names the names of the elements to remove 
1907
--> 
1908
<xsl:function name="functx:remove-elements-deep" as="node()*" xmlns:functx="http://www.functx.com">
1909
  <xsl:param name="nodes" as="node()*"/> 
1910
  <xsl:param name="names" as="xs:string*"/> 
1911
 
1912
   <xsl:for-each select="$nodes">
1913
     <xsl:choose>
1914
       <xsl:when test=". instance of element()">
1915
         <xsl:if test="not(functx:name-test(name(),$names))">
1916
           <xsl:element name="{node-name(.)}">
1917
             <xsl:sequence select="@*,                   functx:remove-elements-deep(node(), $names)"/>
1918
           </xsl:element>
1919
         </xsl:if>
1920
       </xsl:when>
1921
       <xsl:when test=". instance of document-node()">
1922
         <xsl:document>
1923
             <xsl:sequence select="                   functx:remove-elements-deep(node(), $names)"/>
1924
         </xsl:document>
1925
       </xsl:when>
1926
       <xsl:otherwise>
1927
         <xsl:sequence select="."/>
1928
       </xsl:otherwise>
1929
     </xsl:choose>
1930
   </xsl:for-each>
1931
 
1932
</xsl:function>
1933

    
1934

    
1935
<!--
1936
  Removes descendant XML elements but keeps their content 
1937

    
1938
 @author  Priscilla Walmsley, Datypic 
1939
 @version 1.0 
1940
 @see     http://www.xsltfunctions.com/xsl/functx_remove-elements-not-contents.html 
1941
 @param   $nodes the root(s) to start from 
1942
 @param   $names the names of the elements to remove 
1943
--> 
1944
<xsl:function name="functx:remove-elements-not-contents" as="node()*" xmlns:functx="http://www.functx.com">
1945
  <xsl:param name="nodes" as="node()*"/> 
1946
  <xsl:param name="names" as="xs:string*"/> 
1947
 
1948
   <xsl:for-each select="$nodes">
1949
     <xsl:choose>
1950
       <xsl:when test=". instance of element()">
1951
         <xsl:choose>
1952
           <xsl:when test="functx:name-test(name(),$names)">
1953
             <xsl:sequence select="                  functx:remove-elements-not-contents(node(), $names)"/>
1954
           </xsl:when>
1955
           <xsl:otherwise>
1956
             <xsl:element name="{node-name(.)}">
1957
               <xsl:sequence select="@*,                  functx:remove-elements-not-contents(node(),$names)"/>
1958
             </xsl:element>
1959
           </xsl:otherwise>
1960
         </xsl:choose>
1961
       </xsl:when>
1962
       <xsl:when test=". instance of document-node()">
1963
         <xsl:document>
1964
             <xsl:sequence select="                  functx:remove-elements-not-contents(node(), $names)"/>
1965
         </xsl:document>
1966
       </xsl:when>
1967
       <xsl:otherwise>
1968
         <xsl:sequence select="."/>
1969
       </xsl:otherwise>
1970
     </xsl:choose>
1971
   </xsl:for-each>
1972
 
1973
</xsl:function>
1974

    
1975

    
1976
<!--
1977
  Removes child elements from an XML node, based on name 
1978

    
1979
 @author  Priscilla Walmsley, Datypic 
1980
 @version 1.0 
1981
 @see     http://www.xsltfunctions.com/xsl/functx_remove-elements.html 
1982
 @param   $elements the element(s) from which you wish to remove the children 
1983
 @param   $names the names of the child elements to remove 
1984
--> 
1985
<xsl:function name="functx:remove-elements" as="element()*" xmlns:functx="http://www.functx.com">
1986
  <xsl:param name="elements" as="element()*"/> 
1987
  <xsl:param name="names" as="xs:string*"/> 
1988
 
1989
   <xsl:for-each select="$elements">
1990
     <xsl:element name="{node-name(.)}">
1991
       <xsl:sequence select="(@*,       node()[not(functx:name-test(name(),$names))])"/>
1992
     </xsl:element>
1993
   </xsl:for-each>
1994
 
1995
</xsl:function>
1996

    
1997

    
1998
<!--
1999
  Repeats a string a given number of times 
2000

    
2001
 @author  Priscilla Walmsley, Datypic 
2002
 @version 1.0 
2003
 @see     http://www.xsltfunctions.com/xsl/functx_repeat-string.html 
2004
 @param   $stringToRepeat the string to repeat 
2005
 @param   $count the desired number of copies 
2006
--> 
2007
<xsl:function name="functx:repeat-string" as="xs:string" xmlns:functx="http://www.functx.com">
2008
  <xsl:param name="stringToRepeat" as="xs:string?"/> 
2009
  <xsl:param name="count" as="xs:integer"/> 
2010
 
2011
  <xsl:sequence select="     string-join((for $i in 1 to $count return $stringToRepeat),                         '')  "/>
2012
   
2013
</xsl:function>
2014

    
2015

    
2016
<!--
2017
  Replaces the beginning of a string, up to a matched pattern 
2018

    
2019
 @author  Priscilla Walmsley, Datypic 
2020
 @version 1.0 
2021
 @see     http://www.xsltfunctions.com/xsl/functx_replace-beginning.html 
2022
 @param   $arg the entire string to change 
2023
 @param   $pattern the pattern of characters to replace up to 
2024
 @param   $replacement the replacement string 
2025
--> 
2026
<xsl:function name="functx:replace-beginning" as="xs:string" xmlns:functx="http://www.functx.com">
2027
  <xsl:param name="arg" as="xs:string?"/> 
2028
  <xsl:param name="pattern" as="xs:string"/> 
2029
  <xsl:param name="replacement" as="xs:string"/> 
2030
 
2031
  <xsl:sequence select="     replace($arg, concat('^.*?', $pattern), $replacement)  "/>
2032
   
2033
</xsl:function>
2034

    
2035

    
2036
<!--
2037
  Updates the content of one or more elements 
2038

    
2039
 @author  Priscilla Walmsley, Datypic 
2040
 @version 1.0 
2041
 @see     http://www.xsltfunctions.com/xsl/functx_replace-element-values.html 
2042
 @param   $elements the elements whose content you wish to replace 
2043
 @param   $values the replacement values 
2044
--> 
2045
<xsl:function name="functx:replace-element-values" as="element()*" xmlns:functx="http://www.functx.com">
2046
  <xsl:param name="elements" as="element()*"/> 
2047
  <xsl:param name="values" as="xs:anyAtomicType*"/> 
2048
 
2049
   <xsl:for-each select="$elements">
2050
     <xsl:variable name="seq" select="position()"/>
2051
     <xsl:element name="{node-name(.)}">
2052
       <xsl:sequence select="@*, $values[$seq]"/>
2053
     </xsl:element>
2054
   </xsl:for-each>
2055
 
2056
</xsl:function>
2057

    
2058

    
2059
<!--
2060
  Replaces the first match of a pattern 
2061

    
2062
 @author  Priscilla Walmsley, Datypic 
2063
 @version 1.0 
2064
 @see     http://www.xsltfunctions.com/xsl/functx_replace-first.html 
2065
 @param   $arg the entire string to change 
2066
 @param   $pattern the pattern of characters to replace 
2067
 @param   $replacement the replacement string 
2068
--> 
2069
<xsl:function name="functx:replace-first" as="xs:string" xmlns:functx="http://www.functx.com">
2070
  <xsl:param name="arg" as="xs:string?"/> 
2071
  <xsl:param name="pattern" as="xs:string"/> 
2072
  <xsl:param name="replacement" as="xs:string"/> 
2073
 
2074
  <xsl:sequence select="     replace($arg, concat('(^.*?)', $pattern),              concat('$1',$replacement))  "/>
2075
   
2076
</xsl:function>
2077

    
2078

    
2079
<!--
2080
  Performs multiple replacements, using pairs of replace parameters 
2081

    
2082
 @author  Priscilla Walmsley, Datypic 
2083
 @version 1.0 
2084
 @see     http://www.xsltfunctions.com/xsl/functx_replace-multi.html 
2085
 @param   $arg the string to manipulate 
2086
 @param   $changeFrom the sequence of strings or patterns to change from 
2087
 @param   $changeTo the sequence of strings to change to 
2088
--> 
2089
<xsl:function name="functx:replace-multi" as="xs:string?" xmlns:functx="http://www.functx.com">
2090
  <xsl:param name="arg" as="xs:string?"/> 
2091
  <xsl:param name="changeFrom" as="xs:string*"/> 
2092
  <xsl:param name="changeTo" as="xs:string*"/> 
2093
 
2094
  <xsl:sequence select="     if (count($changeFrom) &gt; 0)    then functx:replace-multi(           replace($arg, $changeFrom[1],                      functx:if-absent($changeTo[1],'')),           $changeFrom[position() &gt; 1],           $changeTo[position() &gt; 1])    else $arg  "/>
2095
   
2096
</xsl:function>
2097

    
2098

    
2099
<!--
2100
  Reverses the order of characters 
2101

    
2102
 @author  Priscilla Walmsley, Datypic 
2103
 @version 1.0 
2104
 @see     http://www.xsltfunctions.com/xsl/functx_reverse-string.html 
2105
 @param   $arg the string to reverse 
2106
--> 
2107
<xsl:function name="functx:reverse-string" as="xs:string" xmlns:functx="http://www.functx.com">
2108
  <xsl:param name="arg" as="xs:string?"/> 
2109
 
2110
  <xsl:sequence select="     codepoints-to-string(reverse(string-to-codepoints($arg)))  "/>
2111
   
2112
</xsl:function>
2113

    
2114

    
2115
<!--
2116
  Trims trailing whitespace 
2117

    
2118
 @author  Priscilla Walmsley, Datypic 
2119
 @version 1.0 
2120
 @see     http://www.xsltfunctions.com/xsl/functx_right-trim.html 
2121
 @param   $arg the string to trim 
2122
--> 
2123
<xsl:function name="functx:right-trim" as="xs:string" xmlns:functx="http://www.functx.com">
2124
  <xsl:param name="arg" as="xs:string?"/> 
2125
 
2126
  <xsl:sequence select="     replace($arg,'\s+$','')  "/>
2127
   
2128
</xsl:function>
2129

    
2130

    
2131
<!--
2132
  Returns the scheme from a URI 
2133

    
2134
 @author  Priscilla Walmsley, Datypic 
2135
 @version 1.0 
2136
 @see     http://www.xsltfunctions.com/xsl/functx_scheme-from-uri.html 
2137
 @param   $uri the URI 
2138
--> 
2139
<xsl:function name="functx:scheme-from-uri" as="xs:string?" xmlns:functx="http://www.functx.com">
2140
  <xsl:param name="uri" as="xs:string?"/> 
2141
 
2142
  <xsl:sequence select="     substring-before($uri,':')  "/>
2143
   
2144
</xsl:function>
2145

    
2146

    
2147
<!--
2148
  Whether two sequences have the same XML node content and/or values 
2149

    
2150
 @author  Priscilla Walmsley, Datypic 
2151
 @version 1.0 
2152
 @see     http://www.xsltfunctions.com/xsl/functx_sequence-deep-equal.html 
2153
 @param   $seq1 the first sequence 
2154
 @param   $seq2 the second sequence 
2155
--> 
2156
<xsl:function name="functx:sequence-deep-equal" as="xs:boolean" xmlns:functx="http://www.functx.com">
2157
  <xsl:param name="seq1" as="item()*"/> 
2158
  <xsl:param name="seq2" as="item()*"/> 
2159
 
2160
  <xsl:sequence select="    every $i in 1 to max((count($seq1),count($seq2)))   satisfies deep-equal($seq1[$i],$seq2[$i])  "/>
2161
   
2162
</xsl:function>
2163

    
2164

    
2165
<!--
2166
  Whether two sequences contain the same XML nodes, regardless of order 
2167

    
2168
 @author  Priscilla Walmsley, Datypic 
2169
 @version 1.0 
2170
 @see     http://www.xsltfunctions.com/xsl/functx_sequence-node-equal-any-order.html 
2171
 @param   $seq1 the first sequence of nodes 
2172
 @param   $seq2 the second sequence of nodes 
2173
--> 
2174
<xsl:function name="functx:sequence-node-equal-any-order" as="xs:boolean" xmlns:functx="http://www.functx.com">
2175
  <xsl:param name="seq1" as="node()*"/> 
2176
  <xsl:param name="seq2" as="node()*"/> 
2177
 
2178
  <xsl:sequence select="    not( ($seq1 except $seq2, $seq2 except $seq1))  "/>
2179
   
2180
</xsl:function>
2181

    
2182

    
2183
<!--
2184
  Whether two sequences contain the same XML nodes, in the same order 
2185

    
2186
 @author  Priscilla Walmsley, Datypic 
2187
 @version 1.0 
2188
 @see     http://www.xsltfunctions.com/xsl/functx_sequence-node-equal.html 
2189
 @param   $seq1 the first sequence of nodes 
2190
 @param   $seq2 the second sequence of nodes 
2191
--> 
2192
<xsl:function name="functx:sequence-node-equal" as="xs:boolean" xmlns:functx="http://www.functx.com">
2193
  <xsl:param name="seq1" as="node()*"/> 
2194
  <xsl:param name="seq2" as="node()*"/> 
2195
 
2196
  <xsl:sequence select="    every $i in 1 to max((count($seq1),count($seq2)))   satisfies $seq1[$i] is $seq2[$i]  "/>
2197
   
2198
</xsl:function>
2199

    
2200

    
2201
<!--
2202
  The sequence type that represents a sequence of nodes or values 
2203

    
2204
 @author  Priscilla Walmsley, Datypic 
2205
 @version 1.0 
2206
 @see     http://www.xsltfunctions.com/xsl/functx_sequence-type.html 
2207
 @param   $items the items whose sequence type you want to determine 
2208
--> 
2209
<xsl:function name="functx:sequence-type" as="xs:string" xmlns:functx="http://www.functx.com">
2210
  <xsl:param name="items" as="item()*"/> 
2211
 
2212
  <xsl:sequence select="  concat(   if (empty($items))   then 'empty-sequence()'   else if (every $val in $items            satisfies $val instance of xs:anyAtomicType)   then if (count(distinct-values(functx:atomic-type($items)))            &gt; 1)   then 'xs:anyAtomicType'   else functx:atomic-type($items[1])   else if (some $val in $items            satisfies $val instance of xs:anyAtomicType)   then 'item()'   else if (count(distinct-values(functx:node-kind($items))) &gt; 1)   then 'node()'   else concat(functx:node-kind($items[1]),'()')   ,   if (count($items) &gt; 1)   then '+' else '')    "/>
2213
   
2214
</xsl:function>
2215

    
2216

    
2217
<!--
2218
  The siblings of an XML element that have the same name 
2219

    
2220
 @author  Priscilla Walmsley, Datypic 
2221
 @version 1.0 
2222
 @see     http://www.xsltfunctions.com/xsl/functx_siblings-same-name.html 
2223
 @param   $element the node 
2224
--> 
2225
<xsl:function name="functx:siblings-same-name" as="element()*" xmlns:functx="http://www.functx.com">
2226
  <xsl:param name="element" as="element()?"/> 
2227
 
2228
  <xsl:sequence select="     $element/../*[node-name(.) = node-name($element)]    except $element  "/>
2229
   
2230
</xsl:function>
2231

    
2232

    
2233
<!--
2234
  The siblings of an XML node 
2235

    
2236
 @author  Priscilla Walmsley, Datypic 
2237
 @version 1.0 
2238
 @see     http://www.xsltfunctions.com/xsl/functx_siblings.html 
2239
 @param   $node the node 
2240
--> 
2241
<xsl:function name="functx:siblings" as="node()*" xmlns:functx="http://www.functx.com">
2242
  <xsl:param name="node" as="node()?"/> 
2243
 
2244
  <xsl:sequence select="     $node/../node() except $node  "/>
2245
   
2246
</xsl:function>
2247

    
2248

    
2249
<!--
2250
  Sorts a sequence of numeric values or nodes 
2251

    
2252
 @author  Priscilla Walmsley, Datypic 
2253
 @version 1.0 
2254
 @see     http://www.xsltfunctions.com/xsl/functx_sort-as-numeric.html 
2255
 @param   $seq the sequence to sort 
2256
--> 
2257
<xsl:function name="functx:sort-as-numeric" as="item()*" xmlns:functx="http://www.functx.com">
2258
  <xsl:param name="seq" as="item()*"/> 
2259
 
2260
   <xsl:for-each select="$seq">
2261
     <xsl:sort select="number(.)"/>
2262
     <xsl:copy-of select="."/>
2263
   </xsl:for-each>
2264
 
2265
</xsl:function>
2266

    
2267

    
2268
<!--
2269
  Sorts a sequence of values or nodes regardless of capitalization 
2270

    
2271
 @author  Priscilla Walmsley, Datypic 
2272
 @version 1.0 
2273
 @see     http://www.xsltfunctions.com/xsl/functx_sort-case-insensitive.html 
2274
 @param   $seq the sequence to sort 
2275
--> 
2276
<xsl:function name="functx:sort-case-insensitive" as="item()*" xmlns:functx="http://www.functx.com">
2277
  <xsl:param name="seq" as="item()*"/> 
2278
 
2279
   <xsl:for-each select="$seq">
2280
     <xsl:sort select="upper-case(string(.))"/>
2281
     <xsl:copy-of select="."/>
2282
   </xsl:for-each>
2283
 
2284
</xsl:function>
2285

    
2286

    
2287
<!--
2288
  Sorts a sequence of nodes in document order 
2289

    
2290
 @author  Priscilla Walmsley, Datypic 
2291
 @version 1.0 
2292
 @see     http://www.xsltfunctions.com/xsl/functx_sort-document-order.html 
2293
 @param   $seq the sequence to sort 
2294
--> 
2295
<xsl:function name="functx:sort-document-order" as="node()*" xmlns:functx="http://www.functx.com">
2296
  <xsl:param name="seq" as="node()*"/> 
2297
 
2298
  <xsl:sequence select="     $seq/.  "/>
2299
   
2300
</xsl:function>
2301

    
2302

    
2303
<!--
2304
  Sorts a sequence of values or nodes 
2305

    
2306
 @author  Priscilla Walmsley, Datypic 
2307
 @version 1.0 
2308
 @see     http://www.xsltfunctions.com/xsl/functx_sort.html 
2309
 @param   $seq the sequence to sort 
2310
--> 
2311
<xsl:function name="functx:sort" as="item()*" xmlns:functx="http://www.functx.com">
2312
  <xsl:param name="seq" as="item()*"/> 
2313
 
2314
   <xsl:for-each select="$seq">
2315
     <xsl:sort select="."/>
2316
     <xsl:copy-of select="."/>
2317
   </xsl:for-each>
2318
 
2319
</xsl:function>
2320

    
2321

    
2322
<!--
2323
  Performs substring-after, returning the entire string if it does not contain the delimiter 
2324

    
2325
 @author  Priscilla Walmsley, Datypic 
2326
 @version 1.0 
2327
 @see     http://www.xsltfunctions.com/xsl/functx_substring-after-if-contains.html 
2328
 @param   $arg the string to substring 
2329
 @param   $delim the delimiter 
2330
--> 
2331
<xsl:function name="functx:substring-after-if-contains" as="xs:string?" xmlns:functx="http://www.functx.com">
2332
  <xsl:param name="arg" as="xs:string?"/> 
2333
  <xsl:param name="delim" as="xs:string"/> 
2334
 
2335
  <xsl:sequence select="     if (contains($arg,$delim))    then substring-after($arg,$delim)    else $arg  "/>
2336
   
2337
</xsl:function>
2338

    
2339

    
2340
<!--
2341
  The substring after the last text that matches a regex 
2342

    
2343
 @author  Priscilla Walmsley, Datypic 
2344
 @version 1.0 
2345
 @see     http://www.xsltfunctions.com/xsl/functx_substring-after-last-match.html 
2346
 @param   $arg the string to substring 
2347
 @param   $regex the regular expression 
2348
--> 
2349
<xsl:function name="functx:substring-after-last-match" as="xs:string" xmlns:functx="http://www.functx.com">
2350
  <xsl:param name="arg" as="xs:string?"/> 
2351
  <xsl:param name="regex" as="xs:string"/> 
2352
 
2353
  <xsl:sequence select="     replace($arg,concat('^.*',$regex),'')  "/>
2354
   
2355
</xsl:function>
2356

    
2357

    
2358
<!--
2359
  The substring after the last occurrence of a delimiter 
2360

    
2361
 @author  Priscilla Walmsley, Datypic 
2362
 @version 1.0 
2363
 @see     http://www.xsltfunctions.com/xsl/functx_substring-after-last.html 
2364
 @param   $arg the string to substring 
2365
 @param   $delim the delimiter 
2366
--> 
2367
<xsl:function name="functx:substring-after-last" as="xs:string" xmlns:functx="http://www.functx.com">
2368
  <xsl:param name="arg" as="xs:string?"/> 
2369
  <xsl:param name="delim" as="xs:string"/> 
2370
 
2371
  <xsl:sequence select="     replace ($arg,concat('^.*',functx:escape-for-regex($delim)),'')  "/>
2372
   
2373
</xsl:function>
2374

    
2375

    
2376
<!--
2377
  The substring after the first text that matches a regex 
2378

    
2379
 @author  Priscilla Walmsley, Datypic 
2380
 @version 1.0 
2381
 @see     http://www.xsltfunctions.com/xsl/functx_substring-after-match.html 
2382
 @param   $arg the string to substring 
2383
 @param   $regex the regular expression 
2384
--> 
2385
<xsl:function name="functx:substring-after-match" as="xs:string?" xmlns:functx="http://www.functx.com">
2386
  <xsl:param name="arg" as="xs:string?"/> 
2387
  <xsl:param name="regex" as="xs:string"/> 
2388
 
2389
  <xsl:sequence select="     replace($arg,concat('^.*?',$regex),'')  "/>
2390
   
2391
</xsl:function>
2392

    
2393

    
2394
<!--
2395
  Performs substring-before, returning the entire string if it does not contain the delimiter 
2396

    
2397
 @author  Priscilla Walmsley, Datypic 
2398
 @version 1.0 
2399
 @see     http://www.xsltfunctions.com/xsl/functx_substring-before-if-contains.html 
2400
 @param   $arg the string to substring 
2401
 @param   $delim the delimiter 
2402
--> 
2403
<xsl:function name="functx:substring-before-if-contains" as="xs:string?" xmlns:functx="http://www.functx.com">
2404
  <xsl:param name="arg" as="xs:string?"/> 
2405
  <xsl:param name="delim" as="xs:string"/> 
2406
 
2407
  <xsl:sequence select="     if (contains($arg,$delim))    then substring-before($arg,$delim)    else $arg  "/>
2408
   
2409
</xsl:function>
2410

    
2411

    
2412
<!--
2413
  The substring after the first text that matches a regex 
2414

    
2415
 @author  Priscilla Walmsley, Datypic 
2416
 @version 1.0 
2417
 @see     http://www.xsltfunctions.com/xsl/functx_substring-before-last-match.html 
2418
 @param   $arg the string to substring 
2419
 @param   $regex the regular expression 
2420
--> 
2421
<xsl:function name="functx:substring-before-last-match" as="xs:string?" xmlns:functx="http://www.functx.com">
2422
  <xsl:param name="arg" as="xs:string?"/> 
2423
  <xsl:param name="regex" as="xs:string"/> 
2424
 
2425
  <xsl:sequence select="     replace($arg,concat('^(.*)',$regex,'.*'),'$1')  "/>
2426
   
2427
</xsl:function>
2428

    
2429

    
2430
<!--
2431
  The substring before the last occurrence of a delimiter 
2432

    
2433
 @author  Priscilla Walmsley, Datypic 
2434
 @version 1.0 
2435
 @see     http://www.xsltfunctions.com/xsl/functx_substring-before-last.html 
2436
 @param   $arg the string to substring 
2437
 @param   $delim the delimiter 
2438
--> 
2439
<xsl:function name="functx:substring-before-last" as="xs:string" xmlns:functx="http://www.functx.com">
2440
  <xsl:param name="arg" as="xs:string?"/> 
2441
  <xsl:param name="delim" as="xs:string"/> 
2442
 
2443
  <xsl:sequence select="     if (matches($arg, functx:escape-for-regex($delim)))    then replace($arg,             concat('^(.*)', functx:escape-for-regex($delim),'.*'),             '$1')    else ''  "/>
2444
   
2445
</xsl:function>
2446

    
2447

    
2448
<!--
2449
  The substring before the last text that matches a regex 
2450

    
2451
 @author  Priscilla Walmsley, Datypic 
2452
 @version 1.0 
2453
 @see     http://www.xsltfunctions.com/xsl/functx_substring-before-match.html 
2454
 @param   $arg the string to substring 
2455
 @param   $regex the regular expression 
2456
--> 
2457
<xsl:function name="functx:substring-before-match" as="xs:string" xmlns:functx="http://www.functx.com">
2458
  <xsl:param name="arg" as="xs:string?"/> 
2459
  <xsl:param name="regex" as="xs:string"/> 
2460
 
2461
  <xsl:sequence select="     tokenize($arg,$regex)[1]  "/>
2462
   
2463
</xsl:function>
2464

    
2465

    
2466
<!--
2467
  Construct a time from an hour, minute and second 
2468

    
2469
 @author  Priscilla Walmsley, Datypic 
2470
 @version 1.0 
2471
 @see     http://www.xsltfunctions.com/xsl/functx_time.html 
2472
 @param   $hour the hour 
2473
 @param   $minute the minute 
2474
 @param   $second the second 
2475
--> 
2476
<xsl:function name="functx:time" as="xs:time" xmlns:functx="http://www.functx.com">
2477
  <xsl:param name="hour" as="xs:anyAtomicType"/> 
2478
  <xsl:param name="minute" as="xs:anyAtomicType"/> 
2479
  <xsl:param name="second" as="xs:anyAtomicType"/> 
2480
 
2481
  <xsl:sequence select="     xs:time(      concat(        functx:pad-integer-to-length(xs:integer($hour),2),':',        functx:pad-integer-to-length(xs:integer($minute),2),':',        functx:pad-integer-to-length(xs:integer($second),2)))  "/>
2482
   
2483
</xsl:function>
2484

    
2485

    
2486
<!--
2487
  Converts an xs:dayTimeDuration into a timezone like "-05:00" or "Z" 
2488

    
2489
 @author  Priscilla Walmsley, Datypic 
2490
 @version 1.0 
2491
 @see     http://www.xsltfunctions.com/xsl/functx_timezone-from-duration.html 
2492
 @param   $duration the duration 
2493
--> 
2494
<xsl:function name="functx:timezone-from-duration" as="xs:string" xmlns:functx="http://www.functx.com">
2495
  <xsl:param name="duration" as="xs:dayTimeDuration"/> 
2496
 
2497
  <xsl:sequence select="     if (string($duration) = ('PT0S','-PT0S'))    then 'Z'    else if (matches(string($duration),'-PT[1-9]H'))    then replace(string($duration),'PT([1-9])H','0$1:00')    else if (matches(string($duration),'PT[1-9]H'))    then replace(string($duration),'PT([1-9])H','+0$1:00')    else if (matches(string($duration),'-PT1[0-4]H'))    then replace(string($duration),'PT(1[0-4])H','$1:00')    else if (matches(string($duration),'PT1[0-4]H'))    then replace(string($duration),'PT(1[0-4])H','+$1:00')    else error(xs:QName('functx:Invalid_Duration_Value'))  "/>
2498
   
2499
</xsl:function>
2500

    
2501

    
2502
<!--
2503
  The total number of days in a dayTimeDuration 
2504

    
2505
 @author  Priscilla Walmsley, Datypic 
2506
 @version 1.0 
2507
 @see     http://www.xsltfunctions.com/xsl/functx_total-days-from-duration.html 
2508
 @param   $duration the duration 
2509
--> 
2510
<xsl:function name="functx:total-days-from-duration" as="xs:decimal?" xmlns:functx="http://www.functx.com">
2511
  <xsl:param name="duration" as="xs:dayTimeDuration?"/> 
2512
 
2513
  <xsl:sequence select="     $duration div xs:dayTimeDuration('P1D')  "/>
2514
   
2515
</xsl:function>
2516

    
2517

    
2518
<!--
2519
  The total number of hours in a dayTimeDuration 
2520

    
2521
 @author  Priscilla Walmsley, Datypic 
2522
 @version 1.0 
2523
 @see     http://www.xsltfunctions.com/xsl/functx_total-hours-from-duration.html 
2524
 @param   $duration the duration 
2525
--> 
2526
<xsl:function name="functx:total-hours-from-duration" as="xs:decimal?" xmlns:functx="http://www.functx.com">
2527
  <xsl:param name="duration" as="xs:dayTimeDuration?"/> 
2528
 
2529
  <xsl:sequence select="     $duration div xs:dayTimeDuration('PT1H')  "/>
2530
   
2531
</xsl:function>
2532

    
2533

    
2534
<!--
2535
  The total number of minutes in a dayTimeDuration 
2536

    
2537
 @author  Priscilla Walmsley, Datypic 
2538
 @version 1.0 
2539
 @see     http://www.xsltfunctions.com/xsl/functx_total-minutes-from-duration.html 
2540
 @param   $duration the duration 
2541
--> 
2542
<xsl:function name="functx:total-minutes-from-duration" as="xs:decimal?" xmlns:functx="http://www.functx.com">
2543
  <xsl:param name="duration" as="xs:dayTimeDuration?"/> 
2544
 
2545
  <xsl:sequence select="     $duration div xs:dayTimeDuration('PT1M')  "/>
2546
   
2547
</xsl:function>
2548

    
2549

    
2550
<!--
2551
  The total number of months in a yearMonthDuration 
2552

    
2553
 @author  Priscilla Walmsley, Datypic 
2554
 @version 1.0 
2555
 @see     http://www.xsltfunctions.com/xsl/functx_total-months-from-duration.html 
2556
 @param   $duration the duration 
2557
--> 
2558
<xsl:function name="functx:total-months-from-duration" as="xs:decimal?" xmlns:functx="http://www.functx.com">
2559
  <xsl:param name="duration" as="xs:yearMonthDuration?"/> 
2560
 
2561
  <xsl:sequence select="     $duration div xs:yearMonthDuration('P1M')  "/>
2562
   
2563
</xsl:function>
2564

    
2565

    
2566
<!--
2567
  The total number of seconds in a dayTimeDuration 
2568

    
2569
 @author  Priscilla Walmsley, Datypic 
2570
 @version 1.0 
2571
 @see     http://www.xsltfunctions.com/xsl/functx_total-seconds-from-duration.html 
2572
 @param   $duration the duration 
2573
--> 
2574
<xsl:function name="functx:total-seconds-from-duration" as="xs:decimal?" xmlns:functx="http://www.functx.com">
2575
  <xsl:param name="duration" as="xs:dayTimeDuration?"/> 
2576
 
2577
  <xsl:sequence select="     $duration div xs:dayTimeDuration('PT1S')  "/>
2578
   
2579
</xsl:function>
2580

    
2581

    
2582
<!--
2583
  The total number of years in a yearMonthDuration 
2584

    
2585
 @author  Priscilla Walmsley, Datypic 
2586
 @version 1.0 
2587
 @see     http://www.xsltfunctions.com/xsl/functx_total-years-from-duration.html 
2588
 @param   $duration the duration 
2589
--> 
2590
<xsl:function name="functx:total-years-from-duration" as="xs:decimal?" xmlns:functx="http://www.functx.com">
2591
  <xsl:param name="duration" as="xs:yearMonthDuration?"/> 
2592
 
2593
  <xsl:sequence select="     $duration div xs:yearMonthDuration('P1Y')  "/>
2594
   
2595
</xsl:function>
2596

    
2597

    
2598
<!--
2599
  Trims leading and trailing whitespace 
2600

    
2601
 @author  Priscilla Walmsley, Datypic 
2602
 @version 1.0 
2603
 @see     http://www.xsltfunctions.com/xsl/functx_trim.html 
2604
 @param   $arg the string to trim 
2605
--> 
2606
<xsl:function name="functx:trim" as="xs:string" xmlns:functx="http://www.functx.com">
2607
  <xsl:param name="arg" as="xs:string?"/> 
2608
 
2609
  <xsl:sequence select="     replace(replace($arg,'\s+$',''),'^\s+','')  "/>
2610
   
2611
</xsl:function>
2612

    
2613

    
2614
<!--
2615
  Updates the attribute value of an XML element 
2616

    
2617
 @author  Priscilla Walmsley, Datypic 
2618
 @version 1.0 
2619
 @see     http://www.xsltfunctions.com/xsl/functx_update-attributes.html 
2620
 @param   $elements the element(s) for which you wish to update the attribute 
2621
 @param   $attrNames the name(s) of the attribute(s) to add 
2622
 @param   $attrValues the value(s) of the attribute(s) to add 
2623
--> 
2624
<xsl:function name="functx:update-attributes" as="element()?" xmlns:functx="http://www.functx.com">
2625
  <xsl:param name="elements" as="element()*"/> 
2626
  <xsl:param name="attrNames" as="xs:QName*"/> 
2627
  <xsl:param name="attrValues" as="xs:anyAtomicType*"/> 
2628
 
2629
  <xsl:for-each select="$elements">
2630
    <xsl:variable name="element" select="."/>
2631
    <xsl:copy>
2632
      <xsl:for-each select="$attrNames">
2633
        <xsl:variable name="seq" select="position()"/>
2634
        <xsl:if test="$element/@*[node-name(.) = current()]">
2635
          <xsl:attribute name="{.}" namespace="{namespace-uri-from-QName(.)}" select="$attrValues[$seq]"/>
2636
        </xsl:if>
2637
      </xsl:for-each>
2638
      <xsl:copy-of select="@*[not(node-name(.) = $attrNames)]|node()"/>
2639
    </xsl:copy>
2640
  </xsl:for-each>
2641
 
2642
</xsl:function>
2643

    
2644

    
2645
<!--
2646
  The values in one sequence that aren't in another sequence 
2647

    
2648
 @author  W3C XML Query Working Group 
2649
 @version 1.0 
2650
 @see     http://www.xsltfunctions.com/xsl/functx_value-except.html 
2651
 @param   $arg1 the first sequence 
2652
 @param   $arg2 the second sequence 
2653
--> 
2654
<xsl:function name="functx:value-except" as="xs:anyAtomicType*" xmlns:functx="http://www.functx.com">
2655
  <xsl:param name="arg1" as="xs:anyAtomicType*"/> 
2656
  <xsl:param name="arg2" as="xs:anyAtomicType*"/> 
2657
 
2658
  <xsl:sequence select="    distinct-values($arg1[not(.=$arg2)])  "/>
2659
   
2660
</xsl:function>
2661

    
2662

    
2663
<!--
2664
  The intersection of two sequences of values 
2665

    
2666
 @author  W3C XML Query Working Group 
2667
 @version 1.0 
2668
 @see     http://www.xsltfunctions.com/xsl/functx_value-intersect.html 
2669
 @param   $arg1 the first sequence 
2670
 @param   $arg2 the second sequence 
2671
--> 
2672
<xsl:function name="functx:value-intersect" as="xs:anyAtomicType*" xmlns:functx="http://www.functx.com">
2673
  <xsl:param name="arg1" as="xs:anyAtomicType*"/> 
2674
  <xsl:param name="arg2" as="xs:anyAtomicType*"/> 
2675
 
2676
  <xsl:sequence select="    distinct-values($arg1[.=$arg2])  "/>
2677
   
2678
</xsl:function>
2679

    
2680

    
2681
<!--
2682
  The union of two sequences of values 
2683

    
2684
 @author  W3C XML Query Working Group 
2685
 @version 1.0 
2686
 @see     http://www.xsltfunctions.com/xsl/functx_value-union.html 
2687
 @param   $arg1 the first sequence 
2688
 @param   $arg2 the second sequence 
2689
--> 
2690
<xsl:function name="functx:value-union" as="xs:anyAtomicType*" xmlns:functx="http://www.functx.com">
2691
  <xsl:param name="arg1" as="xs:anyAtomicType*"/> 
2692
  <xsl:param name="arg2" as="xs:anyAtomicType*"/> 
2693
 
2694
  <xsl:sequence select="    distinct-values(($arg1, $arg2))  "/>
2695
   
2696
</xsl:function>
2697

    
2698

    
2699
<!--
2700
  The number of words 
2701

    
2702
 @author  Priscilla Walmsley, Datypic 
2703
 @version 1.0 
2704
 @see     http://www.xsltfunctions.com/xsl/functx_word-count.html 
2705
 @param   $arg the string to measure 
2706
--> 
2707
<xsl:function name="functx:word-count" as="xs:integer" xmlns:functx="http://www.functx.com">
2708
  <xsl:param name="arg" as="xs:string?"/> 
2709
 
2710
  <xsl:sequence select="     count(tokenize($arg, '\W+')[. != ''])  "/>
2711
   
2712
</xsl:function>
2713

    
2714

    
2715
<!--
2716
  Turns a string of words into camelCase 
2717

    
2718
 @author  Priscilla Walmsley, Datypic 
2719
 @version 1.0 
2720
 @see     http://www.xsltfunctions.com/xsl/functx_words-to-camel-case.html 
2721
 @param   $arg the string to modify 
2722
--> 
2723
<xsl:function name="functx:words-to-camel-case" as="xs:string" xmlns:functx="http://www.functx.com">
2724
  <xsl:param name="arg" as="xs:string?"/> 
2725
 
2726
  <xsl:sequence select="       string-join((tokenize($arg,'\s+')[1],        for $word in tokenize($arg,'\s+')[position() &gt; 1]        return functx:capitalize-first($word))       ,'')  "/>
2727
   
2728
</xsl:function>
2729

    
2730

    
2731
<!--
2732
  Wraps a sequence of atomic values in XML elements 
2733

    
2734
 @author  Priscilla Walmsley, Datypic 
2735
 @version 1.0 
2736
 @see     http://www.xsltfunctions.com/xsl/functx_wrap-values-in-elements.html 
2737
 @param   $values the values to wrap in elements 
2738
 @param   $elementName the name of the elements to construct 
2739
--> 
2740
<xsl:function name="functx:wrap-values-in-elements" as="element()*" xmlns:functx="http://www.functx.com">
2741
  <xsl:param name="values" as="xs:anyAtomicType*"/> 
2742
  <xsl:param name="elementName" as="xs:QName"/> 
2743
 
2744
   <xsl:for-each select="$values">
2745
     <xsl:element name="{$elementName}" namespace="{namespace-uri-from-QName($elementName)}">
2746
       <xsl:sequence select="."/>
2747
     </xsl:element>
2748
   </xsl:for-each>
2749
 
2750
</xsl:function>
2751

    
2752

    
2753
<!--
2754
  Construct a yearMonthDuration from a number of years and months 
2755

    
2756
 @author  Priscilla Walmsley, Datypic 
2757
 @version 1.0 
2758
 @see     http://www.xsltfunctions.com/xsl/functx_yearmonthduration.html 
2759
 @param   $years the number of years 
2760
 @param   $months the number of months 
2761
--> 
2762
<xsl:function name="functx:yearMonthDuration" as="xs:yearMonthDuration" xmlns:functx="http://www.functx.com">
2763
  <xsl:param name="years" as="xs:decimal?"/> 
2764
  <xsl:param name="months" as="xs:integer?"/> 
2765
 
2766
  <xsl:sequence select="      (xs:yearMonthDuration('P1M') * functx:if-empty($months,0)) +     (xs:yearMonthDuration('P1Y') * functx:if-empty($years,0))  "/>
2767
   
2768
</xsl:function>
2769

    
2770

    
2771
</xsl:stylesheet>
(1-1/2)