ln.templates/ln.templates/html/HtmlReader.cs

176 lines
5.6 KiB
C#

// /**
// * File: Parser.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
namespace ln.templates.html
{
public class HtmlReader
{
public HtmlReader()
{
}
public void Read(string source) => Read(new StringReader(source));
public void Read(Stream sourceStream)
{
using (StreamReader streamReader = new StreamReader(sourceStream))
Read(streamReader);
}
public void Read(TextReader textReader)
{
while (textReader.Peek() != -1)
{
switch (textReader.Peek())
{
case '<':
ReadTag(textReader);
break;
default:
ReadText(textReader);
break;
}
}
}
public void ReadTag(TextReader textReader)
{
if (textReader.Read() != '<')
throw new FormatException("Expected <");
bool closing = false;
if (textReader.Peek()=='/')
{
textReader.Read();
closing = true;
}
if (textReader.Peek()=='!')
{
textReader.Read();
string doctype = ReadTagName(textReader);
if (!doctype.Equals("DOCTYPE"))
throw new FormatException("Expected DOCTYPE");
string type = ReadAttributeName(textReader);
DOCTYPE(type);
if (textReader.Read() != '>')
throw new FormatException("Expected >");
return;
}
string tagName = ReadTagName(textReader);
if (closing)
{
CloseTag(tagName);
}
else
{
OpenTag(tagName);
while (TestChar((char)textReader.Peek(), (ch) => !char.IsWhiteSpace(ch) && (ch != '\0') && (ch != '"') && (ch != '\'') && (ch != '>') && (ch != '/') && (ch != '=')))
{
string attributeName = ReadAttributeName(textReader);
string attributeValue = "";
if (textReader.Peek() == '=')
{
textReader.Read();
attributeValue = ReadAttributeValue(textReader);
}
Attribute(attributeName, attributeValue);
}
if (textReader.Peek()=='/')
{
textReader.Read();
CloseTag(tagName);
}
}
if (textReader.Read() != '>')
throw new FormatException("Expected >");
}
bool TestChar(char ch, Func<char, bool> condition) => condition(ch);
public string ReadToken(TextReader textReader, Func<char, bool> condition, bool clearFinalChar = false)
{
StringBuilder characters = new StringBuilder();
while (condition((char)textReader.Peek()) && textReader.Peek() != -1)
{
characters.Append((char)textReader.Read());
}
if ((textReader.Peek() != -1) && clearFinalChar)
textReader.Read();
return characters.ToString();
}
public string ReadTokenLWS(TextReader textReader, Func<char, bool> condition,bool clearFinalChar = false)
{
string token = ReadToken(textReader, condition, clearFinalChar);
ReadToken(textReader, char.IsWhiteSpace);
return token;
}
void ReadLWS(TextReader textReader) => ReadToken(textReader, char.IsWhiteSpace);
public string ReadTagName(TextReader textReader) => ReadTokenLWS(textReader, (ch) => char.IsLetterOrDigit(ch));
public string ReadAttributeName(TextReader textReader) => ReadTokenLWS(textReader, (ch) => !char.IsWhiteSpace(ch) && (ch != '\0') && (ch != '"') && (ch != '\'') && (ch != '>') && (ch != '/') && (ch != '='));
public string ReadAttributeValue(TextReader textReader)
{
switch (textReader.Peek())
{
case '"':
textReader.Read();
return ReadTokenLWS(textReader, (ch) => ch != '"', true);
case '\'':
textReader.Read();
return ReadTokenLWS(textReader, (ch)=> ch != '\'', true);
default:
return ReadTokenLWS(textReader, (ch) => !char.IsWhiteSpace(ch) && (ch != '"') && (ch != '\'') && (ch != '<') && (ch != '>') && (ch != '`'));
}
}
public void ReadText(TextReader textReader)
{
StringBuilder stringBuilder = new StringBuilder();
while (textReader.Peek() != '<')
stringBuilder.Append((char)textReader.Read());
Text(stringBuilder.ToString());
}
public virtual void DOCTYPE(string type)
{
}
public virtual void OpenTag(string tagName)
{
}
public virtual void CloseTag(string tagName)
{
}
public virtual void Attribute(string attributeName,string attributeValue)
{
}
public virtual void Text(string text)
{
}
}
}