1 //------------------------------------------------------------------------------
2 // <copyright file="StringFunctions.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace MS
.Internal
.Xml
.XPath
{
10 using System
.Globalization
;
13 using System
.Xml
.XPath
;
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
]);
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
) {
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
);
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
;
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
;
94 funcType
== Function
.FunctionType
.FuncStartsWith
||
95 funcType
== Function
.FunctionType
.FuncContains
97 return XPathResultType
.Boolean
;
99 return XPathResultType
.String
;
102 private string Concat(XPathNodeIterator nodeIterator
) {
104 StringBuilder s
= new StringBuilder();
105 while (count
< argList
.Count
) {
106 s
.Append(argList
[count
++].Evaluate(nodeIterator
).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
) {
148 if (argList
.Count
== 3) {
149 double num1
= XmlConvert
.XPathRound(XmlConvert
.ToXPathDouble(argList
[2].Evaluate(nodeIterator
)));
150 if (Double
.IsNaN(num1
)) {
153 if (num
< 0 || num1
< 0 ) {
155 // NOTE: condition is true for NaN
161 double maxlength
= str1
.Length
- num
;
162 if (num1
> maxlength
) {
165 return str1
.Substring((int)num
,(int)num1
);
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
) {
182 if (argList
.Count
> 0) {
183 str1
= argList
[0].Evaluate(nodeIterator
).ToString();
185 str1
= nodeIterator
.Current
.Value
;
187 str1
= XmlConvert
.TrimString(str1
);
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
])) {
195 str2
.Append(str1
[count
]);
196 } else if (FirstSpace
) {
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
]);
214 if (index
< str3
.Length
) {
215 str
.Append(str3
[index
]);
218 str
.Append(str1
[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
) {