File: CompiledXPathExpr.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (187 lines) | stat: -rw-r--r-- 7,671 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//------------------------------------------------------------------------------
// <copyright file="CompiledXpathExpr.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------

namespace MS.Internal.Xml.XPath {
    using System;
    using System.Xml;
    using System.Xml.XPath;
    using System.Diagnostics;
    using System.Globalization;
    using System.Collections;
    using System.Xml.Xsl;

    internal class CompiledXpathExpr : XPathExpression {
        Query query;
        string expr;
        bool needContext;

        internal CompiledXpathExpr(Query query, string expression, bool needContext) {
            this.query = query;
            this.expr = expression;
            this.needContext = needContext;
        }

        internal Query QueryTree {
            get {
                if (needContext) {
                    throw XPathException.Create(Res.Xp_NoContext);
                }
                return query;
            }
        }

        public override string Expression {
            get { return expr; }
        }

        public virtual void CheckErrors() {
            Debug.Assert(query != null, "In case of error in XPath we create ErrorXPathExpression");
        }

        public override void AddSort(object expr, IComparer comparer) {
            // sort makes sense only when we are dealing with a query that
            // returns a nodeset.
	        Query evalExpr;
            if (expr is string) {
                evalExpr = new QueryBuilder().Build((string)expr, out needContext); // this will throw if expr is invalid
            } else if (expr is CompiledXpathExpr) {
                evalExpr = ((CompiledXpathExpr)expr).QueryTree;
	        } else {
                throw XPathException.Create(Res.Xp_BadQueryObject);
            }
            SortQuery sortQuery = query as SortQuery;
            if (sortQuery == null) {
                query = sortQuery = new SortQuery(query);
            }
            sortQuery.AddSort(evalExpr, comparer);
        }

        public override void AddSort(object expr, XmlSortOrder order, XmlCaseOrder caseOrder, string lang, XmlDataType dataType) {
            AddSort(expr, new XPathComparerHelper(order, caseOrder, lang, dataType));
        }

        public override XPathExpression Clone() {
            return new CompiledXpathExpr(Query.Clone(query), expr, needContext);
        }

        public override void SetContext(XmlNamespaceManager nsManager) {
            SetContext((IXmlNamespaceResolver)nsManager);
        }

        public override void SetContext(IXmlNamespaceResolver nsResolver) {
            XsltContext xsltContext = nsResolver as XsltContext;
            if(xsltContext == null) {
                if(nsResolver == null) {
                    nsResolver = new XmlNamespaceManager(new NameTable());
                }
                xsltContext = new UndefinedXsltContext(nsResolver);
            }
            query.SetXsltContext(xsltContext);

            needContext = false;
        }

        public override XPathResultType ReturnType { get { return query.StaticType; } }

        private class UndefinedXsltContext : XsltContext {
            private IXmlNamespaceResolver nsResolver;

            public UndefinedXsltContext(IXmlNamespaceResolver nsResolver) : base(/*dummy*/false) {
                this.nsResolver = nsResolver;
            }
            //----- Namespace support -----
            public override string DefaultNamespace {
                get { return string.Empty; }
            }
            public override string LookupNamespace(string prefix) {
                Debug.Assert(prefix != null);
                if (prefix.Length == 0) {
                    return string.Empty;
                }
                string ns = this.nsResolver.LookupNamespace(prefix);
                if (ns == null) {
                    throw XPathException.Create(Res.XmlUndefinedAlias, prefix);
                }
                return ns;
            }
            //----- XsltContext support -----
            public override IXsltContextVariable ResolveVariable(string prefix, string name) {
                throw XPathException.Create(Res.Xp_UndefinedXsltContext);
            }
            public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] ArgTypes) {
                throw XPathException.Create(Res.Xp_UndefinedXsltContext);
            }
            public override bool Whitespace { get{ return false; } }
            public override bool PreserveWhitespace(XPathNavigator node) { return false; }
            public override int CompareDocument (string baseUri, string nextbaseUri) {
                return string.CompareOrdinal(baseUri, nextbaseUri);
            }
        }
    }

    internal sealed class XPathComparerHelper : IComparer {
        private XmlSortOrder order;
        private XmlCaseOrder caseOrder;
        private CultureInfo  cinfo;
        private XmlDataType  dataType;

        public XPathComparerHelper(XmlSortOrder order, XmlCaseOrder caseOrder, string lang, XmlDataType dataType) {
            if (lang == null) {
                this.cinfo = System.Threading.Thread.CurrentThread.CurrentCulture;
            } else {
                try {
                    this.cinfo = new CultureInfo(lang);
                }
                catch (System.ArgumentException) {
                    throw;  // Throwing an XsltException would be a breaking change
				}
            }

            if (order == XmlSortOrder.Descending) {
                if (caseOrder == XmlCaseOrder.LowerFirst) {
                    caseOrder = XmlCaseOrder.UpperFirst;
                }
                else if (caseOrder == XmlCaseOrder.UpperFirst) {
                    caseOrder = XmlCaseOrder.LowerFirst;
                }
            }

            this.order     = order;
            this.caseOrder = caseOrder;
            this.dataType  = dataType;
        }

        public int Compare(object x, object y) {
            switch (this.dataType) {
            case XmlDataType.Text:
                string s1 = Convert.ToString(x, this.cinfo);
                string s2 = Convert.ToString(y, this.cinfo);
                int result = string.Compare(s1, s2, /*ignoreCase:*/ this.caseOrder != XmlCaseOrder.None, this.cinfo);

                if (result != 0 || this.caseOrder == XmlCaseOrder.None)
                    return (this.order == XmlSortOrder.Ascending) ? result : -result;

                // If we came this far, it means that strings s1 and s2 are
                // equal to each other when case is ignored. Now it's time to check
                // and see if they differ in case only and take into account the user
                // requested case order for sorting purposes.
                result = string.Compare(s1, s2, /*ignoreCase:*/ false, this.cinfo);
                return (this.caseOrder == XmlCaseOrder.LowerFirst) ? result : -result;

            case XmlDataType.Number:
                double r1 = XmlConvert.ToXPathDouble(x);
                double r2 = XmlConvert.ToXPathDouble(y);
                result = r1.CompareTo(r2);
                return (this.order == XmlSortOrder.Ascending) ? result : -result;

            default:
                // dataType doesn't support any other value
                throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation));
            }
        } // Compare ()
    } // class XPathComparerHelper
}