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
}
|