1 //------------------------------------------------------------------------------
2 // <copyright file="XmlCharacterData.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7 namespace System.Xml {
8     using System.Diagnostics;
9     using System.Text;
10     using System.Xml.XPath;
11 
12     // Provides text-manipulation methods that are used by several classes.
13     public abstract class XmlCharacterData : XmlLinkedNode {
14         string data;
15 
16         //base(doc) will throw exception if doc is null.
XmlCharacterData( string data, XmlDocument doc )17         protected internal XmlCharacterData( string data, XmlDocument doc ): base( doc ) {
18             this.data = data;
19         }
20 
21         // Gets or sets the value of the node.
22         public override String Value {
23             get { return Data;}
24             set { Data = value;}
25         }
26 
27         // Gets or sets the concatenated values of the node and
28         // all its children.
29         public override string InnerText {
30             get { return Value;}
31             set { Value = value;}
32         }
33 
34         // Contains this node's data.
35         public virtual string Data {
36             get {
37                 if (data != null) {
38                     return data;
39                 }
40                 else {
41                     return String.Empty;
42                 }
43             }
44 
45             set {
46                 XmlNode parent = ParentNode;
47                 XmlNodeChangedEventArgs args = GetEventArgs( this, parent, parent, this.data, value, XmlNodeChangedAction.Change );
48 
49                 if (args != null)
50                     BeforeEvent( args );
51 
52                 data = value;
53 
54                 if (args != null)
55                     AfterEvent( args );
56             }
57         }
58 
59         // Gets the length of the data, in characters.
60         public virtual int Length {
61             get {
62                 if (data != null) {
63                         return data.Length;
64                 }
65                 return 0;
66             }
67         }
68 
69         // Retrieves a substring of the full string from the specified range.
Substring(int offset, int count)70         public virtual String Substring(int offset, int count) {
71             int len = data != null ? data.Length : 0;
72             if (len > 0) {
73                 if (len < (offset + count)) {
74                     count = len - offset;
75                 }
76                 return data.Substring( offset, count );
77             }
78             return String.Empty;
79         }
80 
81         // Appends the specified string to the end of the character
82         // data of the node.
AppendData(String strData)83         public virtual void AppendData(String strData) {
84             XmlNode parent = ParentNode;
85             int capacity = data != null ? data.Length : 0;
86             if (strData != null) capacity += strData.Length;
87             string newValue = new StringBuilder( capacity ).Append( data ).Append( strData ).ToString();
88             XmlNodeChangedEventArgs args = GetEventArgs( this, parent, parent, data, newValue, XmlNodeChangedAction.Change );
89 
90             if (args != null)
91                 BeforeEvent( args );
92 
93             this.data = newValue;
94 
95             if (args != null)
96                 AfterEvent( args );
97         }
98 
99         // Insert the specified string at the specified character offset.
InsertData(int offset, string strData)100         public virtual void InsertData(int offset, string strData) {
101             XmlNode parent = ParentNode;
102             int capacity = data != null ? data.Length : 0;
103             if (strData != null) capacity += strData.Length;
104             string newValue = new StringBuilder( capacity ).Append( data ).Insert(offset, strData).ToString();
105             XmlNodeChangedEventArgs args = GetEventArgs( this, parent, parent, data, newValue, XmlNodeChangedAction.Change );
106             if (args != null)
107                 BeforeEvent( args );
108 
109             this.data = newValue;
110 
111             if (args != null)
112                 AfterEvent( args );
113         }
114 
115         // Remove a range of characters from the node.
DeleteData(int offset, int count)116         public virtual void DeleteData(int offset, int count) {
117             //Debug.Assert(offset >= 0 && offset <= Length);
118 
119             int len = data != null ? data.Length : 0;
120             if (len > 0) {
121                 if (len < (offset + count)) {
122                     count = Math.Max ( len - offset, 0);
123                 }
124             }
125 
126             string newValue = new StringBuilder( data ).Remove(offset, count).ToString();
127             XmlNode parent = ParentNode;
128             XmlNodeChangedEventArgs args = GetEventArgs( this, parent, parent, data, newValue, XmlNodeChangedAction.Change );
129 
130             if (args != null)
131                 BeforeEvent( args );
132 
133             this.data = newValue;
134 
135             if (args != null)
136                 AfterEvent( args );
137         }
138 
139         // Replace the specified number of characters starting at the specified offset with the
140         // specified string.
ReplaceData(int offset, int count, String strData)141         public virtual void ReplaceData(int offset, int count, String strData) {
142             //Debug.Assert(offset >= 0 && offset <= Length);
143 
144             int len = data != null ? data.Length : 0;
145             if (len > 0) {
146                 if (len < (offset + count)) {
147                     count = Math.Max ( len - offset, 0);
148                 }
149             }
150 
151             StringBuilder temp = new StringBuilder( data ).Remove( offset, count );
152             string newValue = temp.Insert( offset, strData ).ToString();
153 
154             XmlNode parent = ParentNode;
155             XmlNodeChangedEventArgs args = GetEventArgs( this, parent, parent, data, newValue, XmlNodeChangedAction.Change );
156 
157             if (args != null)
158                 BeforeEvent( args );
159 
160             this.data = newValue;
161 
162             if (args != null)
163                 AfterEvent( args );
164         }
165 
CheckOnData( string data )166         internal bool CheckOnData( string data ) {
167             return XmlCharType.Instance.IsOnlyWhitespace( data );
168         }
169 
DecideXPNodeTypeForTextNodes(XmlNode node, ref XPathNodeType xnt)170         internal bool DecideXPNodeTypeForTextNodes(XmlNode node, ref XPathNodeType xnt) {
171             //returns true - if all siblings of the node are processed else returns false.
172             //The reference XPathNodeType argument being passed in is the watermark that
173             //changes according to the siblings nodetype and will contain the correct
174             //nodetype when it returns.
175 
176             Debug.Assert(XmlDocument.IsTextNode(node.NodeType) || (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.EntityReference));
177             while (node != null) {
178                 switch (node.NodeType) {
179                 case XmlNodeType.Whitespace :
180                     break;
181                 case XmlNodeType.SignificantWhitespace :
182                     xnt = XPathNodeType.SignificantWhitespace;
183                     break;
184                 case XmlNodeType.Text :
185                 case XmlNodeType.CDATA:
186                     xnt = XPathNodeType.Text;
187                     return false;
188                 case XmlNodeType.EntityReference :
189                     if (!DecideXPNodeTypeForTextNodes(node.FirstChild, ref xnt)) {
190                         return false;
191                     }
192                     break;
193                 default :
194                     return false;
195                 }
196                 node = node.NextSibling;
197             }
198             return true;
199         }
200     }
201 }
202 
203