Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Xml / System / Xml / XPath / Internal / StringFunctions.cs
blob8b477ecf78f0fc366c4262d8269efc908878f513
1 //------------------------------------------------------------------------------
2 // <copyright file="StringFunctions.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace MS.Internal.Xml.XPath {
9 using System;
10 using System.Globalization;
11 using System.Text;
12 using System.Xml;
13 using System.Xml.XPath;
14 using System.Xml.Xsl;
15 using System.Collections.Generic;
16 using System.Diagnostics;
18 internal sealed class StringFunctions : ValueQuery {
19 Function.FunctionType funcType;
20 private IList<Query> argList;
22 public StringFunctions(Function.FunctionType funcType, IList<Query> argList) {
23 Debug.Assert(argList != null, "Use 'new Query[]{}' instead.");
24 this.funcType = funcType;
25 this.argList = argList;
27 private StringFunctions(StringFunctions other) : base(other) {
28 this.funcType = other.funcType;
29 Query[] tmp = new Query[other.argList.Count]; {
30 for (int i = 0; i < tmp.Length; i ++) {
31 tmp[i] = Clone(other.argList[i]);
34 this.argList = tmp;
37 public override void SetXsltContext(XsltContext context){
38 for (int i = 0; i < argList.Count; i++) {
39 argList[i].SetXsltContext(context);
43 public override object Evaluate(XPathNodeIterator nodeIterator) {
44 switch (funcType) {
45 case Function.FunctionType.FuncString : return toString(nodeIterator);
46 case Function.FunctionType.FuncConcat : return Concat(nodeIterator);
47 case Function.FunctionType.FuncStartsWith : return StartsWith(nodeIterator);
48 case Function.FunctionType.FuncContains : return Contains(nodeIterator);
49 case Function.FunctionType.FuncSubstringBefore : return SubstringBefore(nodeIterator);
50 case Function.FunctionType.FuncSubstringAfter : return SubstringAfter(nodeIterator);
51 case Function.FunctionType.FuncSubstring : return Substring(nodeIterator);
52 case Function.FunctionType.FuncStringLength : return StringLength(nodeIterator);
53 case Function.FunctionType.FuncNormalize : return Normalize(nodeIterator);
54 case Function.FunctionType.FuncTranslate : return Translate(nodeIterator);
56 return string.Empty;
59 internal static string toString(double num) {
60 return num.ToString("R", NumberFormatInfo.InvariantInfo);
63 internal static string toString(bool b) {
64 return b ? "true" : "false";
67 private string toString(XPathNodeIterator nodeIterator) {
68 if (argList.Count > 0) {
69 object argVal = argList[0].Evaluate(nodeIterator);
71 switch (GetXPathType(argVal)) {
72 case XPathResultType.NodeSet:
73 XPathNavigator value = argList[0].Advance();
74 return value != null ? value.Value : string.Empty;
75 case XPathResultType.String:
76 return (string) argVal;
77 case XPathResultType.Boolean :
78 return ((bool) argVal) ? "true" : "false";
79 case XPathResultType_Navigator:
80 return ((XPathNavigator)argVal).Value;
81 default:
82 Debug.Assert(GetXPathType(argVal) == XPathResultType.Number);
83 return toString((double)argVal);
86 return nodeIterator.Current.Value;
89 public override XPathResultType StaticType { get {
90 if (funcType == Function.FunctionType.FuncStringLength) {
91 return XPathResultType.Number;
93 if (
94 funcType == Function.FunctionType.FuncStartsWith ||
95 funcType == Function.FunctionType.FuncContains
96 ) {
97 return XPathResultType.Boolean;
99 return XPathResultType.String;
102 private string Concat(XPathNodeIterator nodeIterator) {
103 int count = 0;
104 StringBuilder s = new StringBuilder();
105 while (count < argList.Count) {
106 s.Append(argList[count++].Evaluate(nodeIterator).ToString());
108 return s.ToString();
111 private bool StartsWith(XPathNodeIterator nodeIterator) {
112 string s1 = argList[0].Evaluate(nodeIterator).ToString();
113 string s2 = argList[1].Evaluate(nodeIterator).ToString();
114 return s1.Length >= s2.Length && string.CompareOrdinal(s1, 0, s2, 0, s2.Length) == 0;
117 private static readonly CompareInfo compareInfo = CultureInfo.InvariantCulture.CompareInfo;
119 private bool Contains(XPathNodeIterator nodeIterator) {
120 string s1 = argList[0].Evaluate(nodeIterator).ToString();
121 string s2 = argList[1].Evaluate(nodeIterator).ToString();
122 return compareInfo.IndexOf(s1, s2, CompareOptions.Ordinal) >= 0;
125 private string SubstringBefore(XPathNodeIterator nodeIterator) {
126 string s1 = argList[0].Evaluate(nodeIterator).ToString();
127 string s2 = argList[1].Evaluate(nodeIterator).ToString();
128 if (s2.Length == 0) { return s2; }
129 int idx = compareInfo.IndexOf(s1, s2, CompareOptions.Ordinal);
130 return (idx < 1) ? string.Empty : s1.Substring(0, idx);
133 private string SubstringAfter(XPathNodeIterator nodeIterator) {
134 string s1 = argList[0].Evaluate(nodeIterator).ToString();
135 string s2 = argList[1].Evaluate(nodeIterator).ToString();
136 if (s2.Length == 0) { return s1; }
137 int idx = compareInfo.IndexOf(s1, s2, CompareOptions.Ordinal);
138 return (idx < 0) ? string.Empty : s1.Substring(idx + s2.Length);
141 private string Substring(XPathNodeIterator nodeIterator) {
142 string str1 = argList[0].Evaluate(nodeIterator).ToString();
143 double num = XmlConvert.XPathRound(XmlConvert.ToXPathDouble(argList[1].Evaluate(nodeIterator))) - 1 ;
145 if (Double.IsNaN(num) || str1.Length <= num) {
146 return string.Empty;
148 if (argList.Count == 3) {
149 double num1 = XmlConvert.XPathRound(XmlConvert.ToXPathDouble(argList[2].Evaluate(nodeIterator)));
150 if (Double.IsNaN(num1)) {
151 return string.Empty;
153 if (num < 0 || num1 < 0 ) {
154 num1 = num + num1 ;
155 // NOTE: condition is true for NaN
156 if (!(num1 > 0)) {
157 return string.Empty;
159 num = 0;
161 double maxlength = str1.Length - num;
162 if (num1 > maxlength) {
163 num1 = maxlength;
165 return str1.Substring((int)num ,(int)num1);
167 if (num < 0) {
168 num = 0;
170 return str1.Substring((int)num);
173 private Double StringLength(XPathNodeIterator nodeIterator) {
174 if (argList.Count > 0) {
175 return argList[0].Evaluate(nodeIterator).ToString().Length;
177 return nodeIterator.Current.Value.Length;
180 private string Normalize(XPathNodeIterator nodeIterator) {
181 string str1;
182 if (argList.Count > 0) {
183 str1 = argList[0].Evaluate(nodeIterator).ToString();
184 } else {
185 str1 = nodeIterator.Current.Value;
187 str1 = XmlConvert.TrimString(str1);
188 int count = 0;
189 StringBuilder str2 = new StringBuilder();
190 bool FirstSpace = true;
191 XmlCharType xmlCharType = XmlCharType.Instance;
192 while (count < str1.Length) {
193 if (!xmlCharType.IsWhiteSpace(str1[count])) {
194 FirstSpace = true;
195 str2.Append(str1[count]);
196 } else if (FirstSpace) {
197 FirstSpace = false;
198 str2.Append(' ');
200 count++;
202 return str2.ToString();
205 private string Translate(XPathNodeIterator nodeIterator) {
206 string str1 = argList[0].Evaluate(nodeIterator).ToString();
207 string str2 = argList[1].Evaluate(nodeIterator).ToString();
208 string str3 = argList[2].Evaluate(nodeIterator).ToString();
209 int count = 0, index;
210 StringBuilder str = new StringBuilder();
211 while (count < str1.Length) {
212 index = str2.IndexOf(str1[count]);
213 if (index != -1) {
214 if (index < str3.Length) {
215 str.Append(str3[index]);
217 } else {
218 str.Append(str1[count]);
220 count++;
222 return str.ToString();
225 public override XPathNodeIterator Clone() { return new StringFunctions(this); }
227 public override void PrintQuery(XmlWriter w) {
228 w.WriteStartElement(this.GetType().Name);
229 w.WriteAttributeString("name", funcType.ToString());
230 foreach(Query arg in this.argList) {
231 arg.PrintQuery(w);
233 w.WriteEndElement();