]> git.stg.codes - stg.git/blob - doc/xslt/slides/keynote/xsltsl/string.xsl
Merge branch 'stg-2.409'
[stg.git] / doc / xslt / slides / keynote / xsltsl / string.xsl
1 <?xml version="1.0"?>
2
3 <xsl:stylesheet version="1.0"
4         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5         xmlns:doc="http://xsltsl.org/xsl/documentation/1.0"
6         xmlns:str="http://xsltsl.org/string"
7         extension-element-prefixes="doc str">
8
9   <doc:reference xmlns="">
10     <referenceinfo>
11       <releaseinfo role="meta">
12         $Id: string.xsl 3991 2004-11-10 06:51:55Z balls $
13       </releaseinfo>
14       <author>
15         <surname>Ball</surname>
16         <firstname>Steve</firstname>
17       </author>
18       <copyright>
19         <year>2002</year>
20         <year>2001</year>
21         <holder>Steve Ball</holder>
22       </copyright>
23     </referenceinfo>
24
25     <title>String Processing</title>
26
27     <partintro>
28       <section>
29         <title>Introduction</title>
30
31         <para>This module provides templates for manipulating strings.</para>
32
33       </section>
34     </partintro>
35
36   </doc:reference>
37
38   <!-- Common string constants and datasets as XSL variables -->
39
40   <!-- str:lower and str:upper contain pairs of lower and upper case
41        characters. Below insanely long strings should contain the
42        official lower/uppercase pairs, making this stylesheet working
43        for every language on earth. Hopefully. -->
44   <!-- These values are not enough, however. There are some
45        exceptions, dealt with below. -->
46   <xsl:variable name="xsltsl-str-lower" select="'&#x0061;&#x0062;&#x0063;&#x0064;&#x0065;&#x0066;&#x0067;&#x0068;&#x0069;&#x006A;&#x006B;&#x006C;&#x006D;&#x006E;&#x006F;&#x0070;&#x0071;&#x0072;&#x0073;&#x0074;&#x0075;&#x0076;&#x0077;&#x0078;&#x0079;&#x007A;&#x00B5;&#x00E0;&#x00E1;&#x00E2;&#x00E3;&#x00E4;&#x00E5;&#x00E6;&#x00E7;&#x00E8;&#x00E9;&#x00EA;&#x00EB;&#x00EC;&#x00ED;&#x00EE;&#x00EF;&#x00F0;&#x00F1;&#x00F2;&#x00F3;&#x00F4;&#x00F5;&#x00F6;&#x00F8;&#x00F9;&#x00FA;&#x00FB;&#x00FC;&#x00FD;&#x00FE;&#x00FF;&#x0101;&#x0103;&#x0105;&#x0107;&#x0109;&#x010B;&#x010D;&#x010F;&#x0111;&#x0113;&#x0115;&#x0117;&#x0119;&#x011B;&#x011D;&#x011F;&#x0121;&#x0123;&#x0125;&#x0127;&#x0129;&#x012B;&#x012D;&#x012F;&#x0131;&#x0133;&#x0135;&#x0137;&#x013A;&#x013C;&#x013E;&#x0140;&#x0142;&#x0144;&#x0146;&#x0148;&#x014B;&#x014D;&#x014F;&#x0151;&#x0153;&#x0155;&#x0157;&#x0159;&#x015B;&#x015D;&#x015F;&#x0161;&#x0163;&#x0165;&#x0167;&#x0169;&#x016B;&#x016D;&#x016F;&#x0171;&#x0173;&#x0175;&#x0177;&#x017A;&#x017C;&#x017E;&#x017F;&#x0183;&#x0185;&#x0188;&#x018C;&#x0192;&#x0195;&#x0199;&#x01A1;&#x01A3;&#x01A5;&#x01A8;&#x01AD;&#x01B0;&#x01B4;&#x01B6;&#x01B9;&#x01BD;&#x01BF;&#x01C5;&#x01C6;&#x01C8;&#x01C9;&#x01CB;&#x01CC;&#x01CE;&#x01D0;&#x01D2;&#x01D4;&#x01D6;&#x01D8;&#x01DA;&#x01DC;&#x01DD;&#x01DF;&#x01E1;&#x01E3;&#x01E5;&#x01E7;&#x01E9;&#x01EB;&#x01ED;&#x01EF;&#x01F2;&#x01F3;&#x01F5;&#x01F9;&#x01FB;&#x01FD;&#x01FF;&#x0201;&#x0203;&#x0205;&#x0207;&#x0209;&#x020B;&#x020D;&#x020F;&#x0211;&#x0213;&#x0215;&#x0217;&#x0219;&#x021B;&#x021D;&#x021F;&#x0223;&#x0225;&#x0227;&#x0229;&#x022B;&#x022D;&#x022F;&#x0231;&#x0233;&#x0253;&#x0254;&#x0256;&#x0257;&#x0259;&#x025B;&#x0260;&#x0263;&#x0268;&#x0269;&#x026F;&#x0272;&#x0275;&#x0280;&#x0283;&#x0288;&#x028A;&#x028B;&#x0292;&#x0345;&#x03AC;&#x03AD;&#x03AE;&#x03AF;&#x03B1;&#x03B2;&#x03B3;&#x03B4;&#x03B5;&#x03B6;&#x03B7;&#x03B8;&#x03B9;&#x03BA;&#x03BB;&#x03BC;&#x03BD;&#x03BE;&#x03BF;&#x03C0;&#x03C1;&#x03C2;&#x03C3;&#x03C4;&#x03C5;&#x03C6;&#x03C7;&#x03C8;&#x03C9;&#x03CA;&#x03CB;&#x03CC;&#x03CD;&#x03CE;&#x03D0;&#x03D1;&#x03D5;&#x03D6;&#x03DB;&#x03DD;&#x03DF;&#x03E1;&#x03E3;&#x03E5;&#x03E7;&#x03E9;&#x03EB;&#x03ED;&#x03EF;&#x03F0;&#x03F1;&#x03F2;&#x03F5;&#x0430;&#x0431;&#x0432;&#x0433;&#x0434;&#x0435;&#x0436;&#x0437;&#x0438;&#x0439;&#x043A;&#x043B;&#x043C;&#x043D;&#x043E;&#x043F;&#x0440;&#x0441;&#x0442;&#x0443;&#x0444;&#x0445;&#x0446;&#x0447;&#x0448;&#x0449;&#x044A;&#x044B;&#x044C;&#x044D;&#x044E;&#x044F;&#x0450;&#x0451;&#x0452;&#x0453;&#x0454;&#x0455;&#x0456;&#x0457;&#x0458;&#x0459;&#x045A;&#x045B;&#x045C;&#x045D;&#x045E;&#x045F;&#x0461;&#x0463;&#x0465;&#x0467;&#x0469;&#x046B;&#x046D;&#x046F;&#x0471;&#x0473;&#x0475;&#x0477;&#x0479;&#x047B;&#x047D;&#x047F;&#x0481;&#x048D;&#x048F;&#x0491;&#x0493;&#x0495;&#x0497;&#x0499;&#x049B;&#x049D;&#x049F;&#x04A1;&#x04A3;&#x04A5;&#x04A7;&#x04A9;&#x04AB;&#x04AD;&#x04AF;&#x04B1;&#x04B3;&#x04B5;&#x04B7;&#x04B9;&#x04BB;&#x04BD;&#x04BF;&#x04C2;&#x04C4;&#x04C8;&#x04CC;&#x04D1;&#x04D3;&#x04D5;&#x04D7;&#x04D9;&#x04DB;&#x04DD;&#x04DF;&#x04E1;&#x04E3;&#x04E5;&#x04E7;&#x04E9;&#x04EB;&#x04ED;&#x04EF;&#x04F1;&#x04F3;&#x04F5;&#x04F9;&#x0561;&#x0562;&#x0563;&#x0564;&#x0565;&#x0566;&#x0567;&#x0568;&#x0569;&#x056A;&#x056B;&#x056C;&#x056D;&#x056E;&#x056F;&#x0570;&#x0571;&#x0572;&#x0573;&#x0574;&#x0575;&#x0576;&#x0577;&#x0578;&#x0579;&#x057A;&#x057B;&#x057C;&#x057D;&#x057E;&#x057F;&#x0580;&#x0581;&#x0582;&#x0583;&#x0584;&#x0585;&#x0586;&#x1E01;&#x1E03;&#x1E05;&#x1E07;&#x1E09;&#x1E0B;&#x1E0D;&#x1E0F;&#x1E11;&#x1E13;&#x1E15;&#x1E17;&#x1E19;&#x1E1B;&#x1E1D;&#x1E1F;&#x1E21;&#x1E23;&#x1E25;&#x1E27;&#x1E29;&#x1E2B;&#x1E2D;&#x1E2F;&#x1E31;&#x1E33;&#x1E35;&#x1E37;&#x1E39;&#x1E3B;&#x1E3D;&#x1E3F;&#x1E41;&#x1E43;&#x1E45;&#x1E47;&#x1E49;&#x1E4B;&#x1E4D;&#x1E4F;&#x1E51;&#x1E53;&#x1E55;&#x1E57;&#x1E59;&#x1E5B;&#x1E5D;&#x1E5F;&#x1E61;&#x1E63;&#x1E65;&#x1E67;&#x1E69;&#x1E6B;&#x1E6D;&#x1E6F;&#x1E71;&#x1E73;&#x1E75;&#x1E77;&#x1E79;&#x1E7B;&#x1E7D;&#x1E7F;&#x1E81;&#x1E83;&#x1E85;&#x1E87;&#x1E89;&#x1E8B;&#x1E8D;&#x1E8F;&#x1E91;&#x1E93;&#x1E95;&#x1E9B;&#x1EA1;&#x1EA3;&#x1EA5;&#x1EA7;&#x1EA9;&#x1EAB;&#x1EAD;&#x1EAF;&#x1EB1;&#x1EB3;&#x1EB5;&#x1EB7;&#x1EB9;&#x1EBB;&#x1EBD;&#x1EBF;&#x1EC1;&#x1EC3;&#x1EC5;&#x1EC7;&#x1EC9;&#x1ECB;&#x1ECD;&#x1ECF;&#x1ED1;&#x1ED3;&#x1ED5;&#x1ED7;&#x1ED9;&#x1EDB;&#x1EDD;&#x1EDF;&#x1EE1;&#x1EE3;&#x1EE5;&#x1EE7;&#x1EE9;&#x1EEB;&#x1EED;&#x1EEF;&#x1EF1;&#x1EF3;&#x1EF5;&#x1EF7;&#x1EF9;&#x1F00;&#x1F01;&#x1F02;&#x1F03;&#x1F04;&#x1F05;&#x1F06;&#x1F07;&#x1F10;&#x1F11;&#x1F12;&#x1F13;&#x1F14;&#x1F15;&#x1F20;&#x1F21;&#x1F22;&#x1F23;&#x1F24;&#x1F25;&#x1F26;&#x1F27;&#x1F30;&#x1F31;&#x1F32;&#x1F33;&#x1F34;&#x1F35;&#x1F36;&#x1F37;&#x1F40;&#x1F41;&#x1F42;&#x1F43;&#x1F44;&#x1F45;&#x1F51;&#x1F53;&#x1F55;&#x1F57;&#x1F60;&#x1F61;&#x1F62;&#x1F63;&#x1F64;&#x1F65;&#x1F66;&#x1F67;&#x1F70;&#x1F71;&#x1F72;&#x1F73;&#x1F74;&#x1F75;&#x1F76;&#x1F77;&#x1F78;&#x1F79;&#x1F7A;&#x1F7B;&#x1F7C;&#x1F7D;&#x1F80;&#x1F81;&#x1F82;&#x1F83;&#x1F84;&#x1F85;&#x1F86;&#x1F87;&#x1F90;&#x1F91;&#x1F92;&#x1F93;&#x1F94;&#x1F95;&#x1F96;&#x1F97;&#x1FA0;&#x1FA1;&#x1FA2;&#x1FA3;&#x1FA4;&#x1FA5;&#x1FA6;&#x1FA7;&#x1FB0;&#x1FB1;&#x1FB3;&#x1FBE;&#x1FC3;&#x1FD0;&#x1FD1;&#x1FE0;&#x1FE1;&#x1FE5;&#x1FF3;&#x2170;&#x2171;&#x2172;&#x2173;&#x2174;&#x2175;&#x2176;&#x2177;&#x2178;&#x2179;&#x217A;&#x217B;&#x217C;&#x217D;&#x217E;&#x217F;&#x24D0;&#x24D1;&#x24D2;&#x24D3;&#x24D4;&#x24D5;&#x24D6;&#x24D7;&#x24D8;&#x24D9;&#x24DA;&#x24DB;&#x24DC;&#x24DD;&#x24DE;&#x24DF;&#x24E0;&#x24E1;&#x24E2;&#x24E3;&#x24E4;&#x24E5;&#x24E6;&#x24E7;&#x24E8;&#x24E9;&#xFF41;&#xFF42;&#xFF43;&#xFF44;&#xFF45;&#xFF46;&#xFF47;&#xFF48;&#xFF49;&#xFF4A;&#xFF4B;&#xFF4C;&#xFF4D;&#xFF4E;&#xFF4F;&#xFF50;&#xFF51;&#xFF52;&#xFF53;&#xFF54;&#xFF55;&#xFF56;&#xFF57;&#xFF58;&#xFF59;&#xFF5A;&#x10428;&#x10429;&#x1042A;&#x1042B;&#x1042C;&#x1042D;&#x1042E;&#x1042F;&#x10430;&#x10431;&#x10432;&#x10433;&#x10434;&#x10435;&#x10436;&#x10437;&#x10438;&#x10439;&#x1043A;&#x1043B;&#x1043C;&#x1043D;&#x1043E;&#x1043F;&#x10440;&#x10441;&#x10442;&#x10443;&#x10444;&#x10445;&#x10446;&#x10447;&#x10448;&#x10449;&#x1044A;&#x1044B;&#x1044C;&#x1044D;'"/>
47   <xsl:variable name="xsltsl-str-upper" select="'&#x0041;&#x0042;&#x0043;&#x0044;&#x0045;&#x0046;&#x0047;&#x0048;&#x0049;&#x004A;&#x004B;&#x004C;&#x004D;&#x004E;&#x004F;&#x0050;&#x0051;&#x0052;&#x0053;&#x0054;&#x0055;&#x0056;&#x0057;&#x0058;&#x0059;&#x005A;&#x039C;&#x00C0;&#x00C1;&#x00C2;&#x00C3;&#x00C4;&#x00C5;&#x00C6;&#x00C7;&#x00C8;&#x00C9;&#x00CA;&#x00CB;&#x00CC;&#x00CD;&#x00CE;&#x00CF;&#x00D0;&#x00D1;&#x00D2;&#x00D3;&#x00D4;&#x00D5;&#x00D6;&#x00D8;&#x00D9;&#x00DA;&#x00DB;&#x00DC;&#x00DD;&#x00DE;&#x0178;&#x0100;&#x0102;&#x0104;&#x0106;&#x0108;&#x010A;&#x010C;&#x010E;&#x0110;&#x0112;&#x0114;&#x0116;&#x0118;&#x011A;&#x011C;&#x011E;&#x0120;&#x0122;&#x0124;&#x0126;&#x0128;&#x012A;&#x012C;&#x012E;&#x0049;&#x0132;&#x0134;&#x0136;&#x0139;&#x013B;&#x013D;&#x013F;&#x0141;&#x0143;&#x0145;&#x0147;&#x014A;&#x014C;&#x014E;&#x0150;&#x0152;&#x0154;&#x0156;&#x0158;&#x015A;&#x015C;&#x015E;&#x0160;&#x0162;&#x0164;&#x0166;&#x0168;&#x016A;&#x016C;&#x016E;&#x0170;&#x0172;&#x0174;&#x0176;&#x0179;&#x017B;&#x017D;&#x0053;&#x0182;&#x0184;&#x0187;&#x018B;&#x0191;&#x01F6;&#x0198;&#x01A0;&#x01A2;&#x01A4;&#x01A7;&#x01AC;&#x01AF;&#x01B3;&#x01B5;&#x01B8;&#x01BC;&#x01F7;&#x01C4;&#x01C4;&#x01C7;&#x01C7;&#x01CA;&#x01CA;&#x01CD;&#x01CF;&#x01D1;&#x01D3;&#x01D5;&#x01D7;&#x01D9;&#x01DB;&#x018E;&#x01DE;&#x01E0;&#x01E2;&#x01E4;&#x01E6;&#x01E8;&#x01EA;&#x01EC;&#x01EE;&#x01F1;&#x01F1;&#x01F4;&#x01F8;&#x01FA;&#x01FC;&#x01FE;&#x0200;&#x0202;&#x0204;&#x0206;&#x0208;&#x020A;&#x020C;&#x020E;&#x0210;&#x0212;&#x0214;&#x0216;&#x0218;&#x021A;&#x021C;&#x021E;&#x0222;&#x0224;&#x0226;&#x0228;&#x022A;&#x022C;&#x022E;&#x0230;&#x0232;&#x0181;&#x0186;&#x0189;&#x018A;&#x018F;&#x0190;&#x0193;&#x0194;&#x0197;&#x0196;&#x019C;&#x019D;&#x019F;&#x01A6;&#x01A9;&#x01AE;&#x01B1;&#x01B2;&#x01B7;&#x0399;&#x0386;&#x0388;&#x0389;&#x038A;&#x0391;&#x0392;&#x0393;&#x0394;&#x0395;&#x0396;&#x0397;&#x0398;&#x0399;&#x039A;&#x039B;&#x039C;&#x039D;&#x039E;&#x039F;&#x03A0;&#x03A1;&#x03A3;&#x03A3;&#x03A4;&#x03A5;&#x03A6;&#x03A7;&#x03A8;&#x03A9;&#x03AA;&#x03AB;&#x038C;&#x038E;&#x038F;&#x0392;&#x0398;&#x03A6;&#x03A0;&#x03DA;&#x03DC;&#x03DE;&#x03E0;&#x03E2;&#x03E4;&#x03E6;&#x03E8;&#x03EA;&#x03EC;&#x03EE;&#x039A;&#x03A1;&#x03A3;&#x0395;&#x0410;&#x0411;&#x0412;&#x0413;&#x0414;&#x0415;&#x0416;&#x0417;&#x0418;&#x0419;&#x041A;&#x041B;&#x041C;&#x041D;&#x041E;&#x041F;&#x0420;&#x0421;&#x0422;&#x0423;&#x0424;&#x0425;&#x0426;&#x0427;&#x0428;&#x0429;&#x042A;&#x042B;&#x042C;&#x042D;&#x042E;&#x042F;&#x0400;&#x0401;&#x0402;&#x0403;&#x0404;&#x0405;&#x0406;&#x0407;&#x0408;&#x0409;&#x040A;&#x040B;&#x040C;&#x040D;&#x040E;&#x040F;&#x0460;&#x0462;&#x0464;&#x0466;&#x0468;&#x046A;&#x046C;&#x046E;&#x0470;&#x0472;&#x0474;&#x0476;&#x0478;&#x047A;&#x047C;&#x047E;&#x0480;&#x048C;&#x048E;&#x0490;&#x0492;&#x0494;&#x0496;&#x0498;&#x049A;&#x049C;&#x049E;&#x04A0;&#x04A2;&#x04A4;&#x04A6;&#x04A8;&#x04AA;&#x04AC;&#x04AE;&#x04B0;&#x04B2;&#x04B4;&#x04B6;&#x04B8;&#x04BA;&#x04BC;&#x04BE;&#x04C1;&#x04C3;&#x04C7;&#x04CB;&#x04D0;&#x04D2;&#x04D4;&#x04D6;&#x04D8;&#x04DA;&#x04DC;&#x04DE;&#x04E0;&#x04E2;&#x04E4;&#x04E6;&#x04E8;&#x04EA;&#x04EC;&#x04EE;&#x04F0;&#x04F2;&#x04F4;&#x04F8;&#x0531;&#x0532;&#x0533;&#x0534;&#x0535;&#x0536;&#x0537;&#x0538;&#x0539;&#x053A;&#x053B;&#x053C;&#x053D;&#x053E;&#x053F;&#x0540;&#x0541;&#x0542;&#x0543;&#x0544;&#x0545;&#x0546;&#x0547;&#x0548;&#x0549;&#x054A;&#x054B;&#x054C;&#x054D;&#x054E;&#x054F;&#x0550;&#x0551;&#x0552;&#x0553;&#x0554;&#x0555;&#x0556;&#x1E00;&#x1E02;&#x1E04;&#x1E06;&#x1E08;&#x1E0A;&#x1E0C;&#x1E0E;&#x1E10;&#x1E12;&#x1E14;&#x1E16;&#x1E18;&#x1E1A;&#x1E1C;&#x1E1E;&#x1E20;&#x1E22;&#x1E24;&#x1E26;&#x1E28;&#x1E2A;&#x1E2C;&#x1E2E;&#x1E30;&#x1E32;&#x1E34;&#x1E36;&#x1E38;&#x1E3A;&#x1E3C;&#x1E3E;&#x1E40;&#x1E42;&#x1E44;&#x1E46;&#x1E48;&#x1E4A;&#x1E4C;&#x1E4E;&#x1E50;&#x1E52;&#x1E54;&#x1E56;&#x1E58;&#x1E5A;&#x1E5C;&#x1E5E;&#x1E60;&#x1E62;&#x1E64;&#x1E66;&#x1E68;&#x1E6A;&#x1E6C;&#x1E6E;&#x1E70;&#x1E72;&#x1E74;&#x1E76;&#x1E78;&#x1E7A;&#x1E7C;&#x1E7E;&#x1E80;&#x1E82;&#x1E84;&#x1E86;&#x1E88;&#x1E8A;&#x1E8C;&#x1E8E;&#x1E90;&#x1E92;&#x1E94;&#x1E60;&#x1EA0;&#x1EA2;&#x1EA4;&#x1EA6;&#x1EA8;&#x1EAA;&#x1EAC;&#x1EAE;&#x1EB0;&#x1EB2;&#x1EB4;&#x1EB6;&#x1EB8;&#x1EBA;&#x1EBC;&#x1EBE;&#x1EC0;&#x1EC2;&#x1EC4;&#x1EC6;&#x1EC8;&#x1ECA;&#x1ECC;&#x1ECE;&#x1ED0;&#x1ED2;&#x1ED4;&#x1ED6;&#x1ED8;&#x1EDA;&#x1EDC;&#x1EDE;&#x1EE0;&#x1EE2;&#x1EE4;&#x1EE6;&#x1EE8;&#x1EEA;&#x1EEC;&#x1EEE;&#x1EF0;&#x1EF2;&#x1EF4;&#x1EF6;&#x1EF8;&#x1F08;&#x1F09;&#x1F0A;&#x1F0B;&#x1F0C;&#x1F0D;&#x1F0E;&#x1F0F;&#x1F18;&#x1F19;&#x1F1A;&#x1F1B;&#x1F1C;&#x1F1D;&#x1F28;&#x1F29;&#x1F2A;&#x1F2B;&#x1F2C;&#x1F2D;&#x1F2E;&#x1F2F;&#x1F38;&#x1F39;&#x1F3A;&#x1F3B;&#x1F3C;&#x1F3D;&#x1F3E;&#x1F3F;&#x1F48;&#x1F49;&#x1F4A;&#x1F4B;&#x1F4C;&#x1F4D;&#x1F59;&#x1F5B;&#x1F5D;&#x1F5F;&#x1F68;&#x1F69;&#x1F6A;&#x1F6B;&#x1F6C;&#x1F6D;&#x1F6E;&#x1F6F;&#x1FBA;&#x1FBB;&#x1FC8;&#x1FC9;&#x1FCA;&#x1FCB;&#x1FDA;&#x1FDB;&#x1FF8;&#x1FF9;&#x1FEA;&#x1FEB;&#x1FFA;&#x1FFB;&#x1F88;&#x1F89;&#x1F8A;&#x1F8B;&#x1F8C;&#x1F8D;&#x1F8E;&#x1F8F;&#x1F98;&#x1F99;&#x1F9A;&#x1F9B;&#x1F9C;&#x1F9D;&#x1F9E;&#x1F9F;&#x1FA8;&#x1FA9;&#x1FAA;&#x1FAB;&#x1FAC;&#x1FAD;&#x1FAE;&#x1FAF;&#x1FB8;&#x1FB9;&#x1FBC;&#x0399;&#x1FCC;&#x1FD8;&#x1FD9;&#x1FE8;&#x1FE9;&#x1FEC;&#x1FFC;&#x2160;&#x2161;&#x2162;&#x2163;&#x2164;&#x2165;&#x2166;&#x2167;&#x2168;&#x2169;&#x216A;&#x216B;&#x216C;&#x216D;&#x216E;&#x216F;&#x24B6;&#x24B7;&#x24B8;&#x24B9;&#x24BA;&#x24BB;&#x24BC;&#x24BD;&#x24BE;&#x24BF;&#x24C0;&#x24C1;&#x24C2;&#x24C3;&#x24C4;&#x24C5;&#x24C6;&#x24C7;&#x24C8;&#x24C9;&#x24CA;&#x24CB;&#x24CC;&#x24CD;&#x24CE;&#x24CF;&#xFF21;&#xFF22;&#xFF23;&#xFF24;&#xFF25;&#xFF26;&#xFF27;&#xFF28;&#xFF29;&#xFF2A;&#xFF2B;&#xFF2C;&#xFF2D;&#xFF2E;&#xFF2F;&#xFF30;&#xFF31;&#xFF32;&#xFF33;&#xFF34;&#xFF35;&#xFF36;&#xFF37;&#xFF38;&#xFF39;&#xFF3A;&#x10400;&#x10401;&#x10402;&#x10403;&#x10404;&#x10405;&#x10406;&#x10407;&#x10408;&#x10409;&#x1040A;&#x1040B;&#x1040C;&#x1040D;&#x1040E;&#x1040F;&#x10410;&#x10411;&#x10412;&#x10413;&#x10414;&#x10415;&#x10416;&#x10417;&#x10418;&#x10419;&#x1041A;&#x1041B;&#x1041C;&#x1041D;&#x1041E;&#x1041F;&#x10420;&#x10421;&#x10422;&#x10423;&#x10424;&#x10425;'"/>
48   <xsl:variable name="xsltsl-str-digits" select="'0123456789'"/>
49   <!-- space (#x20) characters, carriage returns, line feeds, or tabs. -->
50   <xsl:variable name="xsltsl-str-ws" select="'&#x20;&#x9;&#xD;&#xA;'"/>
51
52   <doc:template name="str:to-upper" xmlns="">
53     <refpurpose>Make string uppercase</refpurpose>
54
55     <refdescription>
56       <para>Converts all lowercase letters to uppercase.</para>
57     </refdescription>
58
59     <refparameter>
60       <variablelist>
61         <varlistentry>
62           <term>text</term>
63           <listitem>
64             <para>The string to be converted</para>
65           </listitem>
66         </varlistentry>
67       </variablelist>
68     </refparameter>
69
70     <refreturn>
71       <para>Returns string with all uppercase letters.</para>
72     </refreturn>
73   </doc:template>
74
75   <xsl:template name="str:to-upper">
76     <xsl:param name="text"/>
77
78     <!-- Below exception is extracted from unicode's SpecialCasing.txt
79          file. It's the german lowercase "eszett" (the thing looking
80          like a greek beta) that's to become "SS" in uppercase (note:
81          that are *two* characters, that's why it doesn't fit in the
82          list of upper/lowercase characters). There are more
83          characters in that file (103, excluding the locale-specific
84          ones), but they seemed to be much less used to me and they
85          add up to a hellish long stylesheet.... - Reinout -->
86     <xsl:param name="modified-text">
87       <xsl:call-template name="str:subst">
88         <xsl:with-param name="text">
89           <xsl:value-of select="$text"/>
90         </xsl:with-param>
91         <xsl:with-param name="replace">
92           <xsl:text>&#x00DF;</xsl:text>
93         </xsl:with-param>
94         <xsl:with-param name="with">
95           <xsl:text>&#x0053;</xsl:text>
96           <xsl:text>&#x0053;</xsl:text>
97         </xsl:with-param>
98       </xsl:call-template>
99     </xsl:param>
100
101     <xsl:value-of select="translate($modified-text, $xsltsl-str-lower, $xsltsl-str-upper)"/>
102   </xsl:template>
103
104   <doc:template name="str:to-lower" xmlns="">
105     <refpurpose>Make string lowercase</refpurpose>
106
107     <refdescription>
108       <para>Converts all uppercase letters to lowercase.</para>
109     </refdescription>
110
111     <refparameter>
112       <variablelist>
113         <varlistentry>
114           <term>text</term>
115           <listitem>
116             <para>The string to be converted</para>
117           </listitem>
118         </varlistentry>
119       </variablelist>
120     </refparameter>
121
122     <refreturn>
123       <para>Returns string with all lowercase letters.</para>
124     </refreturn>
125   </doc:template>
126
127   <xsl:template name="str:to-lower">
128     <xsl:param name="text"/>
129
130     <xsl:value-of select="translate($text, $xsltsl-str-upper, $xsltsl-str-lower)"/>
131   </xsl:template>
132
133   <doc:template name="str:capitalise" xmlns="">
134     <refpurpose>Capitalise string</refpurpose>
135
136     <refdescription>
137       <para>Converts first character of string to an uppercase letter.  All remaining characters are converted to lowercase.</para>
138     </refdescription>
139
140     <refparameter>
141       <variablelist>
142         <varlistentry>
143           <term>text</term>
144           <listitem>
145             <para>The string to be capitalised</para>
146           </listitem>
147         </varlistentry>
148         <varlistentry>
149           <term>all</term>
150           <listitem>
151             <para>Boolean controlling whether all words in the string are capitalised.</para>
152             <para>Default is true.</para>
153           </listitem>
154         </varlistentry>
155       </variablelist>
156     </refparameter>
157
158     <refreturn>
159       <para>Returns string with first character uppcase and all remaining characters lowercase.</para>
160     </refreturn>
161   </doc:template>
162
163   <xsl:template name="str:capitalise">
164     <xsl:param name="text"/>
165     <xsl:param name="all" select="true()"/>
166
167     <xsl:choose>
168       <xsl:when test="$all and (contains($text, ' ') or contains($text, '       ') or contains($text, '&#10;'))">
169         <xsl:variable name="firstword">
170           <xsl:call-template name="str:substring-before-first">
171             <xsl:with-param name="text" select="$text"/>
172             <xsl:with-param name="chars" select="$xsltsl-str-ws"/>
173           </xsl:call-template>
174         </xsl:variable>
175         <xsl:call-template name="str:capitalise">
176           <xsl:with-param name="text">
177             <xsl:value-of select="$firstword"/>
178           </xsl:with-param>
179           <xsl:with-param name="all" select="false()"/>
180         </xsl:call-template>
181         <xsl:value-of select="substring($text, string-length($firstword) + 1, 1)"/>
182         <xsl:call-template name="str:capitalise">
183           <xsl:with-param name="text">
184             <xsl:value-of select="substring($text, string-length($firstword) + 2)"/>
185           </xsl:with-param>
186         </xsl:call-template>
187       </xsl:when>
188
189       <xsl:otherwise>
190         <xsl:call-template name="str:to-upper">
191           <xsl:with-param name="text" select="substring($text, 1, 1)"/>
192         </xsl:call-template>
193         <xsl:call-template name="str:to-lower">
194           <xsl:with-param name="text" select="substring($text, 2)"/>
195         </xsl:call-template>
196       </xsl:otherwise>
197     </xsl:choose>
198   </xsl:template>
199
200   <doc:template name="str:to-camelcase" xmlns="">
201     <refpurpose>Convert a string to one camelcase word</refpurpose>
202
203     <refdescription>
204       <para>Converts a string to one lowerCamelCase or UpperCamelCase
205       word, depending on the setting of the "upper"
206       parameter. UpperCamelCase is also called MixedCase while
207       lowerCamelCase is also called just camelCase. The template
208       removes any spaces, tabs and slashes, but doesn't deal with
209       other punctuation. It's purpose is to convert strings like
210       "hollow timber flush door" to a term suitable as identifier or
211       XML tag like "HollowTimberFlushDoor".
212       </para>
213     </refdescription>
214
215     <refparameter>
216       <variablelist>
217         <varlistentry>
218           <term>text</term>
219           <listitem>
220             <para>The string to be capitalised</para>
221           </listitem>
222         </varlistentry>
223         <varlistentry>
224           <term>upper</term>
225           <listitem>
226             <para>Boolean controlling whether the string becomes an
227             UpperCamelCase word or a lowerCamelCase word.</para>
228             <para>Default is true.</para>
229           </listitem>
230         </varlistentry>
231       </variablelist>
232     </refparameter>
233
234     <refreturn>
235       <para>Returns string with first character uppcase and all remaining characters lowercase.</para>
236     </refreturn>
237   </doc:template>
238
239   <xsl:template name="str:to-camelcase">
240     <xsl:param name="text"/>
241     <xsl:param name="upper" select="true()"/>
242     <!-- First change all 'strange' characters to spaces -->
243     <xsl:param name="string-with-only-spaces">
244       <xsl:value-of select="translate($text,concat($xsltsl-str-ws,'/'),'     ')"/>
245     </xsl:param>
246     <!-- Then process them -->
247     <xsl:param name="before-space-removal">
248       <xsl:variable name="firstword">
249         <xsl:call-template name="str:substring-before-first">
250           <xsl:with-param name="text" select="$string-with-only-spaces"/>
251           <xsl:with-param name="chars" select="$xsltsl-str-ws"/>
252         </xsl:call-template>
253       </xsl:variable>
254       <xsl:choose>
255         <xsl:when test="$upper">
256           <xsl:call-template name="str:to-upper">
257             <xsl:with-param name="text" select="substring($firstword, 1, 1)"/>
258           </xsl:call-template>
259           <xsl:call-template name="str:to-lower">
260             <xsl:with-param name="text" select="substring($firstword, 2)"/>
261           </xsl:call-template>
262         </xsl:when>
263         <xsl:otherwise>
264           <xsl:call-template name="str:to-lower">
265             <xsl:with-param name="text" select="$firstword"/>
266           </xsl:call-template>
267         </xsl:otherwise>
268       </xsl:choose>
269
270       <xsl:call-template name="str:capitalise">
271         <xsl:with-param name="text">
272           <xsl:value-of select="substring($string-with-only-spaces, string-length($firstword) + 2)"/>
273         </xsl:with-param>
274         <xsl:with-param name="all" select="true()"/>            
275       </xsl:call-template>
276     </xsl:param>
277     <xsl:value-of select="translate($before-space-removal,' ','')"/>
278   </xsl:template>
279
280   <doc:template name="str:substring-before-first" xmlns="">
281     <refpurpose>String extraction</refpurpose>
282
283     <refdescription>
284       <para>Extracts the portion of string 'text' which occurs before any of the characters in string 'chars'.</para>
285     </refdescription>
286
287     <refparameter>
288       <variablelist>
289         <varlistentry>
290           <term>text</term>
291           <listitem>
292             <para>The string from which to extract a substring.</para>
293           </listitem>
294         </varlistentry>
295         <varlistentry>
296           <term>chars</term>
297           <listitem>
298             <para>The string containing characters to find.</para>
299           </listitem>
300         </varlistentry>
301       </variablelist>
302     </refparameter>
303
304     <refreturn>
305       <para>Returns string.</para>
306     </refreturn>
307   </doc:template>
308
309   <xsl:template name="str:substring-before-first">
310     <xsl:param name="text"/>
311     <xsl:param name="chars"/>
312
313     <xsl:choose>
314
315       <xsl:when test="string-length($text) = 0"/>
316
317       <xsl:when test="string-length($chars) = 0">
318         <xsl:value-of select="$text"/>
319       </xsl:when>
320
321       <xsl:when test="contains($text, substring($chars, 1, 1))">
322         <xsl:variable name="this" select="substring-before($text, substring($chars, 1, 1))"/>
323         <xsl:variable name="rest">
324           <xsl:call-template name="str:substring-before-first">
325             <xsl:with-param name="text" select="$text"/>
326             <xsl:with-param name="chars" select="substring($chars, 2)"/>
327           </xsl:call-template>
328         </xsl:variable>
329
330         <xsl:choose>
331           <xsl:when test="string-length($this) &lt; string-length($rest)">
332             <xsl:value-of select="$this"/>
333           </xsl:when>
334           <xsl:otherwise>
335             <xsl:value-of select="$rest"/>
336           </xsl:otherwise>
337         </xsl:choose>
338       </xsl:when>
339
340       <xsl:otherwise>
341         <xsl:call-template name="str:substring-before-first">
342           <xsl:with-param name="text" select="$text"/>
343           <xsl:with-param name="chars" select="substring($chars, 2)"/>
344         </xsl:call-template>
345       </xsl:otherwise>
346
347     </xsl:choose>
348   </xsl:template>
349
350   <doc:template name="str:substring-after-last" xmlns="">
351     <refpurpose>String extraction</refpurpose>
352
353     <refdescription>
354       <para>Extracts the portion of string 'text' which occurs after the last of the character in string 'chars'.</para>
355     </refdescription>
356
357     <refparameter>
358       <variablelist>
359         <varlistentry>
360           <term>text</term>
361           <listitem>
362             <para>The string from which to extract a substring.</para>
363           </listitem>
364         </varlistentry>
365         <varlistentry>
366           <term>chars</term>
367           <listitem>
368             <para>The string containing characters to find.</para>
369           </listitem>
370         </varlistentry>
371       </variablelist>
372     </refparameter>
373
374     <refreturn>
375       <para>Returns string.</para>
376     </refreturn>
377   </doc:template>
378
379   <xsl:template name="str:substring-after-last">
380     <xsl:param name="text"/>
381     <xsl:param name="chars"/>
382
383     <xsl:choose>
384
385       <xsl:when test="contains($text, $chars)">
386         <xsl:variable name="last" select="substring-after($text, $chars)"/>
387
388         <xsl:choose>
389           <xsl:when test="contains($last, $chars)">
390             <xsl:call-template name="str:substring-after-last">
391               <xsl:with-param name="text" select="$last"/>
392               <xsl:with-param name="chars" select="$chars"/>
393             </xsl:call-template>
394           </xsl:when>
395           <xsl:otherwise>
396             <xsl:value-of select="$last"/>
397           </xsl:otherwise>
398         </xsl:choose>
399       </xsl:when>
400
401       <xsl:otherwise>
402         <xsl:value-of select="$text"/>
403       </xsl:otherwise>
404
405     </xsl:choose>
406   </xsl:template>
407
408   <doc:template name="str:substring-before-last" xmlns="">
409     <refpurpose>String extraction</refpurpose>
410
411     <refdescription>
412       <para>Extracts the portion of string 'text' which occurs before the first character of the last occurance of string 'chars'.</para>
413     </refdescription>
414
415     <refparameter>
416       <variablelist>
417         <varlistentry>
418           <term>text</term>
419           <listitem>
420             <para>The string from which to extract a substring.</para>
421           </listitem>
422         </varlistentry>
423         <varlistentry>
424           <term>chars</term>
425           <listitem>
426             <para>The string containing characters to find.</para>
427           </listitem>
428         </varlistentry>
429       </variablelist>
430     </refparameter>
431
432     <refreturn>
433       <para>Returns string.</para>
434     </refreturn>
435   </doc:template>
436
437   <xsl:template name="str:substring-before-last">
438     <xsl:param name="text"/>
439     <xsl:param name="chars"/>
440
441     <xsl:choose>
442
443       <xsl:when test="string-length($text) = 0"/>
444
445       <xsl:when test="string-length($chars) = 0">
446         <xsl:value-of select="$text"/>
447       </xsl:when>
448
449       <xsl:when test="contains($text, $chars)">
450         <xsl:call-template name="str:substring-before-last-aux">
451           <xsl:with-param name="text" select="$text"/>
452           <xsl:with-param name="chars" select="$chars"/>
453         </xsl:call-template>
454       </xsl:when>
455
456       <xsl:otherwise>
457         <xsl:value-of select="$text"/>
458       </xsl:otherwise>
459
460     </xsl:choose>
461   </xsl:template>
462
463   <xsl:template name="str:substring-before-last-aux">
464     <xsl:param name="text"/>
465     <xsl:param name="chars"/>
466
467     <xsl:choose>
468       <xsl:when test="string-length($text) = 0"/>
469
470       <xsl:when test="contains($text, $chars)">
471         <xsl:variable name="after">
472           <xsl:call-template name="str:substring-before-last-aux">
473             <xsl:with-param name="text" select="substring-after($text, $chars)"/>
474             <xsl:with-param name="chars" select="$chars"/>
475           </xsl:call-template>
476         </xsl:variable>
477
478         <xsl:value-of select="substring-before($text, $chars)"/>
479         <xsl:if test="string-length($after) &gt; 0">
480           <xsl:value-of select="$chars"/>
481           <xsl:copy-of select="$after"/>
482         </xsl:if>
483       </xsl:when>
484
485       <xsl:otherwise/>
486     </xsl:choose>
487   </xsl:template>
488
489   <doc:template name="str:subst" xmlns="">
490     <refpurpose>String substitution</refpurpose>
491
492     <refdescription>
493       <para>Substitute 'replace' for 'with' in string 'text'.</para>
494     </refdescription>
495
496     <refparameter>
497       <variablelist>
498         <varlistentry>
499           <term>text</term>
500           <listitem>
501             <para>The string upon which to perform substitution.</para>
502           </listitem>
503         </varlistentry>
504         <varlistentry>
505           <term>replace</term>
506           <listitem>
507             <para>The string to substitute.</para>
508           </listitem>
509         </varlistentry>
510         <varlistentry>
511           <term>with</term>
512           <listitem>
513             <para>The string to be substituted.</para>
514           </listitem>
515         </varlistentry>
516         <varlistentry>
517           <term>disable-output-escaping</term>
518           <listitem>
519             <para>A value of <literal>yes</literal> indicates that the result should have output escaping disabled.  Any other value allows normal escaping of text values.  The default is to enable output escaping.</para>
520           </listitem>
521         </varlistentry>
522       </variablelist>
523     </refparameter>
524
525     <refreturn>
526       <para>Returns string.</para>
527     </refreturn>
528   </doc:template>
529
530   <xsl:template name="str:subst">
531     <xsl:param name="text"/>
532     <xsl:param name="replace"/>
533     <xsl:param name="with"/>
534     <xsl:param name='disable-output-escaping'>no</xsl:param>
535
536     <xsl:choose>
537       <xsl:when test="string-length($replace) = 0 and $disable-output-escaping = 'yes'">
538         <xsl:value-of select="$text" disable-output-escaping='yes'/>
539       </xsl:when>
540       <xsl:when test="string-length($replace) = 0">
541         <xsl:value-of select="$text"/>
542       </xsl:when>
543       <xsl:when test="contains($text, $replace)">
544
545         <xsl:variable name="before" select="substring-before($text, $replace)"/>
546         <xsl:variable name="after" select="substring-after($text, $replace)"/>
547
548         <xsl:choose>
549           <xsl:when test='$disable-output-escaping = "yes"'>
550             <xsl:value-of select="$before" disable-output-escaping="yes"/>
551             <xsl:value-of select="$with" disable-output-escaping="yes"/>
552           </xsl:when>
553           <xsl:otherwise>
554             <xsl:value-of select="$before"/>
555             <xsl:value-of select="$with"/>
556           </xsl:otherwise>
557         </xsl:choose>
558         <xsl:call-template name="str:subst">
559           <xsl:with-param name="text" select="$after"/>
560           <xsl:with-param name="replace" select="$replace"/>
561           <xsl:with-param name="with" select="$with"/>
562           <xsl:with-param name="disable-output-escaping" select="$disable-output-escaping"/>
563         </xsl:call-template>
564       </xsl:when>
565       <xsl:when test='$disable-output-escaping = "yes"'>
566         <xsl:value-of select="$text" disable-output-escaping="yes"/>
567       </xsl:when>
568       <xsl:otherwise>
569         <xsl:value-of select="$text"/>
570       </xsl:otherwise>
571     </xsl:choose>            
572   </xsl:template>
573
574   <doc:template name="str:count-substring" xmlns="">
575     <refpurpose>Count Substrings</refpurpose>
576
577     <refdescription>
578       <para>Counts the number of times a substring occurs in a string.  This can also counts the number of times a character occurs in a string, since a character is simply a string of length 1.</para>
579     </refdescription>
580
581     <example>
582       <title>Counting Lines</title>
583       <programlisting><![CDATA[
584 <xsl:call-template name="str:count-substring">
585   <xsl:with-param name="text" select="$mytext"/>
586   <xsl:with-param name="chars" select="'&#x0a;'"/>
587 </xsl:call-template>
588 ]]></programlisting>
589     </example>
590
591     <refparameter>
592       <variablelist>
593         <varlistentry>
594           <term>text</term>
595           <listitem>
596             <para>The source string.</para>
597           </listitem>
598         </varlistentry>
599         <varlistentry>
600           <term>chars</term>
601           <listitem>
602             <para>The substring to count.</para>
603           </listitem>
604         </varlistentry>
605       </variablelist>
606     </refparameter>
607
608     <refreturn>
609       <para>Returns a non-negative integer value.</para>
610     </refreturn>
611   </doc:template>
612
613   <xsl:template name="str:count-substring">
614     <xsl:param name="text"/>
615     <xsl:param name="chars"/>
616
617     <xsl:choose>
618       <xsl:when test="string-length($text) = 0 or string-length($chars) = 0">
619         <xsl:text>0</xsl:text>
620       </xsl:when>
621       <xsl:when test="contains($text, $chars)">
622         <xsl:variable name="remaining">
623           <xsl:call-template name="str:count-substring">
624             <xsl:with-param name="text" select="substring-after($text, $chars)"/>
625             <xsl:with-param name="chars" select="$chars"/>
626           </xsl:call-template>
627         </xsl:variable>
628         <xsl:value-of select="$remaining + 1"/>
629       </xsl:when>
630       <xsl:otherwise>
631         <xsl:text>0</xsl:text>
632       </xsl:otherwise>
633     </xsl:choose>
634   </xsl:template>
635
636   <doc:template name="str:substring-after-at" xmlns="">
637     <refpurpose>String extraction</refpurpose>
638     <refdescription>
639       <para>Extracts the portion of a 'char' delimited 'text' string "array" at a given 'position'.</para>
640     </refdescription>
641     <refparameter>
642       <variablelist>
643         <varlistentry>
644           <term>text</term>
645           <listitem>
646             <para>The string from which to extract a substring.</para>
647           </listitem>
648         </varlistentry>
649         <varlistentry>
650           <term>chars</term>
651           <listitem>
652             <para>delimiters</para>
653           </listitem>
654         </varlistentry>
655         <varlistentry>
656           <term>position</term>
657           <listitem>
658             <para>position of the elements</para>
659           </listitem>
660         </varlistentry>
661         <varlistentry>
662           <term>all</term>
663           <listitem>
664             <para>If true all of the remaining string is returned, otherwise only the element at the given position is returned.  Default: false().</para>
665           </listitem>
666         </varlistentry>
667       </variablelist>
668     </refparameter>
669     <refreturn>
670       <para>Returns string.</para>
671     </refreturn>
672   </doc:template>
673
674
675   <xsl:template name="str:substring-after-at">
676     <xsl:param name="text"/>
677     <xsl:param name="chars"/>
678     <xsl:param name="position"/>
679     <xsl:param name="all" select='false()'/>
680
681     <xsl:choose>
682       <xsl:when test='number($position) = 0 and $all'>
683         <xsl:value-of select='$text'/>
684       </xsl:when>
685       <xsl:when test='number($position) = 0 and not($chars)'>
686         <xsl:value-of select='$text'/>
687       </xsl:when>
688       <xsl:when test='number($position) = 0 and not(contains($text, $chars))'>
689         <xsl:value-of select='$text'/>
690       </xsl:when>
691       <xsl:when test='not(contains($text, $chars))'>
692       </xsl:when>
693       <xsl:when test="number($position) = 0">
694         <xsl:value-of select="substring-before($text, $chars)"/>
695       </xsl:when>
696       <xsl:otherwise>
697         <xsl:call-template name="str:substring-after-at">
698           <xsl:with-param name="text" select="substring-after($text, $chars)"/>
699           <xsl:with-param name="chars" select="$chars"/>
700           <xsl:with-param name="all" select="$all"/>
701           <xsl:with-param name="position" select="$position - 1"/>
702         </xsl:call-template>
703       </xsl:otherwise>
704     </xsl:choose>
705   </xsl:template>
706
707   <doc:template name="str:substring-before-at" xmlns="">
708     <refpurpose>String extraction</refpurpose>
709     <refdescription>
710       <para>Extracts the portion of a 'char' delimited 'text' string "array" at a given 'position' </para>
711     </refdescription>
712     <refparameter>
713       <variablelist>
714         <varlistentry>
715           <term>text</term>
716           <listitem>
717             <para>The string from which to extract a substring.</para>
718           </listitem>
719         </varlistentry>
720         <varlistentry>
721           <term>chars</term>
722           <listitem>
723           <para>delimiters</para>
724           </listitem>
725         </varlistentry>
726         <varlistentry>
727           <term>position</term>
728           <listitem>
729             <para>position of the elements</para>
730           </listitem>
731         </varlistentry>
732       </variablelist>
733     </refparameter>
734     <refreturn>
735       <para>Returns string.</para>
736     </refreturn>
737   </doc:template>
738
739   <xsl:template name="str:substring-before-at">
740     <xsl:param name="text"/>
741     <xsl:param name="chars"/>
742     <xsl:param name="position"/>
743
744     <xsl:choose>
745       <xsl:when test="$position &lt;= 0"/>
746       <xsl:when test="not(contains($text, $chars))"/>
747       <xsl:otherwise>
748         <xsl:value-of select='substring-before($text, $chars)'/>
749         <xsl:value-of select='$chars'/>
750
751         <xsl:call-template name="str:substring-before-at">
752           <xsl:with-param name="text" select="substring-after($text, $chars)"/>
753           <xsl:with-param name="position" select="$position - 1"/>
754           <xsl:with-param name="chars" select="$chars"/>
755         </xsl:call-template>
756         
757       </xsl:otherwise>
758     </xsl:choose>
759   </xsl:template>
760
761   <doc:template name="str:insert-at" xmlns="">
762     <refpurpose>String insertion</refpurpose>
763     <refdescription>
764       <para>Insert 'chars' into "text' at any given "position'</para>
765     </refdescription>
766     <refparameter>
767       <variablelist>
768         <varlistentry>
769           <term>text</term>
770           <listitem>
771             <para>The string upon which to perform insertion</para>
772           </listitem>
773         </varlistentry>
774         <varlistentry>
775           <term>position</term>
776           <listitem>
777             <para>the position where insertion will be performed</para>
778           </listitem>
779         </varlistentry>
780         <varlistentry>
781           <term>with</term>
782           <listitem>
783             <para>The string to be inserted</para>
784           </listitem>
785         </varlistentry>
786       </variablelist>
787     </refparameter>
788     <refreturn>
789       <para>Returns string.</para>
790     </refreturn>
791   </doc:template>
792
793   <xsl:template name="str:insert-at">
794     <xsl:param name="text"/>
795     <xsl:param name="position"/>
796     <xsl:param name="chars"/>
797
798     <xsl:variable name="firstpart" select="substring($text, 0, $position)"/>
799     <xsl:variable name="secondpart" select="substring($text, $position, string-length($text))"/>
800
801     <xsl:value-of select="concat($firstpart, $chars, $secondpart)"/>
802   </xsl:template>
803  
804
805   <doc:template name="str:backward" xmlns="">
806     <refpurpose>String reversal</refpurpose>
807
808     <refdescription>
809       <para>Reverse the content of a given string</para>
810     </refdescription>
811
812     <refparameter>
813       <variablelist>
814         <varlistentry>
815           <term>text</term>
816           <listitem>
817             <para>The string to be reversed</para>
818           </listitem>
819         </varlistentry>
820       </variablelist>
821     </refparameter>
822
823     <refreturn>
824       <para>Returns string.</para>
825     </refreturn>
826   </doc:template>
827
828   <xsl:template name="str:backward">
829     <xsl:param name="text"/>
830     <xsl:variable name="mirror">
831       <xsl:call-template name="str:build-mirror">
832         <xsl:with-param name="text" select="$text"/>
833         <xsl:with-param name="position" select="string-length($text)"/>
834       </xsl:call-template>
835     </xsl:variable>
836     <xsl:value-of select="substring($mirror, string-length($text) + 1, string-length($text))"/>
837   </xsl:template>
838
839   <xsl:template name="str:build-mirror">
840     <xsl:param name="text"/>
841     <xsl:param name="position"/>
842
843     <xsl:choose>
844       <xsl:when test="$position &gt; 0">
845         <xsl:call-template name="str:build-mirror">
846           <xsl:with-param name="text" select="concat($text, substring($text, $position, 1))"/>
847           <xsl:with-param name="position" select="$position - 1"/>
848         </xsl:call-template>
849       </xsl:when>
850       <xsl:otherwise>
851         <xsl:value-of select="$text"/>
852       </xsl:otherwise>
853     </xsl:choose>
854   </xsl:template>
855
856   <doc:template name="str:justify" xmlns="">
857     <refpurpose>Format a string</refpurpose>
858
859     <refdescription>
860       <para>Inserts newlines and spaces into a string to format it as a block of text.</para>
861     </refdescription>
862
863     <refparameter>
864       <variablelist>
865         <varlistentry>
866           <term>text</term>
867           <listitem>
868             <para>String to be formatted.</para>
869           </listitem>
870         </varlistentry>
871         <varlistentry>
872           <term>max</term>
873           <listitem>
874             <para>Maximum line length.</para>
875           </listitem>
876         </varlistentry>
877         <varlistentry>
878           <term>indent</term>
879           <listitem>
880             <para>Number of spaces to insert at the beginning of each line.</para>
881           </listitem>
882         </varlistentry>
883         <varlistentry>
884           <term>justify</term>
885           <listitem>
886             <para>Justify left, right or both.  Not currently implemented (fixed at "left").</para>
887           </listitem>
888         </varlistentry>
889       </variablelist>
890     </refparameter>
891
892     <refreturn>
893       <para>Formatted block of text.</para>
894     </refreturn>
895   </doc:template>
896
897   <xsl:template name='str:justify'>
898     <xsl:param name='text'/>
899     <xsl:param name='max' select='"80"'/>
900     <xsl:param name='indent' select='"0"'/>
901     <xsl:param name='justify' select='"left"'/>
902
903     <xsl:choose>
904       <xsl:when test='string-length($text) = 0 or $max &lt;= 0'/>
905
906       <xsl:when test='string-length($text) > $max and contains($text, " ") and string-length(substring-before($text, " ")) > $max'>
907         <xsl:call-template name='str:generate-string'>
908           <xsl:with-param name='text' select='" "'/>
909           <xsl:with-param name='count' select='$indent'/>
910         </xsl:call-template>
911         <xsl:value-of select='substring-before($text, " ")'/>
912         <xsl:text>
913 </xsl:text>
914         <xsl:call-template name='str:justify'>
915           <xsl:with-param name='text' select='substring-after($text, " ")'/>
916           <xsl:with-param name='max' select='$max'/>
917           <xsl:with-param name='indent' select='$indent'/>
918           <xsl:with-param name='justify' select='$justify'/>
919         </xsl:call-template>
920       </xsl:when>
921
922       <xsl:when test='string-length($text) > $max and contains($text, " ")'>
923         <xsl:variable name='first'>
924           <xsl:call-template name='str:substring-before-last'>
925             <xsl:with-param name='text' select='substring($text, 1, $max)'/>
926             <xsl:with-param name='chars' select='" "'/>
927           </xsl:call-template>
928         </xsl:variable>
929
930         <xsl:call-template name='str:generate-string'>
931           <xsl:with-param name='text' select='" "'/>
932           <xsl:with-param name='count' select='$indent'/>
933         </xsl:call-template>
934         <xsl:value-of select='$first'/>
935         <xsl:text>
936 </xsl:text>
937         <xsl:call-template name='str:justify'>
938           <xsl:with-param name='text' select='substring($text, string-length($first) + 2)'/>
939           <xsl:with-param name='max' select='$max'/>
940           <xsl:with-param name='indent' select='$indent'/>
941           <xsl:with-param name='justify' select='$justify'/>
942         </xsl:call-template>
943       </xsl:when>
944
945       <xsl:otherwise>
946         <xsl:call-template name='str:generate-string'>
947           <xsl:with-param name='text' select='" "'/>
948           <xsl:with-param name='count' select='$indent'/>
949         </xsl:call-template>
950         <xsl:value-of select='$text'/>
951       </xsl:otherwise>
952     </xsl:choose>
953   </xsl:template>
954
955   <doc:template name="str:character-first" xmlns="">
956     <refpurpose>Find first occurring character in a string</refpurpose>
957
958     <refdescription>
959       <para>Finds which of the given characters occurs first in a string.</para>
960     </refdescription>
961
962     <refparameter>
963       <variablelist>
964         <varlistentry>
965           <term>text</term>
966           <listitem>
967             <para>The source string.</para>
968           </listitem>
969         </varlistentry>
970         <varlistentry>
971           <term>chars</term>
972           <listitem>
973             <para>The characters to search for.</para>
974           </listitem>
975         </varlistentry>
976       </variablelist>
977     </refparameter>
978   </doc:template>
979
980   <xsl:template name="str:character-first">
981     <xsl:param name="text"/>
982     <xsl:param name="chars"/>
983
984     <xsl:choose>
985       <xsl:when test="string-length($text) = 0 or string-length($chars) = 0"/>
986
987       <xsl:when test="contains($text, substring($chars, 1, 1))">
988         <xsl:variable name="next-character">
989           <xsl:call-template name="str:character-first">
990             <xsl:with-param name="text" select="$text"/>
991             <xsl:with-param name="chars" select="substring($chars, 2)"/>
992           </xsl:call-template>
993         </xsl:variable>
994
995         <xsl:choose>
996           <xsl:when test="string-length($next-character)">
997             <xsl:variable name="first-character-position" select="string-length(substring-before($text, substring($chars, 1, 1)))"/>
998             <xsl:variable name="next-character-position" select="string-length(substring-before($text, $next-character))"/>
999
1000             <xsl:choose>
1001               <xsl:when test="$first-character-position &lt; $next-character-position">
1002                 <xsl:value-of select="substring($chars, 1, 1)"/>
1003               </xsl:when>
1004               <xsl:otherwise>
1005                 <xsl:value-of select="$next-character"/>
1006               </xsl:otherwise>
1007             </xsl:choose>
1008           </xsl:when>
1009           <xsl:otherwise>
1010             <xsl:value-of select="substring($chars, 1, 1)"/>
1011           </xsl:otherwise>
1012         </xsl:choose>
1013       </xsl:when>
1014       <xsl:otherwise>
1015         <xsl:call-template name="str:character-first">
1016           <xsl:with-param name="text" select="$text"/>
1017           <xsl:with-param name="chars" select="substring($chars, 2)"/>
1018         </xsl:call-template>
1019       </xsl:otherwise>
1020     </xsl:choose>
1021   </xsl:template>
1022
1023   <doc:template name="str:string-match" xmlns="">
1024     <refpurpose>Match A String To A Pattern</refpurpose>
1025
1026     <refdescription>
1027       <para>Performs globbing-style pattern matching on a string.</para>
1028     </refdescription>
1029
1030     <example>
1031       <title>Match Pattern</title>
1032       <programlisting><![CDATA[
1033 <xsl:call-template name="str:string-match">
1034   <xsl:with-param name="text" select="$mytext"/>
1035   <xsl:with-param name="pattern" select="'abc*def?g'"/>
1036 </xsl:call-template>
1037 ]]></programlisting>
1038     </example>
1039
1040     <refparameter>
1041       <variablelist>
1042         <varlistentry>
1043           <term>text</term>
1044           <listitem>
1045             <para>The source string.</para>
1046           </listitem>
1047         </varlistentry>
1048         <varlistentry>
1049           <term>pattern</term>
1050           <listitem>
1051             <para>The pattern to match against.  Certain characters have special meaning:</para>
1052             <variablelist>
1053               <varlistentry>
1054                 <term>*</term>
1055                 <listitem>
1056                   <para>Matches zero or more characters.</para>
1057                 </listitem>
1058               </varlistentry>
1059               <varlistentry>
1060                 <term>?</term>
1061                 <listitem>
1062                   <para>Matches a single character.</para>
1063                 </listitem>
1064               </varlistentry>
1065               <varlistentry>
1066                 <term>\</term>
1067                 <listitem>
1068                   <para>Character escape.  The next character is taken as a literal character.</para>
1069                 </listitem>
1070               </varlistentry>
1071             </variablelist>
1072           </listitem>
1073         </varlistentry>
1074       </variablelist>
1075     </refparameter>
1076
1077     <refreturn>
1078       <para>Returns "1" if the string matches the pattern, "0" otherwise.</para>
1079     </refreturn>
1080   </doc:template>
1081
1082   <xsl:template name="str:string-match">
1083     <xsl:param name="text"/>
1084     <xsl:param name="pattern"/>
1085
1086     <xsl:choose>
1087       <xsl:when test="$pattern = '*'">
1088         <!-- Special case: always matches -->
1089         <xsl:text>1</xsl:text>
1090       </xsl:when>
1091       <xsl:when test="string-length($text) = 0 and string-length($pattern) = 0">
1092         <xsl:text>1</xsl:text>
1093       </xsl:when>
1094       <xsl:when test="string-length($text) = 0 or string-length($pattern) = 0">
1095         <xsl:text>0</xsl:text>
1096       </xsl:when>
1097       <xsl:otherwise>
1098         <xsl:variable name='before-special'>
1099           <xsl:call-template name='str:substring-before-first'>
1100             <xsl:with-param name='text' select='$pattern'/>
1101             <xsl:with-param name='chars' select='"*?\"'/>
1102           </xsl:call-template>
1103         </xsl:variable>
1104         <xsl:variable name='special'>
1105           <xsl:call-template name='str:character-first'>
1106             <xsl:with-param name='text' select='$pattern'/>
1107             <xsl:with-param name='chars' select='"*?\"'/>
1108           </xsl:call-template>
1109         </xsl:variable>
1110
1111         <xsl:variable name='new-text' select='substring($text, string-length($before-special) + 1)'/>
1112         <xsl:variable name='new-pattern' select='substring($pattern, string-length($before-special) + 1)'/>
1113
1114         <xsl:choose>
1115           <xsl:when test="not(starts-with($text, $before-special))">
1116             <!-- Verbatim characters don't match -->
1117             <xsl:text>0</xsl:text>
1118           </xsl:when>
1119
1120           <xsl:when test="$special = '*' and string-length($new-pattern) = 1">
1121             <xsl:text>1</xsl:text>
1122           </xsl:when>
1123           <xsl:when test="$special = '*'">
1124             <xsl:call-template name='str:match-postfix'>
1125               <xsl:with-param name='text' select='$new-text'/>
1126               <xsl:with-param name='pattern' select='substring($new-pattern, 2)'/>
1127             </xsl:call-template>
1128           </xsl:when>
1129
1130           <xsl:when test="$special = '?'">
1131             <xsl:call-template name="str:string-match">
1132               <xsl:with-param name='text' select='substring($new-text, 2)'/>
1133               <xsl:with-param name='pattern' select='substring($new-pattern, 2)'/>
1134             </xsl:call-template>
1135           </xsl:when>
1136
1137           <xsl:when test="$special = '\' and substring($new-text, 1, 1) = substring($new-pattern, 2, 1)">
1138             <xsl:call-template name="str:string-match">
1139               <xsl:with-param name='text' select='substring($new-text, 2)'/>
1140               <xsl:with-param name='pattern' select='substring($new-pattern, 3)'/>
1141             </xsl:call-template>
1142           </xsl:when>
1143           <xsl:when test="$special = '\' and substring($new-text, 1, 1) != substring($new-pattern, 2, 1)">
1144             <xsl:text>0</xsl:text>
1145           </xsl:when>
1146
1147           <xsl:otherwise>
1148             <!-- There were no special characters in the pattern -->
1149             <xsl:choose>
1150               <xsl:when test='$text = $pattern'>
1151                 <xsl:text>1</xsl:text>
1152               </xsl:when>
1153               <xsl:otherwise>
1154                 <xsl:text>0</xsl:text>
1155               </xsl:otherwise>
1156             </xsl:choose>
1157           </xsl:otherwise>
1158         </xsl:choose>
1159       </xsl:otherwise>
1160     </xsl:choose>
1161   </xsl:template>
1162
1163   <xsl:template name="str:match-postfix">
1164     <xsl:param name="text"/>
1165     <xsl:param name="pattern"/>
1166
1167     <xsl:variable name='result'>
1168       <xsl:call-template name='str:string-match'>
1169         <xsl:with-param name='text' select='$text'/>
1170         <xsl:with-param name='pattern' select='$pattern'/>
1171       </xsl:call-template>
1172     </xsl:variable>
1173
1174     <xsl:choose>
1175       <xsl:when test='$result = "1"'>
1176         <xsl:value-of select='$result'/>
1177       </xsl:when>
1178       <xsl:when test='string-length($text) = 0'>
1179         <xsl:text>0</xsl:text>
1180       </xsl:when>
1181       <xsl:otherwise>
1182         <xsl:call-template name='str:match-postfix'>
1183           <xsl:with-param name='text' select='substring($text, 2)'/>
1184           <xsl:with-param name='pattern' select='$pattern'/>
1185         </xsl:call-template>
1186       </xsl:otherwise>
1187     </xsl:choose>
1188
1189   </xsl:template>
1190
1191   <doc:template name="str:generate-string" xmlns="">
1192     <refpurpose>Create A Repeating Sequence of Characters</refpurpose>
1193
1194     <refdescription>
1195       <para>Repeats a string a given number of times.</para>
1196     </refdescription>
1197
1198     <refparameter>
1199       <variablelist>
1200         <varlistentry>
1201           <term>text</term>
1202           <listitem>
1203             <para>The string to repeat.</para>
1204           </listitem>
1205         </varlistentry>
1206         <varlistentry>
1207           <term>count</term>
1208           <listitem>
1209             <para>The number of times to repeat the string.</para>
1210           </listitem>
1211         </varlistentry>
1212       </variablelist>
1213     </refparameter>
1214   </doc:template>
1215
1216   <xsl:template name="str:generate-string">
1217     <xsl:param name="text"/>
1218     <xsl:param name="count"/>
1219
1220     <xsl:choose>
1221       <xsl:when test="string-length($text) = 0 or $count &lt;= 0"/>
1222       <xsl:otherwise>
1223         <xsl:value-of select="$text"/>
1224         <xsl:call-template name="str:generate-string">
1225           <xsl:with-param name="text" select="$text"/>
1226           <xsl:with-param name="count" select="$count - 1"/>
1227         </xsl:call-template>
1228       </xsl:otherwise>
1229     </xsl:choose>
1230   </xsl:template>
1231
1232 </xsl:stylesheet>
1233