| File: FrameworkFork\Microsoft.Xml\Xml\XPath\Internal\CompiledXpathExpr.cs | Web Access |
| Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. namespace MS.Internal.Xml.XPath { using System; using Microsoft.Xml; using Microsoft.Xml.XPath; using System.Diagnostics; using System.Globalization; using System.Collections; using Microsoft.Xml.Xsl; internal class CompiledXpathExpr : XPathExpression { private Query _query; private string _expr; private bool _needContext; internal CompiledXpathExpr(Query query, string expression, bool needContext) { _query = query; _expr = expression; _needContext = needContext; } internal Query QueryTree { get { if (_needContext) { throw XPathException.Create(ResXml.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(ResXml.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) { _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 = _nsResolver.LookupNamespace(prefix); if (ns == null) { throw XPathException.Create(ResXml.XmlUndefinedAlias, prefix); } return ns; } //----- XsltContext support ----- public override IXsltContextVariable ResolveVariable(string prefix, string name) { throw XPathException.Create(ResXml.Xp_UndefinedXsltContext); } public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] ArgTypes) { throw XPathException.Create(ResXml.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) { _cinfo = CultureInfo.CurrentCulture; // System.Threading.Thread.CurrentThread.CurrentCulture; } else { try { _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; } } _order = order; _caseOrder = caseOrder; _dataType = dataType; } public int Compare(object x, object y) { switch (_dataType) { case XmlDataType.Text: string s1 = Convert.ToString(x, _cinfo); string s2 = Convert.ToString(y, _cinfo); int result = string.Compare(s1, s2, /*ignoreCase:*/ _caseOrder != XmlCaseOrder.None); //, this.cinfo); if (result != 0 || _caseOrder == XmlCaseOrder.None) return (_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 (_caseOrder == XmlCaseOrder.LowerFirst) ? result : -result; case XmlDataType.Number: double r1 = XmlConvert.ToXPathDouble(x); double r2 = XmlConvert.ToXPathDouble(y); result = r1.CompareTo(r2); return (_order == XmlSortOrder.Ascending) ? result : -result; default: // dataType doesn't support any other value throw new InvalidOperationException(ResXml.Xml_InvalidOperation); } } // Compare () } // class XPathComparerHelper }