Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Dom / XmlDocument.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlDocument.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 namespace System.Xml
9 {
10     using System;
11     using System.Collections;
12     using System.Diagnostics;
13     using System.IO;
14     using System.Text;
15     using System.Xml.Schema;
16     using System.Xml.XPath;
17     using System.Security;
18     using System.Security.Permissions;
19     using System.Globalization;
20     using System.Runtime.Versioning;
21
22     // Represents an entire document. An XmlDocument contains XML data.
23     public class XmlDocument: XmlNode {
24         private XmlImplementation implementation;
25         private DomNameTable domNameTable; // hash table of XmlName
26         private XmlLinkedNode lastChild;
27         private XmlNamedNodeMap entities;
28         private Hashtable htElementIdMap;
29         private Hashtable htElementIDAttrDecl; //key: id; object: the ArrayList of the elements that have the same id (connected or disconnected)
30         private SchemaInfo schemaInfo;
31         private XmlSchemaSet schemas; // schemas associated with the cache
32         private bool reportValidity;
33         //This variable represents the actual loading status. Since, IsLoading will
34         //be manipulated soemtimes for adding content to EntityReference this variable
35         //has been added which would always represent the loading status of document.
36         private bool actualLoadingStatus;
37
38         private XmlNodeChangedEventHandler onNodeInsertingDelegate;
39         private XmlNodeChangedEventHandler onNodeInsertedDelegate;
40         private XmlNodeChangedEventHandler onNodeRemovingDelegate;
41         private XmlNodeChangedEventHandler onNodeRemovedDelegate;
42         private XmlNodeChangedEventHandler onNodeChangingDelegate;
43         private XmlNodeChangedEventHandler onNodeChangedDelegate;
44
45         // false if there are no ent-ref present, true if ent-ref nodes are or were present (i.e. if all ent-ref were removed, the doc will not clear this flag)
46         internal bool fEntRefNodesPresent;
47         internal bool fCDataNodesPresent;
48
49         private bool preserveWhitespace;
50         private bool isLoading;
51
52         // special name strings for
53         internal string strDocumentName;
54         internal string strDocumentFragmentName;
55         internal string strCommentName;
56         internal string strTextName;
57         internal string strCDataSectionName;
58         internal string strEntityName;
59         internal string strID;
60         internal string strXmlns;
61         internal string strXml;
62         internal string strSpace;
63         internal string strLang;
64         internal string strEmpty;
65
66         internal string strNonSignificantWhitespaceName;
67         internal string strSignificantWhitespaceName;
68         internal string strReservedXmlns;
69         internal string strReservedXml;
70
71         internal String baseURI;
72
73         private XmlResolver resolver;
74         internal bool       bSetResolver;
75         internal object     objLock;
76
77         private XmlAttribute namespaceXml;
78
79         static internal EmptyEnumerator EmptyEnumerator = new EmptyEnumerator();
80         static internal IXmlSchemaInfo NotKnownSchemaInfo = new XmlSchemaInfo(XmlSchemaValidity.NotKnown);
81         static internal IXmlSchemaInfo ValidSchemaInfo = new XmlSchemaInfo(XmlSchemaValidity.Valid);
82         static internal IXmlSchemaInfo InvalidSchemaInfo = new XmlSchemaInfo(XmlSchemaValidity.Invalid);
83
84         // Initializes a new instance of the XmlDocument class.
85         public XmlDocument(): this( new XmlImplementation() ) {
86         }
87
88         // Initializes a new instance
89         // of the XmlDocument class with the specified XmlNameTable.
90         public XmlDocument( XmlNameTable nt ) : this( new XmlImplementation( nt ) ) {
91         }
92
93         protected internal XmlDocument( XmlImplementation imp ): base() {
94
95             implementation = imp;
96             domNameTable = new DomNameTable( this );
97
98             // force the following string instances to be default in the nametable
99             XmlNameTable nt = this.NameTable;
100             nt.Add( string.Empty );            
101             strDocumentName = nt.Add( "#document" );
102             strDocumentFragmentName  = nt.Add( "#document-fragment" );
103             strCommentName = nt.Add( "#comment" );
104             strTextName = nt.Add( "#text" );
105             strCDataSectionName = nt.Add( "#cdata-section" );
106             strEntityName = nt.Add( "#entity" );
107             strID = nt.Add( "id" );
108             strNonSignificantWhitespaceName = nt.Add( "#whitespace" );
109             strSignificantWhitespaceName = nt.Add( "#significant-whitespace" );
110             strXmlns = nt.Add( "xmlns" );
111             strXml = nt.Add(  "xml" );
112             strSpace = nt.Add(  "space" );
113             strLang = nt.Add(  "lang" );
114             strReservedXmlns = nt.Add( XmlReservedNs.NsXmlNs );
115             strReservedXml = nt.Add( XmlReservedNs.NsXml );
116             strEmpty = nt.Add( String.Empty );
117             baseURI = String.Empty; 
118
119             objLock = new object();
120         }
121
122         internal SchemaInfo DtdSchemaInfo {
123             get { return schemaInfo; }
124             set { schemaInfo = value; }
125         }
126
127         // NOTE: This does not correctly check start name char, but we cannot change it since it would be a breaking change.
128         internal static void CheckName( String name ) {
129             int endPos = ValidateNames.ParseNmtoken( name, 0 );
130             if (endPos < name.Length) {
131                 throw new XmlException(Res.Xml_BadNameChar, XmlException.BuildCharExceptionArgs(name, endPos));
132             }
133         }
134
135         internal XmlName AddXmlName(string prefix, string localName, string namespaceURI, IXmlSchemaInfo schemaInfo) { 
136             XmlName n = domNameTable.AddName(prefix, localName, namespaceURI, schemaInfo); 
137             Debug.Assert( (prefix == null) ? (n.Prefix.Length == 0) : (prefix == n.Prefix) );
138             Debug.Assert( n.LocalName == localName );
139             Debug.Assert( (namespaceURI == null) ? (n.NamespaceURI.Length == 0) : (n.NamespaceURI == namespaceURI) );
140             return n;
141         }
142
143         internal XmlName GetXmlName(string prefix, string localName, string namespaceURI, IXmlSchemaInfo schemaInfo) { 
144             XmlName n = domNameTable.GetName(prefix, localName, namespaceURI, schemaInfo); 
145             Debug.Assert(n == null || ((prefix == null) ? (n.Prefix.Length == 0) : (prefix == n.Prefix)));
146             Debug.Assert(n == null || n.LocalName == localName);
147             Debug.Assert(n == null || ((namespaceURI == null) ? (n.NamespaceURI.Length == 0) : (n.NamespaceURI == namespaceURI)));
148             return n;
149         }
150
151         internal XmlName AddAttrXmlName(string prefix, string localName, string namespaceURI, IXmlSchemaInfo schemaInfo) { 
152             XmlName xmlName = AddXmlName(prefix, localName, namespaceURI, schemaInfo); 
153             Debug.Assert( (prefix == null) ? (xmlName.Prefix.Length == 0) : (prefix == xmlName.Prefix) );
154             Debug.Assert( xmlName.LocalName == localName );
155             Debug.Assert( (namespaceURI == null) ? (xmlName.NamespaceURI.Length == 0) : (xmlName.NamespaceURI == namespaceURI) );
156
157             if ( !this.IsLoading ) {
158                 // Use atomized versions instead of prefix, localName and nsURI
159                 object oPrefix       = xmlName.Prefix;
160                 object oNamespaceURI = xmlName.NamespaceURI;
161                 object oLocalName    = xmlName.LocalName;
162                 if ( ( oPrefix == (object)strXmlns || ( oPrefix == (object)strEmpty && oLocalName == (object)strXmlns ) ) ^ ( oNamespaceURI == (object)strReservedXmlns ) )
163                     throw new ArgumentException( Res.GetString( Res.Xdom_Attr_Reserved_XmlNS, namespaceURI ) );
164             }
165             return xmlName;
166         }
167
168         internal bool AddIdInfo( XmlName eleName, XmlName attrName ) {
169             //when XmlLoader call XmlDocument.AddInfo, the element.XmlName and attr.XmlName 
170             //have already been replaced with the ones that don't have namespace values (or just
171             //string.Empty) because in DTD, the namespace is not supported
172             if ( htElementIDAttrDecl == null || htElementIDAttrDecl[eleName] == null ) {
173                 if ( htElementIDAttrDecl == null )
174                     htElementIDAttrDecl = new Hashtable();
175                 htElementIDAttrDecl.Add(eleName, attrName);
176                 return true;
177             }
178             return false;
179         }
180
181         private XmlName GetIDInfoByElement_(XmlName eleName)
182         {
183             //When XmlDocument is getting the IDAttribute for a given element, 
184             //we need only compare the prefix and localname of element.XmlName with
185             //the registered htElementIDAttrDecl.
186             XmlName newName = GetXmlName(eleName.Prefix, eleName.LocalName, string.Empty, null);
187             if (newName != null) {
188                 return (XmlName)(htElementIDAttrDecl[newName]);
189             }
190             return null;
191         }
192
193         internal XmlName GetIDInfoByElement( XmlName eleName ) {
194             if (htElementIDAttrDecl == null)
195                 return null;
196             else
197                 return GetIDInfoByElement_(eleName);
198         }
199
200         private WeakReference GetElement(ArrayList elementList, XmlElement elem) {
201             ArrayList gcElemRefs = new ArrayList();
202             foreach( WeakReference elemRef in elementList) {
203                 if ( !elemRef.IsAlive)
204                     //take notes on the garbage collected nodes
205                     gcElemRefs.Add(elemRef);
206                 else {
207                     if ((XmlElement)(elemRef.Target) == elem)
208                         return elemRef;
209                 }
210             }                 
211             //Clear out the gced elements
212             foreach( WeakReference elemRef in gcElemRefs)
213                 elementList.Remove(elemRef);
214             return null;
215         }
216
217         internal void AddElementWithId( string id, XmlElement elem ) {
218             if (htElementIdMap == null || !htElementIdMap.Contains(id)) {
219                 if ( htElementIdMap == null )
220                     htElementIdMap = new Hashtable();
221                 ArrayList elementList = new ArrayList();
222                 elementList.Add(new WeakReference(elem));
223                 htElementIdMap.Add(id, elementList);
224             }
225             else {
226                 // there are other element(s) that has the same id
227                 ArrayList elementList = (ArrayList)(htElementIdMap[id]);
228                 if (GetElement(elementList, elem) == null)
229                     elementList.Add(new WeakReference(elem));
230             }
231         }
232
233         internal void RemoveElementWithId( string id, XmlElement elem ) {
234             if (htElementIdMap != null && htElementIdMap.Contains(id)) {
235                 ArrayList elementList = (ArrayList)(htElementIdMap[id]);
236                 WeakReference elemRef = GetElement(elementList, elem);
237                 if (elemRef != null) {
238                     elementList.Remove(elemRef);
239                     if (elementList.Count == 0)
240                         htElementIdMap.Remove(id);
241                 }
242             }
243         }
244
245
246         // Creates a duplicate of this node.
247         public override XmlNode CloneNode( bool deep ) {
248             XmlDocument clone = Implementation.CreateDocument();
249             clone.SetBaseURI(this.baseURI);
250             if (deep)
251                 clone.ImportChildren( this, clone, deep );
252
253             return clone;
254         }
255
256         // Gets the type of the current node.
257         public override XmlNodeType NodeType {
258             get { return XmlNodeType.Document; }
259         }
260
261         public override XmlNode ParentNode {
262             get { return null; }
263         }
264
265         // Gets the node for the DOCTYPE declaration.
266         public virtual XmlDocumentType DocumentType {
267             get { return(XmlDocumentType) FindChild( XmlNodeType.DocumentType ); }
268         }
269
270         internal virtual XmlDeclaration Declaration {
271             get {
272                 if ( HasChildNodes ) {
273                     XmlDeclaration dec = FirstChild as XmlDeclaration;
274                     return dec;
275                 }
276                 return null;
277             }
278         }
279
280         // Gets the XmlImplementation object for this document.
281         public XmlImplementation Implementation {
282             get { return this.implementation; }
283         }
284
285         // Gets the name of the node.
286         public override String Name  {
287             get { return strDocumentName; }
288         }
289
290         // Gets the name of the current node without the namespace prefix.
291         public override String LocalName {
292             get { return strDocumentName; }
293         }
294
295         // Gets the root XmlElement for the document.
296         public XmlElement DocumentElement {
297             get { return(XmlElement)FindChild(XmlNodeType.Element); }
298         }
299
300         internal override bool IsContainer {
301             get { return true; }
302         }
303
304         internal override XmlLinkedNode LastNode
305         {
306             get { return lastChild; }
307             set { lastChild = value; }
308         }
309
310         // Gets the XmlDocument that contains this node.
311         public override XmlDocument OwnerDocument
312         {
313             get { return null; }
314         }
315
316         public XmlSchemaSet Schemas {
317             get { 
318                 if (schemas == null) {
319                     schemas = new XmlSchemaSet(NameTable);
320                 }
321                 return schemas; 
322             }
323
324             set { 
325                 schemas = value; 
326             }
327         }
328
329         internal bool CanReportValidity {
330             get { return reportValidity; }
331         }
332
333         internal bool HasSetResolver {
334             get { return bSetResolver; }
335         }
336
337         internal XmlResolver GetResolver() {
338            return resolver;
339         }
340
341         public virtual XmlResolver XmlResolver {
342             set {
343                 if ( value != null ) {
344                     try {
345                         new NamedPermissionSet( "FullTrust" ).Demand();
346                     }
347                     catch ( SecurityException e ) {
348                         throw new SecurityException( Res.GetString( Res.Xml_UntrustedCodeSettingResolver ), e );
349                     }
350                 }   
351
352                 resolver = value;
353                 if ( !bSetResolver )
354                     bSetResolver = true;
355
356                 XmlDocumentType dtd = this.DocumentType;
357                 if ( dtd != null ) {
358                     dtd.DtdSchemaInfo = null;
359                 }
360             }
361         }
362         internal override bool IsValidChildType( XmlNodeType type ) {
363             switch ( type ) {
364                 case XmlNodeType.ProcessingInstruction:
365                 case XmlNodeType.Comment:
366                 case XmlNodeType.Whitespace:
367                 case XmlNodeType.SignificantWhitespace:
368                     return true;
369
370                 case XmlNodeType.DocumentType:
371                     if ( DocumentType != null )
372                         throw new InvalidOperationException( Res.GetString(Res.Xdom_DualDocumentTypeNode) );
373                     return true;
374
375                 case XmlNodeType.Element:
376                     if ( DocumentElement != null )
377                         throw new InvalidOperationException( Res.GetString(Res.Xdom_DualDocumentElementNode) );
378                     return true;
379
380                 case XmlNodeType.XmlDeclaration:
381                     if ( Declaration != null )
382                         throw new InvalidOperationException( Res.GetString(Res.Xdom_DualDeclarationNode) );
383                     return true;
384
385                 default:
386                     return false;
387             }
388         }
389         // the function examines all the siblings before the refNode
390         //  if any of the nodes has type equals to "nt", return true; otherwise, return false;
391         private bool HasNodeTypeInPrevSiblings( XmlNodeType nt, XmlNode refNode ) {
392             if ( refNode == null )
393                 return false;
394
395             XmlNode node = null;
396             if ( refNode.ParentNode != null )
397                 node = refNode.ParentNode.FirstChild;
398             while ( node != null ) {
399                 if ( node.NodeType == nt )
400                     return true;
401                 if ( node == refNode )
402                     break;
403                 node = node.NextSibling;
404             }
405             return false;
406         }
407
408         // the function examines all the siblings after the refNode
409         //  if any of the nodes has the type equals to "nt", return true; otherwise, return false;
410         private bool HasNodeTypeInNextSiblings( XmlNodeType nt, XmlNode refNode ) {
411             XmlNode node = refNode;
412             while ( node != null ) {
413                 if ( node.NodeType == nt )
414                     return true;
415                 node = node.NextSibling;
416             }
417             return false;
418         }
419
420         internal override bool CanInsertBefore( XmlNode newChild, XmlNode refChild ) {
421             if ( refChild == null )
422                 refChild = FirstChild;
423
424             if ( refChild == null )
425                 return true;
426
427             switch ( newChild.NodeType ) {
428                 case XmlNodeType.XmlDeclaration:
429                     return ( refChild == FirstChild ); 
430
431                 case XmlNodeType.ProcessingInstruction:
432                 case XmlNodeType.Comment:
433                     return refChild.NodeType != XmlNodeType.XmlDeclaration;
434
435                 case XmlNodeType.DocumentType: {
436                     if ( refChild.NodeType != XmlNodeType.XmlDeclaration ) {
437                         //if refChild is not the XmlDeclaration node, only need to go through the sibling before and including refChild to
438                         //  make sure no Element ( rootElem node ) before the current position
439                         return !HasNodeTypeInPrevSiblings( XmlNodeType.Element, refChild.PreviousSibling );
440                     }
441                 }
442                 break;
443
444                 case XmlNodeType.Element: {
445                     if ( refChild.NodeType != XmlNodeType.XmlDeclaration ) {
446                         //if refChild is not the XmlDeclaration node, only need to go through the siblings after and including the refChild to
447                         //  make sure no DocType node and XmlDeclaration node after the current posistion.
448                         return !HasNodeTypeInNextSiblings( XmlNodeType.DocumentType, refChild );
449                     }
450                 }
451                 break;
452             }
453
454             return false;
455         }
456
457         internal override bool CanInsertAfter( XmlNode newChild, XmlNode refChild ) {
458             if ( refChild == null )
459                 refChild = LastChild;
460
461             if ( refChild == null )
462                 return true;
463
464             switch ( newChild.NodeType ) {
465                 case XmlNodeType.ProcessingInstruction:
466                 case XmlNodeType.Comment:
467                 case XmlNodeType.Whitespace:
468                 case XmlNodeType.SignificantWhitespace:
469                     return true;
470
471                 case XmlNodeType.DocumentType: {
472                     //we will have to go through all the siblings before the refChild just to make sure no Element node ( rootElem )
473                     //  before the current position
474                     return !HasNodeTypeInPrevSiblings( XmlNodeType.Element, refChild );
475                 }
476
477                 case XmlNodeType.Element: {
478                     return !HasNodeTypeInNextSiblings( XmlNodeType.DocumentType, refChild.NextSibling );
479                 }
480
481             }
482
483             return false;
484         }
485
486         // Creates an XmlAttribute with the specified name.
487         public XmlAttribute CreateAttribute( String name ) {
488             String prefix = String.Empty;
489             String localName = String.Empty;
490             String namespaceURI = String.Empty;
491
492             SplitName( name, out prefix, out localName );
493
494             SetDefaultNamespace( prefix, localName, ref namespaceURI );
495
496             return CreateAttribute( prefix, localName, namespaceURI );
497         }
498
499         internal void SetDefaultNamespace( String prefix, String localName, ref String namespaceURI ) {
500             if ( prefix == strXmlns || ( prefix.Length == 0 && localName == strXmlns ) ) {
501                 namespaceURI = strReservedXmlns;
502             } else if ( prefix == strXml ) {
503                 namespaceURI = strReservedXml;
504             }
505         }
506
507         // Creates a XmlCDataSection containing the specified data.
508         public virtual XmlCDataSection CreateCDataSection( String data ) {
509             fCDataNodesPresent = true;
510             return new XmlCDataSection( data, this );
511         }
512
513         // Creates an XmlComment containing the specified data.
514         public virtual XmlComment CreateComment( String data ) {
515             return new XmlComment( data, this );
516         }
517
518         // Returns a new XmlDocumentType object.
519         [PermissionSetAttribute( SecurityAction.InheritanceDemand, Name = "FullTrust" )]
520         public virtual XmlDocumentType CreateDocumentType( string name, string publicId, string systemId, string internalSubset ) {
521             return new XmlDocumentType( name, publicId, systemId, internalSubset, this );
522         }
523
524         // Creates an XmlDocumentFragment.
525         public virtual XmlDocumentFragment CreateDocumentFragment() {
526             return new XmlDocumentFragment( this );
527         }
528
529         // Creates an element with the specified name.
530         public XmlElement CreateElement( String name ) {
531             string prefix = String.Empty;
532             string localName = String.Empty;
533             SplitName( name, out prefix, out localName );
534             return CreateElement( prefix, localName, string.Empty );
535         }
536
537
538         internal void AddDefaultAttributes( XmlElement elem ) {
539             SchemaInfo schInfo = DtdSchemaInfo;
540             SchemaElementDecl ed = GetSchemaElementDecl( elem );
541             if ( ed != null && ed.AttDefs != null ) {
542                 IDictionaryEnumerator attrDefs = ed.AttDefs.GetEnumerator();
543                 while ( attrDefs.MoveNext() ) {
544                     SchemaAttDef attdef = (SchemaAttDef)attrDefs.Value;
545                     if ( attdef.Presence == SchemaDeclBase.Use.Default ||
546                          attdef.Presence == SchemaDeclBase.Use.Fixed ) {
547                          //build a default attribute and return
548                          string attrPrefix = string.Empty;
549                          string attrLocalname = attdef.Name.Name;
550                          string attrNamespaceURI = string.Empty;
551                          if ( schInfo.SchemaType == SchemaType.DTD )
552                             attrPrefix = attdef.Name.Namespace;
553                          else {
554                             attrPrefix = attdef.Prefix;
555                             attrNamespaceURI = attdef.Name.Namespace;
556                          }
557                          XmlAttribute defattr = PrepareDefaultAttribute( attdef, attrPrefix, attrLocalname, attrNamespaceURI );
558                          elem.SetAttributeNode( defattr );
559                     }
560                 }
561             }
562         }
563
564         private SchemaElementDecl GetSchemaElementDecl( XmlElement elem ) {
565             SchemaInfo schInfo = DtdSchemaInfo;
566             if ( schInfo != null ) {
567                 //build XmlQualifiedName used to identify the element schema declaration
568                 XmlQualifiedName   qname = new XmlQualifiedName( elem.LocalName, schInfo.SchemaType == SchemaType.DTD ? elem.Prefix : elem.NamespaceURI );
569                 //get the schema info for the element
570                 SchemaElementDecl elemDecl;
571                 if ( schInfo.ElementDecls.TryGetValue(qname, out elemDecl) ) {
572                     return elemDecl;
573                 }
574             }
575             return null;
576         }
577
578         //Will be used by AddDeafulatAttributes() and GetDefaultAttribute() methods
579         private XmlAttribute PrepareDefaultAttribute( SchemaAttDef attdef, string attrPrefix, string attrLocalname, string attrNamespaceURI ) {
580             SetDefaultNamespace( attrPrefix, attrLocalname, ref attrNamespaceURI );
581             XmlAttribute defattr = CreateDefaultAttribute( attrPrefix, attrLocalname, attrNamespaceURI );
582             //parsing the default value for the default attribute
583             defattr.InnerXml = attdef.DefaultValueRaw;
584             //during the expansion of the tree, the flag could be set to true, we need to set it back.
585             XmlUnspecifiedAttribute unspAttr = defattr as XmlUnspecifiedAttribute;
586             if ( unspAttr != null ) {
587                 unspAttr.SetSpecified( false );
588             }
589             return defattr;
590         }
591
592         // Creates an XmlEntityReference with the specified name.
593         public virtual XmlEntityReference CreateEntityReference( String name ) {
594             return new XmlEntityReference( name, this );
595         }
596
597         // Creates a XmlProcessingInstruction with the specified name
598         // and data strings.
599         public virtual XmlProcessingInstruction CreateProcessingInstruction( String target, String data ) {
600             return new XmlProcessingInstruction( target, data, this );
601         }
602
603         // Creates a XmlDeclaration node with the specified values.
604         public virtual XmlDeclaration CreateXmlDeclaration( String version, string encoding, string standalone ) {
605             return new XmlDeclaration( version, encoding, standalone, this );
606         }
607
608         // Creates an XmlText with the specified text.
609         public virtual XmlText CreateTextNode( String text ) {
610             return new XmlText( text, this );
611         }
612
613         // Creates a XmlSignificantWhitespace node.
614         public virtual XmlSignificantWhitespace CreateSignificantWhitespace( string text ) {
615             return new XmlSignificantWhitespace( text, this );
616         }
617
618         public override XPathNavigator CreateNavigator() {
619             return CreateNavigator(this);
620         }
621
622         internal protected virtual XPathNavigator CreateNavigator(XmlNode node) {
623             XmlNodeType nodeType = node.NodeType;
624             XmlNode parent;
625             XmlNodeType parentType;
626
627             switch (nodeType) {
628                 case XmlNodeType.EntityReference:
629                 case XmlNodeType.Entity:
630                 case XmlNodeType.DocumentType:
631                 case XmlNodeType.Notation:
632                 case XmlNodeType.XmlDeclaration:
633                     return null;
634                 case XmlNodeType.Text:
635                 case XmlNodeType.CDATA:
636                 case XmlNodeType.SignificantWhitespace:
637                     parent = node.ParentNode;
638                     if (parent != null) {
639                         do {
640                             parentType = parent.NodeType;
641                             if (parentType == XmlNodeType.Attribute) {
642                                 return null;
643                             }
644                             else if (parentType == XmlNodeType.EntityReference) {
645                                 parent = parent.ParentNode;
646                             }
647                             else {
648                                 break;
649                             }
650                         }
651                         while (parent != null);
652                     }
653                     node = NormalizeText(node);
654                     break;
655                 case XmlNodeType.Whitespace:
656                     parent = node.ParentNode;
657                     if (parent != null) {
658                         do {
659                             parentType = parent.NodeType;
660                             if (parentType == XmlNodeType.Document
661                                 || parentType == XmlNodeType.Attribute) {
662                                 return null;
663                             }
664                             else if (parentType == XmlNodeType.EntityReference) {
665                                 parent = parent.ParentNode;
666                             }
667                             else {
668                                 break;
669                             }
670                         }
671                         while (parent != null);
672                     }
673                     node = NormalizeText(node);
674                     break;
675                 default:
676                     break;
677             }
678             return new DocumentXPathNavigator(this, node);
679         }
680
681         internal static bool IsTextNode( XmlNodeType nt ) {
682             switch( nt ) {
683                 case XmlNodeType.Text:
684                 case XmlNodeType.CDATA:
685                 case XmlNodeType.Whitespace:
686                 case XmlNodeType.SignificantWhitespace:
687                     return true;
688                 default:
689                     return false;
690             }
691         }
692
693         private XmlNode NormalizeText( XmlNode n ) {
694             XmlNode retnode = null;
695             while( IsTextNode( n.NodeType ) ) {
696                 retnode = n;
697                 n = n.PreviousSibling;
698
699                 if( n == null ) {
700                     XmlNode intnode = retnode;
701                     while ( true ) {
702                         if  ( intnode.ParentNode != null && intnode.ParentNode.NodeType == XmlNodeType.EntityReference ) {
703                             if (intnode.ParentNode.PreviousSibling != null ) {
704                                 n = intnode.ParentNode.PreviousSibling;
705                                 break;
706                             }
707                             else {
708                                 intnode = intnode.ParentNode;
709                                 if( intnode == null )
710                                     break;
711                             }
712                         }
713                         else
714                             break;
715                     }
716                 }
717
718                 if( n == null )
719                     break;                    
720                 while( n.NodeType == XmlNodeType.EntityReference ) {                    
721                     n = n.LastChild;
722                 }
723             }
724             return retnode;
725         }
726
727         // Creates a XmlWhitespace node.
728         public virtual XmlWhitespace CreateWhitespace( string text ) {
729             return new XmlWhitespace( text, this );
730         }
731
732         // Returns an XmlNodeList containing
733         // a list of all descendant elements that match the specified name.
734         public virtual XmlNodeList GetElementsByTagName( String name ) {
735             return new XmlElementList( this, name );
736         }
737
738         // DOM Level 2
739
740         // Creates an XmlAttribute with the specified LocalName
741         // and NamespaceURI.
742         public XmlAttribute CreateAttribute( String qualifiedName, String namespaceURI ) {
743             string prefix = String.Empty;
744             string localName = String.Empty;
745
746             SplitName( qualifiedName, out prefix, out localName );
747             return CreateAttribute( prefix, localName, namespaceURI );
748         }
749
750         // Creates an XmlElement with the specified LocalName and
751         // NamespaceURI.
752         public XmlElement CreateElement( String qualifiedName, String namespaceURI ) {
753             string prefix = String.Empty;
754             string localName = String.Empty;
755             SplitName( qualifiedName, out prefix, out localName );
756             return CreateElement( prefix, localName, namespaceURI );
757         }
758
759         // Returns a XmlNodeList containing
760         // a list of all descendant elements that match the specified name.
761         public virtual XmlNodeList GetElementsByTagName( String localName, String namespaceURI ) {
762             return new XmlElementList( this, localName, namespaceURI );
763         }
764
765         // Returns the XmlElement with the specified ID.
766         public virtual XmlElement GetElementById( string elementId ) {
767             if (htElementIdMap != null) {
768                 ArrayList elementList = (ArrayList)(htElementIdMap[elementId]);
769                 if (elementList != null) {
770                     foreach (WeakReference elemRef in elementList) {
771                         XmlElement elem = (XmlElement)elemRef.Target;
772                         if (elem != null
773                             && elem.IsConnected())
774                             return elem;
775                     }
776                 }
777             }
778             return null;
779         }
780
781         // Imports a node from another document to this document.
782         public virtual XmlNode ImportNode( XmlNode node, bool deep ) {
783             return ImportNodeInternal( node, deep );
784         }
785
786         private XmlNode ImportNodeInternal( XmlNode node, bool deep ) {
787             XmlNode newNode = null;
788
789             if ( node == null ) {
790                 throw new InvalidOperationException(  Res.GetString(Res.Xdom_Import_NullNode) );
791             }
792             else {
793                 switch ( node.NodeType ) {
794                     case XmlNodeType.Element:
795                         newNode = CreateElement( node.Prefix, node.LocalName, node.NamespaceURI );
796                         ImportAttributes( node, newNode );
797                         if ( deep )
798                             ImportChildren( node, newNode, deep );
799                         break;
800
801                     case XmlNodeType.Attribute:
802                         Debug.Assert( ((XmlAttribute)node).Specified );
803                         newNode = CreateAttribute( node.Prefix, node.LocalName, node.NamespaceURI );
804                         ImportChildren( node, newNode, true );
805                         break;
806
807                     case XmlNodeType.Text:
808                         newNode = CreateTextNode( node.Value );
809                         break;
810                     case XmlNodeType.Comment:
811                         newNode = CreateComment( node.Value);
812                         break;
813                     case XmlNodeType.ProcessingInstruction:
814                         newNode = CreateProcessingInstruction( node.Name, node.Value );
815                         break;
816                     case XmlNodeType.XmlDeclaration:
817                         XmlDeclaration decl = (XmlDeclaration) node;
818                         newNode = CreateXmlDeclaration( decl.Version, decl.Encoding, decl.Standalone );
819                         break;
820                     case XmlNodeType.CDATA:
821                         newNode = CreateCDataSection( node.Value );
822                         break;
823                     case XmlNodeType.DocumentType:
824                         XmlDocumentType docType = (XmlDocumentType)node;
825                         newNode = CreateDocumentType( docType.Name, docType.PublicId, docType.SystemId, docType.InternalSubset );
826                         break;
827                     case XmlNodeType.DocumentFragment:
828                         newNode = CreateDocumentFragment();
829                         if (deep)
830                             ImportChildren( node, newNode, deep );
831                         break;
832
833                     case XmlNodeType.EntityReference:
834                         newNode = CreateEntityReference( node.Name );
835                         // we don't import the children of entity reference because they might result in different
836                         // children nodes given different namesapce context in the new document.
837                         break;
838
839                     case XmlNodeType.Whitespace:
840                         newNode = CreateWhitespace( node.Value );
841                         break;
842
843                     case XmlNodeType.SignificantWhitespace:
844                         newNode = CreateSignificantWhitespace( node.Value );
845                         break;
846
847                     default:
848                         throw new InvalidOperationException( String.Format( CultureInfo.InvariantCulture, Res.GetString(Res.Xdom_Import), node.NodeType.ToString() ) );
849                 }
850             }
851
852             return newNode;
853         }
854
855         private void ImportAttributes( XmlNode fromElem, XmlNode toElem ) {
856             int cAttr = fromElem.Attributes.Count;
857             for ( int iAttr = 0; iAttr < cAttr; iAttr++ ) {
858                 if ( fromElem.Attributes[iAttr].Specified )
859                     toElem.Attributes.SetNamedItem( ImportNodeInternal( fromElem.Attributes[iAttr], true ) );
860             }
861         }
862
863         private void ImportChildren( XmlNode fromNode, XmlNode toNode, bool deep ) {
864             Debug.Assert( toNode.NodeType != XmlNodeType.EntityReference );
865             for ( XmlNode n = fromNode.FirstChild; n != null; n = n.NextSibling ) {
866                 toNode.AppendChild( ImportNodeInternal( n, deep ) );
867             }
868         }
869
870         // Microsoft extensions
871          
872         // Gets the XmlNameTable associated with this
873         // implementation.
874         public XmlNameTable NameTable
875         {
876             get { return implementation.NameTable; }
877         }
878
879         // Creates a XmlAttribute with the specified Prefix, LocalName,
880         // and NamespaceURI.
881         public virtual XmlAttribute CreateAttribute( string prefix, string localName, string namespaceURI ) {
882             return new XmlAttribute( AddAttrXmlName( prefix, localName, namespaceURI, null ), this );
883         }
884
885         protected internal virtual XmlAttribute CreateDefaultAttribute( string prefix, string localName, string namespaceURI ) {
886             return new XmlUnspecifiedAttribute( prefix, localName, namespaceURI, this );
887         }
888
889         public virtual XmlElement CreateElement( string prefix, string localName, string namespaceURI) {
890             XmlElement elem = new XmlElement( AddXmlName( prefix, localName, namespaceURI, null ), true, this );
891             if ( !IsLoading )
892                 AddDefaultAttributes( elem );
893             return elem;
894         }
895
896         // Gets or sets a value indicating whether to preserve whitespace.
897         public bool PreserveWhitespace {
898             get { return preserveWhitespace;}
899             set { preserveWhitespace = value;}
900         }
901
902         // Gets a value indicating whether the node is read-only.
903         public override bool IsReadOnly {
904             get { return false;}
905         }
906
907         internal XmlNamedNodeMap Entities {
908             get {
909                 if ( entities == null )
910                     entities = new XmlNamedNodeMap( this );
911                 return entities;
912             }
913             set { entities = value; }
914         }
915
916         internal bool IsLoading {
917             get { return isLoading;}
918             set { isLoading = value; }
919         }
920
921         internal bool ActualLoadingStatus{
922             get { return actualLoadingStatus;}
923             set { actualLoadingStatus = value; }
924         }
925
926
927         // Creates a XmlNode with the specified XmlNodeType, Prefix, Name, and NamespaceURI.
928         public virtual XmlNode CreateNode( XmlNodeType type, string prefix, string name, string namespaceURI ) {
929             switch (type) {
930                 case XmlNodeType.Element:
931                     if (prefix != null)
932                         return CreateElement( prefix, name, namespaceURI );
933                     else
934                         return CreateElement( name, namespaceURI );
935
936                 case XmlNodeType.Attribute:
937                     if (prefix != null)
938                         return CreateAttribute( prefix, name, namespaceURI );
939                     else
940                         return CreateAttribute( name, namespaceURI );
941
942                 case XmlNodeType.Text:
943                     return CreateTextNode( string.Empty );
944
945                 case XmlNodeType.CDATA:
946                     return CreateCDataSection( string.Empty );
947
948                 case XmlNodeType.EntityReference:
949                     return CreateEntityReference( name );
950
951                 case XmlNodeType.ProcessingInstruction:
952                     return CreateProcessingInstruction( name, string.Empty );
953
954                 case XmlNodeType.XmlDeclaration:
955                     return CreateXmlDeclaration( "1.0", null, null );
956
957                 case XmlNodeType.Comment:
958                     return CreateComment( string.Empty );
959
960                 case XmlNodeType.DocumentFragment:
961                     return CreateDocumentFragment();
962
963                 case XmlNodeType.DocumentType:
964                     return CreateDocumentType( name, string.Empty, string.Empty, string.Empty );
965
966                 case XmlNodeType.Document:
967                     return new XmlDocument();
968
969                 case XmlNodeType.SignificantWhitespace:
970                     return CreateSignificantWhitespace( string.Empty );
971
972                 case XmlNodeType.Whitespace:
973                     return CreateWhitespace( string.Empty );
974
975                 default:
976                     throw new ArgumentException( Res.GetString( Res.Arg_CannotCreateNode, type ) );
977             }
978         }
979
980         // Creates an XmlNode with the specified node type, Name, and
981         // NamespaceURI.
982         public virtual XmlNode CreateNode( string nodeTypeString, string name, string namespaceURI ) {
983             return CreateNode( ConvertToNodeType( nodeTypeString ), name, namespaceURI );
984         }
985
986         // Creates an XmlNode with the specified XmlNodeType, Name, and
987         // NamespaceURI.
988         public virtual XmlNode CreateNode( XmlNodeType type, string name, string namespaceURI ) {
989             return CreateNode( type, null, name, namespaceURI );
990         }
991
992         // Creates an XmlNode object based on the information in the XmlReader.
993         // The reader must be positioned on a node or attribute.
994         [PermissionSetAttribute( SecurityAction.InheritanceDemand, Name = "FullTrust" )]
995         public virtual XmlNode ReadNode( XmlReader reader ) {
996             XmlNode node = null;
997             try {
998                 IsLoading = true;
999                 XmlLoader loader = new XmlLoader();
1000                 node = loader.ReadCurrentNode( this, reader );
1001             }
1002             finally {
1003                 IsLoading = false;
1004             }
1005             return node;
1006         }
1007
1008         internal XmlNodeType ConvertToNodeType( string nodeTypeString ) {
1009             if ( nodeTypeString == "element" ) {
1010                 return XmlNodeType.Element;
1011             }
1012             else if ( nodeTypeString == "attribute" ) {
1013                 return XmlNodeType.Attribute;
1014             }
1015             else if ( nodeTypeString == "text" ) {
1016                 return XmlNodeType.Text;
1017             }
1018             else if ( nodeTypeString == "cdatasection" ) {
1019                 return XmlNodeType.CDATA;
1020             }
1021             else if ( nodeTypeString == "entityreference" ) {
1022                 return XmlNodeType.EntityReference;
1023             }
1024             else if ( nodeTypeString == "entity" ) {
1025                 return XmlNodeType.Entity;
1026             }
1027             else if ( nodeTypeString == "processinginstruction" ) {
1028                 return XmlNodeType.ProcessingInstruction;
1029             }
1030             else if ( nodeTypeString == "comment" ) {
1031                 return XmlNodeType.Comment;
1032             }
1033             else if ( nodeTypeString == "document" ) {
1034                 return XmlNodeType.Document;
1035             }
1036             else if ( nodeTypeString == "documenttype" ) {
1037                 return XmlNodeType.DocumentType;
1038             }
1039             else if ( nodeTypeString == "documentfragment" ) {
1040                 return XmlNodeType.DocumentFragment;
1041             }
1042             else if ( nodeTypeString == "notation" ) {
1043                 return XmlNodeType.Notation;
1044             }
1045             else if ( nodeTypeString == "significantwhitespace" ) {
1046                 return XmlNodeType.SignificantWhitespace;
1047             }
1048             else if ( nodeTypeString == "whitespace" ) {
1049                 return XmlNodeType.Whitespace;
1050             }
1051             throw new ArgumentException( Res.GetString( Res.Xdom_Invalid_NT_String, nodeTypeString ) );
1052         }
1053
1054
1055         private XmlTextReader SetupReader( XmlTextReader tr ) {
1056             tr.XmlValidatingReaderCompatibilityMode = true;
1057             tr.EntityHandling = EntityHandling.ExpandCharEntities;
1058             if ( this.HasSetResolver )
1059                 tr.XmlResolver = GetResolver();
1060             return tr;
1061         }
1062
1063         // Loads the XML document from the specified URL.
1064         [ResourceConsumption(ResourceScope.Machine)]
1065         [ResourceExposure(ResourceScope.Machine)]
1066         public virtual void Load( string filename ) {
1067             XmlTextReader reader = SetupReader( new XmlTextReader( filename, NameTable ) );
1068             try {
1069                 Load( reader );
1070             }
1071             finally {
1072                 reader.Close();
1073             }
1074         }
1075
1076         public virtual void Load( Stream inStream ) {
1077             XmlTextReader reader = SetupReader( new XmlTextReader( inStream, NameTable ) );
1078             try {
1079                 Load( reader );
1080             }
1081             finally {
1082                 reader.Impl.Close( false );
1083             }
1084         }
1085
1086         // Loads the XML document from the specified TextReader.
1087         public virtual void Load( TextReader txtReader ) {
1088             XmlTextReader reader = SetupReader( new XmlTextReader( txtReader, NameTable ) );
1089             try {
1090                 Load( reader );
1091             }
1092             finally {
1093                 reader.Impl.Close( false );
1094             }
1095         }
1096
1097         // Loads the XML document from the specified XmlReader.
1098         public virtual void Load( XmlReader reader ) {
1099             try {
1100                 IsLoading = true;
1101                 actualLoadingStatus = true;
1102                 RemoveAll();
1103                 fEntRefNodesPresent = false;
1104                 fCDataNodesPresent  = false;
1105                 reportValidity = true;
1106
1107                 XmlLoader loader = new XmlLoader();
1108                 loader.Load( this, reader, preserveWhitespace );
1109             }
1110             finally {
1111                 IsLoading = false;
1112                 actualLoadingStatus = false;
1113
1114                 // Ensure the bit is still on after loading a dtd 
1115                 reportValidity = true;
1116             }
1117         }
1118
1119         // Loads the XML document from the specified string.
1120         public virtual void LoadXml( string xml ) {
1121             XmlTextReader reader = SetupReader( new XmlTextReader( new StringReader( xml ), NameTable ));
1122             try {
1123                 Load( reader );
1124             }
1125             finally {
1126                 reader.Close();
1127             }
1128         }
1129
1130         //TextEncoding is the one from XmlDeclaration if there is any
1131         internal Encoding TextEncoding {
1132             get {
1133                 if ( Declaration != null )
1134                 {
1135                     string value = Declaration.Encoding;
1136                     if ( value.Length > 0 ) {
1137                         return System.Text.Encoding.GetEncoding( value );
1138                     }
1139                 }
1140                 return null;
1141             }
1142         }
1143
1144         public override string InnerText {
1145             set {
1146                 throw new InvalidOperationException(Res.GetString(Res.Xdom_Document_Innertext));
1147             }
1148         }
1149
1150         public override string InnerXml {
1151             get {
1152                 return base.InnerXml;
1153             }
1154             set {
1155                 LoadXml( value );
1156             }
1157         }
1158
1159         // Saves the XML document to the specified file.
1160         //Saves out the to the file with exact content in the XmlDocument.
1161         [ResourceConsumption(ResourceScope.Machine)]
1162         [ResourceExposure(ResourceScope.Machine)]
1163         public virtual void Save( string filename ) {
1164             if ( DocumentElement == null )
1165                 throw new XmlException( Res.Xml_InvalidXmlDocument, Res.GetString( Res.Xdom_NoRootEle ) );
1166             XmlDOMTextWriter xw = new XmlDOMTextWriter( filename, TextEncoding );
1167             try {
1168                 if ( preserveWhitespace == false )
1169                     xw.Formatting = Formatting.Indented;
1170                  WriteTo( xw );
1171                  xw.Flush();
1172             }
1173             finally {
1174                 xw.Close();
1175             }
1176         }
1177
1178         //Saves out the to the file with exact content in the XmlDocument.
1179         public virtual void Save( Stream outStream ) {
1180             XmlDOMTextWriter xw = new XmlDOMTextWriter( outStream, TextEncoding );
1181             if ( preserveWhitespace == false )
1182                 xw.Formatting = Formatting.Indented;
1183             WriteTo( xw );
1184             xw.Flush();
1185         }
1186
1187         // Saves the XML document to the specified TextWriter.
1188         //
1189         //Saves out the file with xmldeclaration which has encoding value equal to
1190         //that of textwriter's encoding
1191         public virtual void Save( TextWriter writer ) {
1192             XmlDOMTextWriter xw = new XmlDOMTextWriter( writer );
1193             if ( preserveWhitespace == false )
1194                     xw.Formatting = Formatting.Indented;
1195             Save( xw );
1196         }
1197
1198         // Saves the XML document to the specified XmlWriter.
1199         // 
1200         //Saves out the file with xmldeclaration which has encoding value equal to
1201         //that of textwriter's encoding
1202         public virtual void Save( XmlWriter w ) {
1203             XmlNode n = this.FirstChild;
1204             if( n == null )
1205                 return;
1206             if( w.WriteState == WriteState.Start ) {
1207                 if( n is XmlDeclaration ) {
1208                     if( Standalone.Length == 0 )
1209                         w.WriteStartDocument();
1210                     else if( Standalone == "yes" )
1211                         w.WriteStartDocument( true );
1212                     else if( Standalone == "no" )
1213                         w.WriteStartDocument( false );
1214                     n = n.NextSibling;
1215                 }
1216                 else {
1217                     w.WriteStartDocument();
1218                 }
1219             }
1220             while( n != null ) {
1221                 //Debug.Assert( n.NodeType != XmlNodeType.XmlDeclaration );
1222                 n.WriteTo( w );
1223                 n = n.NextSibling;
1224             }
1225             w.Flush();
1226         }
1227
1228         // Saves the node to the specified XmlWriter.
1229         // 
1230         //Writes out the to the file with exact content in the XmlDocument.
1231         public override void WriteTo( XmlWriter w ) {
1232             WriteContentTo( w );
1233         }
1234
1235         // Saves all the children of the node to the specified XmlWriter.
1236         // 
1237         //Writes out the to the file with exact content in the XmlDocument.
1238         public override void WriteContentTo( XmlWriter xw ) {
1239             foreach( XmlNode n in this ) {
1240                 n.WriteTo( xw );
1241             }
1242         }
1243
1244         public void Validate(ValidationEventHandler validationEventHandler) {
1245             Validate(validationEventHandler, this);
1246         }
1247
1248         public void Validate(ValidationEventHandler validationEventHandler, XmlNode nodeToValidate) {
1249             if (this.schemas == null || this.schemas.Count == 0) { //Should we error
1250                 throw new InvalidOperationException(Res.GetString(Res.XmlDocument_NoSchemaInfo));
1251             }
1252             XmlDocument parentDocument = nodeToValidate.Document;
1253             if (parentDocument != this) {
1254                 throw new ArgumentException(Res.GetString(Res.XmlDocument_NodeNotFromDocument, "nodeToValidate"));
1255             }
1256             if (nodeToValidate == this) {
1257                 reportValidity = false;
1258             }
1259             DocumentSchemaValidator validator = new DocumentSchemaValidator(this, schemas, validationEventHandler);
1260             validator.Validate(nodeToValidate);
1261             if (nodeToValidate == this) {
1262                 reportValidity = true;
1263             }
1264         }
1265
1266         public event XmlNodeChangedEventHandler NodeInserting {
1267             add {
1268                 onNodeInsertingDelegate += value;
1269             }
1270             remove {
1271                 onNodeInsertingDelegate -= value;
1272             }
1273         }
1274
1275         public event XmlNodeChangedEventHandler NodeInserted {
1276             add {
1277                 onNodeInsertedDelegate += value;
1278             }
1279             remove {
1280                 onNodeInsertedDelegate -= value;
1281             }
1282         }
1283
1284         public event XmlNodeChangedEventHandler NodeRemoving {
1285             add {
1286                 onNodeRemovingDelegate += value;
1287             }
1288             remove {
1289                 onNodeRemovingDelegate -= value;
1290             }
1291         }
1292
1293         public event XmlNodeChangedEventHandler NodeRemoved {
1294             add {
1295                 onNodeRemovedDelegate += value;
1296             }
1297             remove {
1298                 onNodeRemovedDelegate -= value;
1299             }
1300         }
1301
1302         public event XmlNodeChangedEventHandler NodeChanging {
1303             add {
1304                 onNodeChangingDelegate += value;
1305             }
1306             remove {
1307                 onNodeChangingDelegate -= value;
1308             }
1309         }
1310
1311         public event XmlNodeChangedEventHandler NodeChanged {
1312             add {
1313                 onNodeChangedDelegate += value;
1314             }
1315             remove {
1316                 onNodeChangedDelegate -= value;
1317             }
1318         }
1319
1320         internal override XmlNodeChangedEventArgs GetEventArgs(XmlNode node, XmlNode oldParent, XmlNode newParent, string oldValue, string newValue, XmlNodeChangedAction action) {
1321             reportValidity = false;
1322
1323             switch (action) {
1324                 case XmlNodeChangedAction.Insert:
1325                     if (onNodeInsertingDelegate == null && onNodeInsertedDelegate == null) {
1326                         return null;
1327                     }
1328                     break;
1329                 case XmlNodeChangedAction.Remove:
1330                     if (onNodeRemovingDelegate == null && onNodeRemovedDelegate == null) {
1331                         return null;
1332                     }
1333                     break;
1334                 case XmlNodeChangedAction.Change:
1335                     if (onNodeChangingDelegate == null && onNodeChangedDelegate == null) {
1336                         return null;
1337                     }
1338                     break;
1339             }
1340             return new XmlNodeChangedEventArgs( node, oldParent, newParent, oldValue, newValue, action );
1341         }
1342
1343         internal XmlNodeChangedEventArgs GetInsertEventArgsForLoad( XmlNode node, XmlNode newParent ) {
1344             if (onNodeInsertingDelegate == null && onNodeInsertedDelegate == null) {
1345                 return null;
1346             }
1347             string nodeValue = node.Value;
1348             return new XmlNodeChangedEventArgs(node, null, newParent, nodeValue, nodeValue, XmlNodeChangedAction.Insert);
1349         }
1350
1351         internal override void BeforeEvent( XmlNodeChangedEventArgs args ) {
1352             if ( args != null ) {
1353                 switch ( args.Action ) {
1354                     case XmlNodeChangedAction.Insert:
1355                         if ( onNodeInsertingDelegate != null )
1356                             onNodeInsertingDelegate( this, args );
1357                         break;
1358
1359                     case XmlNodeChangedAction.Remove:
1360                         if ( onNodeRemovingDelegate != null )
1361                             onNodeRemovingDelegate( this, args );
1362                         break;
1363
1364                     case XmlNodeChangedAction.Change:
1365                         if ( onNodeChangingDelegate != null )
1366                             onNodeChangingDelegate( this, args );
1367                         break;
1368                 }
1369             }
1370         }
1371
1372         internal override void AfterEvent( XmlNodeChangedEventArgs args ) {
1373             if ( args != null ) {
1374                 switch ( args.Action ) {
1375                     case XmlNodeChangedAction.Insert:
1376                         if ( onNodeInsertedDelegate != null )
1377                             onNodeInsertedDelegate( this, args );
1378                         break;
1379
1380                     case XmlNodeChangedAction.Remove:
1381                         if ( onNodeRemovedDelegate != null )
1382                             onNodeRemovedDelegate( this, args );
1383                         break;
1384
1385                     case XmlNodeChangedAction.Change:
1386                         if ( onNodeChangedDelegate != null )
1387                             onNodeChangedDelegate( this, args );
1388                         break;
1389                 }
1390             }
1391         }
1392
1393         // The function such through schema info to find out if there exists a default attribute with passed in names in the passed in element
1394         // If so, return the newly created default attribute (with children tree);
1395         // Otherwise, return null.
1396
1397         internal XmlAttribute GetDefaultAttribute( XmlElement elem, string attrPrefix, string attrLocalname, string attrNamespaceURI ) {
1398             SchemaInfo schInfo = DtdSchemaInfo;
1399             SchemaElementDecl ed = GetSchemaElementDecl( elem );
1400             if ( ed != null && ed.AttDefs != null ) {
1401                 IDictionaryEnumerator attrDefs = ed.AttDefs.GetEnumerator();
1402                 while ( attrDefs.MoveNext() ) {
1403                     SchemaAttDef attdef = (SchemaAttDef)attrDefs.Value;
1404                     if ( attdef.Presence == SchemaDeclBase.Use.Default ||
1405                         attdef.Presence == SchemaDeclBase.Use.Fixed ) {
1406                         if ( attdef.Name.Name == attrLocalname ) {
1407                             if ( ( schInfo.SchemaType == SchemaType.DTD && attdef.Name.Namespace == attrPrefix ) ||
1408                                  ( schInfo.SchemaType != SchemaType.DTD && attdef.Name.Namespace == attrNamespaceURI ) ) {
1409                                  //find a def attribute with the same name, build a default attribute and return
1410                                  XmlAttribute defattr = PrepareDefaultAttribute( attdef, attrPrefix, attrLocalname, attrNamespaceURI );
1411                                  return defattr;
1412                             }
1413                         }
1414                     }
1415                 }
1416             }
1417             return null;
1418         }
1419
1420         internal String Version {
1421             get {
1422                 XmlDeclaration decl = Declaration;
1423                 if ( decl != null )
1424                     return decl.Version;
1425                 return null;
1426             }
1427         }
1428
1429         internal String Encoding {
1430             get {
1431                 XmlDeclaration decl = Declaration;
1432                 if ( decl != null )
1433                     return decl.Encoding;
1434                 return null;
1435             }
1436         }
1437
1438         internal String Standalone {
1439             get {
1440                 XmlDeclaration decl = Declaration;
1441                 if ( decl != null )
1442                     return decl.Standalone;
1443                 return null;
1444             }
1445         }
1446
1447         internal XmlEntity GetEntityNode( String name ) {
1448             if ( DocumentType != null ) {
1449                 XmlNamedNodeMap entites = DocumentType.Entities;
1450                 if ( entites != null )
1451                     return (XmlEntity)(entites.GetNamedItem( name ));
1452             }
1453             return null;
1454         }
1455
1456         public override IXmlSchemaInfo SchemaInfo {
1457             get {
1458                 if (reportValidity) {
1459                     XmlElement documentElement = DocumentElement;
1460                     if (documentElement != null) {
1461                         switch (documentElement.SchemaInfo.Validity) {
1462                             case XmlSchemaValidity.Valid:
1463                                 return ValidSchemaInfo;
1464                             case XmlSchemaValidity.Invalid:
1465                                 return InvalidSchemaInfo;
1466                         }
1467                     }
1468                 }
1469                 return NotKnownSchemaInfo;
1470             }
1471         }
1472
1473         public override String BaseURI {
1474             get { return baseURI; }
1475         }
1476
1477         internal void SetBaseURI( String inBaseURI ) {
1478             baseURI = inBaseURI;
1479         }
1480
1481         internal override XmlNode AppendChildForLoad( XmlNode newChild, XmlDocument doc ) {
1482             Debug.Assert( doc == this );
1483
1484             if ( !IsValidChildType( newChild.NodeType ))
1485                 throw new InvalidOperationException( Res.GetString(Res.Xdom_Node_Insert_TypeConflict) );
1486
1487             if ( !CanInsertAfter( newChild, LastChild ) )
1488                 throw new InvalidOperationException( Res.GetString(Res.Xdom_Node_Insert_Location) );
1489
1490             XmlNodeChangedEventArgs args = GetInsertEventArgsForLoad( newChild, this );
1491
1492             if ( args != null )
1493                 BeforeEvent( args );
1494
1495             XmlLinkedNode newNode = (XmlLinkedNode) newChild;
1496
1497             if ( lastChild == null ) {
1498                 newNode.next = newNode;
1499             }
1500             else {
1501                 newNode.next = lastChild.next;
1502                 lastChild.next = newNode;
1503             }
1504
1505             lastChild = newNode;
1506             newNode.SetParentForLoad( this );
1507
1508             if ( args != null )
1509                 AfterEvent( args );
1510
1511             return newNode;
1512         }
1513
1514         internal override XPathNodeType XPNodeType { get { return XPathNodeType.Root; } }
1515
1516         internal bool HasEntityReferences {
1517             get {
1518                 return fEntRefNodesPresent;
1519             }
1520         }
1521
1522         internal XmlAttribute NamespaceXml {  
1523             get {
1524                 if (namespaceXml == null) {
1525                     namespaceXml = new XmlAttribute(AddAttrXmlName(strXmlns, strXml, strReservedXmlns, null), this);
1526                     namespaceXml.Value = strReservedXml;
1527                 }
1528                 return namespaceXml;
1529             }
1530         }
1531     }
1532 }