XsltInput.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / XmlUtils / System / Xml / Xsl / Xslt / XsltInput.cs / 1305376 / XsltInput.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
#define XSLT2 

using System.Diagnostics; 
using System.Text;
using System.Xml.XPath;
using System.Collections.Generic;
 
namespace System.Xml.Xsl.Xslt {
    using Res = System.Xml.Utils.Res; 
    using StringConcat = System.Xml.Xsl.Runtime.StringConcat; 
    //         a) Forward only, one pass.
    //         b) You should call MoveToFirstChildren on nonempty element node. (or may be skip) 

    internal class XsltInput : IErrorHelper {
    #if DEBUG
        const int InitRecordsSize = 1; 
    #else
        const int InitRecordsSize = 1 + 21; 
    #endif 

        private XmlReader           reader; 
        private IXmlLineInfo        readerLineInfo;
        private bool                topLevelReader;
        private CompilerScopeManager scopeManager;
        private KeywordsTable       atoms; 
        private Compiler            compiler;
        private bool                reatomize; 
 
        // Cached properties. MoveTo* functions set them.
        private XmlNodeType         nodeType; 
        private Record[]            records = new Record[InitRecordsSize];
        private int                 currentRecord;
        private bool                isEmptyElement;
        private int                 lastTextNode; 
        private int                 numAttributes;
        private ContextInfo         ctxInfo; 
        private bool                attributesRead; 

        public XsltInput(XmlReader reader, Compiler compiler, KeywordsTable atoms) { 
            Debug.Assert(reader != null);
            Debug.Assert(atoms != null);
            EnsureExpandEntities(reader);
            IXmlLineInfo xmlLineInfo = reader as IXmlLineInfo; 

            this.atoms          = atoms; 
            this.reader         = reader; 
            this.reatomize      = reader.NameTable != atoms.NameTable;
            this.readerLineInfo = (xmlLineInfo != null && xmlLineInfo.HasLineInfo()) ? xmlLineInfo : null; 
            this.topLevelReader = reader.ReadState == ReadState.Initial;
            this.scopeManager   = new CompilerScopeManager(atoms);
            this.compiler       = compiler;
            this.nodeType       = XmlNodeType.Document; 
        }
 
        // Cached properties 
        public XmlNodeType   NodeType       { get { return nodeType == XmlNodeType.Element && 0 < currentRecord ? XmlNodeType.Attribute : nodeType; } }
        public string        LocalName      { get { return records[currentRecord].localName      ;} } 
        public string        NamespaceUri   { get { return records[currentRecord].nsUri          ;} }
        public string        Prefix         { get { return records[currentRecord].prefix         ;} }
        public string        Value          { get { return records[currentRecord].value          ;} }
        public string        BaseUri        { get { return records[currentRecord].baseUri        ;} } 
        public string        QualifiedName  { get { return records[currentRecord].QualifiedName  ;} }
        public bool          IsEmptyElement { get { return isEmptyElement; } } 
 
        public string        Uri            { get { return records[currentRecord].baseUri        ; } }
        public Location      Start          { get { return records[currentRecord].start          ; } } 
        public Location      End            { get { return records[currentRecord].end            ; } }

        private static void EnsureExpandEntities(XmlReader reader) {
            XmlTextReader tr = reader as XmlTextReader; 
            if (tr != null && tr.EntityHandling != EntityHandling.ExpandEntities) {
                Debug.Assert(tr.Settings == null, "XmlReader created with XmlReader.Create should always expand entities."); 
                tr.EntityHandling = EntityHandling.ExpandEntities; 
            }
        } 

        private void ExtendRecordBuffer(int position) {
            if (records.Length <= position) {
                int newSize = records.Length * 2; 
                if (newSize <= position) {
                    newSize = position + 1; 
                } 
                Record[] tmp = new Record[newSize];
                Array.Copy(records, tmp, records.Length); 
                records = tmp;
            }
        }
 
        public bool FindStylesheetElement() {
            if (! topLevelReader) { 
                if (reader.ReadState != ReadState.Interactive) { 
                    return false;
                } 
            }

            // The stylesheet may be an embedded stylesheet. If this is the case the reader will be in Interactive state and should be
            // positioned on xsl:stylesheet element (or any preceding whitespace) but there also can be namespaces defined on one 
            // of the ancestor nodes. These namespace definitions have to be copied to the xsl:stylesheet element scope. Otherwise it
            // will not be possible to resolve them later and loading the stylesheet will end up with throwing an exception. 
            IDictionary namespacesInScope = null; 
            if (reader.ReadState == ReadState.Interactive) {
                // This may be an embedded stylesheet - store namespaces in scope 
                IXmlNamespaceResolver nsResolver = reader as IXmlNamespaceResolver;
                if (nsResolver != null) {
                    namespacesInScope = nsResolver.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml);
                } 
            }
 
            while (MoveToNextSibling() && nodeType == XmlNodeType.Whitespace) ; 

            // An Element node was reached. Potentially this is xsl:stylesheet instruction. 
            if (nodeType == XmlNodeType.Element) {
                // If namespacesInScope is not null then the stylesheet being read is an embedded stylesheet that can have namespaces
                // defined outside of xsl:stylesheet instruction. In this case the namespace definitions collected above have to be added
                // to the element scope. 
                if (namespacesInScope != null) {
                    foreach (KeyValuePair prefixNamespacePair in namespacesInScope) { 
                        // The namespace could be redefined on the element we just read. If this is the case scopeManager already has 
                        // namespace definition for this prefix and the old definition must not be added to the scope.
                        if (scopeManager.LookupNamespace(prefixNamespacePair.Key) == null) { 
                            string nsAtomizedValue = atoms.NameTable.Add(prefixNamespacePair.Value);
                            scopeManager.AddNsDeclaration(prefixNamespacePair.Key, nsAtomizedValue);
                            ctxInfo.AddNamespace(prefixNamespacePair.Key, nsAtomizedValue);
                        } 
                    }
                } 
 
                // return true to indicate that we reached XmlNodeType.Element node - potentially xsl:stylesheet element.
                return true; 
            }

            // return false to indicate that we did not reach XmlNodeType.Element node so it is not a valid stylesheet.
            return false; 
        }
 
        public void Finish() { 
            scopeManager.CheckEmpty();
 
            if (topLevelReader) {
                while (reader.ReadState == ReadState.Interactive) {
                    reader.Skip();
                } 
            }
        } 
 
        private void FillupRecord(ref Record rec) {
            rec.localName       = reader.LocalName; 
            rec.nsUri           = reader.NamespaceURI;
            rec.prefix          = reader.Prefix;
            rec.value           = reader.Value;
            rec.baseUri         = reader.BaseURI; 

            if (reatomize) { 
                rec.localName = atoms.NameTable.Add(rec.localName); 
                rec.nsUri     = atoms.NameTable.Add(rec.nsUri    );
                rec.prefix    = atoms.NameTable.Add(rec.prefix   ); 
            }

            if (readerLineInfo != null) {
                rec.start       = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition - PositionAdjustment(reader.NodeType)); 
            }
        } 
 
        private void SetRecordEnd(ref Record rec) {
            if (readerLineInfo != null) { 
                rec.end = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition - PositionAdjustment(reader.NodeType));
                if (reader.BaseURI != rec.baseUri || rec.end.LessOrEqual(rec.start)) {
                    rec.end = new Location(rec.start.Line, int.MaxValue);
                } 
            }
        } 
 
        private void FillupTextRecord(ref Record rec) {
            Debug.Assert( 
                reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.SignificantWhitespace ||
                reader.NodeType == XmlNodeType.Text       || reader.NodeType == XmlNodeType.CDATA
            );
            rec.localName       = string.Empty; 
            rec.nsUri           = string.Empty;
            rec.prefix          = string.Empty; 
            rec.value           = reader.Value; 
            rec.baseUri         = reader.BaseURI;
 
            if (readerLineInfo != null) {
                bool isCDATA = (reader.NodeType == XmlNodeType.CDATA);
                int line = readerLineInfo.LineNumber;
                int pos  = readerLineInfo.LinePosition; 
                rec.start = new Location(line, pos - (isCDATA ? 9 : 0));
                char prevChar = ' '; 
                foreach (char ch in rec.value) { 
                    switch (ch) {
                    case '\n': 
                        if (prevChar != '\r') {
                            goto case '\r';
                        }
                        break; 
                    case '\r':
                        line ++; 
                        pos = 1; 
                        break;
                    default : 
                        pos ++;
                        break;
                    }
                    prevChar = ch; 
                }
                rec.end = new Location(line, pos + (isCDATA ? 3 : 0)); 
            } 
        }
 
        private void FillupCharacterEntityRecord(ref Record rec) {
            Debug.Assert(reader.NodeType == XmlNodeType.EntityReference);
            string local = reader.LocalName;
            Debug.Assert(local[0] == '#' || local == "lt" || local == "gt" || local == "quot" || local == "apos"); 
            rec.localName       = string.Empty;
            rec.nsUri           = string.Empty; 
            rec.prefix          = string.Empty; 
            rec.baseUri         = reader.BaseURI;
 
            if (readerLineInfo != null) {
                rec.start = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition - 1);
            }
            reader.ResolveEntity(); 
            reader.Read();
            Debug.Assert(reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.SignificantWhitespace); 
            rec.value = reader.Value; 
            reader.Read();
            Debug.Assert(reader.NodeType == XmlNodeType.EndEntity); 
            if (readerLineInfo != null) {
                int line = readerLineInfo.LineNumber;
                int pos = readerLineInfo.LinePosition;
                rec.end = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition + 1); 
            }
        } 
 
        StringConcat strConcat = new StringConcat();
 
        // returns false if attribute is actualy namespace
        private bool ReadAttribute(ref Record rec) {
            Debug.Assert(reader.NodeType == XmlNodeType.Attribute, "reader.NodeType == XmlNodeType.Attribute");
            FillupRecord(ref rec); 
            if (Ref.Equal(rec.prefix, atoms.Xmlns)) {                                      // xmlns:foo="NS_FOO"
                string atomizedValue = atoms.NameTable.Add(reader.Value); 
                if (!Ref.Equal(rec.localName, atoms.Xml)) { 
                    scopeManager.AddNsDeclaration(rec.localName, atomizedValue);
                    ctxInfo.AddNamespace(rec.localName, atomizedValue); 
                }
                return false;
            } else if (rec.prefix.Length == 0 && Ref.Equal(rec.localName, atoms.Xmlns)) {  // xmlns="NS_FOO"
                string atomizedValue = atoms.NameTable.Add(reader.Value); 
                scopeManager.AddNsDeclaration(string.Empty, atomizedValue);
                ctxInfo.AddNamespace(string.Empty, atomizedValue); 
                return false; 
            }
            /* Read Attribute Value */ { 
                if (!reader.ReadAttributeValue()) {
                    // XmlTextReader never returns false from first call to ReadAttributeValue()
                    rec.value = string.Empty;
                    SetRecordEnd(ref rec); 
                    return true;
                } 
                if (readerLineInfo != null) { 
                    int correction = (reader.NodeType == XmlNodeType.EntityReference) ? -2 : -1;
                    rec.valueStart = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition + correction); 
                    if (reader.BaseURI != rec.baseUri || rec.valueStart.LessOrEqual(rec.start)) {
                        int nameLength = ((rec.prefix.Length != 0) ? rec.prefix.Length + 1 : 0) + rec.localName.Length;
                        rec.end = new Location(rec.start.Line, rec.start.Pos + nameLength + 1);
                    } 
                }
                string lastText = string.Empty; 
                strConcat.Clear(); 
                do {
                    switch (reader.NodeType) { 
                    case XmlNodeType.EntityReference:
                        reader.ResolveEntity();
                        break;
                    case XmlNodeType.EndEntity: 
                        break;
                    default: 
                        Debug.Assert(reader.NodeType == XmlNodeType.Text, "Unexpected node type inside attribute value"); 
                        lastText = reader.Value;
                        strConcat.Concat(lastText); 
                        break;
                    }
                } while (reader.ReadAttributeValue());
                rec.value = strConcat.GetResult(); 
                if (readerLineInfo != null) {
                    Debug.Assert(reader.NodeType != XmlNodeType.EntityReference); 
                    int correction = ((reader.NodeType == XmlNodeType.EndEntity) ? 1 : lastText.Length) + 1; 
                    rec.end = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition + correction);
                    if (reader.BaseURI != rec.baseUri || rec.end.LessOrEqual(rec.valueStart)) { 
                        rec.end = new Location(rec.start.Line, int.MaxValue);
                    }
                }
            } 
            return true;
        } 
 
        // --------------------
 
        public bool MoveToFirstChild() {
            Debug.Assert(nodeType == XmlNodeType.Element, "To call MoveToFirstChild() XsltI---- should be positioned on an Element.");
            if (IsEmptyElement) {
                return false; 
            }
            return ReadNextSibling(); 
        } 

        public bool MoveToNextSibling() { 
            Debug.Assert(nodeType != XmlNodeType.Element || IsEmptyElement, "On non-empty elements we should call MoveToFirstChild()");
            if (nodeType == XmlNodeType.Element || nodeType == XmlNodeType.EndElement) {
                scopeManager.ExitScope();
            } 
            return ReadNextSibling();
        } 
 
        public void SkipNode() {
            if (nodeType == XmlNodeType.Element && MoveToFirstChild()) { 
                do {
                    SkipNode();
                } while (MoveToNextSibling());
            } 
        }
 
        private int ReadTextNodes() { 
            bool textPreserveWS = reader.XmlSpace == XmlSpace.Preserve;
            bool textIsWhite = true; 
            int curTextNode = 0;
            do {
                switch (reader.NodeType) {
                case XmlNodeType.Text: 
                    // XLinq reports WS nodes as Text so we need to analyze them here
                case XmlNodeType.CDATA: 
                    if (textIsWhite && ! XmlCharType.Instance.IsOnlyWhitespace(reader.Value)) { 
                        textIsWhite = false;
                    } 
                    goto case XmlNodeType.SignificantWhitespace;
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                    ExtendRecordBuffer(curTextNode); 
                    FillupTextRecord(ref records[curTextNode]);
                    reader.Read(); 
                    curTextNode++; 
                    break;
                case XmlNodeType.EntityReference: 
                    string local = reader.LocalName;
                    if (local.Length > 0 && (
                        local[0] == '#' ||
                        local == "lt" || local == "gt" || local == "quot" || local == "apos" 
                    )) {
                        // Special treatment for character and built-in entities 
                        ExtendRecordBuffer(curTextNode); 
                        FillupCharacterEntityRecord(ref records[curTextNode]);
                        if (textIsWhite && !XmlCharType.Instance.IsOnlyWhitespace(records[curTextNode].value)) { 
                            textIsWhite = false;
                        }
                        curTextNode++;
                    } else { 
                        reader.ResolveEntity();
                        reader.Read(); 
                    } 
                    break;
                case XmlNodeType.EndEntity: 
                    reader.Read();
                    break;
                default:
                    this.nodeType = ( 
                        ! textIsWhite  ? XmlNodeType.Text :
                        textPreserveWS ? XmlNodeType.SignificantWhitespace : 
                        /*default:    */ XmlNodeType.Whitespace 
                    );
                    return curTextNode; 
                }
            } while (true);
        }
 
        private bool ReadNextSibling() {
            if (currentRecord < lastTextNode) { 
                Debug.Assert(nodeType == XmlNodeType.Text || nodeType == XmlNodeType.Whitespace || nodeType == XmlNodeType.SignificantWhitespace); 
                currentRecord++;
                if (currentRecord == lastTextNode) { 
                    lastTextNode = 0;  // we are done with text nodes. Reset this counter
                }
                return true;
            } 
            currentRecord = 0;
            while (! reader.EOF) { 
                switch (reader.NodeType) { 
                case XmlNodeType.Text:
                case XmlNodeType.CDATA: 
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                case XmlNodeType.EntityReference:
                    int numTextNodes = ReadTextNodes(); 
                    if (numTextNodes == 0) {
                        // Most likely this was Entity that starts from non-text node 
                        continue; 
                    }
                    lastTextNode = numTextNodes - 1; 
                    return true;
                case XmlNodeType.Element:
                    scopeManager.EnterScope();
                    numAttributes = ReadElement(); 
                    return true;
                case XmlNodeType.EndElement: 
                    nodeType = XmlNodeType.EndElement; 
                    isEmptyElement = false;
                    FillupRecord(ref records[0]); 
                    reader.Read();
                    SetRecordEnd(ref records[0]);
                    return false;
                default: 
                    reader.Read();
                    break; 
                } 
            }
            return false; 
        }

        private int ReadElement() {
            Debug.Assert(reader.NodeType == XmlNodeType.Element); 

            attributesRead = false; 
            FillupRecord(ref records[0]); 
            nodeType = XmlNodeType.Element;
            isEmptyElement = reader.IsEmptyElement; 
            ctxInfo = new ContextInfo(this);

            int record = 1;
            if (reader.MoveToFirstAttribute()) { 
                do {
                    ExtendRecordBuffer(record); 
                    if (ReadAttribute(ref records[record])) { 
                        record++;
                    } 
                } while (reader.MoveToNextAttribute());
                reader.MoveToElement();
            }
            reader.Read(); 
            SetRecordEnd(ref records[0]);
            ctxInfo.lineInfo = BuildLineInfo(); 
            attributes = null; 
            return record - 1;
        } 

        public void MoveToElement() {
            Debug.Assert(nodeType == XmlNodeType.Element, "For MoveToElement() we should be positioned on Element or Attribute");
            currentRecord = 0; 
        }
 
        private bool MoveToAttributeBase(int attNum) { 
            Debug.Assert(nodeType == XmlNodeType.Element, "For MoveToLiteralAttribute() we should be positioned on Element or Attribute");
            if (0 < attNum && attNum <= numAttributes) { 
                currentRecord = attNum;
                return true;
            } else {
                currentRecord = 0; 
                return false;
            } 
        } 

        public bool MoveToLiteralAttribute(int attNum) { 
            Debug.Assert(nodeType == XmlNodeType.Element, "For MoveToLiteralAttribute() we should be positioned on Element or Attribute");
            if (0 < attNum && attNum <= numAttributes) {
                currentRecord = attNum;
                return true; 
            } else {
                currentRecord = 0; 
                return false; 
            }
        } 

        public bool MoveToXsltAttribute(int attNum, string attName) {
            Debug.Assert(attributes != null && attributes[attNum].name == attName, "Attribute numbering error.");
            this.currentRecord = xsltAttributeNumber[attNum]; 
            return this.currentRecord != 0;
        } 
 
        public bool IsRequiredAttribute(int attNum) {
            return (attributes[attNum].flags & (compiler.Version == 2 ? XsltLoader.V2Req : XsltLoader.V1Req)) != 0; 
        }

        public bool AttributeExists(int attNum, string attName) {
            Debug.Assert(attributes != null && attributes[attNum].name == attName, "Attribute numbering error."); 
            return xsltAttributeNumber[attNum] != 0;
        } 
 
        public struct DelayedQName {
            string prefix   ; 
            string localName;
            public DelayedQName(ref Record rec) {
                this.prefix    = rec.prefix;
                this.localName = rec.localName; 
            }
            public static implicit operator string(DelayedQName qn) { 
                return qn.prefix.Length == 0 ? qn.localName : (qn.prefix + ':' + qn.localName); 
            }
        } 

        public DelayedQName ElementName {
            get {
                Debug.Assert(nodeType == XmlNodeType.Element || nodeType == XmlNodeType.EndElement, "Input is positioned on element or attribute"); 
                return new DelayedQName(ref records[0]);
            } 
        } 

        // -------------------- Keywords testing -------------------- 

        public bool IsNs(string ns)             { return Ref.Equal(ns, NamespaceUri); }
        public bool IsKeyword(string kwd)       { return Ref.Equal(kwd, LocalName);  }
        public bool IsXsltNamespace()           { return IsNs(atoms.UriXsl); } 
        public bool IsNullNamespace()           { return IsNs(string.Empty); }
        public bool IsXsltAttribute(string kwd) { return IsKeyword(kwd) && IsNullNamespace(); } 
        public bool IsXsltKeyword(  string kwd) { return IsKeyword(kwd) && IsXsltNamespace(); } 

        // -------------------- Scope Management -------------------- 
        // See private class InputScopeManager bellow.
        // InputScopeManager handles some flags and values with respect of scope level where they as defined.
        // To parse XSLT style sheet we need the folloing values:
        //  BackwardCompatibility -- this flag is set when compiler.version==2 && xsl:version<2. 
        //  ForwardCompatibility  -- this flag is set when compiler.version==2 && xsl:version>1 or compiler.version==1 && xsl:version!=1
        //  CanHaveApplyImports  -- we allow xsl:apply-templates instruction to apear in any template with match!=null, but not inside xsl:for-each 
        //                          so it can't be inside global variable and has initial value = false 
        //  ExtentionNamespace   -- is defined by extension-element-prefixes attribute on LRE or xsl:stylesheet
 
        public bool CanHaveApplyImports {
            get { return scopeManager.CanHaveApplyImports;  }
            set { scopeManager.CanHaveApplyImports = value; }
        } 

        public bool IsExtensionNamespace(string uri) { 
            Debug.Assert(nodeType != XmlNodeType.Element || attributesRead, "Should first read attributes"); 
            return scopeManager.IsExNamespace(uri);
        } 

        public bool ForwardCompatibility {
            get {
                Debug.Assert(nodeType != XmlNodeType.Element || attributesRead, "Should first read attributes"); 
                return scopeManager.ForwardCompatibility;
            } 
        } 

        public bool BackwardCompatibility { 
            get {
                Debug.Assert(nodeType != XmlNodeType.Element || attributesRead, "Should first read attributes");
                return scopeManager.BackwardCompatibility;
            } 
        }
 
        public XslVersion XslVersion { 
            get { return scopeManager.ForwardCompatibility ? XslVersion.ForwardsCompatible : XslVersion.Current; }
        } 

        private void SetVersion(int attVersion) {
            MoveToLiteralAttribute(attVersion);
            Debug.Assert(IsKeyword(atoms.Version)); 
            double version = XPathConvert.StringToDouble(Value);
            if (double.IsNaN(version)) { 
                ReportError(/*[XT0110]*/Res.Xslt_InvalidAttrValue, atoms.Version, Value); 
#if XSLT2
                version = 2.0; 
#else
                version = 1.0;
#endif
            } 
            SetVersion(version);
        } 
        private void SetVersion(double version) { 
            if (compiler.Version == 0) {
#if XSLT2 
                compiler.Version = version < 2.0 ? 1 : 2;
#else
                compiler.Version = 1;
#endif 
            }
 
            if (compiler.Version == 1) { 
                scopeManager.BackwardCompatibility = false;
                scopeManager.ForwardCompatibility = (version != 1.0); 
            } else {
                scopeManager.BackwardCompatibility = version < 2;
                scopeManager.ForwardCompatibility = 2 < version;
            } 
        }
 
        // --------------- GetAtributes(...) ------------------------- 
        // All Xslt Instructions allows fixed set of attributes in null-ns, no in XSLT-ns and any in other ns.
        // In ForwardCompatibility mode we should ignore any of this problems. 
        // We not use these functions for parseing LiteralResultElement and xsl:stylesheet

        public struct XsltAttribute {
            public string name; 
            public int    flags;
            public XsltAttribute(string name, int flags) { 
                this.name  = name; 
                this.flags = flags;
            } 
        }

        private XsltAttribute[] attributes = null;
        // Mapping of attribute names as they ordered in 'attributes' array 
        // to there's numbers in actual stylesheet as they ordered in 'records' array
        private int[] xsltAttributeNumber = new int[21]; 
 
        static private XsltAttribute[] noAttributes = new XsltAttribute[]{};
        public ContextInfo GetAttributes() { 
            return GetAttributes(noAttributes);
        }

        public ContextInfo GetAttributes(XsltAttribute[] attributes) { 
            Debug.Assert(NodeType == XmlNodeType.Element);
            Debug.Assert(attributes.Length <= xsltAttributeNumber.Length); 
            this.attributes = attributes; 
            // temp hack to fix value? = new AttValue(records[values[?]].value);
            records[0].value = null; 

            // Standard Attributes:
            int attExtension = 0;
            int attExclude   = 0; 
            int attNamespace = 0;
            int attCollation = 0; 
            int attUseWhen   = 0; 

            bool isXslOutput = IsXsltNamespace() && IsKeyword(atoms.Output); 
            bool SS = IsXsltNamespace() && (IsKeyword(atoms.Stylesheet) || IsKeyword(atoms.Transform));
            bool V2 = compiler.Version == 2;

            for (int i = 0; i < attributes.Length; i++) { 
                xsltAttributeNumber[i] = 0;
            } 
 
            compiler.EnterForwardsCompatible();
            if (SS || V2 && !isXslOutput) { 
                for (int i = 1; MoveToAttributeBase(i); i++) {
                    if (IsNullNamespace() && IsKeyword(atoms.Version)) {
                        SetVersion(i);
                        break; 
                    }
                } 
            } 
            if (compiler.Version == 0) {
                Debug.Assert(SS, "First we parse xsl:stylesheet element"); 
#if XSLT2
                SetVersion(2.0);
#else
                SetVersion(1.0); 
#endif
            } 
            V2 = compiler.Version == 2; 
            int OptOrReq = V2 ? XsltLoader.V2Opt | XsltLoader.V2Req : XsltLoader.V1Opt | XsltLoader.V1Req;
 
            for (int attNum = 1; MoveToAttributeBase(attNum); attNum++) {
                if (IsNullNamespace()) {
                    string localName = LocalName;
                    int kwd; 
                    for (kwd = 0; kwd < attributes.Length; kwd++) {
                        if (Ref.Equal(localName, attributes[kwd].name) && (attributes[kwd].flags & OptOrReq) != 0) { 
                            xsltAttributeNumber[kwd] = attNum; 
                            break;
                        } 
                    }

                    if (kwd == attributes.Length) {
                        if (Ref.Equal(localName, atoms.ExcludeResultPrefixes   ) && (SS || V2)) {attExclude   = attNum; } else 
                        if (Ref.Equal(localName, atoms.ExtensionElementPrefixes) && (SS || V2)) {attExtension = attNum; } else
                        if (Ref.Equal(localName, atoms.XPathDefaultNamespace   ) && (      V2)) {attNamespace = attNum; } else 
                        if (Ref.Equal(localName, atoms.DefaultCollation        ) && (      V2)) {attCollation = attNum; } else 
                        if (Ref.Equal(localName, atoms.UseWhen                 ) && (      V2)) {attUseWhen   = attNum; } else {
                            ReportError(/*[XT0090]*/Res.Xslt_InvalidAttribute, QualifiedName, records[0].QualifiedName); 
                        }
                    }
                } else if (IsXsltNamespace()) {
                    ReportError(/*[XT0090]*/Res.Xslt_InvalidAttribute, QualifiedName, records[0].QualifiedName); 
                } else {
                    // Ignore the attribute. 
                    // An element from the XSLT namespace may have any attribute not from the XSLT namespace, 
                    // provided that the expanded-name of the attribute has a non-null namespace URI.
                    // For example, it may be 'xml:space'. 
                }
            }

            attributesRead = true; 

            // Ignore invalid attributes if forwards-compatible behavior is enabled. Note that invalid 
            // attributes may encounter before ForwardCompatibility flag is set to true. For example, 
            // 
            compiler.ExitForwardsCompatible(ForwardCompatibility); 

            InsertExNamespaces(attExtension, ctxInfo, /*extensions:*/ true );
            InsertExNamespaces(attExclude  , ctxInfo, /*extensions:*/ false);
            SetXPathDefaultNamespace(attNamespace); 
            SetDefaultCollation(attCollation);
            if (attUseWhen != 0) { 
                ReportNYI(atoms.UseWhen); 
            }
 
            MoveToElement();
            // Report missing mandatory attributes
            for (int i = 0; i < attributes.Length; i ++) {
                if (xsltAttributeNumber[i] == 0) { 
                    int flags = attributes[i].flags;
                    if ( 
                        compiler.Version == 2 && (flags & XsltLoader.V2Req) != 0 || 
                        compiler.Version == 1 && (flags & XsltLoader.V1Req) != 0 && (!ForwardCompatibility || (flags & XsltLoader.V2Req) != 0)
                    ) { 
                        ReportError(/*[XT_001]*/Res.Xslt_MissingAttribute, attributes[i].name);
                    }
                }
            } 

            return ctxInfo; 
        } 

        public ContextInfo GetLiteralAttributes(bool asStylesheet) { 
            Debug.Assert(NodeType == XmlNodeType.Element);

            // Standard Attributes:
            int attVersion   = 0; 
            int attExtension = 0;
            int attExclude   = 0; 
            int attNamespace = 0; 
            int attCollation = 0;
            int attUseWhen   = 0; 

            for (int i = 1; MoveToLiteralAttribute(i); i++) {
                if (IsXsltNamespace()) {
                    string localName = LocalName; 
                    if (Ref.Equal(localName, atoms.Version                 )) {attVersion   = i; } else
                    if (Ref.Equal(localName, atoms.ExtensionElementPrefixes)) {attExtension = i; } else 
                    if (Ref.Equal(localName, atoms.ExcludeResultPrefixes   )) {attExclude   = i; } else 
                    if (Ref.Equal(localName, atoms.XPathDefaultNamespace   )) {attNamespace = i; } else
                    if (Ref.Equal(localName, atoms.DefaultCollation        )) {attCollation = i; } else 
                    if (Ref.Equal(localName, atoms.UseWhen                 )) {attUseWhen   = i; }
                }
            }
 
            attributesRead = true;
            this.MoveToElement(); 
 
            if (attVersion != 0) {
                // Enable forwards-compatible behavior if version attribute is not "1.0" 
                SetVersion(attVersion);
            } else {
                if (asStylesheet) {
                    ReportError(Ref.Equal(NamespaceUri, atoms.UriWdXsl) && Ref.Equal(LocalName, atoms.Stylesheet) ? 
                        /*[XT_025]*/Res.Xslt_WdXslNamespace : /*[XT0150]*/Res.Xslt_WrongStylesheetElement
                    ); 
#if XSLT2 
                    SetVersion(2.0);
#else 
                    SetVersion(1.0);
#endif
                }
            } 

            // Parse xsl:extension-element-prefixes attribute (now that forwards-compatible mode is known) 
            InsertExNamespaces(attExtension, ctxInfo, /*extensions:*/true); 

            if (! IsExtensionNamespace(records[0].nsUri)) { 
                // Parse other attributes (now that it's known this is a literal result element)
                if (compiler.Version == 2) {
                    SetXPathDefaultNamespace(attNamespace);
                    SetDefaultCollation(attCollation); 
                    if (attUseWhen != 0) {
                        ReportNYI(atoms.UseWhen); 
                    } 
                }
 
                InsertExNamespaces(attExclude, ctxInfo, /*extensions:*/false);
            }

            return ctxInfo; 
        }
 
        // Get just the 'version' attribute of an unknown XSLT instruction. All other attributes 
        // are ignored since we do not want to report an error on each of them.
        public void GetVersionAttribute() { 
            Debug.Assert(NodeType == XmlNodeType.Element && IsXsltNamespace());
            bool V2 = compiler.Version == 2;

            if (V2) { 
                for (int i = 1; MoveToAttributeBase(i); i++) {
                    if (IsNullNamespace() && IsKeyword(atoms.Version)) { 
                        SetVersion(i); 
                        break;
                    } 
                }
            }
            attributesRead = true;
        } 

        private void InsertExNamespaces(int attExPrefixes, ContextInfo ctxInfo, bool extensions) { 
            // List of Extension namespaces are maintaned by XsltInput's ScopeManager and is used by IsExtensionNamespace() in XsltLoader.LoadLiteralResultElement() 
            // Both Extension and Exclusion namespaces will not be coppied by LiteralResultElement. Logic of copping namespaces are in QilGenerator.CompileLiteralElement().
            // At this time we will have different scope manager and need preserve all required information from load time to compile time. 
            // Each XslNode contains list of NsDecls (nsList) wich stores prefix+namespaces pairs for each namespace decls as well as exclusion namespaces.
            // In addition it also contains Exclusion namespace. They are represented as (null+namespace). Special case is Exlusion "#all" represented as (null+null).
            //and Exclusion namespace
            if (MoveToLiteralAttribute(attExPrefixes)) { 
                Debug.Assert(extensions ? IsKeyword(atoms.ExtensionElementPrefixes) : IsKeyword(atoms.ExcludeResultPrefixes));
                string value = Value; 
                if (value.Length != 0) { 
                    if (!extensions && compiler.Version != 1 && value == "#all") {
                        ctxInfo.nsList = new NsDecl(ctxInfo.nsList, /*prefix:*/null, /*nsUri:*/null);    // null, null means Exlusion #all 
                    } else {
                        compiler.EnterForwardsCompatible();
                        string[] list = XmlConvert.SplitString(value);
                        for (int idx = 0; idx < list.Length; idx++) { 
                            if (list[idx] == "#default") {
                                list[idx] = this.LookupXmlNamespace(string.Empty); 
                                if (list[idx].Length == 0 && compiler.Version != 1 && !BackwardCompatibility) { 
                                    ReportError(/*[XTSE0809]*/Res.Xslt_ExcludeDefault);
                                } 
                            } else {
                                list[idx] = this.LookupXmlNamespace(list[idx]);
                            }
                        } 
                        if (!compiler.ExitForwardsCompatible(this.ForwardCompatibility)) {
                            // There were errors in the list, ignore the whole list 
                            return; 
                        }
 
                        for (int idx = 0; idx < list.Length; idx++) {
                            if (list[idx] != null) {
                                ctxInfo.nsList = new NsDecl(ctxInfo.nsList, /*prefix:*/null, list[idx]); // null means that this Exlusion NS
                                if (extensions) { 
                                    this.scopeManager.AddExNamespace(list[idx]);                         // At Load time we need to know Extencion namespaces to ignore such literal elements.
                                } 
                            } 
                        }
                    } 
                }
            }
        }
 
        private void SetXPathDefaultNamespace(int attNamespace) {
            if (MoveToLiteralAttribute(attNamespace)) { 
                Debug.Assert(IsKeyword(atoms.XPathDefaultNamespace)); 
                if (Value.Length != 0) {
                    ReportNYI(atoms.XPathDefaultNamespace); 
                }
            }
        }
 
        private void SetDefaultCollation(int attCollation) {
            if (MoveToLiteralAttribute(attCollation)) { 
                Debug.Assert(IsKeyword(atoms.DefaultCollation)); 
                string[] list = XmlConvert.SplitString(Value);
                int col; 
                for (col = 0; col < list.Length; col++) {
                    if (System.Xml.Xsl.Runtime.XmlCollation.Create(list[col], /*throw:*/false) != null) {
                        break;
                    } 
                }
                if (col == list.Length) { 
                    ReportErrorFC(/*[XTSE0125]*/Res.Xslt_CollationSyntax); 
                } else {
                    if (list[col] != XmlReservedNs.NsCollCodePoint) { 
                        ReportNYI(atoms.DefaultCollation);
                    }
                }
            } 
        }
 
        // ----------------------- ISourceLineInfo ----------------------- 

        private static int PositionAdjustment(XmlNodeType nt) { 
            switch (nt) {
            case XmlNodeType.Element:
                return 1;   // "<"
            case XmlNodeType.CDATA: 
                return 9;   // "' 
            private int             elemNameLength; 

            public ContextInfo(XsltInput input) { 
                elemNameLength = input.QualifiedName.Length;
            }

            public void AddNamespace(string prefix, string nsUri) { 
                nsList = new NsDecl(nsList, prefix, nsUri);
            } 
 
            public void SaveExtendedLineInfo(XsltInput input) {
                if (lineInfo.Start.Line == 0) { 
                    elemNameLi = endTagLi = null;
                    return;
                }
 
                elemNameLi = new SourceLineInfo(
                    lineInfo.Uri, 
                    lineInfo.Start.Line, lineInfo.Start.Pos + 1,  // "<" 
                    lineInfo.Start.Line, lineInfo.Start.Pos + 1 + elemNameLength
                ); 

                if (!input.IsEmptyElement) {
                    Debug.Assert(input.NodeType == XmlNodeType.EndElement);
                    endTagLi = input.BuildLineInfo(); 
                } else {
                    Debug.Assert(input.NodeType == XmlNodeType.Element || input.NodeType == XmlNodeType.Attribute); 
                    endTagLi = new EmptyElementEndTag(lineInfo); 
                }
            } 

            // We need this wrapper class because elementTagLi is not yet calculated
            internal class EmptyElementEndTag : ISourceLineInfo {
                private ISourceLineInfo elementTagLi; 

                public EmptyElementEndTag(ISourceLineInfo elementTagLi) { 
                    this.elementTagLi = elementTagLi; 
                }
 
                public string Uri       { get { return elementTagLi.Uri;        } }
                public bool IsNoSource  { get { return elementTagLi.IsNoSource; } }
                public Location Start   { get { return new Location(elementTagLi.End.Line, elementTagLi.End.Pos - 2); } }
                public Location End     { get { return elementTagLi.End ; } } 
            }
        } 
        internal struct Record { 
            public string       localName ;
            public string       nsUri     ; 
            public string       prefix    ;
            public string       value     ;
            public string       baseUri   ;
            public Location     start     ; 
            public Location     valueStart;
            public Location     end       ; 
            public string       QualifiedName  { get { return prefix.Length == 0 ? localName : string.Concat(prefix, ":", localName); } } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
#define XSLT2 

using System.Diagnostics; 
using System.Text;
using System.Xml.XPath;
using System.Collections.Generic;
 
namespace System.Xml.Xsl.Xslt {
    using Res = System.Xml.Utils.Res; 
    using StringConcat = System.Xml.Xsl.Runtime.StringConcat; 
    //         a) Forward only, one pass.
    //         b) You should call MoveToFirstChildren on nonempty element node. (or may be skip) 

    internal class XsltInput : IErrorHelper {
    #if DEBUG
        const int InitRecordsSize = 1; 
    #else
        const int InitRecordsSize = 1 + 21; 
    #endif 

        private XmlReader           reader; 
        private IXmlLineInfo        readerLineInfo;
        private bool                topLevelReader;
        private CompilerScopeManager scopeManager;
        private KeywordsTable       atoms; 
        private Compiler            compiler;
        private bool                reatomize; 
 
        // Cached properties. MoveTo* functions set them.
        private XmlNodeType         nodeType; 
        private Record[]            records = new Record[InitRecordsSize];
        private int                 currentRecord;
        private bool                isEmptyElement;
        private int                 lastTextNode; 
        private int                 numAttributes;
        private ContextInfo         ctxInfo; 
        private bool                attributesRead; 

        public XsltInput(XmlReader reader, Compiler compiler, KeywordsTable atoms) { 
            Debug.Assert(reader != null);
            Debug.Assert(atoms != null);
            EnsureExpandEntities(reader);
            IXmlLineInfo xmlLineInfo = reader as IXmlLineInfo; 

            this.atoms          = atoms; 
            this.reader         = reader; 
            this.reatomize      = reader.NameTable != atoms.NameTable;
            this.readerLineInfo = (xmlLineInfo != null && xmlLineInfo.HasLineInfo()) ? xmlLineInfo : null; 
            this.topLevelReader = reader.ReadState == ReadState.Initial;
            this.scopeManager   = new CompilerScopeManager(atoms);
            this.compiler       = compiler;
            this.nodeType       = XmlNodeType.Document; 
        }
 
        // Cached properties 
        public XmlNodeType   NodeType       { get { return nodeType == XmlNodeType.Element && 0 < currentRecord ? XmlNodeType.Attribute : nodeType; } }
        public string        LocalName      { get { return records[currentRecord].localName      ;} } 
        public string        NamespaceUri   { get { return records[currentRecord].nsUri          ;} }
        public string        Prefix         { get { return records[currentRecord].prefix         ;} }
        public string        Value          { get { return records[currentRecord].value          ;} }
        public string        BaseUri        { get { return records[currentRecord].baseUri        ;} } 
        public string        QualifiedName  { get { return records[currentRecord].QualifiedName  ;} }
        public bool          IsEmptyElement { get { return isEmptyElement; } } 
 
        public string        Uri            { get { return records[currentRecord].baseUri        ; } }
        public Location      Start          { get { return records[currentRecord].start          ; } } 
        public Location      End            { get { return records[currentRecord].end            ; } }

        private static void EnsureExpandEntities(XmlReader reader) {
            XmlTextReader tr = reader as XmlTextReader; 
            if (tr != null && tr.EntityHandling != EntityHandling.ExpandEntities) {
                Debug.Assert(tr.Settings == null, "XmlReader created with XmlReader.Create should always expand entities."); 
                tr.EntityHandling = EntityHandling.ExpandEntities; 
            }
        } 

        private void ExtendRecordBuffer(int position) {
            if (records.Length <= position) {
                int newSize = records.Length * 2; 
                if (newSize <= position) {
                    newSize = position + 1; 
                } 
                Record[] tmp = new Record[newSize];
                Array.Copy(records, tmp, records.Length); 
                records = tmp;
            }
        }
 
        public bool FindStylesheetElement() {
            if (! topLevelReader) { 
                if (reader.ReadState != ReadState.Interactive) { 
                    return false;
                } 
            }

            // The stylesheet may be an embedded stylesheet. If this is the case the reader will be in Interactive state and should be
            // positioned on xsl:stylesheet element (or any preceding whitespace) but there also can be namespaces defined on one 
            // of the ancestor nodes. These namespace definitions have to be copied to the xsl:stylesheet element scope. Otherwise it
            // will not be possible to resolve them later and loading the stylesheet will end up with throwing an exception. 
            IDictionary namespacesInScope = null; 
            if (reader.ReadState == ReadState.Interactive) {
                // This may be an embedded stylesheet - store namespaces in scope 
                IXmlNamespaceResolver nsResolver = reader as IXmlNamespaceResolver;
                if (nsResolver != null) {
                    namespacesInScope = nsResolver.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml);
                } 
            }
 
            while (MoveToNextSibling() && nodeType == XmlNodeType.Whitespace) ; 

            // An Element node was reached. Potentially this is xsl:stylesheet instruction. 
            if (nodeType == XmlNodeType.Element) {
                // If namespacesInScope is not null then the stylesheet being read is an embedded stylesheet that can have namespaces
                // defined outside of xsl:stylesheet instruction. In this case the namespace definitions collected above have to be added
                // to the element scope. 
                if (namespacesInScope != null) {
                    foreach (KeyValuePair prefixNamespacePair in namespacesInScope) { 
                        // The namespace could be redefined on the element we just read. If this is the case scopeManager already has 
                        // namespace definition for this prefix and the old definition must not be added to the scope.
                        if (scopeManager.LookupNamespace(prefixNamespacePair.Key) == null) { 
                            string nsAtomizedValue = atoms.NameTable.Add(prefixNamespacePair.Value);
                            scopeManager.AddNsDeclaration(prefixNamespacePair.Key, nsAtomizedValue);
                            ctxInfo.AddNamespace(prefixNamespacePair.Key, nsAtomizedValue);
                        } 
                    }
                } 
 
                // return true to indicate that we reached XmlNodeType.Element node - potentially xsl:stylesheet element.
                return true; 
            }

            // return false to indicate that we did not reach XmlNodeType.Element node so it is not a valid stylesheet.
            return false; 
        }
 
        public void Finish() { 
            scopeManager.CheckEmpty();
 
            if (topLevelReader) {
                while (reader.ReadState == ReadState.Interactive) {
                    reader.Skip();
                } 
            }
        } 
 
        private void FillupRecord(ref Record rec) {
            rec.localName       = reader.LocalName; 
            rec.nsUri           = reader.NamespaceURI;
            rec.prefix          = reader.Prefix;
            rec.value           = reader.Value;
            rec.baseUri         = reader.BaseURI; 

            if (reatomize) { 
                rec.localName = atoms.NameTable.Add(rec.localName); 
                rec.nsUri     = atoms.NameTable.Add(rec.nsUri    );
                rec.prefix    = atoms.NameTable.Add(rec.prefix   ); 
            }

            if (readerLineInfo != null) {
                rec.start       = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition - PositionAdjustment(reader.NodeType)); 
            }
        } 
 
        private void SetRecordEnd(ref Record rec) {
            if (readerLineInfo != null) { 
                rec.end = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition - PositionAdjustment(reader.NodeType));
                if (reader.BaseURI != rec.baseUri || rec.end.LessOrEqual(rec.start)) {
                    rec.end = new Location(rec.start.Line, int.MaxValue);
                } 
            }
        } 
 
        private void FillupTextRecord(ref Record rec) {
            Debug.Assert( 
                reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.SignificantWhitespace ||
                reader.NodeType == XmlNodeType.Text       || reader.NodeType == XmlNodeType.CDATA
            );
            rec.localName       = string.Empty; 
            rec.nsUri           = string.Empty;
            rec.prefix          = string.Empty; 
            rec.value           = reader.Value; 
            rec.baseUri         = reader.BaseURI;
 
            if (readerLineInfo != null) {
                bool isCDATA = (reader.NodeType == XmlNodeType.CDATA);
                int line = readerLineInfo.LineNumber;
                int pos  = readerLineInfo.LinePosition; 
                rec.start = new Location(line, pos - (isCDATA ? 9 : 0));
                char prevChar = ' '; 
                foreach (char ch in rec.value) { 
                    switch (ch) {
                    case '\n': 
                        if (prevChar != '\r') {
                            goto case '\r';
                        }
                        break; 
                    case '\r':
                        line ++; 
                        pos = 1; 
                        break;
                    default : 
                        pos ++;
                        break;
                    }
                    prevChar = ch; 
                }
                rec.end = new Location(line, pos + (isCDATA ? 3 : 0)); 
            } 
        }
 
        private void FillupCharacterEntityRecord(ref Record rec) {
            Debug.Assert(reader.NodeType == XmlNodeType.EntityReference);
            string local = reader.LocalName;
            Debug.Assert(local[0] == '#' || local == "lt" || local == "gt" || local == "quot" || local == "apos"); 
            rec.localName       = string.Empty;
            rec.nsUri           = string.Empty; 
            rec.prefix          = string.Empty; 
            rec.baseUri         = reader.BaseURI;
 
            if (readerLineInfo != null) {
                rec.start = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition - 1);
            }
            reader.ResolveEntity(); 
            reader.Read();
            Debug.Assert(reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.SignificantWhitespace); 
            rec.value = reader.Value; 
            reader.Read();
            Debug.Assert(reader.NodeType == XmlNodeType.EndEntity); 
            if (readerLineInfo != null) {
                int line = readerLineInfo.LineNumber;
                int pos = readerLineInfo.LinePosition;
                rec.end = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition + 1); 
            }
        } 
 
        StringConcat strConcat = new StringConcat();
 
        // returns false if attribute is actualy namespace
        private bool ReadAttribute(ref Record rec) {
            Debug.Assert(reader.NodeType == XmlNodeType.Attribute, "reader.NodeType == XmlNodeType.Attribute");
            FillupRecord(ref rec); 
            if (Ref.Equal(rec.prefix, atoms.Xmlns)) {                                      // xmlns:foo="NS_FOO"
                string atomizedValue = atoms.NameTable.Add(reader.Value); 
                if (!Ref.Equal(rec.localName, atoms.Xml)) { 
                    scopeManager.AddNsDeclaration(rec.localName, atomizedValue);
                    ctxInfo.AddNamespace(rec.localName, atomizedValue); 
                }
                return false;
            } else if (rec.prefix.Length == 0 && Ref.Equal(rec.localName, atoms.Xmlns)) {  // xmlns="NS_FOO"
                string atomizedValue = atoms.NameTable.Add(reader.Value); 
                scopeManager.AddNsDeclaration(string.Empty, atomizedValue);
                ctxInfo.AddNamespace(string.Empty, atomizedValue); 
                return false; 
            }
            /* Read Attribute Value */ { 
                if (!reader.ReadAttributeValue()) {
                    // XmlTextReader never returns false from first call to ReadAttributeValue()
                    rec.value = string.Empty;
                    SetRecordEnd(ref rec); 
                    return true;
                } 
                if (readerLineInfo != null) { 
                    int correction = (reader.NodeType == XmlNodeType.EntityReference) ? -2 : -1;
                    rec.valueStart = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition + correction); 
                    if (reader.BaseURI != rec.baseUri || rec.valueStart.LessOrEqual(rec.start)) {
                        int nameLength = ((rec.prefix.Length != 0) ? rec.prefix.Length + 1 : 0) + rec.localName.Length;
                        rec.end = new Location(rec.start.Line, rec.start.Pos + nameLength + 1);
                    } 
                }
                string lastText = string.Empty; 
                strConcat.Clear(); 
                do {
                    switch (reader.NodeType) { 
                    case XmlNodeType.EntityReference:
                        reader.ResolveEntity();
                        break;
                    case XmlNodeType.EndEntity: 
                        break;
                    default: 
                        Debug.Assert(reader.NodeType == XmlNodeType.Text, "Unexpected node type inside attribute value"); 
                        lastText = reader.Value;
                        strConcat.Concat(lastText); 
                        break;
                    }
                } while (reader.ReadAttributeValue());
                rec.value = strConcat.GetResult(); 
                if (readerLineInfo != null) {
                    Debug.Assert(reader.NodeType != XmlNodeType.EntityReference); 
                    int correction = ((reader.NodeType == XmlNodeType.EndEntity) ? 1 : lastText.Length) + 1; 
                    rec.end = new Location(readerLineInfo.LineNumber, readerLineInfo.LinePosition + correction);
                    if (reader.BaseURI != rec.baseUri || rec.end.LessOrEqual(rec.valueStart)) { 
                        rec.end = new Location(rec.start.Line, int.MaxValue);
                    }
                }
            } 
            return true;
        } 
 
        // --------------------
 
        public bool MoveToFirstChild() {
            Debug.Assert(nodeType == XmlNodeType.Element, "To call MoveToFirstChild() XsltI---- should be positioned on an Element.");
            if (IsEmptyElement) {
                return false; 
            }
            return ReadNextSibling(); 
        } 

        public bool MoveToNextSibling() { 
            Debug.Assert(nodeType != XmlNodeType.Element || IsEmptyElement, "On non-empty elements we should call MoveToFirstChild()");
            if (nodeType == XmlNodeType.Element || nodeType == XmlNodeType.EndElement) {
                scopeManager.ExitScope();
            } 
            return ReadNextSibling();
        } 
 
        public void SkipNode() {
            if (nodeType == XmlNodeType.Element && MoveToFirstChild()) { 
                do {
                    SkipNode();
                } while (MoveToNextSibling());
            } 
        }
 
        private int ReadTextNodes() { 
            bool textPreserveWS = reader.XmlSpace == XmlSpace.Preserve;
            bool textIsWhite = true; 
            int curTextNode = 0;
            do {
                switch (reader.NodeType) {
                case XmlNodeType.Text: 
                    // XLinq reports WS nodes as Text so we need to analyze them here
                case XmlNodeType.CDATA: 
                    if (textIsWhite && ! XmlCharType.Instance.IsOnlyWhitespace(reader.Value)) { 
                        textIsWhite = false;
                    } 
                    goto case XmlNodeType.SignificantWhitespace;
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                    ExtendRecordBuffer(curTextNode); 
                    FillupTextRecord(ref records[curTextNode]);
                    reader.Read(); 
                    curTextNode++; 
                    break;
                case XmlNodeType.EntityReference: 
                    string local = reader.LocalName;
                    if (local.Length > 0 && (
                        local[0] == '#' ||
                        local == "lt" || local == "gt" || local == "quot" || local == "apos" 
                    )) {
                        // Special treatment for character and built-in entities 
                        ExtendRecordBuffer(curTextNode); 
                        FillupCharacterEntityRecord(ref records[curTextNode]);
                        if (textIsWhite && !XmlCharType.Instance.IsOnlyWhitespace(records[curTextNode].value)) { 
                            textIsWhite = false;
                        }
                        curTextNode++;
                    } else { 
                        reader.ResolveEntity();
                        reader.Read(); 
                    } 
                    break;
                case XmlNodeType.EndEntity: 
                    reader.Read();
                    break;
                default:
                    this.nodeType = ( 
                        ! textIsWhite  ? XmlNodeType.Text :
                        textPreserveWS ? XmlNodeType.SignificantWhitespace : 
                        /*default:    */ XmlNodeType.Whitespace 
                    );
                    return curTextNode; 
                }
            } while (true);
        }
 
        private bool ReadNextSibling() {
            if (currentRecord < lastTextNode) { 
                Debug.Assert(nodeType == XmlNodeType.Text || nodeType == XmlNodeType.Whitespace || nodeType == XmlNodeType.SignificantWhitespace); 
                currentRecord++;
                if (currentRecord == lastTextNode) { 
                    lastTextNode = 0;  // we are done with text nodes. Reset this counter
                }
                return true;
            } 
            currentRecord = 0;
            while (! reader.EOF) { 
                switch (reader.NodeType) { 
                case XmlNodeType.Text:
                case XmlNodeType.CDATA: 
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                case XmlNodeType.EntityReference:
                    int numTextNodes = ReadTextNodes(); 
                    if (numTextNodes == 0) {
                        // Most likely this was Entity that starts from non-text node 
                        continue; 
                    }
                    lastTextNode = numTextNodes - 1; 
                    return true;
                case XmlNodeType.Element:
                    scopeManager.EnterScope();
                    numAttributes = ReadElement(); 
                    return true;
                case XmlNodeType.EndElement: 
                    nodeType = XmlNodeType.EndElement; 
                    isEmptyElement = false;
                    FillupRecord(ref records[0]); 
                    reader.Read();
                    SetRecordEnd(ref records[0]);
                    return false;
                default: 
                    reader.Read();
                    break; 
                } 
            }
            return false; 
        }

        private int ReadElement() {
            Debug.Assert(reader.NodeType == XmlNodeType.Element); 

            attributesRead = false; 
            FillupRecord(ref records[0]); 
            nodeType = XmlNodeType.Element;
            isEmptyElement = reader.IsEmptyElement; 
            ctxInfo = new ContextInfo(this);

            int record = 1;
            if (reader.MoveToFirstAttribute()) { 
                do {
                    ExtendRecordBuffer(record); 
                    if (ReadAttribute(ref records[record])) { 
                        record++;
                    } 
                } while (reader.MoveToNextAttribute());
                reader.MoveToElement();
            }
            reader.Read(); 
            SetRecordEnd(ref records[0]);
            ctxInfo.lineInfo = BuildLineInfo(); 
            attributes = null; 
            return record - 1;
        } 

        public void MoveToElement() {
            Debug.Assert(nodeType == XmlNodeType.Element, "For MoveToElement() we should be positioned on Element or Attribute");
            currentRecord = 0; 
        }
 
        private bool MoveToAttributeBase(int attNum) { 
            Debug.Assert(nodeType == XmlNodeType.Element, "For MoveToLiteralAttribute() we should be positioned on Element or Attribute");
            if (0 < attNum && attNum <= numAttributes) { 
                currentRecord = attNum;
                return true;
            } else {
                currentRecord = 0; 
                return false;
            } 
        } 

        public bool MoveToLiteralAttribute(int attNum) { 
            Debug.Assert(nodeType == XmlNodeType.Element, "For MoveToLiteralAttribute() we should be positioned on Element or Attribute");
            if (0 < attNum && attNum <= numAttributes) {
                currentRecord = attNum;
                return true; 
            } else {
                currentRecord = 0; 
                return false; 
            }
        } 

        public bool MoveToXsltAttribute(int attNum, string attName) {
            Debug.Assert(attributes != null && attributes[attNum].name == attName, "Attribute numbering error.");
            this.currentRecord = xsltAttributeNumber[attNum]; 
            return this.currentRecord != 0;
        } 
 
        public bool IsRequiredAttribute(int attNum) {
            return (attributes[attNum].flags & (compiler.Version == 2 ? XsltLoader.V2Req : XsltLoader.V1Req)) != 0; 
        }

        public bool AttributeExists(int attNum, string attName) {
            Debug.Assert(attributes != null && attributes[attNum].name == attName, "Attribute numbering error."); 
            return xsltAttributeNumber[attNum] != 0;
        } 
 
        public struct DelayedQName {
            string prefix   ; 
            string localName;
            public DelayedQName(ref Record rec) {
                this.prefix    = rec.prefix;
                this.localName = rec.localName; 
            }
            public static implicit operator string(DelayedQName qn) { 
                return qn.prefix.Length == 0 ? qn.localName : (qn.prefix + ':' + qn.localName); 
            }
        } 

        public DelayedQName ElementName {
            get {
                Debug.Assert(nodeType == XmlNodeType.Element || nodeType == XmlNodeType.EndElement, "Input is positioned on element or attribute"); 
                return new DelayedQName(ref records[0]);
            } 
        } 

        // -------------------- Keywords testing -------------------- 

        public bool IsNs(string ns)             { return Ref.Equal(ns, NamespaceUri); }
        public bool IsKeyword(string kwd)       { return Ref.Equal(kwd, LocalName);  }
        public bool IsXsltNamespace()           { return IsNs(atoms.UriXsl); } 
        public bool IsNullNamespace()           { return IsNs(string.Empty); }
        public bool IsXsltAttribute(string kwd) { return IsKeyword(kwd) && IsNullNamespace(); } 
        public bool IsXsltKeyword(  string kwd) { return IsKeyword(kwd) && IsXsltNamespace(); } 

        // -------------------- Scope Management -------------------- 
        // See private class InputScopeManager bellow.
        // InputScopeManager handles some flags and values with respect of scope level where they as defined.
        // To parse XSLT style sheet we need the folloing values:
        //  BackwardCompatibility -- this flag is set when compiler.version==2 && xsl:version<2. 
        //  ForwardCompatibility  -- this flag is set when compiler.version==2 && xsl:version>1 or compiler.version==1 && xsl:version!=1
        //  CanHaveApplyImports  -- we allow xsl:apply-templates instruction to apear in any template with match!=null, but not inside xsl:for-each 
        //                          so it can't be inside global variable and has initial value = false 
        //  ExtentionNamespace   -- is defined by extension-element-prefixes attribute on LRE or xsl:stylesheet
 
        public bool CanHaveApplyImports {
            get { return scopeManager.CanHaveApplyImports;  }
            set { scopeManager.CanHaveApplyImports = value; }
        } 

        public bool IsExtensionNamespace(string uri) { 
            Debug.Assert(nodeType != XmlNodeType.Element || attributesRead, "Should first read attributes"); 
            return scopeManager.IsExNamespace(uri);
        } 

        public bool ForwardCompatibility {
            get {
                Debug.Assert(nodeType != XmlNodeType.Element || attributesRead, "Should first read attributes"); 
                return scopeManager.ForwardCompatibility;
            } 
        } 

        public bool BackwardCompatibility { 
            get {
                Debug.Assert(nodeType != XmlNodeType.Element || attributesRead, "Should first read attributes");
                return scopeManager.BackwardCompatibility;
            } 
        }
 
        public XslVersion XslVersion { 
            get { return scopeManager.ForwardCompatibility ? XslVersion.ForwardsCompatible : XslVersion.Current; }
        } 

        private void SetVersion(int attVersion) {
            MoveToLiteralAttribute(attVersion);
            Debug.Assert(IsKeyword(atoms.Version)); 
            double version = XPathConvert.StringToDouble(Value);
            if (double.IsNaN(version)) { 
                ReportError(/*[XT0110]*/Res.Xslt_InvalidAttrValue, atoms.Version, Value); 
#if XSLT2
                version = 2.0; 
#else
                version = 1.0;
#endif
            } 
            SetVersion(version);
        } 
        private void SetVersion(double version) { 
            if (compiler.Version == 0) {
#if XSLT2 
                compiler.Version = version < 2.0 ? 1 : 2;
#else
                compiler.Version = 1;
#endif 
            }
 
            if (compiler.Version == 1) { 
                scopeManager.BackwardCompatibility = false;
                scopeManager.ForwardCompatibility = (version != 1.0); 
            } else {
                scopeManager.BackwardCompatibility = version < 2;
                scopeManager.ForwardCompatibility = 2 < version;
            } 
        }
 
        // --------------- GetAtributes(...) ------------------------- 
        // All Xslt Instructions allows fixed set of attributes in null-ns, no in XSLT-ns and any in other ns.
        // In ForwardCompatibility mode we should ignore any of this problems. 
        // We not use these functions for parseing LiteralResultElement and xsl:stylesheet

        public struct XsltAttribute {
            public string name; 
            public int    flags;
            public XsltAttribute(string name, int flags) { 
                this.name  = name; 
                this.flags = flags;
            } 
        }

        private XsltAttribute[] attributes = null;
        // Mapping of attribute names as they ordered in 'attributes' array 
        // to there's numbers in actual stylesheet as they ordered in 'records' array
        private int[] xsltAttributeNumber = new int[21]; 
 
        static private XsltAttribute[] noAttributes = new XsltAttribute[]{};
        public ContextInfo GetAttributes() { 
            return GetAttributes(noAttributes);
        }

        public ContextInfo GetAttributes(XsltAttribute[] attributes) { 
            Debug.Assert(NodeType == XmlNodeType.Element);
            Debug.Assert(attributes.Length <= xsltAttributeNumber.Length); 
            this.attributes = attributes; 
            // temp hack to fix value? = new AttValue(records[values[?]].value);
            records[0].value = null; 

            // Standard Attributes:
            int attExtension = 0;
            int attExclude   = 0; 
            int attNamespace = 0;
            int attCollation = 0; 
            int attUseWhen   = 0; 

            bool isXslOutput = IsXsltNamespace() && IsKeyword(atoms.Output); 
            bool SS = IsXsltNamespace() && (IsKeyword(atoms.Stylesheet) || IsKeyword(atoms.Transform));
            bool V2 = compiler.Version == 2;

            for (int i = 0; i < attributes.Length; i++) { 
                xsltAttributeNumber[i] = 0;
            } 
 
            compiler.EnterForwardsCompatible();
            if (SS || V2 && !isXslOutput) { 
                for (int i = 1; MoveToAttributeBase(i); i++) {
                    if (IsNullNamespace() && IsKeyword(atoms.Version)) {
                        SetVersion(i);
                        break; 
                    }
                } 
            } 
            if (compiler.Version == 0) {
                Debug.Assert(SS, "First we parse xsl:stylesheet element"); 
#if XSLT2
                SetVersion(2.0);
#else
                SetVersion(1.0); 
#endif
            } 
            V2 = compiler.Version == 2; 
            int OptOrReq = V2 ? XsltLoader.V2Opt | XsltLoader.V2Req : XsltLoader.V1Opt | XsltLoader.V1Req;
 
            for (int attNum = 1; MoveToAttributeBase(attNum); attNum++) {
                if (IsNullNamespace()) {
                    string localName = LocalName;
                    int kwd; 
                    for (kwd = 0; kwd < attributes.Length; kwd++) {
                        if (Ref.Equal(localName, attributes[kwd].name) && (attributes[kwd].flags & OptOrReq) != 0) { 
                            xsltAttributeNumber[kwd] = attNum; 
                            break;
                        } 
                    }

                    if (kwd == attributes.Length) {
                        if (Ref.Equal(localName, atoms.ExcludeResultPrefixes   ) && (SS || V2)) {attExclude   = attNum; } else 
                        if (Ref.Equal(localName, atoms.ExtensionElementPrefixes) && (SS || V2)) {attExtension = attNum; } else
                        if (Ref.Equal(localName, atoms.XPathDefaultNamespace   ) && (      V2)) {attNamespace = attNum; } else 
                        if (Ref.Equal(localName, atoms.DefaultCollation        ) && (      V2)) {attCollation = attNum; } else 
                        if (Ref.Equal(localName, atoms.UseWhen                 ) && (      V2)) {attUseWhen   = attNum; } else {
                            ReportError(/*[XT0090]*/Res.Xslt_InvalidAttribute, QualifiedName, records[0].QualifiedName); 
                        }
                    }
                } else if (IsXsltNamespace()) {
                    ReportError(/*[XT0090]*/Res.Xslt_InvalidAttribute, QualifiedName, records[0].QualifiedName); 
                } else {
                    // Ignore the attribute. 
                    // An element from the XSLT namespace may have any attribute not from the XSLT namespace, 
                    // provided that the expanded-name of the attribute has a non-null namespace URI.
                    // For example, it may be 'xml:space'. 
                }
            }

            attributesRead = true; 

            // Ignore invalid attributes if forwards-compatible behavior is enabled. Note that invalid 
            // attributes may encounter before ForwardCompatibility flag is set to true. For example, 
            // 
            compiler.ExitForwardsCompatible(ForwardCompatibility); 

            InsertExNamespaces(attExtension, ctxInfo, /*extensions:*/ true );
            InsertExNamespaces(attExclude  , ctxInfo, /*extensions:*/ false);
            SetXPathDefaultNamespace(attNamespace); 
            SetDefaultCollation(attCollation);
            if (attUseWhen != 0) { 
                ReportNYI(atoms.UseWhen); 
            }
 
            MoveToElement();
            // Report missing mandatory attributes
            for (int i = 0; i < attributes.Length; i ++) {
                if (xsltAttributeNumber[i] == 0) { 
                    int flags = attributes[i].flags;
                    if ( 
                        compiler.Version == 2 && (flags & XsltLoader.V2Req) != 0 || 
                        compiler.Version == 1 && (flags & XsltLoader.V1Req) != 0 && (!ForwardCompatibility || (flags & XsltLoader.V2Req) != 0)
                    ) { 
                        ReportError(/*[XT_001]*/Res.Xslt_MissingAttribute, attributes[i].name);
                    }
                }
            } 

            return ctxInfo; 
        } 

        public ContextInfo GetLiteralAttributes(bool asStylesheet) { 
            Debug.Assert(NodeType == XmlNodeType.Element);

            // Standard Attributes:
            int attVersion   = 0; 
            int attExtension = 0;
            int attExclude   = 0; 
            int attNamespace = 0; 
            int attCollation = 0;
            int attUseWhen   = 0; 

            for (int i = 1; MoveToLiteralAttribute(i); i++) {
                if (IsXsltNamespace()) {
                    string localName = LocalName; 
                    if (Ref.Equal(localName, atoms.Version                 )) {attVersion   = i; } else
                    if (Ref.Equal(localName, atoms.ExtensionElementPrefixes)) {attExtension = i; } else 
                    if (Ref.Equal(localName, atoms.ExcludeResultPrefixes   )) {attExclude   = i; } else 
                    if (Ref.Equal(localName, atoms.XPathDefaultNamespace   )) {attNamespace = i; } else
                    if (Ref.Equal(localName, atoms.DefaultCollation        )) {attCollation = i; } else 
                    if (Ref.Equal(localName, atoms.UseWhen                 )) {attUseWhen   = i; }
                }
            }
 
            attributesRead = true;
            this.MoveToElement(); 
 
            if (attVersion != 0) {
                // Enable forwards-compatible behavior if version attribute is not "1.0" 
                SetVersion(attVersion);
            } else {
                if (asStylesheet) {
                    ReportError(Ref.Equal(NamespaceUri, atoms.UriWdXsl) && Ref.Equal(LocalName, atoms.Stylesheet) ? 
                        /*[XT_025]*/Res.Xslt_WdXslNamespace : /*[XT0150]*/Res.Xslt_WrongStylesheetElement
                    ); 
#if XSLT2 
                    SetVersion(2.0);
#else 
                    SetVersion(1.0);
#endif
                }
            } 

            // Parse xsl:extension-element-prefixes attribute (now that forwards-compatible mode is known) 
            InsertExNamespaces(attExtension, ctxInfo, /*extensions:*/true); 

            if (! IsExtensionNamespace(records[0].nsUri)) { 
                // Parse other attributes (now that it's known this is a literal result element)
                if (compiler.Version == 2) {
                    SetXPathDefaultNamespace(attNamespace);
                    SetDefaultCollation(attCollation); 
                    if (attUseWhen != 0) {
                        ReportNYI(atoms.UseWhen); 
                    } 
                }
 
                InsertExNamespaces(attExclude, ctxInfo, /*extensions:*/false);
            }

            return ctxInfo; 
        }
 
        // Get just the 'version' attribute of an unknown XSLT instruction. All other attributes 
        // are ignored since we do not want to report an error on each of them.
        public void GetVersionAttribute() { 
            Debug.Assert(NodeType == XmlNodeType.Element && IsXsltNamespace());
            bool V2 = compiler.Version == 2;

            if (V2) { 
                for (int i = 1; MoveToAttributeBase(i); i++) {
                    if (IsNullNamespace() && IsKeyword(atoms.Version)) { 
                        SetVersion(i); 
                        break;
                    } 
                }
            }
            attributesRead = true;
        } 

        private void InsertExNamespaces(int attExPrefixes, ContextInfo ctxInfo, bool extensions) { 
            // List of Extension namespaces are maintaned by XsltInput's ScopeManager and is used by IsExtensionNamespace() in XsltLoader.LoadLiteralResultElement() 
            // Both Extension and Exclusion namespaces will not be coppied by LiteralResultElement. Logic of copping namespaces are in QilGenerator.CompileLiteralElement().
            // At this time we will have different scope manager and need preserve all required information from load time to compile time. 
            // Each XslNode contains list of NsDecls (nsList) wich stores prefix+namespaces pairs for each namespace decls as well as exclusion namespaces.
            // In addition it also contains Exclusion namespace. They are represented as (null+namespace). Special case is Exlusion "#all" represented as (null+null).
            //and Exclusion namespace
            if (MoveToLiteralAttribute(attExPrefixes)) { 
                Debug.Assert(extensions ? IsKeyword(atoms.ExtensionElementPrefixes) : IsKeyword(atoms.ExcludeResultPrefixes));
                string value = Value; 
                if (value.Length != 0) { 
                    if (!extensions && compiler.Version != 1 && value == "#all") {
                        ctxInfo.nsList = new NsDecl(ctxInfo.nsList, /*prefix:*/null, /*nsUri:*/null);    // null, null means Exlusion #all 
                    } else {
                        compiler.EnterForwardsCompatible();
                        string[] list = XmlConvert.SplitString(value);
                        for (int idx = 0; idx < list.Length; idx++) { 
                            if (list[idx] == "#default") {
                                list[idx] = this.LookupXmlNamespace(string.Empty); 
                                if (list[idx].Length == 0 && compiler.Version != 1 && !BackwardCompatibility) { 
                                    ReportError(/*[XTSE0809]*/Res.Xslt_ExcludeDefault);
                                } 
                            } else {
                                list[idx] = this.LookupXmlNamespace(list[idx]);
                            }
                        } 
                        if (!compiler.ExitForwardsCompatible(this.ForwardCompatibility)) {
                            // There were errors in the list, ignore the whole list 
                            return; 
                        }
 
                        for (int idx = 0; idx < list.Length; idx++) {
                            if (list[idx] != null) {
                                ctxInfo.nsList = new NsDecl(ctxInfo.nsList, /*prefix:*/null, list[idx]); // null means that this Exlusion NS
                                if (extensions) { 
                                    this.scopeManager.AddExNamespace(list[idx]);                         // At Load time we need to know Extencion namespaces to ignore such literal elements.
                                } 
                            } 
                        }
                    } 
                }
            }
        }
 
        private void SetXPathDefaultNamespace(int attNamespace) {
            if (MoveToLiteralAttribute(attNamespace)) { 
                Debug.Assert(IsKeyword(atoms.XPathDefaultNamespace)); 
                if (Value.Length != 0) {
                    ReportNYI(atoms.XPathDefaultNamespace); 
                }
            }
        }
 
        private void SetDefaultCollation(int attCollation) {
            if (MoveToLiteralAttribute(attCollation)) { 
                Debug.Assert(IsKeyword(atoms.DefaultCollation)); 
                string[] list = XmlConvert.SplitString(Value);
                int col; 
                for (col = 0; col < list.Length; col++) {
                    if (System.Xml.Xsl.Runtime.XmlCollation.Create(list[col], /*throw:*/false) != null) {
                        break;
                    } 
                }
                if (col == list.Length) { 
                    ReportErrorFC(/*[XTSE0125]*/Res.Xslt_CollationSyntax); 
                } else {
                    if (list[col] != XmlReservedNs.NsCollCodePoint) { 
                        ReportNYI(atoms.DefaultCollation);
                    }
                }
            } 
        }
 
        // ----------------------- ISourceLineInfo ----------------------- 

        private static int PositionAdjustment(XmlNodeType nt) { 
            switch (nt) {
            case XmlNodeType.Element:
                return 1;   // "<"
            case XmlNodeType.CDATA: 
                return 9;   // "' 
            private int             elemNameLength; 

            public ContextInfo(XsltInput input) { 
                elemNameLength = input.QualifiedName.Length;
            }

            public void AddNamespace(string prefix, string nsUri) { 
                nsList = new NsDecl(nsList, prefix, nsUri);
            } 
 
            public void SaveExtendedLineInfo(XsltInput input) {
                if (lineInfo.Start.Line == 0) { 
                    elemNameLi = endTagLi = null;
                    return;
                }
 
                elemNameLi = new SourceLineInfo(
                    lineInfo.Uri, 
                    lineInfo.Start.Line, lineInfo.Start.Pos + 1,  // "<" 
                    lineInfo.Start.Line, lineInfo.Start.Pos + 1 + elemNameLength
                ); 

                if (!input.IsEmptyElement) {
                    Debug.Assert(input.NodeType == XmlNodeType.EndElement);
                    endTagLi = input.BuildLineInfo(); 
                } else {
                    Debug.Assert(input.NodeType == XmlNodeType.Element || input.NodeType == XmlNodeType.Attribute); 
                    endTagLi = new EmptyElementEndTag(lineInfo); 
                }
            } 

            // We need this wrapper class because elementTagLi is not yet calculated
            internal class EmptyElementEndTag : ISourceLineInfo {
                private ISourceLineInfo elementTagLi; 

                public EmptyElementEndTag(ISourceLineInfo elementTagLi) { 
                    this.elementTagLi = elementTagLi; 
                }
 
                public string Uri       { get { return elementTagLi.Uri;        } }
                public bool IsNoSource  { get { return elementTagLi.IsNoSource; } }
                public Location Start   { get { return new Location(elementTagLi.End.Line, elementTagLi.End.Pos - 2); } }
                public Location End     { get { return elementTagLi.End ; } } 
            }
        } 
        internal struct Record { 
            public string       localName ;
            public string       nsUri     ; 
            public string       prefix    ;
            public string       value     ;
            public string       baseUri   ;
            public Location     start     ; 
            public Location     valueStart;
            public Location     end       ; 
            public string       QualifiedName  { get { return prefix.Length == 0 ? localName : string.Concat(prefix, ":", localName); } } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK