1
2
3
4
5
6 using System;
7 using System.Collections;
8
9 namespace System.Xml
10 {
11 public class Element : ParentNode
12 {
13 public Element(const System.Lex.Span& span_, int fileIndex_, const string& name_) : base(NodeKind.elementNode, span_, fileIndex_, name_)
14 {
15 }
16 public const Map<string, UniquePtr<AttributeNode>>& Attributes() const
17 {
18 return attributeMap;
19 }
20 public AttributeNode* GetAttributeNode(const string& attributeName) const
21 {
22 auto it = attributeMap.Find(attributeName);
23 if (it != attributeMap.End())
24 {
25 return it->second.Get();
26 }
27 else
28 {
29 return null;
30 }
31 }
32 public string GetAttribute(const string& name) const
33 {
34 AttributeNode* attributeNode = GetAttributeNode(name);
35 if (attributeNode != null)
36 {
37 return attributeNode->Value();
38 }
39 else
40 {
41 return string();
42 }
43 }
44 public void AddAttribute(AttributeNode* attributeNode)
45 {
46 attributeMap[attributeNode->Name()] = UniquePtr<AttributeNode>(attributeNode);
47 }
48 public void SetAttribute(const System.Lex.Span& span, int fileIndex, const string& name, const string& value)
49 {
50 AttributeNode* attributeNode = GetAttributeNode(name);
51 if (attributeNode != null)
52 {
53 attributeNode->SetValue(value);
54 }
55 else
56 {
57 AddAttribute(new AttributeNode(span, fileIndex, name, value));
58 }
59 }
60 public void SetAttribute(const string& name, const string& value)
61 {
62 SetAttribute(System.Lex.Span(), -1, name, value);
63 }
64 public override bool HasAttributes() const
65 {
66 return !attributeMap.IsEmpty();
67 }
68 public override void Accept(Visitor& visitor)
69 {
70 visitor.BeginVisit(*this);
71 base->Accept(visitor);
72 visitor.EndVisit(*this);
73 }
74 [nodiscard]
75 public override Result<bool> Write(System.Text.CodeFormatter& formatter)
76 {
77 if (formatter.Error())
78 {
79 return Result<bool>(ErrorId(formatter.GetErrorId()));
80 }
81 if (HasChildNodes())
82 {
83 if (attributeMap.IsEmpty())
84 {
85 formatter << "<" << Name() << ">";
86 }
87 else
88 {
89 formatter << "<" << Name();
90 WriteAttributes(formatter);
91 formatter << ">";
92 }
93 bool prevPreserveSpace = formatter.PreserveSpace();
94 if (GetAttribute("xml:space") == "preserve")
95 {
96 formatter.SetPreserveSpace(true);
97 }
98 bool preserveSpace = formatter.PreserveSpace() || !HasMultilineContent();
99 if (!preserveSpace)
100 {
101 auto result = formatter.WriteLine();
102 if (result.Error()) return result;
103 formatter.IncIndent();
104 }
105 auto result = base->Write(formatter);
106 if (result.Error()) return result;
107 if (!preserveSpace)
108 {
109 formatter.DecIndent();
110 formatter << "</" << Name() << ">" << endl();
111 }
112 else if (prevPreserveSpace)
113 {
114 formatter << "</" << Name() << ">";
115 }
116 else
117 {
118 formatter << "</" << Name() << ">" << endl();
119 }
120 formatter.SetPreserveSpace(prevPreserveSpace);
121 }
122 else
123 {
124 if (attributeMap.IsEmpty())
125 {
126 formatter << "<" << Name() << "/>" << endl();
127 }
128 else
129 {
130 formatter << "<" << Name();
131 WriteAttributes(formatter);
132 formatter << "/>" << endl();
133 }
134 }
135 return Result<bool>(true);
136 }
137 public override Node* Clone(bool deep) const
138 {
139 Element* clone = new Element(Span(), FileIndex(), Name());
140 for (const auto& a : attributeMap)
141 {
142 clone->AddAttribute(cast<AttributeNode*>(a.second->Clone(deep)));
143 }
144 if (deep)
145 {
146 Node* child = FirstChild();
147 while (child != null)
148 {
149 clone->AppendChild(child->Clone(deep));
150 child = child->Next();
151 }
152 }
153 return clone;
154 }
155 public void WriteAttributes(System.Text.CodeFormatter& formatter)
156 {
157 for (const auto& a : attributeMap)
158 {
159 a.second->Write(formatter);
160 }
161 }
162 public bool HasMultilineContent() const
163 {
164 if (FirstChild() != LastChild())
165 {
166 return true;
167 }
168 Node* child = FirstChild();
169 if (child != null)
170 {
171 if (child->IsElementNode() || child->IsDocumentNode())
172 {
173 return true;
174 }
175 if (child->ValueContainsNewLine())
176 {
177 return true;
178 }
179 }
180 return false;
181 }
182 public override void WalkAttribute(NodeOperation& operation)
183 {
184 for (const auto& attribute : attributeMap)
185 {
186 operation.Apply(attribute.second.Get());
187 }
188 }
189 private Map<string, UniquePtr<AttributeNode>> attributeMap;
190 }
191
192 public Element* MakeElement(const string& name)
193 {
194 return new Element(System.Lex.Span(), -1, name);
195 }
196 }