C# 用C验证HTML5#
我们目前正在C#中构建一个green fields应用程序。我们有大量使用SeleniumWeb驱动程序的UI测试。这些测试(以及单元测试)由我们的CI服务器运行 Selenium公开了一个.PageSource属性,并且(对我来说)通过HTML5验证程序运行该源代码作为每个UI测试的另一部分是有意义的 我想学习和我一样的东西。作为奖励,我还想了解一下508期 我的问题是,我找不到任何可以在本地实现这一点的东西,并且很容易集成到我的UI测试中。。W3C站点公开了一个SOAP api,但是我不想在CI过程中访问他们的站点。它们似乎也不支持返回SOAP响应。我希望避免在本地安装完整的W3C服务器 我看到的最接近的事情是,使用它需要编写临时文件和解析报告 在我走这条路之前,我想看看有没有人知道另一条路。最好是我可以调用的DotNet程序集C# 用C验证HTML5#,c#,html,selenium,C#,Html,Selenium,我们目前正在C#中构建一个green fields应用程序。我们有大量使用SeleniumWeb驱动程序的UI测试。这些测试(以及单元测试)由我们的CI服务器运行 Selenium公开了一个.PageSource属性,并且(对我来说)通过HTML5验证程序运行该源代码作为每个UI测试的另一部分是有意义的 我想学习和我一样的东西。作为奖励,我还想了解一下508期 我的问题是,我找不到任何可以在本地实现这一点的东西,并且很容易集成到我的UI测试中。。W3C站点公开了一个SOAP api,但是我不想在
c看起来此链接可能有您想要的内容: 您可以在接受的答案中下载一个标记验证程序,并将您的HTML传递给该验证程序。很抱歉,它们不是.NET程序集:/,但如果您真的愿意,可以将其包装在DLL中
此外,这个问题的一个答案表明W3C服务实际上公开了一个RESTful API,但可以返回一个SOAP响应:在花了整个周末的时间研究这个问题之后,我能看到的唯一解决方案是一个名为CSE HTML Validator的商业库 它就在这里 我为它写了一个简单的包装。这是密码
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
[assembly: CLSCompliant(true)]
namespace HtmlValidator
{
public class Validator
{
#region Constructors...
public Validator(string htmlToValidate)
{
HtmlToValidate = htmlToValidate;
HasExecuted = false;
Errors = new List<ValidationResult>();
Warnings = new List<ValidationResult>();
OtherMessages = new List<ValidationResult>();
}
#endregion
#region Properties...
public IList<ValidationResult> Errors { get; private set; }
public bool HasExecuted { get; private set; }
public string HtmlToValidate { get; private set; }
public IList<ValidationResult> OtherMessages { get; private set; }
public string ResultsString { get; private set; }
public string TempFilePath { get; private set; }
public IList<ValidationResult> Warnings { get; private set; }
#endregion
#region Public methods...
public void ValidateHtmlFile()
{
WriteTempFile();
ExecuteValidator();
DeleteTempFile();
ParseResults();
HasExecuted = true;
}
#endregion
#region Private methods...
private void DeleteTempFile()
{
TempFilePath = Path.GetTempFileName();
File.Delete(TempFilePath);
}
private void ExecuteValidator()
{
var psi = new ProcessStartInfo(GetHTMLValidatorPath())
{
RedirectStandardInput = false,
RedirectStandardOutput = true,
RedirectStandardError = false,
UseShellExecute = false,
Arguments = String.Format(@"-e,(stdout),0,16 ""{0}""", TempFilePath)
};
var p = new Process
{
StartInfo = psi
};
p.Start();
var stdOut = p.StandardOutput;
ResultsString = stdOut.ReadToEnd();
}
private static string GetHTMLValidatorPath()
{
return @"C:\Program Files (x86)\HTMLValidator120\cmdlineprocessor.exe";
}
private void ParseResults()
{
var results = JsonConvert.DeserializeObject<dynamic>(ResultsString);
IList<InternalValidationResult> messages = results.messages.ToObject<List<InternalValidationResult>>();
foreach (InternalValidationResult internalValidationResult in messages)
{
ValidationResult result = new ValidationResult()
{
Message = internalValidationResult.message,
LineNumber = internalValidationResult.linenumber,
MessageCategory = internalValidationResult.messagecategory,
MessageType = internalValidationResult.messagetype,
CharLocation = internalValidationResult.charlocation
};
switch (internalValidationResult.messagetype)
{
case "ERROR":
Errors.Add(result);
break;
case "WARNING":
Warnings.Add(result);
break;
default:
OtherMessages.Add(result);
break;
}
}
}
private void WriteTempFile()
{
TempFilePath = Path.GetTempFileName();
StreamWriter streamWriter = File.AppendText(TempFilePath);
streamWriter.WriteLine(HtmlToValidate);
streamWriter.Flush();
streamWriter.Close();
}
#endregion
}
}
public class ValidationResult
{
public string MessageType { get; set; }
public string MessageCategory { get; set; }
public string Message { get; set; }
public int LineNumber { get; set; }
public int CharLocation { get; set; }
public override string ToString()
{
return String.Format("{0} Line {1} Char {2}:: {3}", this.MessageType, this.LineNumber, this.CharLocation, this.Message);
}
}
public class InternalValidationResult
{
/*
* DA: this class is used as in intermediate store of messages that come back from the underlying validator. The fields must be cased as per the underlying Json object.
* That is why they are ignored.
*/
#region Properties...
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "charlocation"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "charlocation")]
public int charlocation { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "linenumber"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "linenumber")]
public int linenumber { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "message"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "message")]
public string message { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "messagecategory"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "messagecategory")]
public string messagecategory { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "messagetype"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "messagetype")]
public string messagetype { get; set; }
#endregion
}
使用Newtonsoft.Json;
使用制度;
使用System.Collections.Generic;
使用系统诊断;
使用System.IO;
使用System.Linq;
[大会:CLSCompliant(true)]
命名空间HtmlValidator
{
公共类验证器
{
#区域构造函数。。。
公共验证器(字符串htmlToValidate)
{
HtmlToValidate=HtmlToValidate;
HasExecuted=false;
错误=新列表();
警告=新列表();
OtherMessages=新列表();
}
#端区
#区域属性。。。
公共IList错误{get;private set;}
公共bool已执行{get;private set;}
公共字符串HtmlToValidate{get;private set;}
公共IList其他消息{get;private set;}
公共字符串ResultsString{get;private set;}
公共字符串TempFilePath{get;private set;}
公共IList警告{get;private set;}
#端区
#区域公共方法。。。
public void ValidateHtmlFile()
{
WriteTempFile();
ExecuteValidator();
DeleteTempFile();
ParseResults();
HasExecuted=true;
}
#端区
#区域私有方法。。。
私有void DeleteTempFile()
{
TempFilePath=Path.GetTempFileName();
Delete(TempFilePath);
}
私有void ExecuteValidator()
{
var psi=new ProcessStartInfo(GetHTMLValidatorPath())
{
重定向标准输入=false,
重定向标准输出=真,
重定向标准错误=false,
UseShellExecute=false,
Arguments=String.Format(@“-e,(标准输出),0,16”“{0}”“,TempFilePath)
};
var p=新流程
{
StartInfo=psi
};
p、 Start();
var stdOut=p.StandardOutput;
ResultsString=stdOut.ReadToEnd();
}
私有静态字符串GetHTMLValidatorPath()
{
返回@“C:\ProgramFiles(x86)\HTMLValidator120\cmdlineprocessor.exe”;
}
私有void ParseResults()
{
var results=JsonConvert.DeserializeObject(ResultsString);
IList messages=results.messages.ToObject();
foreach(消息中的InternalValidationResult InternalValidationResult)
{
ValidationResult=新的ValidationResult()
{
Message=internalValidationResult.Message,
LineNumber=internalValidationResult.LineNumber,
MessageCategory=internalValidationResult.MessageCategory,
MessageType=internalValidationResult.MessageType,
CharLocation=internalValidationResult.CharLocation
};
开关(internalValidationResult.messagetype)
{
案例“错误”:
错误。添加(结果);
打破
案例“警告”:
警告。添加(结果);
打破
违约:
添加(结果);
打破
}
}
}
私有void WriteTempFile()
{
TempFilePath=Path.GetTempFileName();
StreamWriter StreamWriter=File.AppendText(TempFilePath);
streamWriter.WriteLine(HtmlToValidate);
streamWriter.Flush();
streamWriter.Close();
}
#端区
}
}
公共类验证结果
{
公共字符串MessageType{get;set;}
公共字符串MessageCategory{get;set;}
公共字符串消息{get;set;}
公共整数行号{get;set;}
public int CharLocation{get;set;}
公共重写字符串ToString()
{
返回String.Format(“{0}行{1}字符{2}::{3}”,this.MessageType,this.LineNumber,this.CharLocation,this.Message);
}
}
公共类InternalValidationResult
{
/*
*DA:此类用作从基础验证器返回的消息的中间存储。字段必须按照基础Json对象大小写。
*这就是他们被忽视的原因。
*/
#区域属性。。。
[System.Diagnostics.CodeAnalysis.SuppressMessage(“Microsoft.Naming”,“CA1709:Identifiers应正确拼写”,MessageId=“charlocation”),System.Diagnostics.CodeAnalysis.SuppressMessage(“Microsoft.Naming”,“CA1704:Identifiers应正确拼写”),Message
private const string ValidHtml = "<!DOCType html><html><head></head><body><p>Hello World</p></body></html>";
private const string BrokenHtml = "<!DOCType html><html><head></head><body><p>Hello World</p></body>";
[TestMethod]
public void CanValidHtmlStringReturnNoErrors()
{
Validator subject = new Validator(ValidHtml);
subject.ValidateHtmlFile();
Assert.IsTrue(subject.HasExecuted);
Assert.IsTrue(subject.Errors.Count == 0);
}
[TestMethod]
public void CanInvalidHtmlStringReturnErrors()
{
Validator subject = new Validator(BrokenHtml);
subject.ValidateHtmlFile();
Assert.IsTrue(subject.HasExecuted);
Assert.IsTrue(subject.Errors.Count > 0);
Assert.IsTrue(subject.Errors[0].ToString().Contains("ERROR"));
}
public ref class LibTidy
{
public:
System::String^ __clrcall Test(System::String^ input);
};
System::String^ __clrcall LibTidy::Test(System::String^ input)
{
CStringW cstring(input);
const size_t newsizew = (cstring.GetLength() + 1) * 2;
char* nstringw = new char[newsizew];
size_t convertedCharsw = 0;
wcstombs_s(&convertedCharsw, nstringw, newsizew, cstring, _TRUNCATE);
TidyBuffer errbuf = { 0 };
int rc = -1;
Bool ok;
TidyDoc tdoc = tidyCreate(); // Initialize "document"
ok = tidyOptSetBool(tdoc, TidyShowInfo, no);
ok = tidyOptSetBool(tdoc, TidyQuiet, yes);
ok = tidyOptSetBool(tdoc, TidyEmacs, yes);
if (ok)
rc = tidySetErrorBuffer(tdoc, &errbuf); // Capture diagnostics
if (rc >= 0)
rc = tidyParseString(tdoc, nstringw); // Parse the input
if (rc >= 0)
rc = tidyCleanAndRepair(tdoc); // Tidy it up!
if (rc >= 0)
rc = tidyRunDiagnostics(tdoc); // Kvetch
char* outputBytes = (char*)errbuf.bp;
if (errbuf.allocator != NULL) tidyBufFree(&errbuf);
tidyRelease(tdoc);
return gcnew System::String(outputBytes);
}