Я сделал это некоторое время назад для проверки RSS-каналов. Метод для проверки с помощью локально сохраненного DTD заключался в вставке пользовательского XmlResolver
в XmlReader
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.ValidationType = ValidationType.DTD;
readerSettings.ProhibitDtd = false;
readerSettings.XmlResolver = new XmlFakeDtdResolver();
, который даст читателю локальное DTD (для известных форматов) вместо загрузки его с URL-адреса, указанного в DOCTYPE.
class XmlFakeDtdResolver : XmlUrlResolver
{
public static Dictionary<Uri, byte[]> dtdMap = new Dictionary<Uri, byte[]>();
public static Dictionary<string, Uri> uriMap = new Dictionary<string, Uri>();
static XmlFakeDtdResolver()
{
Uri rss091uri = new Uri("http://fake.uri/rss091");
uriMap["-//Netscape Communications//DTD RSS 0.91//EN"] = rss091uri;
uriMap["http://my.netscape.com/publish/formats/rss-0.91.dtd"] = rss091uri;
dtdMap[rss091uri] = Encoding.ASCII.GetBytes(Resources.rss_0_91dtd);
}
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
if (dtdMap.ContainsKey(absoluteUri) && ofObjectToReturn == typeof(Stream))
{
return new MemoryStream(dtdMap[absoluteUri]);
}
return base.GetEntity(absoluteUri, role, ofObjectToReturn);
}
public override Uri ResolveUri(Uri baseUri, string relativeUri)
{
if (uriMap.ContainsKey(relativeUri))
return uriMap[relativeUri];
return base.ResolveUri(baseUri, relativeUri);
}
}
В качестве заключительного замечания я решил не использовать проверку DTD в конце и перейти к проверке по схеме XML, одной из причин которой является то, что многие каналы не содержат DOCTYPE