// (C) 2003 Atsushi Enomoto
//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
using System;
using System.Collections;
+using System.Globalization;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
XslAvt groupingSize;
public XslNumber (Compiler c) : base (c) {}
-
+
+ // This behaves differently from Math.Round. For n + 0.5,
+ // Math.Round() truncates, while XSLT expects ceiling.
+ public static double Round (double n)
+ {
+ double f = System.Math.Floor (n);
+ return (n - f >= 0.5) ? f + 1.0 : f;
+ }
+
protected override void Compile (Compiler c)
{
switch (c.GetAttribute ("level"))
string lang = null;
string letterValue = null;
char groupingSeparatorChar = '\0';
- int groupingSize = 0;
+ decimal groupingSize = 0;
if (this.format != null)
formatStr = this.format.Evaluate (p);
groupingSeparatorChar = this.groupingSeparator.Evaluate (p) [0];
if (this.groupingSize != null)
- groupingSize = int.Parse (this.groupingSize.Evaluate (p));
+ groupingSize = decimal.Parse (this.groupingSize.Evaluate (p), CultureInfo.InvariantCulture);
- return new XslNumberFormatter (formatStr, lang, letterValue, groupingSeparatorChar, groupingSize);
+ //FIXME: Negative test compliency: .NET throws exception on negative grouping-size
+ if (groupingSize > Int32.MaxValue || groupingSize < 1)
+ groupingSize = 0;
+
+ return new XslNumberFormatter (formatStr, lang, letterValue, groupingSeparatorChar, (int)groupingSize);
}
string GetFormat (XslTransformProcessor p)
if (this.value != null) {
double result = p.EvaluateNumber (this.value);
- result = (int) ((result - (int) result >= 0.5) ? result + 1 : result);
- return nf.Format ((int) result);
+ //Do we need to round the result here???
+ //result = (int) ((result - (int) result >= 0.5) ? result + 1 : result);
+ return nf.Format (result);
}
switch (this.level) {
return 0;
};
}
- } while (true);\r
+ } while (true);
}
int NumberSingle (XslTransformProcessor p)
}
// return the format for a single value, ie, if using Single or Any
- public string Format (int value)
+ public string Format (double value)
{
return Format (value, true);
}
- public string Format (int value, bool formatContent)
+ public string Format (double value, bool formatContent)
{
StringBuilder b = new StringBuilder ();
if (firstSep != null) b.Append (firstSep);
if (formatContent)
((FormatItem)fmtList [0]).Format (b, value);
if (lastSep != null) b.Append (lastSep);
-
return b.ToString ();
}
this.sep = sep;
}
- public abstract void Format (StringBuilder b, int num);
+ public abstract void Format (StringBuilder b, double num);
public static FormatItem GetItem (string sep, string item, char gpSep, int gpSize)
{
switch (item [0])
{
default: // See XSLT 1.0 spec 7.7.1.
+ return new DigitItem (sep, 1, gpSep, gpSize);
case '0': case '1':
- return new DigitItem (sep, item.Length, gpSep, gpSize);
+ int len = 1;
+ for (; len < item.Length; len++)
+ if (!Char.IsDigit (item, len))
+ break;
+ return new DigitItem (sep, len, gpSep, gpSize);
case 'a':
return new AlphaItem (sep, false);
case 'A':
this.uc = uc;
}
- public override void Format (StringBuilder b, int num)
+ public override void Format (StringBuilder b, double num)
{
alphaSeq (b, num, uc ? ucl : lcl);
}
- static void alphaSeq (StringBuilder b, int n, char [] alphabet) {
+ static void alphaSeq (StringBuilder b, double n, char [] alphabet) {
+ n = XslNumber.Round (n);
+ if (n == 0)
+ return;
if (n > alphabet.Length)
- alphaSeq (b, (n-1) / alphabet.Length, alphabet);
- b.Append (alphabet [(n-1) % alphabet.Length]);
+ alphaSeq (b, System.Math.Floor ((n - 1) / alphabet.Length), alphabet);
+ b.Append (alphabet [((int) n - 1) % alphabet.Length]);
}
}
static readonly int [] decValues =
{1000, 900 , 500, 400 , 100, 90 , 50 , 40 , 10 , 9 , 5 , 4 , 1 };
- public override void Format (StringBuilder b, int num)
+ public override void Format (StringBuilder b, double num)
{
if (num < 1 || num > 4999) {
b.Append (num);
return;
}
-
+ num = XslNumber.Round (num);
for (int i = 0; i < decValues.Length; i++) {
while (decValues [i] <= num) {
if (uc)
}
class DigitItem : FormatItem {
- System.Globalization.NumberFormatInfo nfi;
+ NumberFormatInfo nfi;
int decimalSectionLength;
StringBuilder numberBuilder;
public DigitItem (string sep, int len, char gpSep, int gpSize) : base (sep)
{
- nfi = new System.Globalization.NumberFormatInfo ();
+ nfi = new NumberFormatInfo ();
nfi.NumberDecimalDigits = 0;
+ nfi.NumberGroupSizes = new int [] {0};
if (gpSep != '\0' && gpSize > 0) {
// ignored if either of them doesn't exist.
nfi.NumberGroupSeparator = gpSep.ToString ();
decimalSectionLength = len;
}
- public override void Format (StringBuilder b, int num)
+ public override void Format (StringBuilder b, double num)
{
string number = num.ToString ("N", nfi);
int len = decimalSectionLength;