2 //------------------------------------------------------------------------------
3 // <copyright file="XmlWellFormedWriterHelpers.cs" company="Microsoft">
4 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <owner current="true" primary="true">Microsoft</owner>
7 //------------------------------------------------------------------------------
11 using System
.Diagnostics
;
12 using System
.Collections
.Generic
;
14 namespace System
.Xml
{
16 internal partial class XmlWellFormedWriter
: XmlWriter
{
21 class NamespaceResolverProxy
: IXmlNamespaceResolver
{
22 XmlWellFormedWriter wfWriter
;
24 internal NamespaceResolverProxy(XmlWellFormedWriter wfWriter
) {
25 this.wfWriter
= wfWriter
;
28 IDictionary
<string, string> IXmlNamespaceResolver
.GetNamespacesInScope(XmlNamespaceScope scope
) {
29 throw new NotImplementedException();
31 string IXmlNamespaceResolver
.LookupNamespace(string prefix
) {
32 return wfWriter
.LookupNamespace(prefix
);
35 string IXmlNamespaceResolver
.LookupPrefix(string namespaceName
) {
36 return wfWriter
.LookupPrefix(namespaceName
);
40 partial struct ElementScope
{
42 internal int prevNSTop
;
43 internal string prefix
;
44 internal string localName
;
45 internal string namespaceUri
;
46 internal XmlSpace xmlSpace
;
47 internal string xmlLang
;
49 internal void Set(string prefix
, string localName
, string namespaceUri
, int prevNSTop
) {
50 this.prevNSTop
= prevNSTop
;
52 this.namespaceUri
= namespaceUri
;
53 this.localName
= localName
;
54 this.xmlSpace
= (System
.Xml
.XmlSpace
)(int)-1;
58 internal void WriteEndElement(XmlRawWriter rawWriter
) {
59 rawWriter
.WriteEndElement(prefix
, localName
, namespaceUri
);
62 internal void WriteFullEndElement(XmlRawWriter rawWriter
) {
63 rawWriter
.WriteFullEndElement(prefix
, localName
, namespaceUri
);
74 partial struct Namespace
{
76 internal string prefix
;
77 internal string namespaceUri
;
78 internal NamespaceKind kind
;
79 internal int prevNsIndex
;
81 internal void Set(string prefix
, string namespaceUri
, NamespaceKind kind
) {
83 this.namespaceUri
= namespaceUri
;
85 this.prevNsIndex
= -1;
88 internal void WriteDecl(XmlWriter writer
, XmlRawWriter rawWriter
) {
89 Debug
.Assert(kind
== NamespaceKind
.NeedToWrite
);
90 if (null != rawWriter
) {
91 rawWriter
.WriteNamespaceDeclaration(prefix
, namespaceUri
);
94 if (prefix
.Length
== 0) {
95 writer
.WriteStartAttribute(string.Empty
, "xmlns", XmlReservedNs
.NsXmlNs
);
98 writer
.WriteStartAttribute("xmlns", prefix
, XmlReservedNs
.NsXmlNs
);
100 writer
.WriteString(namespaceUri
);
101 writer
.WriteEndAttribute();
107 internal string prefix
;
108 internal string namespaceUri
;
109 internal string localName
;
112 internal void Set(string prefix
, string localName
, string namespaceUri
) {
113 this.prefix
= prefix
;
114 this.namespaceUri
= namespaceUri
;
115 this.localName
= localName
;
119 internal bool IsDuplicate(string prefix
, string localName
, string namespaceUri
) {
120 return ((this.localName
== localName
)
121 && ((this.prefix
== prefix
) || (this.namespaceUri
== namespaceUri
)));
125 enum SpecialAttribute
{
133 partial class AttributeValueCache
{
148 internal ItemType type
;
149 internal object data
;
153 internal void Set(ItemType type
, object data
) {
160 internal char[] buffer
;
164 internal BufferChunk(char[] buffer
, int index
, int count
) {
165 this.buffer
= buffer
;
171 StringBuilder stringValue
= new StringBuilder();
172 string singleStringValue
; // special-case for a single WriteString call
177 internal string StringValue
{
179 if (singleStringValue
!= null) {
180 return singleStringValue
;
183 return stringValue
.ToString();
188 internal void WriteEntityRef(string name
) {
189 if (singleStringValue
!= null) {
195 stringValue
.Append('<');
198 stringValue
.Append('>');
201 stringValue
.Append('"');
204 stringValue
.Append('\'');
207 stringValue
.Append('&');
210 stringValue
.Append('&');
211 stringValue
.Append(name
);
212 stringValue
.Append(';');
216 AddItem(ItemType
.EntityRef
, name
);
219 internal void WriteCharEntity(char ch
) {
220 if (singleStringValue
!= null) {
223 stringValue
.Append(ch
);
224 AddItem(ItemType
.CharEntity
, ch
);
227 internal void WriteSurrogateCharEntity(char lowChar
, char highChar
) {
228 if (singleStringValue
!= null) {
231 stringValue
.Append(highChar
);
232 stringValue
.Append(lowChar
);
233 AddItem(ItemType
.SurrogateCharEntity
, new char[] { lowChar, highChar }
);
236 internal void WriteWhitespace(string ws
) {
237 if (singleStringValue
!= null) {
240 stringValue
.Append(ws
);
241 AddItem(ItemType
.Whitespace
, ws
);
244 internal void WriteString(string text
) {
245 if (singleStringValue
!= null) {
249 // special-case for a single WriteString
250 if (lastItem
== -1) {
251 singleStringValue
= text
;
256 stringValue
.Append(text
);
257 AddItem(ItemType
.String
, text
);
260 internal void WriteChars(char[] buffer
, int index
, int count
) {
261 if (singleStringValue
!= null) {
264 stringValue
.Append(buffer
, index
, count
);
265 AddItem(ItemType
.StringChars
, new BufferChunk(buffer
, index
, count
));
268 internal void WriteRaw(char[] buffer
, int index
, int count
) {
269 if (singleStringValue
!= null) {
272 stringValue
.Append(buffer
, index
, count
);
273 AddItem(ItemType
.RawChars
, new BufferChunk(buffer
, index
, count
));
276 internal void WriteRaw(string data
) {
277 if (singleStringValue
!= null) {
280 stringValue
.Append(data
);
281 AddItem(ItemType
.Raw
, data
);
284 internal void WriteValue(string value) {
285 if (singleStringValue
!= null) {
288 stringValue
.Append(value);
289 AddItem(ItemType
.ValueString
, value);
292 internal void Replay(XmlWriter writer
) {
293 if (singleStringValue
!= null) {
294 writer
.WriteString(singleStringValue
);
298 BufferChunk bufChunk
;
299 for (int i
= firstItem
; i
<= lastItem
; i
++) {
300 Item item
= items
[i
];
302 case ItemType
.EntityRef
:
303 writer
.WriteEntityRef((string)item
.data
);
305 case ItemType
.CharEntity
:
306 writer
.WriteCharEntity((char)item
.data
);
308 case ItemType
.SurrogateCharEntity
:
309 char[] chars
= (char[])item
.data
;
310 writer
.WriteSurrogateCharEntity(chars
[0], chars
[1]);
312 case ItemType
.Whitespace
:
313 writer
.WriteWhitespace((string)item
.data
);
315 case ItemType
.String
:
316 writer
.WriteString((string)item
.data
);
318 case ItemType
.StringChars
:
319 bufChunk
= (BufferChunk
)item
.data
;
320 writer
.WriteChars(bufChunk
.buffer
, bufChunk
.index
, bufChunk
.count
);
323 writer
.WriteRaw((string)item
.data
);
325 case ItemType
.RawChars
:
326 bufChunk
= (BufferChunk
)item
.data
;
327 writer
.WriteChars(bufChunk
.buffer
, bufChunk
.index
, bufChunk
.count
);
329 case ItemType
.ValueString
:
330 writer
.WriteValue((string)item
.data
);
333 Debug
.Assert(false, "Unexpected ItemType value.");
339 // This method trims whitespaces from the beginnig and the end of the string and cached writer events
340 internal void Trim() {
341 // if only one string value -> trim the write spaces directly
342 if (singleStringValue
!= null) {
343 singleStringValue
= XmlConvert
.TrimString(singleStringValue
);
347 // trim the string in StringBuilder
348 string valBefore
= stringValue
.ToString();
349 string valAfter
= XmlConvert
.TrimString(valBefore
);
350 if (valBefore
!= valAfter
) {
351 stringValue
= new StringBuilder(valAfter
);
354 // trim the beginning of the recorded writer events
355 XmlCharType xmlCharType
= XmlCharType
.Instance
;
358 while (i
== firstItem
&& i
<= lastItem
) {
359 Item item
= items
[i
];
361 case ItemType
.Whitespace
:
364 case ItemType
.String
:
366 case ItemType
.ValueString
:
367 item
.data
= XmlConvert
.TrimStringStart((string)item
.data
);
368 if (((string)item
.data
).Length
== 0) {
369 // no characters left -> move the firstItem index to exclude it from the Replay
373 case ItemType
.StringChars
:
374 case ItemType
.RawChars
:
375 BufferChunk bufChunk
= (BufferChunk
)item
.data
;
376 int endIndex
= bufChunk
.index
+ bufChunk
.count
;
377 while (bufChunk
.index
< endIndex
&& xmlCharType
.IsWhiteSpace(bufChunk
.buffer
[bufChunk
.index
])) {
381 if (bufChunk
.index
== endIndex
) {
382 // no characters left -> move the firstItem index to exclude it from the Replay
390 // trim the end of the recorded writer events
392 while (i
== lastItem
&& i
>= firstItem
) {
393 Item item
= items
[i
];
395 case ItemType
.Whitespace
:
398 case ItemType
.String
:
400 case ItemType
.ValueString
:
401 item
.data
= XmlConvert
.TrimStringEnd((string)item
.data
);
402 if (((string)item
.data
).Length
== 0) {
403 // no characters left -> move the lastItem index to exclude it from the Replay
407 case ItemType
.StringChars
:
408 case ItemType
.RawChars
:
409 BufferChunk bufChunk
= (BufferChunk
)item
.data
;
410 while (bufChunk
.count
> 0 && xmlCharType
.IsWhiteSpace(bufChunk
.buffer
[bufChunk
.index
+ bufChunk
.count
- 1])) {
413 if (bufChunk
.count
== 0) {
414 // no characters left -> move the lastItem index to exclude it from the Replay
423 internal void Clear() {
424 singleStringValue
= null;
427 stringValue
.Length
= 0;
430 private void StartComplexValue() {
431 Debug
.Assert(singleStringValue
!= null);
432 Debug
.Assert(lastItem
== -1);
434 stringValue
.Append( singleStringValue
);
435 AddItem(ItemType
.String
, singleStringValue
);
437 singleStringValue
= null;
440 void AddItem(ItemType type
, object data
) {
441 int newItemIndex
= lastItem
+ 1;
445 else if (items
.Length
== newItemIndex
) {
446 Item
[] newItems
= new Item
[newItemIndex
* 2];
447 Array
.Copy(items
, newItems
, newItemIndex
);
450 if (items
[newItemIndex
] == null) {
451 items
[newItemIndex
] = new Item();
453 items
[newItemIndex
].Set(type
, data
);
454 lastItem
= newItemIndex
;