From 541eddd8617437c916153ae1d8660fb4f7c27851 Mon Sep 17 00:00:00 2001 From: Ryan Lamansky <13633345+RyanLamansky@users.noreply.github.com> Date: Sun, 4 Aug 2024 20:42:18 -0500 Subject: [PATCH] Used a more memory-efficient technique to store the sparsely-used attributes of standardized elements. --- Examples/AspNetPageEmitter/Program.cs | 4 +++ HtmlUtilities/Validated/StandardElement.cs | 30 +++++++++++++++++-- HtmlUtilities/Validated/Standardized/Link.cs | 4 +-- HtmlUtilities/Validated/Standardized/Style.cs | 2 +- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Examples/AspNetPageEmitter/Program.cs b/Examples/AspNetPageEmitter/Program.cs index 8d96939..77864c6 100644 --- a/Examples/AspNetPageEmitter/Program.cs +++ b/Examples/AspNetPageEmitter/Program.cs @@ -32,6 +32,10 @@ class TestDocument : IHtmlDocument Task IHtmlDocument.WriteBodyContentsAsync(HtmlWriter writer, CancellationToken cancellationToken) { writer.WriteElement("p", null, children => children.WriteText("Test bytes.")); + writer.WriteElement("p", null, children => + { + children.WriteElement("a", attributes => attributes.Write("href", "/"), children => children.WriteText("Test link.")); + }); writer.WriteScript(ValidatedScript.ForInlineSource("console.log('test')")); return Task.CompletedTask; } diff --git a/HtmlUtilities/Validated/StandardElement.cs b/HtmlUtilities/Validated/StandardElement.cs index ed407be..bed9569 100644 --- a/HtmlUtilities/Validated/StandardElement.cs +++ b/HtmlUtilities/Validated/StandardElement.cs @@ -1,4 +1,6 @@ -namespace HtmlUtilities.Validated; +using System.Runtime.CompilerServices; + +namespace HtmlUtilities.Validated; /// /// Provides friendly syntax for use of standardized HTML elements. @@ -7,17 +9,38 @@ public abstract class StandardElement { // Global attribute list from https://html.spec.whatwg.org/#global-attributes. + private readonly Dictionary attributes = []; + + private protected ValidatedAttributeValue? GetAttribute([CallerMemberName] string name = null!) + => attributes.TryGetValue(name, out var value) ? value : null; + + private protected void SetAttribute(ValidatedAttributeValue? value, [CallerMemberName] string name = null!) + { + if (value is null) + return; + + attributes[name] = value.GetValueOrDefault(); + } + + /// + /// All HTML elements may have the accesskey content attribute set + /// The accesskey attribute's value is used by the user agent as a guide for creating a keyboard shortcut that activates or focuses the element. + /// If specified, the value must be an ordered set of unique space-separated tokens none of which are identical to another token and each of which must be exactly one code point in length. + /// Source: https://html.spec.whatwg.org/#the-accesskey-attribute + /// + public ValidatedAttributeValue? AccessKey { get => GetAttribute(); set => SetAttribute(value); } + /// /// Uniquely identifies an element. /// Source: https://dom.spec.whatwg.org/#concept-id /// - public ValidatedAttributeValue? Id { get; set; } + public ValidatedAttributeValue? Id { get => GetAttribute(); set => SetAttribute(value); } /// /// The title attribute represents advisory information for the element, such as would be appropriate for a tooltip. /// Source: https://html.spec.whatwg.org/#attr-title /// - public ValidatedAttributeValue? Title { get; set; } + public ValidatedAttributeValue? Title { get => GetAttribute(); set => SetAttribute(value); } private protected StandardElement() { @@ -31,6 +54,7 @@ private protected StandardElement() /// Receives the attributes. private protected void Write(AttributeWriter writer) { + writer.Write(" accesskey"u8, AccessKey); writer.Write(" id"u8, Id); writer.Write(" title"u8, Title); } diff --git a/HtmlUtilities/Validated/Standardized/Link.cs b/HtmlUtilities/Validated/Standardized/Link.cs index 62c8e17..401322b 100644 --- a/HtmlUtilities/Validated/Standardized/Link.cs +++ b/HtmlUtilities/Validated/Standardized/Link.cs @@ -8,12 +8,12 @@ public class Link : StandardElement /// /// Relationship between the document containing the hyperlink and the destination resource. /// - public string? Rel { get; set; } + public ValidatedAttributeValue? Rel { get => GetAttribute(); set => SetAttribute(value); } /// /// Address of the hyperlink. /// - public string? Href { get; set; } + public ValidatedAttributeValue? Href { get => GetAttribute(); set => SetAttribute(value); } internal sealed override void Write(HtmlWriter writer) { diff --git a/HtmlUtilities/Validated/Standardized/Style.cs b/HtmlUtilities/Validated/Standardized/Style.cs index 2dc9d00..89f7a6c 100644 --- a/HtmlUtilities/Validated/Standardized/Style.cs +++ b/HtmlUtilities/Validated/Standardized/Style.cs @@ -13,7 +13,7 @@ public class Style : StandardElement /// /// Applicable media. /// - public ValidatedAttributeValue? Media { get; set; } + public ValidatedAttributeValue? Media { get => GetAttribute(); set => SetAttribute(value); } internal sealed override void Write(HtmlWriter writer) {