Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
HtmlElement.cs
1using System;
3using System.Text;
4using System.Xml;
6
7namespace Waher.Content.Html
8{
12 public class HtmlElement : HtmlNode
13 {
14 private Dictionary<string, HtmlAttribute> attributesByName = null;
15 private ChunkedList<HtmlAttribute> attributes = null;
16 private Dictionary<string, HtmlAttribute> namespacesByPrefix = null;
17 private ChunkedList<HtmlNode> children = null;
18 private readonly string fullName;
19 private readonly string localName;
20 private readonly string prefix;
21 private readonly bool hasPrefix;
22 private string @namespace;
23
33 {
34 SplitName(Name, out this.prefix, out this.localName, out this.hasPrefix);
35 this.fullName = Name;
36 this.@namespace = null;
37 }
38
42 public string FullName => this.fullName;
43
47 public string LocalName => this.localName;
48
52 public string Prefix => this.prefix;
53
57 public bool HasPrefix => this.hasPrefix;
58
62 public string Namespace => this.@namespace;
63
64 internal void Add(HtmlNode Node)
65 {
66 if (this.children is null)
67 this.children = new ChunkedList<HtmlNode>();
68
69 this.children.Add(Node);
70 }
71
72 internal void AddAttribute(HtmlAttribute Attribute)
73 {
74 if (!Attribute.HasPrefix && Attribute.LocalName == "xmlns")
75 {
76 if (string.IsNullOrEmpty(this.@namespace))
77 this.@namespace = Attribute.Value;
78 }
79 else if (Attribute.HasPrefix && Attribute.Prefix == "xmlns")
80 {
81 if (this.namespacesByPrefix is null)
82 this.namespacesByPrefix = new Dictionary<string, HtmlAttribute>();
83
84 this.namespacesByPrefix[Attribute.LocalName] = Attribute;
85 }
86 else
87 {
88 if (this.attributes is null)
89 {
90 this.attributes = new ChunkedList<HtmlAttribute>();
91 this.attributesByName = new Dictionary<string, HtmlAttribute>(StringComparer.OrdinalIgnoreCase);
92 }
93
94 if (!this.attributesByName.ContainsKey(Attribute.FullName))
95 {
96 this.attributes.Add(Attribute);
97 this.attributesByName[Attribute.FullName] = Attribute;
98 }
99 }
100 }
101
105 public bool HasChildren => !(this.children is null);
106
110 public bool HasAttributes => !(this.attributes is null);
111
115 public IEnumerable<HtmlNode> Children => this.children;
116
120 public IEnumerable<HtmlAttribute> Attributes => this.attributes;
121
128 public bool TryGetAttribute(string Name, out HtmlAttribute Attribute)
129 {
130 if (this.attributesByName is null)
131 {
132 Attribute = null;
133 return false;
134 }
135 else
136 return this.attributesByName.TryGetValue(Name, out Attribute);
137 }
138
142 public string InnerHtml
143 {
144 get
145 {
146 int? Start = null;
147 int? End = null;
148
149 if (!(this.children is null))
150 {
151 foreach (HtmlNode N in this.children)
152 {
153 if (!Start.HasValue)
154 Start = N.StartPosition;
155
156 End = N.EndPosition;
157 }
158 }
159
160 if (Start.HasValue && End.HasValue)
161 return this.Document.HtmlText.Substring(Start.Value, End.Value - Start.Value + 1);
162 else
163 return string.Empty;
164 }
165 }
166
170 public string InnerText
171 {
172 get
173 {
174 StringBuilder sb = new StringBuilder();
175
176 if (!(this.children is null))
177 {
178 foreach (HtmlNode N in this.children)
179 {
180 if (N is HtmlText Text)
181 sb.Append(Text.InlineText);
182 else if (N is HtmlElement Element)
183 sb.Append(Element.InnerText);
184 else if (N is HtmlEntity Entity)
185 sb.Append(Entity.ToString());
186 else if (N is CDATA CDATA)
187 sb.Append(CDATA.Content);
188 }
189 }
190
191 return sb.ToString();
192 }
193 }
194
198 public string StartTag
199 {
200 get
201 {
202 if (!(this.children is null))
203 {
204 foreach (HtmlNode N in this.children)
205 return this.Document.HtmlText.Substring(this.StartPosition, N.StartPosition - this.StartPosition);
206 }
207
208 return this.OuterHtml;
209 }
210 }
211
216 {
217 get
218 {
219 if (!(this.children is null))
220 {
221 foreach (HtmlNode N in this.children)
222 return N.StartPosition - 1;
223 }
224
225 return this.EndPosition;
226 }
227 }
228
230 public override string ToString()
231 {
232 return this.StartTag;
233 }
234
240 public override void Export(XmlWriter Output, Dictionary<string, string> Namespaces)
241 {
242 ChunkedList<KeyValuePair<string, string>> NamespaceBak = null;
243
244 if (!(this.namespacesByPrefix is null))
245 {
246 foreach (KeyValuePair<string, HtmlAttribute> P in this.namespacesByPrefix)
247 {
248 if (Namespaces.TryGetValue(P.Key, out string s))
249 {
250 if (NamespaceBak is null)
251 NamespaceBak = new ChunkedList<KeyValuePair<string, string>>();
252
253 NamespaceBak.Add(new KeyValuePair<string, string>(P.Key, s));
254 }
255
256 Namespaces[P.Key] = P.Value.Value;
257 }
258 }
259
260 if (this.hasPrefix)
261 {
262 if (Namespaces.TryGetValue(this.prefix, out string s))
263 Output.WriteStartElement(this.prefix, this.localName, s);
264 else
265 Output.WriteStartElement(this.prefix, this.localName, this.@namespace);
266 }
267 else if (this.@namespace is null)
268 Output.WriteStartElement(this.localName);
269 else
270 Output.WriteStartElement(this.localName, this.@namespace);
271
272 if (!(this.attributes is null))
273 {
274 foreach (HtmlAttribute Attr in this.attributes)
275 Attr.Export(Output, Namespaces);
276 }
277
278 if (!(this.namespacesByPrefix is null))
279 {
280 foreach (KeyValuePair<string, HtmlAttribute> P in this.namespacesByPrefix)
281 P.Value.Export(Output, Namespaces);
282 }
283
284 if (!(this.children is null))
285 {
286 foreach (HtmlNode Child in this.children)
287 Child.Export(Output, Namespaces);
288 }
289
290 Output.WriteEndElement();
291
292 if (!(this.namespacesByPrefix is null))
293 {
294 foreach (KeyValuePair<string, HtmlAttribute> P in this.namespacesByPrefix)
295 Namespaces.Remove(P.Key);
296 }
297
298 if (!(NamespaceBak is null))
299 {
300 foreach (KeyValuePair<string, string> P in NamespaceBak)
301 Namespaces[P.Key] = P.Value;
302 }
303 }
304
309 public override void Export(StringBuilder Output)
310 {
311 Output.Append('<');
312 Output.Append(this.fullName);
313
314 if (!(this.attributes is null))
315 {
316 foreach (HtmlAttribute Attr in this.attributes)
317 Attr.Export(Output);
318 }
319
320 if (!(this.@namespace is null))
321 {
322 Output.Append(" xmlns=\"");
323 Output.Append(Xml.XML.Encode(this.@namespace));
324 Output.Append('"');
325 }
326
327 if (!(this.namespacesByPrefix is null))
328 {
329 foreach (KeyValuePair<string, HtmlAttribute> P in this.namespacesByPrefix)
330 P.Value.Export(Output);
331 }
332
333 if (this.children is null)
334 Output.Append("/>");
335 else
336 {
337 Output.Append('>');
338
339 foreach (HtmlNode Child in this.children)
340 Child.Export(Output);
341
342 Output.Append("</");
343 Output.Append(this.fullName);
344 Output.Append('>');
345 }
346 }
347
351 public virtual bool IsEmptyElement => false;
352
358 public bool HasAttribute(string Name)
359 {
360 if (Name.StartsWith("xmlns"))
361 {
362 if (Name == "xmlns")
363 return !(this.@namespace is null);
364
365 if (Name.Length > 6 && Name[5] == ':')
366 {
367 if (this.namespacesByPrefix is null)
368 return false;
369
370 return this.namespacesByPrefix.ContainsKey(Name.Substring(6));
371 }
372 }
373
374 if (this.attributes is null)
375 return false;
376
377 foreach (HtmlAttribute Attr in this.attributes)
378 {
379 if (string.Compare(Attr.FullName, Name, true) == 0)
380 return true;
381 }
382
383 return false;
384 }
385
391 public string GetAttribute(string Name)
392 {
393 if (Name.StartsWith("xmlns"))
394 {
395 if (Name == "xmlns")
396 return this.@namespace;
397
398 if (Name.Length > 6 && Name[5] == ':')
399 {
400 if (this.namespacesByPrefix is null)
401 return string.Empty;
402
403 if (this.namespacesByPrefix.TryGetValue(Name.Substring(6), out HtmlAttribute NsAttr))
404 return NsAttr.Value;
405 else
406 return string.Empty;
407 }
408 }
409
410 if (this.attributesByName is null)
411 return string.Empty;
412
413 if (this.attributesByName.TryGetValue(Name, out HtmlAttribute Attr))
414 return Attr.Value;
415 else
416 return string.Empty;
417 }
418
424 public string this[string Name] => this.GetAttribute(Name);
425 }
426}
CDATA content.
Definition: CDATA.cs:11
string Content
CDATA Content
Definition: CDATA.cs:32
override void Export(XmlWriter Output, Dictionary< string, string > Namespaces)
Exports the HTML document to XML.
string Prefix
Attribute prefix.
bool HasPrefix
If the attribute has a prefix.
string LocalName
Attribute local name.
string FullName
Attribute full name (including prefix).
Base class for all HTML elements.
Definition: HtmlElement.cs:13
bool HasPrefix
If the element has a prefix.
Definition: HtmlElement.cs:57
bool HasChildren
If the element has children.
Definition: HtmlElement.cs:105
virtual bool IsEmptyElement
If the element is an empty element.
Definition: HtmlElement.cs:351
override void Export(XmlWriter Output, Dictionary< string, string > Namespaces)
Exports the HTML document to XML.
Definition: HtmlElement.cs:240
HtmlElement(HtmlDocument Document, HtmlElement Parent, int StartPosition, string Name)
Base class for all HTML elements.
Definition: HtmlElement.cs:31
bool TryGetAttribute(string Name, out HtmlAttribute Attribute)
Tries to get an attribute from the element, by its name.
Definition: HtmlElement.cs:128
string Prefix
Element prefix.
Definition: HtmlElement.cs:52
bool HasAttribute(string Name)
If the element has an attribute with a given (case-insensitive) name.
Definition: HtmlElement.cs:358
IEnumerable< HtmlAttribute > Attributes
Attributes, or null if none.
Definition: HtmlElement.cs:120
string GetAttribute(string Name)
Gets a given attribute value, if available. The empty string is returned if the attribute does not ex...
Definition: HtmlElement.cs:391
override void Export(StringBuilder Output)
Exports the HTML document to XML.
Definition: HtmlElement.cs:309
int EndPositionOfStartTag
End position of start tag.
Definition: HtmlElement.cs:216
bool HasAttributes
If the element has attributes.
Definition: HtmlElement.cs:110
string FullName
Element full name (including prefix).
Definition: HtmlElement.cs:42
string Namespace
Namespace, if provided, null if not.
Definition: HtmlElement.cs:62
string LocalName
Element local name.
Definition: HtmlElement.cs:47
IEnumerable< HtmlNode > Children
Child nodes, or null if none.
Definition: HtmlElement.cs:115
override string ToString()
Definition: HtmlElement.cs:230
Base class for all HTML nodes.
Definition: HtmlNode.cs:11
int StartPosition
Start position of element.
Definition: HtmlNode.cs:60
static void SplitName(string FullName, out string Prefix, out string LocalName, out bool HasPrefix)
Splits a full name into a prefix (if available) and a local name.
Definition: HtmlNode.cs:92
HtmlDocument Document
HTML Document
Definition: HtmlNode.cs:49
HtmlNode Parent
Parent node, if available.
Definition: HtmlNode.cs:54
int EndPosition
End position of element.
Definition: HtmlNode.cs:69
abstract void Export(XmlWriter Output, Dictionary< string, string > Namespaces)
Exports the HTML document to XML.
string OuterHtml
Outer HTML
Definition: HtmlNode.cs:78
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272