2010-09-17 22 views
6

装载DTD我需要装载一定数量的顶部有这样的XHTML文件:如何通过加快DOCTYPE

<?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。

谢谢。

回答

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"); 
+0

谢谢,但XmlPreloadedResolver是.NET 4中仅:-(我在3.5。 – Polyfun 2010-09-17 08:47:02

+1

你可以创建你自己的'XmlResolver'的派生类,它基本上是一样的。 – 2010-09-17 09:21:54

+0

感谢这就是我所做的,使用这里的例子http://www.codeproject.com/KB/XML/HTML2XHTML.aspx?显示=打印。 – Polyfun 2010-09-17 09:35:05

1

对于.NET框架3.5及以下,它可能已经可以使用XmlUrlResolver,如图this answer。然而,这种方法在运行时从W3C网站下载DTD,这不是一个好主意,这不仅仅是因为W3C似乎正在阻止这样的请求。 other answer建议将DTD缓存为程序集中的嵌入资源,类似于HTML2XHTML

对于使用.NET Framework 4.0及更高版本的其他读者,可以使用XmlPreloadedResolver,建议by Daniel Renshaw,它支持XHTML 1.0。为了支持XHTML 1.1,您可以使用W3C网站上的xhtml11-flat.dtd的扁平化版本的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);