2010-09-17 59 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);