2005-12-05 Lluis Sanchez Gual <lluis@novell.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlDocumentNavigator.cs
1 //
2 // System.Xml.XmlDocumentNavigator
3 //
4 // Authors:
5 //   Jason Diamond <jason@injektilo.org>
6 //   Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
7 //
8 // (C) 2002 Jason Diamond
9 // (C) 2003 Atsushi Enomoto
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Xml;
36 using System.Xml.XPath;
37
38 namespace System.Xml
39 {
40         internal class XmlDocumentNavigator : XPathNavigator, IHasXmlNode
41         {
42                 #region Constructors
43
44                 internal XmlDocumentNavigator (XmlNode node)
45                         : this (node, null)
46                 {
47                         nsNodeXml = document.CreateAttribute ("xmlns", "xml", Xmlns);
48                         nsNodeXml.Value = XmlnsXML;
49                         if (node.NodeType == XmlNodeType.Attribute && node.NamespaceURI == XmlNamespaceManager.XmlnsXmlns) {
50                                 nsNode = (XmlAttribute) node; 
51                                 node = nsNode.OwnerElement;
52                         }
53                 }
54
55                 private XmlDocumentNavigator (XmlNode node, XmlAttribute nsNodeXml)
56                 {
57                         this.node = node;
58                         this.document = node.NodeType == XmlNodeType.Document ?
59                                 node as XmlDocument : node.OwnerDocument;
60                         this.nsNodeXml = nsNodeXml;
61                 }
62
63                 #endregion
64
65                 #region Fields
66                 private const string Xmlns = "http://www.w3.org/2000/xmlns/";
67                 private const string XmlnsXML = "http://www.w3.org/XML/1998/namespace";
68
69                 private XmlAttribute nsNodeXml;
70                 private XmlNode node;
71                 private XmlDocument document;
72                 // Current namespace node (ancestor's attribute of current node).
73                 private XmlAttribute nsNode;
74                 private ArrayList iteratedNsNames;
75                 #endregion
76
77                 #region Properties
78
79                 public override string BaseURI {
80                         get {
81                                 return node.BaseURI;
82                         }
83                 }
84
85                 public override bool HasAttributes {
86                         get {
87                                 if (NsNode != null)
88                                         return false;
89
90                                 if (node.Attributes != null)
91                                         for (int i = 0; i < node.Attributes.Count; i++)
92                                                 if (node.Attributes [i].NamespaceURI != Xmlns)
93                                                         return true;
94                                 return false;
95                         }
96                 }
97
98                 public override bool HasChildren {
99                         get {
100                                 if (NsNode != null)
101                                         return false;
102
103                                 XPathNodeType nodeType = NodeType;
104                                 bool canHaveChildren = nodeType == XPathNodeType.Root || nodeType == XPathNodeType.Element;
105                                 return canHaveChildren && GetFirstChild (node) != null;
106                         }
107                 }
108
109                 public override bool IsEmptyElement {
110                         get {
111                                 if (NsNode != null)
112                                         return false;
113
114                                 return node.NodeType == XmlNodeType.Element 
115                                         && ((XmlElement) node).IsEmpty;
116                         }
117                 }
118
119                 public XmlAttribute NsNode {
120                         get { return nsNode; }
121                         set {
122                                 if (value == null)
123                                         iteratedNsNames = null;
124                                 else
125                                 {
126                                         if (iteratedNsNames == null)
127                                                 iteratedNsNames = new ArrayList();
128                                         else
129                                         {
130                                                 if (iteratedNsNames.IsReadOnly)
131                                                         iteratedNsNames = new ArrayList(iteratedNsNames);
132                                         }
133                                         iteratedNsNames.Add (value.Name);
134                                 }
135                                 nsNode = value;
136                         }
137                 }
138
139                 public override string LocalName {
140                         get {
141                                 XmlAttribute nsNode = NsNode;
142                                 if (nsNode != null) {
143                                         if (nsNode == nsNodeXml)
144                                                 return "xml";
145                                         else
146                                                 return (nsNode.Name == "xmlns") ? String.Empty : nsNode.LocalName;
147                                 }
148
149                                 XPathNodeType nodeType = NodeType;
150                                 bool canHaveName = 
151                                         nodeType == XPathNodeType.Element || 
152                                         nodeType == XPathNodeType.Attribute || 
153                                         nodeType == XPathNodeType.ProcessingInstruction ||
154                                         nodeType == XPathNodeType.Namespace;
155                                 return canHaveName ? node.LocalName : String.Empty;
156                         }
157                 }
158
159                 public override string Name {
160                         get {
161                                 if (NsNode != null)
162                                         return LocalName;
163
164                                 XPathNodeType nodeType = NodeType;
165                                 bool canHaveName = 
166                                         nodeType == XPathNodeType.Element || 
167                                         nodeType == XPathNodeType.Attribute || 
168                                         nodeType == XPathNodeType.ProcessingInstruction ||
169                                         nodeType == XPathNodeType.Namespace;
170                                 return canHaveName ? node.Name : String.Empty;
171                         }
172                 }
173
174                 public override string NamespaceURI {
175                         get { return (NsNode != null) ? String.Empty : node.NamespaceURI; }
176                 }
177
178                 public override XmlNameTable NameTable {
179                         get {
180                                 return document.NameTable;
181                         }
182                 }
183
184                 public override XPathNodeType NodeType {
185                         get {
186                                 if (NsNode != null)
187                                         return XPathNodeType.Namespace;
188                                 XmlNode n = node;
189                                 bool sw = false;
190                                 do {
191                                         switch (n.NodeType) {
192                                         case XmlNodeType.SignificantWhitespace:
193                                                 sw = true;
194                                                 n = GetNextSibling (n);
195                                                 break;
196                                         case XmlNodeType.Whitespace:
197                                                 n = GetNextSibling (n);
198                                                 break;
199                                         case XmlNodeType.Text:
200                                         case XmlNodeType.CDATA:
201                                                 return XPathNodeType.Text;
202                                         default:
203                                                 n = null;
204                                                 break;
205                                         }
206                                 } while (n != null);
207                                 return sw ?
208                                         XPathNodeType.SignificantWhitespace :
209                                         node.XPathNodeType;
210                         }
211                 }
212
213                 public override string Prefix {
214                         get { return (NsNode != null) ? String.Empty : node.Prefix; }
215                 }
216
217                 public override string Value {
218                         get {
219                                 switch (NodeType) {
220                                 case XPathNodeType.Attribute:
221                                 case XPathNodeType.Comment:
222                                 case XPathNodeType.ProcessingInstruction:
223                                         return node.Value;
224                                 case XPathNodeType.Text:
225                                 case XPathNodeType.Whitespace:
226                                 case XPathNodeType.SignificantWhitespace:
227                                         string value = node.Value;
228                                         for (XmlNode n = GetNextSibling (node); n != null; n = GetNextSibling (n)) {
229                                                 switch (n.XPathNodeType) {
230                                                 case XPathNodeType.Text:
231                                                 case XPathNodeType.Whitespace:
232                                                 case XPathNodeType.SignificantWhitespace:
233                                                         value += n.Value;
234                                                         continue;
235                                                 }
236                                                 break;
237                                         }
238                                         return value;
239                                 case XPathNodeType.Element:
240                                 case XPathNodeType.Root:
241                                         return node.InnerText;
242                                 case XPathNodeType.Namespace:
243                                         return NsNode == nsNodeXml ? XmlnsXML : NsNode.Value;
244                                 }
245                                 return String.Empty;
246                         }
247                 }
248
249                 public override string XmlLang {
250                         get {
251                                 return node.XmlLang;
252                         }
253                 }
254
255                 #endregion
256
257                 #region Methods
258
259                 private bool CheckNsNameAppearance (string name, string ns)
260                 {
261                         if (iteratedNsNames != null && iteratedNsNames.Contains (name))
262                                 return true;
263                         // default namespace erasure - just add name and never return this node
264                         if (ns == String.Empty) {
265                                 if (iteratedNsNames == null)
266                                         iteratedNsNames = new ArrayList();
267                                 else
268                                 {
269                                         if (iteratedNsNames.IsReadOnly)
270                                                 iteratedNsNames = new ArrayList(iteratedNsNames);
271                                 }
272                                 iteratedNsNames.Add ("xmlns");
273                                 return true;
274                         }
275
276                         return false;
277                 }
278
279                 public override XPathNavigator Clone ()
280                 {
281                         XmlDocumentNavigator clone = new XmlDocumentNavigator (node, nsNodeXml);
282                         clone.nsNode = nsNode;
283                         clone.iteratedNsNames = (iteratedNsNames == null || iteratedNsNames.IsReadOnly) ? iteratedNsNames : ArrayList.ReadOnly(iteratedNsNames);
284                         return clone;
285                 }
286
287                 public override string GetAttribute (string localName, string namespaceURI)
288                 {
289                         if (HasAttributes) {
290                                 XmlElement el = Node as XmlElement;
291                                 return el != null ? el.GetAttribute (localName, namespaceURI) : String.Empty;
292                         }
293                         return String.Empty;
294                 }
295
296                 public override string GetNamespace (string name)
297                 {
298                         // MSDN says "String.Empty if a matching namespace 
299                         // node is not found or if the navigator is not 
300                         // positioned on an element node", but in fact it
301                         // returns actual namespace for the other nodes.
302                         return Node.GetNamespaceOfPrefix (name);
303                 }
304
305                 public override bool IsDescendant (XPathNavigator other)
306                 {
307                         if (NsNode != null)
308                                 return false;
309                         XmlDocumentNavigator o = other as XmlDocumentNavigator;
310                         if (o == null)
311                                 return false;
312                         XmlNode n =
313                                 o.node.NodeType == XmlNodeType.Attribute ?
314                                 ((XmlAttribute) o.node).OwnerElement :
315                                 o.node.ParentNode;
316                         for (;n != null; n = n.ParentNode)
317                                 if (n == node)
318                                         return true;
319                         return false;
320                 }
321
322                 public override bool IsSamePosition (XPathNavigator other)
323                 {
324                         XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
325                         if (otherDocumentNavigator != null)
326                                 return node == otherDocumentNavigator.node
327                                         && NsNode == otherDocumentNavigator.NsNode;
328                         return false;
329                 }
330
331                 public override bool MoveTo (XPathNavigator other)
332                 {
333                         XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
334                         if (otherDocumentNavigator != null) {
335                                 if (document == otherDocumentNavigator.document) {
336                                         node = otherDocumentNavigator.node;
337                                         NsNode = otherDocumentNavigator.NsNode;
338                                         return true;
339                                 }
340                         }
341                         return false;
342                 }
343
344                 public override bool MoveToAttribute (string localName, string namespaceURI)
345                 {
346                         if (node.Attributes != null) {
347                                 for (int i = 0; i < node.Attributes.Count; i++) {
348                                         XmlAttribute attr = node.Attributes [i];
349                                         if (attr.LocalName == localName
350                                                 && attr.NamespaceURI == namespaceURI) {
351                                                 node = attr;
352                                                 NsNode = null;
353                                                 return true;
354                                         }
355                                 }
356                         }
357                         return false;
358                 }
359
360 #if NET_2_0
361 #else
362                 public override bool MoveToFirst ()
363                 {
364                         return MoveToFirstImpl ();
365                 }
366 #endif
367
368                 public override bool MoveToFirstAttribute ()
369                 {
370                         if (node.Attributes == null)
371                                 return false;
372                         if (NodeType == XPathNodeType.Element) {
373                                 for (int i = 0; i < node.Attributes.Count; i++) {
374                                         XmlAttribute attr = node.Attributes [i];
375                                         if (attr.NamespaceURI != Xmlns) {
376                                                 node = attr;
377                                                 NsNode = null;
378                                                 return true;
379                                         }
380                                 }
381                         }
382                         return false;
383                 }
384
385                 public override bool MoveToFirstChild ()
386                 {
387                         if (HasChildren) {
388                                 XmlNode n = GetFirstChild (node);
389                                 if (n == null)
390                                         return false;
391                                 node = n;
392                                 return true;
393                         }
394                         return false;
395                 }
396
397                 public override bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope)
398                 {
399                         if (NodeType != XPathNodeType.Element)
400                                 return false;
401                         XmlElement el = node as XmlElement;
402                         if (node.Attributes != null) {
403                                 do {
404                                         for (int i = 0; i < el.Attributes.Count; i++) {
405                                                 XmlAttribute attr = el.Attributes [i];
406                                                 if (attr.NamespaceURI == Xmlns) {
407                                                         if (CheckNsNameAppearance (attr.Name, attr.Value))
408                                                                 continue;
409                                                         NsNode = attr;
410                                                         return true;
411                                                 }
412                                         }
413                                         if (namespaceScope == XPathNamespaceScope.Local)
414                                                 return false;
415                                         el = GetParentNode (el) as XmlElement;
416                                 } while (el != null);
417                         }
418
419                         if (namespaceScope == XPathNamespaceScope.All) {
420                                 if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
421                                         return false;
422                                 NsNode = nsNodeXml;
423                                 return true;
424                         }
425                         else
426                                 return false;
427                 }
428
429                 public override bool MoveToId (string id)
430                 {
431                         XmlElement eltNew = document.GetElementById (id);
432                         if (eltNew == null)
433                                 return false;
434
435                         node = eltNew;
436                         return true;
437                 }
438
439                 public override bool MoveToNamespace (string name)
440                 {
441                         if (name == "xml") {
442                                 NsNode = nsNodeXml;
443                                 return true;
444                         }
445
446                         if (NodeType != XPathNodeType.Element)
447                                 return false;
448
449                         XmlElement el = node as XmlElement;
450                         if (node.Attributes != null) {
451                                 do {
452                                         for (int i = 0; i < el.Attributes.Count; i++) {
453                                                 XmlAttribute attr = el.Attributes [i];
454                                                 if (attr.NamespaceURI == Xmlns && attr.Name == name) {
455                                                         NsNode = attr;
456                                                         return true;
457                                                 }
458                                         }
459                                         el = GetParentNode (node) as XmlElement;
460                                 } while (el != null);
461                         }
462                         return false;
463                 }
464
465                 public override bool MoveToNext ()
466                 {
467                         if (NsNode != null)
468                                 return false;
469
470                         XmlNode n = node;
471                         if (NodeType == XPathNodeType.Text) {
472                                 do {
473                                         n = GetNextSibling (n);
474                                         if (n == null)
475                                                 return false;
476                                         switch (n.NodeType) {
477                                         case XmlNodeType.CDATA:
478                                         case XmlNodeType.SignificantWhitespace:
479                                         case XmlNodeType.Text:
480                                         case XmlNodeType.Whitespace:
481                                                 continue;
482                                         default:
483                                                 break;
484                                         }
485                                         break;
486                                 } while (true);
487                         }
488                         else
489                                 n = GetNextSibling (n);
490                         if (n == null)
491                                 return false;
492                         node = n;
493                         return true;
494                 }
495
496                 public override bool MoveToNextAttribute ()
497                 {
498                         if (node == null)
499                                 return false;
500                         if (NodeType != XPathNodeType.Attribute)
501                                 return false;
502
503                         // Find current attribute.
504                         int pos = 0;
505                         XmlElement owner = ((XmlAttribute) node).OwnerElement;
506                         if (owner == null)
507                                 return false;
508
509                         int count = owner.Attributes.Count;
510                         for(; pos < count; pos++)
511                                 if (owner.Attributes [pos] == node)
512                                         break;
513                         if (pos == count)
514                                 return false;   // Where is current attribute? Maybe removed.
515
516                         // Find next attribute.
517                         for(pos++; pos < count; pos++) {
518                                 if (owner.Attributes [pos].NamespaceURI != Xmlns) {
519                                         node = owner.Attributes [pos];
520                                         NsNode = null;
521                                         return true;
522                                 }
523                         }
524                         return false;
525                 }
526
527                 public override bool MoveToNextNamespace (XPathNamespaceScope namespaceScope)
528                 {
529                         if (NsNode == nsNodeXml)
530                                 // Current namespace is "xml", so there should be no more namespace nodes.
531                                 return false;
532
533                         if (NsNode == null)
534                                 return false;
535
536                         // Get current attribute's position.
537                         int pos = 0;
538                         XmlElement owner = ((XmlAttribute) NsNode).OwnerElement;
539                         if (owner == null)
540                                 return false;
541
542                         int count = owner.Attributes.Count;
543                         for(; pos < count; pos++)
544                                 if (owner.Attributes [pos] == NsNode)
545                                         break;
546                         if (pos == count)
547                                 return false;   // Where is current attribute? Maybe removed.
548
549                         // Find next namespace from the same element as current ns node.
550                         for(pos++; pos < count; pos++) {
551                                 if (owner.Attributes [pos].NamespaceURI == Xmlns) {
552                                         XmlAttribute a = owner.Attributes [pos];
553                                         if (CheckNsNameAppearance (a.Name, a.Value))
554                                                 continue;
555                                         NsNode = a;
556                                         return true;
557                                 }
558                         }
559
560                         // If not found more, then find from ancestors.
561                         // But if scope is Local, then it returns false here.
562                         if (namespaceScope == XPathNamespaceScope.Local)
563                                 return false;
564                         owner = GetParentNode (owner) as XmlElement;
565                         while (owner != null) {
566                                 for (int i = 0; i < owner.Attributes.Count; i++) {
567                                         XmlAttribute attr = owner.Attributes [i];
568                                         if (attr.NamespaceURI == Xmlns) {
569                                                 if (CheckNsNameAppearance (attr.Name, attr.Value))
570                                                         continue;
571                                                 NsNode = attr;
572                                                 return true;
573                                         }
574                                 }
575                                 owner = GetParentNode (owner) as XmlElement;
576                         }
577
578                         if (namespaceScope == XPathNamespaceScope.All) {
579                                 if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
580                                         return false;
581                                 NsNode = nsNodeXml;
582                                 return true;
583                         }
584                         return false;
585                 }
586
587                 public override bool MoveToParent ()
588                 {
589                         if (NsNode != null) {
590                                 NsNode = null;
591                                 return true;
592                         }
593                         else if (node.NodeType == XmlNodeType.Attribute) {
594                                 XmlElement ownerElement = ((XmlAttribute)node).OwnerElement;
595                                 if (ownerElement != null) {
596                                         node = ownerElement;
597                                         NsNode = null;
598                                         return true;
599                                 }
600                                 else
601                                         return false;
602                         }
603                         XmlNode n = GetParentNode (node);
604                         if (n == null)
605                                 return false;
606                         node = n;
607                         NsNode = null;
608                         return true;
609                 }
610
611                 public override bool MoveToPrevious ()
612                 {
613                         if (NsNode != null)
614                                 return false;
615
616                         XmlNode p = GetPreviousSibling (node);
617                         if (p == null)
618                                 return false;
619                         node = p;
620                         return true;
621                 }
622
623                 public override void MoveToRoot ()
624                 {
625                         XmlAttribute attr = node as XmlAttribute;
626                         XmlNode tmp = attr != null ? attr.OwnerElement : node;
627                         for (XmlNode tmp2 = GetParentNode (tmp); tmp2 != null; tmp2 = GetParentNode (tmp2))
628                                 tmp = tmp2;
629                         node = tmp;
630                         NsNode = null;
631                 }
632
633                 private XmlNode Node { get { return NsNode != null ? NsNode : node; } }
634
635                 XmlNode IHasXmlNode.GetNode ()
636                 {
637                         return Node;
638                 }
639
640                 private XmlNode GetFirstChild (XmlNode n)
641                 {
642                         if (n.FirstChild == null)
643                                 return null;
644                         switch (n.FirstChild.NodeType) {
645                         case XmlNodeType.XmlDeclaration:
646                         case XmlNodeType.DocumentType:
647                                 return GetNextSibling (n.FirstChild);
648                         case XmlNodeType.EntityReference:
649                                 foreach (XmlNode c in n.ChildNodes) {
650                                         if (c.NodeType == XmlNodeType.EntityReference) {
651                                                 XmlNode ec = GetFirstChild (c);
652                                                 if (ec != null)
653                                                         return ec;
654                                         }
655                                         return c;
656                                 }
657                                 return null;
658                         default:
659                                 return n.FirstChild;
660                         }
661                 }
662
663                 private XmlNode GetLastChild (XmlNode n)
664                 {
665                         if (n.LastChild == null)
666                                 return null;
667                         switch (n.LastChild.NodeType) {
668                         case XmlNodeType.XmlDeclaration:
669                         case XmlNodeType.DocumentType:
670                                 return GetPreviousSibling (n.LastChild);
671                         case XmlNodeType.EntityReference:
672                                 for (XmlNode c = n.LastChild; c != null; c = c.PreviousSibling) {
673                                         if (c.NodeType == XmlNodeType.EntityReference) {
674                                                 XmlNode ec = GetLastChild (c);
675                                                 if (ec != null)
676                                                         return ec;
677                                         }
678                                         return c;
679                                 }
680                                 return null;
681                         default:
682                                 return n.LastChild;
683                         }
684                 }
685
686                 private XmlNode GetPreviousSibling (XmlNode n)
687                 {
688                         if (n.PreviousSibling != null) {
689                                 switch (n.PreviousSibling.NodeType) {
690                                 case XmlNodeType.EntityReference:
691                                         XmlNode c = GetLastChild (n.PreviousSibling);
692                                         if (c != null)
693                                                 return c;
694                                         else // empty entity reference etc.
695                                                 return GetPreviousSibling (n.PreviousSibling);
696                                 case XmlNodeType.XmlDeclaration:
697                                 case XmlNodeType.DocumentType:
698                                         return GetPreviousSibling (n.PreviousSibling);
699                                 default:
700                                         return n.PreviousSibling;
701                                 }
702                         } else {
703                                 if (n.ParentNode == null || n.ParentNode.NodeType != XmlNodeType.EntityReference)
704                                         return null;
705                                 return GetPreviousSibling (n.ParentNode);
706                         }
707                 }
708
709                 private XmlNode GetNextSibling (XmlNode n)
710                 {
711                         if (n.NextSibling != null) {
712                                 switch (n.NextSibling.NodeType) {
713                                 case XmlNodeType.EntityReference:
714                                         XmlNode c = GetFirstChild (n.NextSibling);
715                                         if (c != null)
716                                                 return c;
717                                         else // empty entity reference etc.
718                                                 return GetNextSibling (n.NextSibling);
719                                 case XmlNodeType.XmlDeclaration:
720                                 case XmlNodeType.DocumentType:
721                                         return GetNextSibling (n.NextSibling);
722                                 default:
723                                         return n.NextSibling;
724                                 }
725                         } else {
726                                 if (n.ParentNode == null || n.ParentNode.NodeType != XmlNodeType.EntityReference)
727                                         return null;
728                                 return GetNextSibling (n.ParentNode);
729                         }
730                 }
731
732                 private XmlNode GetParentNode (XmlNode n)
733                 {
734                         if (n.ParentNode == null)
735                                 return null;
736                         for (XmlNode p = n.ParentNode; p != null; p = p.ParentNode)
737                                 if (p.NodeType != XmlNodeType.EntityReference)
738                                         return p;
739                         return null;
740                 }
741
742                 #endregion
743         }
744 }