如何加快通过DOCTYPE加载DTD

时间:2010-09-17 06:58:04

标签: c# .net xml

我需要加载一些在顶部有这个的xhtml文件:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

每个文件都将加载到单独的System.Xml.XmlDocument中。由于DOCTYPE声明,它们需要很长时间才能加载。我尝试设置XmlResolver = null,但后来我抛出了XmlException,因为我有无效的实体(例如,“)。所以我认为我可以为第一个XmlDocument下载DTD,并以某种方式将其重用于后续的XmlDocuments(从而避免性能损失),但我不知道如何做到这一点。

我正在使用.Net 3.5。

感谢。

2 个答案:

答案 0 :(得分:4)

我认为您应该能够使用XmlPreloadedResolver解决此解析程序问题。但是,我在使自己工作时遇到了一些困难。看起来XHTML 1.0更容易支持,因为它是一个“已知的”DTD:XmlKnownDtds而XHTML 1.1当前不是“已知”,这意味着你将不得不重新加载一堆URI。

例如:

XmlPreloadedResolver xmlPreloadedResolver = new XmlPreloadedResolver(XmlKnownDtds.Xhtml10);
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"), File.ReadAllBytes("D:\\xhtml11.dtd"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-inlstyle-1.mod"), File.ReadAllBytes("D:\\xhtml-inlstyle-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-framework-1.mod"), File.ReadAllBytes("D:\\xhtml-framework-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-text-1.mod"), File.ReadAllBytes("D:\\xhtml-text-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-hypertext-1.mod"), File.ReadAllBytes("D:\\xhtml-hypertext-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-list-1.mod"), File.ReadAllBytes("D:\\xhtml-list-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-edit-1.mod"), File.ReadAllBytes("D:\\xhtml-edit-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-bdo-1.mod"), File.ReadAllBytes("D:\\xhtml-bdo-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/ruby/xhtml-ruby-1.mod"), File.ReadAllBytes("D:\\xhtml-ruby-1.mod"));
xmlPreloadedResolver.Add(new Uri("http://www.w3.org/TR/xhtml-modularization/DTD/xhtml-pres-1.mod"), File.ReadAllBytes("D:\\xhtml-pres-1.mod"));
// TODO: Add other modules here (see the xhtml11.dtd for the full list)
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.XmlResolver = xmlPreloadedResolver;
xmlDocument.Load("D:\\doc1.xml");

答案 1 :(得分:1)

对于.NET Framework 3.5及更低版本,可能可以使用XmlUrlResolver,如this answer所示。但是,这种方法在运行时从W3C网站下载DTD,这不是一个好主意,尤其是因为W3C似乎正在阻止此类请求。 other answer建议将DTD缓存为程序集中的嵌入资源,类似于HTML2XHTML

对于使用.NET Framework 4.0及更高版本的其他读者,您可以使用XmlPreloadedResolver,如支持XHTML 1.0的建议by Daniel Renshaw。为了支持XHTML 1.1,您可以使用DT3的展平版本(可在W3C网站上的xhtml11-flat.dtd获得)来简化您的实施。我为此目的定义了一个扩展方法:

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;
    }
}

然后可以像普通XmlResolver实例一样使用它:

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);