MinifyMarkupFormatter
Represents the an HTML5 markup formatter with a normalization scheme.
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using AngleSharp.Io;
using AngleSharp.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
namespace AngleSharp.Html
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class MinifyMarkupFormatter : HtmlMarkupFormatter
{
private IEnumerable<string> _preservedTags = new string[2] {
TagNames.Pre,
TagNames.Textarea
};
public IEnumerable<string> PreservedTags {
get {
return _preservedTags ?? Array.Empty<string>();
}
set {
_preservedTags = value;
}
}
public bool ShouldKeepStandardElements { get; set; }
public bool ShouldKeepComments { get; set; }
public bool ShouldKeepAttributeQuotes { get; set; }
public bool ShouldKeepEmptyAttributes { get; set; }
public bool ShouldKeepImpliedEndTag { get; set; }
public override string Comment(IComment comment)
{
if (!ShouldKeepComments)
return string.Empty;
return base.Comment(comment);
}
public override string Text(ICharacterData text)
{
if (text.Parent is IHtmlHeadElement || text.Parent is IHtmlHtmlElement)
return string.Empty;
string text2 = base.Text(text);
if (!PreservedTags.Contains(text.ParentElement?.LocalName)) {
StringBuilder stringBuilder = StringBuilderPool.Obtain();
bool flag = false;
bool flag2 = true;
foreach (char c in text2) {
if (c.IsWhiteSpaceCharacter()) {
if (!flag) {
stringBuilder.Append(' ');
flag = true;
}
} else {
stringBuilder.Append(c);
flag2 = false;
flag = false;
}
}
if (!flag2 || ShouldOutput(text))
return stringBuilder.ToPool();
stringBuilder.ReturnToPool();
return string.Empty;
}
return text2;
}
public override string OpenTag(IElement element, bool selfClosing)
{
if (!CanBeRemoved(element)) {
StringBuilder stringBuilder = StringBuilderPool.Obtain();
stringBuilder.Append('<');
if (!string.IsNullOrEmpty(element.Prefix))
stringBuilder.Append(element.Prefix).Append(':');
stringBuilder.Append(element.LocalName);
foreach (IAttr attribute in element.Attributes) {
if (ShouldKeep(element, attribute)) {
if (!element.IsBooleanAttribute(attribute.Name)) {
string value = Attribute(attribute);
if (!string.IsNullOrEmpty(value))
stringBuilder.Append(' ').Append(value);
} else
stringBuilder.Append(' ').Append(attribute.Name);
}
}
if (stringBuilder[stringBuilder.Length - 1] == '/')
stringBuilder.Append(' ');
stringBuilder.Append('>');
return stringBuilder.ToPool();
}
return string.Empty;
}
public override string CloseTag(IElement element, bool selfClosing)
{
if (!CanBeRemoved(element) && !CanBeSkipped(element))
return base.CloseTag(element, selfClosing);
return string.Empty;
}
protected override string Attribute(IAttr attr)
{
string value = attr.Value;
if (ShouldKeepEmptyAttributes || !string.IsNullOrEmpty(value)) {
StringBuilder stringBuilder = StringBuilderPool.Obtain();
HtmlMarkupFormatter.WriteAttributeName(attr, stringBuilder);
if (value != null) {
stringBuilder.Append('=');
bool num = ShouldKeepAttributeQuotes || value.Any(MustBeQuotedAttributeValue);
if (num)
stringBuilder.Append('"');
HtmlMarkupFormatter.WriteAttributeValue(attr, stringBuilder);
if (num)
stringBuilder.Append('"');
}
return stringBuilder.ToPool();
}
return string.Empty;
}
private bool CanBeRemoved(IElement element)
{
if (!ShouldKeepStandardElements && element.Attributes.Length == 0)
return element.LocalName.IsOneOf(TagNames.Html, TagNames.Head, TagNames.Body);
return false;
}
private bool CanBeSkipped(IElement element)
{
if (!ShouldKeepImpliedEndTag && element.Flags.HasFlag(NodeFlags.ImpliedEnd)) {
if (element.NextElementSibling != null)
return element.NextElementSibling.LocalName == element.LocalName;
return true;
}
return false;
}
private static bool ShouldOutput(ICharacterData text)
{
if (text.Parent is HtmlBodyElement) {
if (text.NextSibling != null)
return text.PreviousSibling != null;
return false;
}
return true;
}
private static bool ShouldKeep(IElement element, IAttr attribute)
{
if (!IsStandardScript(element, attribute))
return !IsStandardStyle(element, attribute);
return false;
}
private static bool IsStandardScript(IElement element, IAttr attr)
{
if (element is HtmlScriptElement && attr.Name.Is(AttributeNames.Type))
return attr.Value.Is(MimeTypeNames.DefaultJavaScript);
return false;
}
private static bool IsStandardStyle(IElement element, IAttr attr)
{
if (element is HtmlStyleElement && attr.Name.Is(AttributeNames.Type))
return attr.Value.Is(MimeTypeNames.Css);
return false;
}
private static bool MustBeQuotedAttributeValue(char c)
{
if (!c.IsWhiteSpaceCharacter() && c != '"' && c != '\'' && c != '=' && c != '>' && c != '<')
return c == '`';
return true;
}
}
}