For .NET Framework 3.5 and below, it might have been possible to use the XmlUrlResolver
, as shown in this answer. However, this approach downloads the DTDs from the W3C website at runtime, which is not a good idea, not least because W3C seems to be currently blocking such requests. The other answer suggests caching the DTDs as embedded resources in the assembly, similar to your HTML2XHTML.
For other readers using .NET Framework 4.0 and above, you could use XmlPreloadedResolver
, as suggested by Daniel Renshaw, which supports XHTML 1.0. To support XHTML 1.1, you could simplify your implementation by using the flattened version of the DTD, available at xhtml11-flat.dtd on the W3C website. I define an extension method for this purpose:
public static class XmlPreloadedResolverExtensions
{
private const string Xhtml11DtdPublicId = "-//W3C//DTD XHTML 1.1//EN";
private const string Xhtml11DtdSystemId = "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd";
public static void AddXhtml11(this XmlPreloadedResolver resolver, bool @override = false)
{
Add(resolver, new Uri(Xhtml11DtdPublicId, UriKind.RelativeOrAbsolute), ManifestResources.xhtml11_flat_dtd, @override);
Add(resolver, new Uri(Xhtml11DtdSystemId, UriKind.RelativeOrAbsolute), ManifestResources.xhtml11_flat_dtd, @override);
}
public static bool Add(this XmlPreloadedResolver resolver, Uri uri, Stream value, bool @override)
{
if (@override || !resolver.PreloadedUris.Contains(uri))
{
resolver.Add(uri, value);
return true;
}
return false;
}
}
This could then be used like ordinary XmlResolver
instances:
var xmlResolver = new XmlPreloadedResolver();
xmlResolver.AddXhtml11();
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.XmlResolver = xmlResolver;
XDocument document;
using (var xmlReader = XmlReader.Create(input, settings))
document = XDocument.Load(xmlReader);