The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.XsltOld \ FormatInfo

  1. //------------------------------------------------------------------------------
  2. // <copyright file="NumberAction.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Xml.Xsl.XsltOld
  16. {
  17.     using Res = System.Xml.Utils.Res;
  18.     using System.Diagnostics;
  19.     using System.Text;
  20.     using System.Globalization;
  21.     using System.Collections;
  22.     using System.Collections.Generic;
  23.     using System.Xml.XPath;
  24.     using System.Xml.Xsl.Runtime;
  25.    
  26.     internal class NumberAction : ContainerAction
  27.     {
  28.         const long msofnfcNil = 0;
  29.         // no flags
  30.         const long msofnfcTraditional = 1;
  31.         // use traditional numbering
  32.         const long msofnfcAlwaysFormat = 2;
  33.         // if requested format is not supported, use Arabic (Western) style
  34.         const int cchMaxFormat = 63;
  35.         // max size of formatted result
  36.         const int cchMaxFormatDecimal = 11;
  37.         // max size of formatted decimal result (doesn't handle the case of a very large pwszSeparator or minlen)
  38.         internal class FormatInfo
  39.         {
  40.             public bool isSeparator;
  41.             // False for alphanumeric strings of chars
  42.             public NumberingSequence numSequence;
  43.             // Specifies numbering sequence
  44.             public int length;
  45.             // Minimum length of decimal numbers (if necessary, pad to left with zeros)
  46.             public string formatString;
  47.             // Format string for separator token
  48.             public FormatInfo(bool isSeparator, string formatString)
  49.             {
  50.                 this.isSeparator = isSeparator;
  51.                 this.formatString = formatString;
  52.             }
  53.            
  54.             public FormatInfo()
  55.             {
  56.             }
  57.         }
  58.        
  59.         static FormatInfo DefaultFormat = new FormatInfo(false, "0");
  60.         static FormatInfo DefaultSeparator = new FormatInfo(true, ".");
  61.        
  62.         class NumberingFormat : NumberFormatterBase
  63.         {
  64.             NumberingSequence seq;
  65.             int cMinLen;
  66.             string separator;
  67.             int sizeGroup;
  68.            
  69.             internal NumberingFormat()
  70.             {
  71.             }
  72.            
  73.             internal void setNumberingType(NumberingSequence seq)
  74.             {
  75.                 this.seq = seq;
  76.             }
  77.             //void setLangID(LID langid) {_langid = langid;}
  78.             //internal void setTraditional(bool fTraditional) {_grfnfc = fTraditional ? msofnfcTraditional : 0;}
  79.             internal void setMinLen(int cMinLen)
  80.             {
  81.                 this.cMinLen = cMinLen;
  82.             }
  83.             internal void setGroupingSeparator(string separator)
  84.             {
  85.                 this.separator = separator;
  86.             }
  87.            
  88.             internal void setGroupingSize(int sizeGroup)
  89.             {
  90.                 if (0 <= sizeGroup && sizeGroup <= 9) {
  91.                     this.sizeGroup = sizeGroup;
  92.                 }
  93.             }
  94.            
  95.             internal string FormatItem(object value)
  96.             {
  97.                 double dblVal;
  98.                
  99.                 if (value is int) {
  100.                     dblVal = (int)value;
  101.                 }
  102.                 else {
  103.                     dblVal = XmlConvert.ToXPathDouble(value);
  104.                    
  105.                     if (0.5 <= dblVal && !double.IsPositiveInfinity(dblVal)) {
  106.                         dblVal = XmlConvert.XPathRound(dblVal);
  107.                     }
  108.                     else {
  109.                         // It is an error if the number is NaN, infinite or less than 0.5; an XSLT processor may signal the error;
  110.                         // if it does not signal the error, it must recover by converting the number to a string as if by a call
  111.                         // to the string function and inserting the resulting string into the result tree.
  112.                         return XmlConvert.ToXPathString(value);
  113.                     }
  114.                 }
  115.                
  116.                 Debug.Assert(dblVal >= 1);
  117.                
  118.                 switch (seq) {
  119.                     case NumberingSequence.Arabic:
  120.                         break;
  121.                     case NumberingSequence.UCLetter:
  122.                     case NumberingSequence.LCLetter:
  123.                         if (dblVal <= MaxAlphabeticValue) {
  124.                             StringBuilder sb = new StringBuilder();
  125.                             ConvertToAlphabetic(sb, dblVal, seq == NumberingSequence.UCLetter ? 'A' : 'a', 26);
  126.                             return sb.ToString();
  127.                         }
  128.                         break;
  129.                     case NumberingSequence.UCRoman:
  130.                     case NumberingSequence.LCRoman:
  131.                         if (dblVal <= MaxRomanValue) {
  132.                             StringBuilder sb = new StringBuilder();
  133.                             ConvertToRoman(sb, dblVal, seq == NumberingSequence.UCRoman);
  134.                             return sb.ToString();
  135.                         }
  136.                         break;
  137.                 }
  138.                
  139.                 return ConvertToArabic(dblVal, cMinLen, sizeGroup, separator);
  140.             }
  141.            
  142.             static string ConvertToArabic(double val, int minLength, int groupSize, string groupSeparator)
  143.             {
  144.                 string str;
  145.                
  146.                 if (groupSize != 0 && groupSeparator != null) {
  147.                     NumberFormatInfo NumberFormat = new NumberFormatInfo();
  148.                     NumberFormat.NumberGroupSizes = new int[] {groupSize};
  149.                     NumberFormat.NumberGroupSeparator = groupSeparator;
  150.                     if (Math.Floor(val) == val) {
  151.                         NumberFormat.NumberDecimalDigits = 0;
  152.                     }
  153.                     str = val.ToString("N", NumberFormat);
  154.                 }
  155.                 else {
  156.                     str = Convert.ToString(val, CultureInfo.InvariantCulture);
  157.                 }
  158.                
  159.                 if (str.Length >= minLength) {
  160.                     return str;
  161.                 }
  162.                 else {
  163.                     StringBuilder sb = new StringBuilder(minLength);
  164.                     sb.Append('0', minLength - str.Length);
  165.                     sb.Append(str);
  166.                     return sb.ToString();
  167.                 }
  168.             }
  169.         }
  170.        
  171.         // States:
  172.         private const int OutputNumber = 2;
  173.        
  174.         private string level;
  175.         private string countPattern;
  176.         private int countKey = Compiler.InvalidQueryKey;
  177.         private string from;
  178.         private int fromKey = Compiler.InvalidQueryKey;
  179.         private string value;
  180.         private int valueKey = Compiler.InvalidQueryKey;
  181.         private Avt formatAvt;
  182.         private Avt langAvt;
  183.         private Avt letterAvt;
  184.         private Avt groupingSepAvt;
  185.         private Avt groupingSizeAvt;
  186.         // Compile time precalculated AVTs
  187.         private List<FormatInfo> formatTokens;
  188.         private string lang;
  189.         private string letter;
  190.         private string groupingSep;
  191.         private string groupingSize;
  192.         private bool forwardCompatibility;
  193.        
  194.         internal override bool CompileAttribute(Compiler compiler)
  195.         {
  196.             string name = compiler.Input.LocalName;
  197.             string value = compiler.Input.Value;
  198.             if (Keywords.Equals(name, compiler.Atoms.Level)) {
  199.                 if (value != "any" && value != "multiple" && value != "single") {
  200.                     throw XsltException.Create(Res.Xslt_InvalidAttrValue, Keywords.s_Level, value);
  201.                 }
  202.                 this.level = value;
  203.             }
  204.             else if (Keywords.Equals(name, compiler.Atoms.Count)) {
  205.                 this.countPattern = value;
  206.                     /*allowVars:*/                    /*allowKey:*/                    /*pattern*/                this.countKey = compiler.AddQuery(value, true, true, true);
  207.             }
  208.             else if (Keywords.Equals(name, compiler.Atoms.From)) {
  209.                 this.from = value;
  210.                     /*allowVars:*/                    /*allowKey:*/                    /*pattern*/                this.fromKey = compiler.AddQuery(value, true, true, true);
  211.             }
  212.             else if (Keywords.Equals(name, compiler.Atoms.Value)) {
  213.                 this.value = value;
  214.                 this.valueKey = compiler.AddQuery(value);
  215.             }
  216.             else if (Keywords.Equals(name, compiler.Atoms.Format)) {
  217.                 this.formatAvt = Avt.CompileAvt(compiler, value);
  218.             }
  219.             else if (Keywords.Equals(name, compiler.Atoms.Lang)) {
  220.                 this.langAvt = Avt.CompileAvt(compiler, value);
  221.             }
  222.             else if (Keywords.Equals(name, compiler.Atoms.LetterValue)) {
  223.                 this.letterAvt = Avt.CompileAvt(compiler, value);
  224.             }
  225.             else if (Keywords.Equals(name, compiler.Atoms.GroupingSeparator)) {
  226.                 this.groupingSepAvt = Avt.CompileAvt(compiler, value);
  227.             }
  228.             else if (Keywords.Equals(name, compiler.Atoms.GroupingSize)) {
  229.                 this.groupingSizeAvt = Avt.CompileAvt(compiler, value);
  230.             }
  231.             else {
  232.                 return false;
  233.             }
  234.             return true;
  235.         }
  236.        
  237.         internal override void Compile(Compiler compiler)
  238.         {
  239.             CompileAttributes(compiler);
  240.             CheckEmpty(compiler);
  241.            
  242.             this.forwardCompatibility = compiler.ForwardCompatibility;
  243.             this.formatTokens = ParseFormat(PrecalculateAvt(ref this.formatAvt));
  244.             this.letter = ParseLetter(PrecalculateAvt(ref this.letterAvt));
  245.             this.lang = PrecalculateAvt(ref this.langAvt);
  246.             this.groupingSep = PrecalculateAvt(ref this.groupingSepAvt);
  247.             if (this.groupingSep != null && this.groupingSep.Length > 1) {
  248.                 throw XsltException.Create(Res.Xslt_CharAttribute, Keywords.s_GroupingSeparator);
  249.             }
  250.             this.groupingSize = PrecalculateAvt(ref this.groupingSizeAvt);
  251.         }
  252.        
  253.         private int numberAny(Processor processor, ActionFrame frame)
  254.         {
  255.             int result = 0;
  256.             // Our current point will be our end point in this search
  257.             XPathNavigator endNode = frame.Node;
  258.             if (endNode.NodeType == XPathNodeType.Attribute || endNode.NodeType == XPathNodeType.Namespace) {
  259.                 endNode = endNode.Clone();
  260.                 endNode.MoveToParent();
  261.             }
  262.             XPathNavigator startNode = endNode.Clone();
  263.            
  264.             if (this.fromKey != Compiler.InvalidQueryKey) {
  265.                 bool hitFrom = false;
  266.                 // First try to find start by traversing up. This gives the best candidate or we hit root
  267.                 do {
  268.                     if (processor.Matches(startNode, this.fromKey)) {
  269.                         hitFrom = true;
  270.                         break;
  271.                     }
  272.                 }
  273.                 while (startNode.MoveToParent());
  274.                
  275.                     // we hit 'from' or
  276.                     // we are at root
  277.                 Debug.Assert(processor.Matches(startNode, this.fromKey) || startNode.NodeType == XPathNodeType.Root);
  278.                
  279.                 // from this point (matched parent | root) create descendent quiery:
  280.                 // we have to reset 'result' on each 'from' node, because this point can' be not last from point;
  281.                     /*matchSelf:*/                XPathNodeIterator sel = startNode.SelectDescendants(XPathNodeType.All, true);
  282.                 while (sel.MoveNext()) {
  283.                     if (processor.Matches(sel.Current, this.fromKey)) {
  284.                         hitFrom = true;
  285.                         result = 0;
  286.                     }
  287.                     else if (MatchCountKey(processor, frame.Node, sel.Current)) {
  288.                         result++;
  289.                     }
  290.                     if (sel.Current.IsSamePosition(endNode)) {
  291.                         break;
  292.                     }
  293.                 }
  294.                 if (!hitFrom) {
  295.                     result = 0;
  296.                 }
  297.             }
  298.             else {
  299.                 // without 'from' we startting from the root
  300.                 startNode.MoveToRoot();
  301.                     /*matchSelf:*/                XPathNodeIterator sel = startNode.SelectDescendants(XPathNodeType.All, true);
  302.                 // and count root node by itself
  303.                 while (sel.MoveNext()) {
  304.                     if (MatchCountKey(processor, frame.Node, sel.Current)) {
  305.                         result++;
  306.                     }
  307.                     if (sel.Current.IsSamePosition(endNode)) {
  308.                         break;
  309.                     }
  310.                 }
  311.             }
  312.             return result;
  313.         }
  314.        
  315.         // check 'from' condition:
  316.         // if 'from' exist it has to be ancestor-or-self for the nav
  317.         private bool checkFrom(Processor processor, XPathNavigator nav)
  318.         {
  319.             if (this.fromKey == Compiler.InvalidQueryKey) {
  320.                 return true;
  321.             }
  322.             do {
  323.                 if (processor.Matches(nav, this.fromKey)) {
  324.                     return true;
  325.                 }
  326.             }
  327.             while (nav.MoveToParent());
  328.             return false;
  329.         }
  330.        
  331.         private bool moveToCount(XPathNavigator nav, Processor processor, XPathNavigator contextNode)
  332.         {
  333.             do {
  334.                 if (this.fromKey != Compiler.InvalidQueryKey && processor.Matches(nav, this.fromKey)) {
  335.                     return false;
  336.                 }
  337.                 if (MatchCountKey(processor, contextNode, nav)) {
  338.                     return true;
  339.                 }
  340.             }
  341.             while (nav.MoveToParent());
  342.             return false;
  343.         }
  344.        
  345.         private int numberCount(XPathNavigator nav, Processor processor, XPathNavigator contextNode)
  346.         {
  347.             Debug.Assert(nav.NodeType != XPathNodeType.Attribute && nav.NodeType != XPathNodeType.Namespace);
  348.             Debug.Assert(MatchCountKey(processor, contextNode, nav));
  349.             XPathNavigator runner = nav.Clone();
  350.             int number = 1;
  351.             if (runner.MoveToParent()) {
  352.                 runner.MoveToFirstChild();
  353.                 while (!runner.IsSamePosition(nav)) {
  354.                     if (MatchCountKey(processor, contextNode, runner)) {
  355.                         number++;
  356.                     }
  357.                     if (!runner.MoveToNext()) {
  358.                         Debug.Fail("We implementing preceding-sibling::node() and some how miss context node 'nav'");
  359.                         break;
  360.                     }
  361.                 }
  362.             }
  363.             return number;
  364.         }
  365.        
  366.         private static object SimplifyValue(object value)
  367.         {
  368.             // If result of xsl:number is not in correct range it should be returned as is.
  369.             // so we need intermidiate string value.
  370.             // If it's already a double we would like to keep it as double.
  371.             // So this function converts to string only if if result is nodeset or RTF
  372.             Debug.Assert(!(value is int));
  373.             if (Type.GetTypeCode(value.GetType()) == TypeCode.Object) {
  374.                 XPathNodeIterator nodeset = value as XPathNodeIterator;
  375.                 if (nodeset != null) {
  376.                     if (nodeset.MoveNext()) {
  377.                         return nodeset.Current.Value;
  378.                     }
  379.                     return string.Empty;
  380.                 }
  381.                 XPathNavigator nav = value as XPathNavigator;
  382.                 if (nav != null) {
  383.                     return nav.Value;
  384.                 }
  385.             }
  386.             return value;
  387.         }
  388.        
  389.         internal override void Execute(Processor processor, ActionFrame frame)
  390.         {
  391.             Debug.Assert(processor != null && frame != null);
  392.             ArrayList list = processor.NumberList;
  393.             switch (frame.State) {
  394.                 case Initialized:
  395.                     Debug.Assert(frame != null);
  396.                     Debug.Assert(frame.NodeSet != null);
  397.                     list.Clear();
  398.                     if (this.valueKey != Compiler.InvalidQueryKey) {
  399.                         list.Add(SimplifyValue(processor.Evaluate(frame, this.valueKey)));
  400.                     }
  401.                     else if (this.level == "any") {
  402.                         int number = numberAny(processor, frame);
  403.                         if (number != 0) {
  404.                             list.Add(number);
  405.                         }
  406.                     }
  407.                     else {
  408.                         bool multiple = (this.level == "multiple");
  409.                         XPathNavigator contextNode = frame.Node;
  410.                         // context of xsl:number element. We using this node in MatchCountKey()
  411.                         XPathNavigator countNode = frame.Node.Clone();
  412.                         // node we count for
  413.                         if (countNode.NodeType == XPathNodeType.Attribute || countNode.NodeType == XPathNodeType.Namespace) {
  414.                             countNode.MoveToParent();
  415.                         }
  416.                         while (moveToCount(countNode, processor, contextNode)) {
  417.                             list.Insert(0, numberCount(countNode, processor, contextNode));
  418.                             if (!multiple || !countNode.MoveToParent()) {
  419.                                 break;
  420.                             }
  421.                         }
  422.                         if (!checkFrom(processor, countNode)) {
  423.                             list.Clear();
  424.                         }
  425.                     }
  426.                    
  427.                     /*CalculatingFormat:*/                   
  428. frame.StoredOutput = Format(list, this.formatAvt == null ? this.formatTokens : ParseFormat(this.formatAvt.Evaluate(processor, frame)), this.langAvt == null ? this.lang : this.langAvt.Evaluate(processor, frame), this.letterAvt == null ? this.letter : ParseLetter(this.letterAvt.Evaluate(processor, frame)), this.groupingSepAvt == null ? this.groupingSep : this.groupingSepAvt.Evaluate(processor, frame), this.groupingSizeAvt == null ? this.groupingSize : this.groupingSizeAvt.Evaluate(processor, frame));
  429.                     goto case OutputNumber;
  430.                     break;
  431.                 case OutputNumber:
  432.                     Debug.Assert(frame.StoredOutput != null);
  433.                     if (!processor.TextEvent(frame.StoredOutput)) {
  434.                         frame.State = OutputNumber;
  435.                         break;
  436.                     }
  437.                     frame.Finished();
  438.                     break;
  439.                 default:
  440.                     Debug.Fail("Invalid Number Action execution state");
  441.                     break;
  442.             }
  443.         }
  444.        
  445.         private bool MatchCountKey(Processor processor, XPathNavigator contextNode, XPathNavigator nav)
  446.         {
  447.             if (this.countKey != Compiler.InvalidQueryKey) {
  448.                 return processor.Matches(nav, this.countKey);
  449.             }
  450.             if (contextNode.Name == nav.Name && BasicNodeType(contextNode.NodeType) == BasicNodeType(nav.NodeType)) {
  451.                 return true;
  452.             }
  453.             return false;
  454.         }
  455.        
  456.         private XPathNodeType BasicNodeType(XPathNodeType type)
  457.         {
  458.             if (type == XPathNodeType.SignificantWhitespace || type == XPathNodeType.Whitespace) {
  459.                 return XPathNodeType.Text;
  460.             }
  461.             else {
  462.                 return type;
  463.             }
  464.         }
  465.        
  466.        
  467.         private static string Format(ArrayList numberlist, List<FormatInfo> tokens, string lang, string letter, string groupingSep, string groupingSize)
  468.         {
  469.             StringBuilder result = new StringBuilder();
  470.             int cFormats = 0;
  471.             if (tokens != null) {
  472.                 cFormats = tokens.Count;
  473.             }
  474.            
  475.             NumberingFormat numberingFormat = new NumberingFormat();
  476.             if (groupingSize != null) {
  477.                 try {
  478.                     numberingFormat.setGroupingSize(Convert.ToInt32(groupingSize, CultureInfo.InvariantCulture));
  479.                 }
  480.                 catch (System.FormatException) {
  481.                 }
  482.                 catch (System.OverflowException) {
  483.                 }
  484.             }
  485.             if (groupingSep != null) {
  486.                 if (groupingSep.Length > 1) {
  487.                 }
  488.                 numberingFormat.setGroupingSeparator(groupingSep);
  489.             }
  490.             if (0 < cFormats) {
  491.                 FormatInfo prefix = tokens[0];
  492.                 Debug.Assert(prefix == null || prefix.isSeparator);
  493.                 FormatInfo sufix = null;
  494.                 if (cFormats % 2 == 1) {
  495.                     sufix = tokens[cFormats - 1];
  496.                     cFormats--;
  497.                 }
  498.                 FormatInfo periodicSeparator = 2 < cFormats ? tokens[cFormats - 2] : DefaultSeparator;
  499.                 FormatInfo periodicFormat = 0 < cFormats ? tokens[cFormats - 1] : DefaultFormat;
  500.                 if (prefix != null) {
  501.                     result.Append(prefix.formatString);
  502.                 }
  503.                 int numberlistCount = numberlist.Count;
  504.                 for (int i = 0; i < numberlistCount; i++) {
  505.                     int formatIndex = i * 2;
  506.                     bool haveFormat = formatIndex < cFormats;
  507.                     if (0 < i) {
  508.                         FormatInfo thisSeparator = haveFormat ? tokens[formatIndex + 0] : periodicSeparator;
  509.                         Debug.Assert(thisSeparator.isSeparator);
  510.                         result.Append(thisSeparator.formatString);
  511.                     }
  512.                    
  513.                     FormatInfo thisFormat = haveFormat ? tokens[formatIndex + 1] : periodicFormat;
  514.                     Debug.Assert(!thisFormat.isSeparator);
  515.                    
  516.                     //numberingFormat.setletter(this.letter);
  517.                     //numberingFormat.setLang(this.lang);
  518.                    
  519.                     numberingFormat.setNumberingType(thisFormat.numSequence);
  520.                     numberingFormat.setMinLen(thisFormat.length);
  521.                     result.Append(numberingFormat.FormatItem(numberlist[i]));
  522.                 }
  523.                
  524.                 if (sufix != null) {
  525.                     result.Append(sufix.formatString);
  526.                 }
  527.             }
  528.             else {
  529.                 numberingFormat.setNumberingType(NumberingSequence.Arabic);
  530.                 for (int i = 0; i < numberlist.Count; i++) {
  531.                     if (i != 0) {
  532.                         result.Append(".");
  533.                     }
  534.                     result.Append(numberingFormat.FormatItem(numberlist[i]));
  535.                 }
  536.             }
  537.             return result.ToString();
  538.         }
  539.        
  540. /*
  541.         ----------------------------------------------------------------------------
  542.             mapFormatToken()
  543.             Maps a token of alphanumeric characters to a numbering format ID and a
  544.             minimum length bound.  Tokens specify the character(s) that begins a
  545.             Unicode
  546.             numbering sequence.  For example, "i" specifies lower case roman numeral
  547.             numbering.  Leading "zeros" specify a minimum length to be maintained by
  548.             padding, if necessary.
  549.         ----------------------------------------------------------------------------
  550.         */       
  551.         private static void mapFormatToken(string wsToken, int startLen, int tokLen, out NumberingSequence seq, out int pminlen)
  552.         {
  553.             char wch = wsToken[startLen];
  554.             bool UseArabic = false;
  555.             pminlen = 1;
  556.             seq = NumberingSequence.Nil;
  557.            
  558.             switch ((int)wch) {
  559.                 case 48:
  560.                 case 2406:
  561.                 case 3664:
  562.                 case 51067:
  563.                 case 65296:
  564.                     // Digit zero
  565.                     // Hindi digit zero
  566.                     // Thai digit zero
  567.                     // Korean digit zero
  568.                     // Digit zero (double-byte)
  569.                     do {
  570.                         // Leading zeros request padding. Track how much.
  571.                         pminlen++;
  572.                     }
  573.                     while ((--tokLen > 0) && (wch == wsToken[++startLen]));
  574.                    
  575.                     if (wsToken[startLen] != (char)(wch + 1)) {
  576.                         // If next character isn't "one", then use Arabic
  577.                         UseArabic = true;
  578.                     }
  579.                     break;
  580.             }
  581.            
  582.             if (!UseArabic) {
  583.                 // Map characters of token to number format ID
  584.                 switch ((int)wsToken[startLen]) {
  585.                     case 49:
  586.                         seq = NumberingSequence.Arabic;
  587.                         break;
  588.                     case 65:
  589.                         seq = NumberingSequence.UCLetter;
  590.                         break;
  591.                     case 73:
  592.                         seq = NumberingSequence.UCRoman;
  593.                         break;
  594.                     case 97:
  595.                         seq = NumberingSequence.LCLetter;
  596.                         break;
  597.                     case 105:
  598.                         seq = NumberingSequence.LCRoman;
  599.                         break;
  600.                     case 1040:
  601.                         seq = NumberingSequence.UCRus;
  602.                         break;
  603.                     case 1072:
  604.                         seq = NumberingSequence.LCRus;
  605.                         break;
  606.                     case 1488:
  607.                         seq = NumberingSequence.Hebrew;
  608.                         break;
  609.                     case 1571:
  610.                         seq = NumberingSequence.ArabicScript;
  611.                         break;
  612.                     case 2309:
  613.                         seq = NumberingSequence.Hindi2;
  614.                         break;
  615.                     case 2325:
  616.                         seq = NumberingSequence.Hindi1;
  617.                         break;
  618.                     case 2407:
  619.                         seq = NumberingSequence.Hindi3;
  620.                         break;
  621.                     case 3585:
  622.                         seq = NumberingSequence.Thai1;
  623.                         break;
  624.                     case 3665:
  625.                         seq = NumberingSequence.Thai2;
  626.                         break;
  627.                     case 12450:
  628.                         seq = NumberingSequence.DAiueo;
  629.                         break;
  630.                     case 12452:
  631.                         seq = NumberingSequence.DIroha;
  632.                         break;
  633.                     case 12593:
  634.                         seq = NumberingSequence.DChosung;
  635.                         break;
  636.                     case 19968:
  637.                         seq = NumberingSequence.FEDecimal;
  638.                         break;
  639.                     case 22769:
  640.                         seq = NumberingSequence.DbNum3;
  641.                         break;
  642.                     case 22777:
  643.                         seq = NumberingSequence.ChnCmplx;
  644.                         break;
  645.                     case 23376:
  646.                         seq = NumberingSequence.Zodiac2;
  647.                         break;
  648.                     case 44032:
  649.                         seq = NumberingSequence.Ganada;
  650.                         break;
  651.                     case 51068:
  652.                         seq = NumberingSequence.KorDbNum1;
  653.                         break;
  654.                     case 54616:
  655.                         seq = NumberingSequence.KorDbNum3;
  656.                         break;
  657.                     case 65297:
  658.                         seq = NumberingSequence.DArabic;
  659.                         break;
  660.                     case 65393:
  661.                         seq = NumberingSequence.Aiueo;
  662.                         break;
  663.                     case 65394:
  664.                         seq = NumberingSequence.Iroha;
  665.                         break;
  666.                     case 30002:
  667.                        
  668.                         if (tokLen > 1 && wsToken[startLen + 1] == 23376) {
  669.                             // 60-based Zodiak numbering begins with two characters
  670.                             seq = NumberingSequence.Zodiac3;
  671.                             tokLen--;
  672.                             startLen++;
  673.                         }
  674.                         else {
  675.                             // 10-based Zodiak numbering begins with one character
  676.                             seq = NumberingSequence.Zodiac1;
  677.                         }
  678.                         break;
  679.                     default:
  680.                         seq = NumberingSequence.Arabic;
  681.                         break;
  682.                 }
  683.             }
  684.            
  685.             //if (tokLen != 1 || UseArabic) {
  686.             if (UseArabic) {
  687.                 // If remaining token length is not 1, then don't recognize
  688.                 // sequence and default to Arabic with no zero padding.
  689.                 seq = NumberingSequence.Arabic;
  690.                 pminlen = 0;
  691.             }
  692.         }
  693.        
  694.        
  695. /*
  696.         ----------------------------------------------------------------------------
  697.             parseFormat()
  698.             Parse format string into format tokens (alphanumeric) and separators
  699.             (non-alphanumeric).
  700.         */       
  701.         private static List<FormatInfo> ParseFormat(string formatString)
  702.         {
  703.             if (formatString == null || formatString.Length == 0) {
  704.                 return null;
  705.             }
  706.             int length = 0;
  707.             bool lastAlphaNumeric = CharUtil.IsAlphaNumeric(formatString[length]);
  708.             List<FormatInfo> tokens = new List<FormatInfo>();
  709.             int count = 0;
  710.            
  711.             if (lastAlphaNumeric) {
  712.                 // If the first one is alpha num add empty separator as a prefix.
  713.                 tokens.Add(null);
  714.             }
  715.            
  716.             while (length <= formatString.Length) {
  717.                 // Loop until a switch from format token to separator is detected (or vice-versa)
  718.                 bool currentchar = length < formatString.Length ? CharUtil.IsAlphaNumeric(formatString[length]) : !lastAlphaNumeric;
  719.                 if (lastAlphaNumeric != currentchar) {
  720.                     FormatInfo formatInfo = new FormatInfo();
  721.                     if (lastAlphaNumeric) {
  722.                         // We just finished a format token. Map it to a numbering format ID and a min-length bound.
  723.                         mapFormatToken(formatString, count, length - count, out formatInfo.numSequence, out formatInfo.length);
  724.                     }
  725.                     else {
  726.                         formatInfo.isSeparator = true;
  727.                         // We just finished a separator. Save its length and a pointer to it.
  728.                         formatInfo.formatString = formatString.Substring(count, length - count);
  729.                     }
  730.                     count = length;
  731.                     length++;
  732.                     // Begin parsing the next format token or separator
  733.                    
  734.                     tokens.Add(formatInfo);
  735.                     // Flip flag from format token to separator (or vice-versa)
  736.                     lastAlphaNumeric = currentchar;
  737.                 }
  738.                 else {
  739.                     length++;
  740.                 }
  741.             }
  742.            
  743.             return tokens;
  744.         }
  745.        
  746.         private string ParseLetter(string letter)
  747.         {
  748.             if (letter == null || letter == "traditional" || letter == "alphabetic") {
  749.                 return letter;
  750.             }
  751.             if (!this.forwardCompatibility) {
  752.                 throw XsltException.Create(Res.Xslt_InvalidAttrValue, Keywords.s_LetterValue, letter);
  753.             }
  754.             return null;
  755.         }
  756.     }
  757. }

Developer Fusion