webForumDet fria alternativet

XHTMLStrictFilter

24 svar · 1 617 visningar · startad av Web-Tor

Web-TorMedlem sedan nov. 200013 890 inlägg
#1

1. Jag använda följande kod för få min sida validerad som XHTML:

/* 
* Written by Mark Pasternak, [email]mark.pasternak@universum.se[/email] 
* Feel free to modify 
*/ 
using System; 
using System.IO; 
using System.Text.RegularExpressions; 

namespace Consolidate 
{ 
	/// <summary> 
	/// Response Filter that modifies the ASP.NET output so it can validate against the XHTML 1.1 Strict standard. 
	/// Two things are modified: 
	/// 1. The form name attribute is removed. Warning, this may break JavaScript code! 
	/// 2. The viewstate is wrapped in a div element. 
	/// </summary> 
	public class XHTMLStrictFilter : Stream 
	{ 
		private Stream _sink; 
		private long _position; 

		private static Regex _regForm = new Regex([b][red]"<form .*name=.* .*>"[/red][/b], RegexOptions.Compiled|RegexOptions.IgnoreCase); 
		private static Regex _regNameReplace = new Regex("name=[^ ]*", RegexOptions.Compiled|RegexOptions.IgnoreCase); 
		private static Regex _regViewState = new Regex("<input type=\"hidden\" name=\"__VIEWSTATE\" value=\".*\" />", RegexOptions.Compiled|RegexOptions.IgnoreCase); 

		private bool _formFix; 
		private bool _viewStateFix; 

		public XHTMLStrictFilter(Stream sink) 
		{ 
			_sink = sink; 
		} 

		// The following members of Stream must be overriden. 
		public override bool CanRead 
		{ 
			get { return true; } 
		} 

		public override bool CanSeek 
		{ 
			get { return true; } 
		} 

		public override bool CanWrite 
		{ 
			get { return true; } 
		} 

		public override long Length 
		{ 
			get { return 0; } 
		} 

		public override long Position 
		{ 
			get { return _position; } 
			set { _position = value; } 
		} 

		public override long Seek(long offset, System.IO.SeekOrigin direction) 
		{ 
			return _sink.Seek(offset, direction); 
		} 

		public override void SetLength(long length) 
		{ 
			_sink.SetLength(length); 
		} 

		public override void Close() 
		{ 
			_sink.Close(); 
		} 

		public override void Flush() 
		{ 
			_sink.Flush(); 
		} 

		public override int Read(byte[] buffer, int offset, int count) 
		{ 
			return _sink.Read(buffer, offset, count); 
		} 

		// The Write method actually does the filtering. 
		public override void Write(byte[] buffer, int offset, int count) 
		{ 
			byte[] data; 

			if(!_formFix || !_viewStateFix) 
			{ 
				string htmlOutput = System.Text.UTF8Encoding.UTF8.GetString(buffer); 
				int length = htmlOutput.Length; 
				if(!_formFix && _regForm.IsMatch(htmlOutput)) 
				{ 
					string formMatch=_regForm.Match(htmlOutput).Value; 
					htmlOutput=Regex.Replace(htmlOutput, formMatch, _regNameReplace.Replace(formMatch, ""), RegexOptions.IgnoreCase); 
					_formFix=true; 
				} 
				if(!_viewStateFix && _regViewState.IsMatch(htmlOutput)) 
				{ 
					string viewStateMatch=_regViewState.Match(htmlOutput).Value; 
					htmlOutput=Regex.Replace(htmlOutput, viewStateMatch, "<div>"+viewStateMatch+"</div>", RegexOptions.IgnoreCase); 
					_viewStateFix=true; 
				} 
				data = System.Text.UTF8Encoding.UTF8.GetBytes(htmlOutput); 
				count -= length - htmlOutput.Length; 
			} 
			else 
			{ 
				data = new byte[count]; 
				Buffer.BlockCopy(buffer, offset, data, 0, count); 
			} 
			_sink.Write(data, 0, count); 
		} 
	} 
}

Den ska bl.a. ta bort name="foo" ur alla form-taggar. Problemet är att det inte funkar om action-attributet innehåller ett frågetecken:

<!-- Funkar -->
<form name="foo" action="test.html">

<!-- Funkar inte -->
<form name="foo" action="test.html?var=1">

Hur kan man lösa det?

2. Vad jag förstår går det att lägga till ovanstående klass i global.asax så att alla sidor körs genom XHTML-filtrer. Hur gör jag det?

Web-TorMedlem sedan nov. 200013 890 inlägg
#2

Ok! Jag vet att det är en rejäl bit kod men någon borde väl vara duktigt på Regex. :q

Problemet borde väl ligga i den fetmarkerade biten ovanför?

icaaqMedlem sedan okt. 20005 273 inlägg
#3

1.

[red]
private static Regex _regForm = new Regex("<form .*name=\".*\">", RegexOptions.Compiled|RegexOptions.IgnoreCase);
[/red]

2.

[red]
		protected void Application_EndRequest(Object sender, EventArgs e)
		{
			Response.Filter = new XHTMLStrictFilter(Response.Filter);
		}[/red]

helt otestat ;)

Web-TorMedlem sedan nov. 200013 890 inlägg
#4

1. Ingen skillnad. :(
2. /r Det funkade om jag lade den i Application_BeginRequest. :)

Web-TorMedlem sedan nov. 200013 890 inlägg
#5

Jag ställer väl frågan på ett annat sätt då:
Hur gör jag för att matcha name="" när det ligger i form-tagg?

Web-TorMedlem sedan nov. 200013 890 inlägg
#6

Ingen som kan något om reguljära uttryck alltså?

DavidBMedlem sedan jan. 20001 372 inlägg
#7

kolla här:
http://www.webeye.nu/default2.asp?que=asp/default.asp&exec=asp/artiklar/asp_11.asp

Det e ju dock asp men jag antar att det är samma för asp.net

spangoMedlem sedan juni 20008 205 inlägg
#8

Alltså... nu kan ju inte jag C#, men jag gör ett försök ändå. Jag tror att regexpen i sin nuvarande form kan vara något för girig, om det ser ut så här:
@"<form .*name=(.).*?\1 .*>"
skulle det kanske funka. :OO

Web-TorMedlem sedan nov. 200013 890 inlägg
#9

Det var inte fel på min RegEx överhuvudtaget.
Jag fick hjälp på ett annat forum :r och svaret låg i den här raden.

// Gammal och fel
htmlOutput=Regex.Replace(htmlOutput, formMatch, _regNameReplace.Replace(formMatch, "")

// Ny och rätt
htmlOutput=Regex.Replace(htmlOutput,_regNameReplace.Match(formMatch).value,"")

Inte för att jag fattar varför men nu funkar det. :)

Web-TorMedlem sedan nov. 200013 890 inlägg
#10

Jag har hittat ett fel till. :(
Den här gången är det div-taggarna runt ViewState som inte funkar om ViewState-fältet innehåller ett plus (+).

Funkar
<input type="hidden" name="__VIEWSTATE" value="dDwtMTE5MjY4" />

Funkar inte
<input type="hidden" name="__VIEWSTATE" value="**+**dDwtMTE5MjY4" />

Snälla, hjälp!

Web-TorMedlem sedan nov. 200013 890 inlägg
#11

Nu har hag fått hjälp att lösa detta och felet var att alla RegEx-tecken (+, ?, \, ^, m.m.) tolkades som just RegEx.

// Fel
htmlOutput=Regex.Replace(htmlOutput, viewStateMatch, "<div>"+viewStateMatch+"</div>");

// Rätt
htmlOutput=Regex.Replace(htmlOutput, "<input type=\"hidden\" name=\"__VIEWSTATE\" value=\".*\" />", "<div>"+viewStateMatch+"</div>");

Det kan vara bra att veta för alla andra som använder det här filtret. ;)

icaaqMedlem sedan okt. 20005 273 inlägg
#12

Jag skulle vilja kicka igång denna tråd igen och undrar om man kan ta bort alla border="0" genom detta filter.

någon med stora regEx kunskaper kanske kan ge mig ett filter som funkar ;)

mv icaaq

icaaqMedlem sedan okt. 20005 273 inlägg
#13

Fixade det själv :)

[red]
/*
* Written by Mark Pasternak, [email]mark.pasternak@universum.se[/email]
* Feel free to modify
*/
using System;
using System.IO;
using System.Text.RegularExpressions;

namespace NineteenDecember
{
	/// <summary>
	/// Response Filter that modifies the ASP.NET output so it can validate against the XHTML 1.1 Strict standard.
	/// Two things are modified:
	/// 1. The form name attribute is removed. Warning, this may break JavaScript code!
	/// 2. The viewstate is wrapped in a div element.
	/// </summary>
	public class XHTMLStrictFilter : Stream
	{
		private Stream _sink;
		private long _position;

		private static Regex _regForm = new Regex("<form .*name=.* .*>", RegexOptions.Compiled|RegexOptions.IgnoreCase);
		private static Regex _regNameReplace = new Regex("name=[^ ]*", RegexOptions.Compiled|RegexOptions.IgnoreCase);
		private static Regex _regViewState = new Regex("<input type=\"hidden\" name=\"__VIEWSTATE\" value=\".*\" />", RegexOptions.Compiled|RegexOptions.IgnoreCase);
		// Tillagd 2004-02-11. Tar bort alla border="0"
		private static Regex _regBorder = new Regex("border=[^ ]*", RegexOptions.Compiled|RegexOptions.IgnoreCase);

		private bool _formFix;
		private bool _viewStateFix;
		private bool _borderFix;

		public XHTMLStrictFilter(Stream sink)
		{
			_sink = sink;
		}

		// The following members of Stream must be overriden.
		public override bool CanRead
		{
			get { return true; }
		}

		public override bool CanSeek
		{
			get { return true; }
		}

		public override bool CanWrite
		{
			get { return true; }
		}

		public override long Length
		{
			get { return 0; }
		}

		public override long Position
		{
			get { return _position; }
			set { _position = value; }
		}

		public override long Seek(long offset, System.IO.SeekOrigin direction)
		{
			return _sink.Seek(offset, direction);
		}

		public override void SetLength(long length)
		{
			_sink.SetLength(length);
		}

		public override void Close()
		{
			_sink.Close();
		}

		public override void Flush()
		{
			_sink.Flush();
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			return _sink.Read(buffer, offset, count);
		}

		// The Write method actually does the filtering.
		public override void Write(byte[] buffer, int offset, int count)
		{
			byte[] data;

			if(!_formFix || !_viewStateFix || !_borderFix)
			{
				//string htmlOutput = System.Text.UTF8Encoding.UTF8.GetString(buffer);
				string htmlOutput = System.Text.Encoding.GetEncoding("iso-8859-1").GetString(buffer);
				int length = htmlOutput.Length;
				if(!_formFix && _regForm.IsMatch(htmlOutput))
				{
					string formMatch=_regForm.Match(htmlOutput).Value;
					
					// *** Borttagen 03-06-17 ***
					// *** htmlOutput=Regex.Replace(htmlOutput, formMatch, _regNameReplace.Replace(formMatch, ""), RegexOptions.IgnoreCase);
					htmlOutput=Regex.Replace(htmlOutput, _regNameReplace.Match(formMatch).Value,"", RegexOptions.IgnoreCase);
					_formFix=true;
				}
				if(!_viewStateFix && _regViewState.IsMatch(htmlOutput))
				{
					string viewStateMatch=_regViewState.Match(htmlOutput).Value;
					htmlOutput=Regex.Replace(htmlOutput, "<input type=\"hidden\" name=\"__VIEWSTATE\" value=\".*\" />", "<div>"+viewStateMatch+"</div>", RegexOptions.IgnoreCase); 
					_viewStateFix=true;
				}
				// Tillagd 2004-02-11. Tar bort alla border="0"
				if(!_borderFix && _regBorder.IsMatch(htmlOutput))
				{
					string formMatch=_regBorder.Match(htmlOutput).Value;
					htmlOutput=Regex.Replace(htmlOutput, _regBorder.Match(formMatch).Value,"", RegexOptions.IgnoreCase);
					_borderFix=true;
				}
				//data = System.Text.UTF8Encoding.UTF8.GetBytes(htmlOutput);
				data = System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(htmlOutput);
				count -= length - htmlOutput.Length;
			}
			else
			{
				data = new byte[count];
				Buffer.BlockCopy(buffer, offset, data, 0, count);
			}
			_sink.Write(data, 0, count);
		}
	}
}
[/red]

Det kan vara bra att veta för alla andra som använder det här filtret. ;)

mv icaaq

maqeMedlem sedan dec. 2003824 inlägg
#14

Använder det filtret som finns i den senaste tråden men jag får endå fel på hidden taggarna för viewstate <input type="hidden" name="__EVENTTARGET" value="" /> samt <script language="javascript" type="text/javascript"> ... Är inte det filtret komplett?

maqeMedlem sedan dec. 2003824 inlägg
#15

__EVENTTAGET och __EVENTARGUMENT fick jag lägga till i koden bara men 2 language="javascript" skulle jag även vilja ta bort ... man får väl göra en regexp för det med antar jag?

maqeMedlem sedan dec. 2003824 inlägg
#16

Verkar som att __dopostback funktionen har både languge och type? <script language="javascript" type="text/javascript"> Är det ingen som använder detta filter längre och har en nyare version. Jag löste javascript felet i __doPostBack genom att ta bort language attributet men det är ju inte så vettigt kanske...

Web-TorMedlem sedan nov. 200013 890 inlägg
#17

Poängen med scriptet är ju att få sidan att validera enligt XHTML standarden. Då kan du ju ta bort language-attributet. ;)

maqeMedlem sedan dec. 2003824 inlägg
#18

Näe jag vet det men eftersom __doPostBack innehåller både language och type så var jag tvungen att ta bort language för att endast får type kvar :) ... förstår inte varför min __doPostBack function innehåller både language och type ... kanske för att jag kör episerver?

maqeMedlem sedan dec. 2003824 inlägg
#19

Verkar som att man får ersätta __dopostback på något sätt ... nån som vet hur?

maqeMedlem sedan dec. 2003824 inlägg
#20

Nu verkar jag ha fått allt att fungera förutom att jag måste ha name attributet i formuläret. När jag plockar bort name attributet i form taggen och bara har id så smäller __dopostback funktionen med felet att __EVENTTARGET är null eller inget objekt. Skulle vara otroligt tacksam om nåon som själv kör detta kunde vara lite hjälpsam.

144 ms totalt · 3 externa anrop · v20260731065814-full.0e50b1ef
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
141 ms — hämta tråd, inlägg och bilagor (db)