XhtmlMarkupFormatter
Represents the standard XHTML markup formatter.
using AngleSharp.Dom;
using AngleSharp.Text;
using System.Runtime.CompilerServices;
using System.Text;
namespace AngleSharp.Xhtml
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class XhtmlMarkupFormatter : IMarkupFormatter
{
public static readonly IMarkupFormatter Instance = new XhtmlMarkupFormatter();
private readonly bool _emptyTagsToSelfClosing;
public bool IsSelfClosingEmptyTags => _emptyTagsToSelfClosing;
public XhtmlMarkupFormatter()
: this(true)
{
}
public XhtmlMarkupFormatter(bool emptyTagsToSelfClosing)
{
_emptyTagsToSelfClosing = emptyTagsToSelfClosing;
}
public virtual string CloseTag(IElement element, bool selfClosing)
{
string prefix = element.Prefix;
string localName = element.LocalName;
string str = (!string.IsNullOrEmpty(prefix)) ? (prefix + ":" + localName) : localName;
if (!selfClosing && (!_emptyTagsToSelfClosing || element.HasChildNodes))
return "</" + str + ">";
return string.Empty;
}
public virtual string Comment(IComment comment)
{
return "<!--" + comment.Data + "-->";
}
public virtual string Doctype(IDocumentType doctype)
{
string publicIdentifier = doctype.PublicIdentifier;
string systemIdentifier = doctype.SystemIdentifier;
string str = (string.IsNullOrEmpty(publicIdentifier) && string.IsNullOrEmpty(systemIdentifier)) ? string.Empty : (" " + (string.IsNullOrEmpty(publicIdentifier) ? ("SYSTEM \"" + systemIdentifier + "\"") : ("PUBLIC \"" + publicIdentifier + "\" \"" + systemIdentifier + "\"")));
return "<!DOCTYPE " + doctype.Name + str + ">";
}
public virtual string OpenTag(IElement element, bool selfClosing)
{
string prefix = element.Prefix;
StringBuilder stringBuilder = StringBuilderPool.Obtain();
stringBuilder.Append('<');
if (!string.IsNullOrEmpty(prefix))
stringBuilder.Append(prefix).Append(':');
stringBuilder.Append(element.LocalName);
foreach (IAttr attribute in element.Attributes) {
stringBuilder.Append(' ').Append(Attribute(attribute));
}
if (selfClosing || (_emptyTagsToSelfClosing && !element.HasChildNodes))
stringBuilder.Append(" /");
stringBuilder.Append('>');
return stringBuilder.ToPool();
}
public virtual string Processing(IProcessingInstruction processing)
{
string str = processing.Target + " " + processing.Data;
return "<?" + str + "?>";
}
public virtual string LiteralText(ICharacterData text)
{
return text.Data;
}
public virtual string Text(ICharacterData text)
{
return EscapeText(text.Data);
}
protected virtual string Attribute(IAttr attribute)
{
string namespaceUri = attribute.NamespaceUri;
string localName = attribute.LocalName;
string value = attribute.Value;
StringBuilder stringBuilder = StringBuilderPool.Obtain();
if (string.IsNullOrEmpty(namespaceUri))
stringBuilder.Append(localName);
else if (namespaceUri.Is(NamespaceNames.XmlUri)) {
stringBuilder.Append(NamespaceNames.XmlPrefix).Append(':').Append(localName);
} else if (namespaceUri.Is(NamespaceNames.XLinkUri)) {
stringBuilder.Append(NamespaceNames.XLinkPrefix).Append(':').Append(localName);
} else if (namespaceUri.Is(NamespaceNames.XmlNsUri)) {
stringBuilder.Append(XmlNamespaceLocalName(localName));
} else {
stringBuilder.Append(attribute.Name);
}
stringBuilder.Append('=').Append('"');
for (int i = 0; i < value.Length; i++) {
switch (value[i]) {
case '&':
stringBuilder.Append("&");
break;
case ' ':
stringBuilder.Append(" ");
break;
case '<':
stringBuilder.Append("<");
break;
case '"':
stringBuilder.Append(""");
break;
default:
stringBuilder.Append(value[i]);
break;
}
}
return stringBuilder.Append('"').ToPool();
}
public static string EscapeText(string content)
{
StringBuilder stringBuilder = StringBuilderPool.Obtain();
for (int i = 0; i < content.Length; i++) {
switch (content[i]) {
case '&':
stringBuilder.Append("&");
break;
case ' ':
stringBuilder.Append(" ");
break;
case '>':
stringBuilder.Append(">");
break;
case '<':
stringBuilder.Append("<");
break;
default:
stringBuilder.Append(content[i]);
break;
}
}
return stringBuilder.ToPool();
}
public static string XmlNamespaceLocalName(string localName)
{
if (localName.Is(NamespaceNames.XmlNsPrefix))
return localName;
return NamespaceNames.XmlNsPrefix + ':' + localName;
}
}
}