1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 
  8 namespace System.Xml
  9 {
 10     public enum NodeKind
 11     {
 12         attributeNodedocumentFragmentNodedocumentNodeelementNodeentityNodeentityReferenceNodenotationNode
 13         processingInstructionNodetextNodecdataSectionNodecommentNode
 14     }
 15 
 16     public string NodeKindStr(NodeKind kind)
 17     {
 18         switch (kind)
 19         {
 20             case NodeKind.attributeNode: return "attributeNode";
 21             case NodeKind.documentFragmentNode: return "documentFragementNode";
 22             case NodeKind.documentNode: return "documentNode";
 23             case NodeKind.elementNode: return "elementNode";
 24             case NodeKind.entityNode: return "entityNode";
 25             case NodeKind.entityReferenceNode: return "entityReferenceNode";
 26             case NodeKind.notationNode: return "notationNode";
 27             case NodeKind.processingInstructionNode: return "processingInstructionNode";
 28             case NodeKind.textNode: return "textNode";
 29             case NodeKind.cdataSectionNode: return "cdataSectionNode";
 30             case NodeKind.commentNode: return "commentNode";
 31         }
 32         return "<unknown node kind>";
 33     }
 34 
 35     public abstract class Node
 36     {
 37         public Node(NodeKind kind_const System.Lex.Span& span_int fileIndex_const string& name_) : 
 38             kind(kind_)span(span_)fileIndex(fileIndex_)name(name_)parent(null)prev(null)next(null)ownerDocument(null)
 39         {
 40         }
 41         public virtual default ~Node();
 42         public inline NodeKind Kind() const
 43         {
 44             return kind;
 45         }
 46         public const System.Lex.Span& Span() const
 47         {
 48             return span;
 49         }
 50         public inline int FileIndex() const
 51         {
 52             return fileIndex;
 53         }
 54         public const string& Name() const
 55         {
 56             return name;
 57         }
 58         public const string& NamespaceUri() const
 59         {
 60             return namespaceUri;
 61         }
 62         public void SetNamespaceUri(const string& namespaceUri_)
 63         {
 64             namespaceUri = namespaceUri_;
 65         }
 66         public inline bool IsAttributeNode() const
 67         {
 68             return kind == NodeKind.attributeNode;
 69         }
 70         public inline bool IsDocumentFragmentNode() const
 71         {
 72             return kind == NodeKind.documentFragmentNode;
 73         }
 74         public inline bool IsDocumentNode() const
 75         {
 76             return kind == NodeKind.documentNode;
 77         }
 78         public inline bool IsElementNode() const
 79         {
 80             return kind == NodeKind.elementNode;
 81         }
 82         public inline bool IsEntityNode() const
 83         {
 84             return kind == NodeKind.entityNode;
 85         }
 86         public inline bool IsEntityReferenceNode() const
 87         {
 88             return kind == NodeKind.entityReferenceNode;
 89         }
 90         public inline bool IsNotationNode() const
 91         {
 92             return kind == NodeKind.notationNode;
 93         }
 94         public inline bool IsProcessingInstructionNode() const
 95         {
 96             return kind == NodeKind.processingInstructionNode;
 97         }
 98         public inline bool IsTextNode() const
 99         {
100             return kind == NodeKind.textNode;
101         }
102         public inline bool IsCDataSectionNode() const
103         {
104             return kind == NodeKind.cdataSectionNode;
105         }
106         public inline bool IsCommentNode() const
107         {
108             return kind == NodeKind.commentNode;
109         }
110         public ParentNode* Parent() const
111         {
112             return parent;
113         }
114         public void SetParent(ParentNode* parent_)
115         {
116             parent = parent_;
117         }
118         public Node* Prev() const
119         {
120             return prev;
121         }
122         public void SetPrev(Node* prev_)
123         {
124             prev = prev_;
125         }
126         public Node* Next() const
127         {
128             return next;
129         }
130         public void SetNext(Node* next_)
131         {
132             next = next_;
133         }
134         public void LinkBefore(Node* node)
135         {
136             if (prev != null)
137             {
138                 prev->next = node;
139             }
140             node->prev = prev;
141             node->next = this;
142             prev = node;
143         }
144         public void LinkAfter(Node* node)
145         {
146             if (next != null)
147             {
148                 next->prev = node;
149             }
150             node->prev = this;
151             node->next = next;
152             next = node;
153         }
154         public void Unlink()
155         {
156             if (prev != null)
157             {
158                 prev->next = next;
159             }
160             if (next != null)
161             {
162                 next->prev = prev;
163             }
164         }
165         public Document* OwnerDocument() const
166         {
167             return ownerDocument;
168         }
169         public void SetOwnerDocument(Document* ownerDocument_)
170         {
171             ownerDocument = ownerDocument_;
172         }
173         public string Prefix() const
174         {
175             if (IsElementNode() || IsAttributeNode())
176             {
177                 auto colonPos = name.Find(':');
178                 if (colonPos != -1)
179                 {
180                     return name.Substring(0colonPos);
181                 }
182             }
183             return string();
184         }
185         public void SetPrefix(const string& prefix)
186         {
187             if (IsElementNode() || IsAttributeNode())
188             {
189                 auto colonPos = name.Find(':');
190                 if (prefix.IsEmpty())
191                 {
192                     if (colonPos != -1)
193                     {
194                         name = name.Substring(colonPos + 1);
195                     }
196                 }
197                 else
198                 {
199                     if (colonPos != -1)
200                     {
201                         name = prefix + ":" + name.Substring(colonPos + 1);
202                     }
203                     else
204                     {
205                         name = prefix + ":" + name;
206                     }
207                 }
208             }
209         }
210         public string LocalName() const
211         {
212             if (IsElementNode() || IsAttributeNode())
213             {
214                 auto colonPos = name.Find(':');
215                 if (colonPos != -1)
216                 {
217                     return name.Substring(colonPos + 1);
218                 }
219                 else
220                 {
221                     return name;
222                 }
223             }
224             else
225             {
226                 return string();
227             }
228         }
229         public virtual void Accept(Visitor& visitor)
230         {
231         }
232         public virtual bool HasChildNodes() const
233         {
234             return false;
235         }
236         public virtual bool HasAttributes() const
237         {
238             return false;
239         }
240         public virtual bool ValueContainsNewLine() const
241         {
242             return false;
243         }
244         public abstract Node* Clone(bool deep) const;
245         public abstract Result<bool> Write(System.Text.CodeFormatter& formatter);
246         public void Walk(NodeOperation& operationAxis axis)
247         {
248             switch (axis)
249             {
250                 case Axis.child:
251                 {
252                     WalkChildren(operation);
253                     break;
254                 }
255                 case Axis.descendant:
256                 {
257                     WalkDescendant(operation);
258                     break;
259                 }
260                 case Axis.descendantOrSelf:
261                 {
262                     WalkDescendantOrSelf(operation);
263                     break;
264                 }
265                 case Axis.parent:
266                 {
267                     WalkParent(operation);
268                     break;
269                 }
270                 case Axis.ancestor:
271                 {
272                     WalkAncestor(operation);
273                     break;
274                 }
275                 case Axis.ancestorOrSelf:
276                 {
277                     WalkAncestorOrSelf(operation);
278                     break;
279                 }
280                 case Axis.followingSibling:
281                 {
282                     WalkFollowingSibling(operation);
283                     break;
284                 }
285                 case Axis.precedingSibling:
286                 {
287                     WalkPrecedingSibling(operation);
288                     break;
289                 }
290                 case Axis.following:
291                 {
292                     WalkFollowing(operation);
293                     break;
294                 }
295                 case Axis.preceding:
296                 {
297                     WalkPreceding(operation);
298                     break;
299                 }
300                 case Axis.attribute:
301                 {
302                     WalkAttribute(operation);
303                     break;
304                 }
305                 case Axis.self:
306                 {
307                     operation.Apply(this);
308                     break;
309                 }
310             }
311         }
312         public virtual void WalkChildren(NodeOperation& operation)
313         {
314         }
315         public virtual void WalkDescendant(NodeOperation& operation)
316         {
317         }
318         public virtual void WalkDescendantOrSelf(NodeOperation& operation)
319         {
320             operation.Apply(this);
321         }
322         public void WalkParent(NodeOperation& operation)
323         {
324             if (parent != null)
325             {
326                 operation.Apply(parent);
327             }
328         }
329         public virtual void WalkFollowing(NodeOperation& operation)
330         {
331             Node* n = next;
332             if (n != null)
333             {
334                 n->WalkDescendantOrSelf(operation);
335             }
336         }
337         public virtual void WalkPreceding(NodeOperation& operation)
338         {
339         }
340         public virtual void WalkPrecedingOrSelf(NodeOperation& operation)
341         {
342             operation.Apply(this);
343         }
344         public void WalkAncestor(NodeOperation& operation)
345         {
346             if (parent != null)
347             {
348                 parent->WalkAncestorOrSelf(operation);
349             }
350         }
351         public void WalkAncestorOrSelf(NodeOperation& operation)
352         {
353             operation.Apply(this);
354             if (parent != null)
355             {
356                 parent->WalkAncestorOrSelf(operation);
357             }
358         }
359         public void WalkFollowingSibling(NodeOperation& operation)
360         {
361             Node* n = next;
362             while (n != null)
363             {
364                 operation.Apply(n);
365                 n = n->next;
366             }
367         }
368         public void WalkPrecedingSibling(NodeOperation& operation)
369         {
370             Node* p = prev;
371             while (p != null)
372             {
373                 operation.Apply(p);
374                 p = p->prev;
375             }
376         }
377         public virtual void WalkAttribute(NodeOperation& operation)
378         {
379         }
380         private NodeKind kind;
381         private System.Lex.Span span;
382         private int fileIndex;
383         private string name;
384         private string namespaceUri;
385         private ParentNode* parent;
386         private Node* prev;
387         private Node* next;
388         private Document* ownerDocument;
389     }