2009-10-29 13 views
9

Próbuję wczytać dokument XHTML do XDocument, ale otrzymuję "odwołanie do niezadeklarowanego obiektu", który został mi zgłoszony. Muszę rozwiązać takie podmioty, jak ® i ».Jak rozwiązywać elementy podczas ładowania do XDocument?

wierzę mój dokument jest prawidłowo uformowane, tutaj jest głowa:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 

Kiedy zrobić XDocument.Load(<StringReader>) jest, gdy dostaję te wyjątki rzucane.

Odpowiedz

10

To jest współpraca z msdn i blogów.

 XDocument document; 

     using (var stringReader = new StringReader(output)) 
     { 
      var settings = new XmlReaderSettings 
      { 
       ProhibitDtd = false, 
       XmlResolver = new LocalXhtmlXmlResolver(bool.Parse(ConfigurationManager.AppSettings["CacheDTDs"])) 
      }; 

      document = XDocument.Load(XmlReader.Create(stringReader, settings)); 
     } 

    private class LocalXhtmlXmlResolver : XmlUrlResolver 
    { 
     private static readonly Dictionary<string, Uri> KnownUris = new Dictionary<string, Uri> 
     { 
      { "-//W3C//DTD XHTML 1.0 Strict//EN", new Uri("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd") }, 
      { "-//W3C XHTML 1.0 Transitional//EN", new Uri("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd") }, 
      { "-//W3C//DTD XHTML 1.0 Transitional//EN", new Uri("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd") }, 
      { "-//W3C XHTML 1.0 Frameset//EN", new Uri("http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd") }, 
      { "-//W3C//DTD XHTML 1.1//EN", new Uri("http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd") } 
     }; 

     private bool enableHttpCaching; 
     private ICredentials credentials; 

     public LocalXhtmlXmlResolver(bool enableHttpCaching) 
     { 
      this.enableHttpCaching = enableHttpCaching; 
     } 

     public override Uri ResolveUri(Uri baseUri, string relativeUri) 
     { 
      Debug.WriteLineIf(!KnownUris.ContainsKey(relativeUri), "Could not find: " + relativeUri); 

      return KnownUris.ContainsKey(relativeUri) ? KnownUris[relativeUri] : base.ResolveUri(baseUri, relativeUri); 
     } 

     public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) 
     { 
      if (absoluteUri == null) 
      { 
       throw new ArgumentNullException("absoluteUri"); 
      } 

      //resolve resources from cache (if possible) 
      if (absoluteUri.Scheme == "http" && this.enableHttpCaching && (ofObjectToReturn == null || ofObjectToReturn == typeof(Stream))) 
      { 
       var request = WebRequest.Create(absoluteUri); 

       request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.Default); 

       if (this.credentials != null) 
       { 
        request.Credentials = this.credentials; 
       } 

       var response = request.GetResponse(); 

       return response.GetResponseStream(); 
      } 

      //otherwise use the default behavior of the XmlUrlResolver class (resolve resources from source) 
      return base.GetEntity(absoluteUri, role, ofObjectToReturn); 
     } 
    } 
+8

Rozwiązywania DTD z sieci jest ogólnie zły pomysł - oprócz faktu, że jesteś niepotrzebnie uderzanie serwerów W3C z prośbami jest to dość powolne, a połączenie internetowe jest dostępne i niezawodne. O wiele lepszym sposobem jest przechowywanie lokalnych kopii tych DTD jako zasobów i ładowanie ich za pomocą 'Assembly.GetManifestResourceStream'; lub jako pliki lokalne w tym samym katalogu, co plik wykonywalny. –

+0

@Pavel dzięki za wgląd! – Dave

8

Miałem ten sam problem co Dave i natknąłem się na to pytanie, które bardzo mi pomogło. Na podstawie odpowiedzi Dave'a i sugestii Pavela o optymalizacji zaktualizowałem klasę. Teraz DTD mogą być przechowywane jako zasoby osadzone i ładowane w razie potrzeby. Wiem, że ten post ma kilka lat, ale może to komuś pomóc.

Przykład użycia: Klasa

XmlReaderSettings readerSettings = new XmlReaderSettings 
    { 
     DtdProcessing = DtdProcessing.Parse, 
     XmlResolver = new LocalXhtmlXmlResolver() 
    }; 

using (XmlReader reader = XmlReader.Create(xhtmlStream, readerSettings)) 
{ 
    XDocument xhtml = XDocument.Load(reader); 
    ... 
} 

LocalXhtmlXmlResolver:

public class LocalXhtmlXmlResolver : XmlUrlResolver 
{ 
    private const string ResourcePrefix = "Your.Namespace.Here."; 

    private static readonly Dictionary<string, string> _knownDtds = new Dictionary<string, string> 
     { 
      { "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", ResourcePrefix + "xhtml1-strict.dtd" }, 
      { "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", ResourcePrefix + "xhtml1-transitional.dtd" }, 
      { "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd", ResourcePrefix + "xhtml1-frameset.dtd" }, 
      { "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd", ResourcePrefix + "xhtml11.dtd" }, 
      { "http://www.w3.org/TR/xhtml1/DTD/-//W3C//ENTITIES Latin 1 for XHTML//EN", ResourcePrefix + "xhtml-lat1.ent" }, 
      { "http://www.w3.org/TR/xhtml1/DTD/-//W3C//ENTITIES Special for XHTML//EN", ResourcePrefix + "xhtml-special.ent" }, 
      { "http://www.w3.org/TR/xhtml1/DTD/-//W3C//ENTITIES Symbols for XHTML//EN", ResourcePrefix + "xhtml-symbol.ent" } 
     }; 

    private static readonly Dictionary<string, Uri> _knownUris = new Dictionary<string, Uri> 
     { 
      { "-//W3C//DTD XHTML 1.0 Strict//EN", new Uri("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd") }, 
      { "-//W3C XHTML 1.0 Transitional//EN", new Uri("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd") }, 
      { "-//W3C//DTD XHTML 1.0 Transitional//EN", new Uri("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd") }, 
      { "-//W3C XHTML 1.0 Frameset//EN", new Uri("http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd") }, 
      { "-//W3C//DTD XHTML 1.1//EN", new Uri("http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd") } 
     }; 

    public override Uri ResolveUri(Uri baseUri, string relativeUri) 
    { 
     return _knownUris.ContainsKey(relativeUri) ? _knownUris[relativeUri] : base.ResolveUri(baseUri, relativeUri); 
    } 

    public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) 
    { 
     if (absoluteUri == null) 
     { 
      throw new ArgumentNullException("absoluteUri"); 
     } 

     if (_knownDtds.ContainsKey(absoluteUri.OriginalString)) 
     { 
      string resourceName = _knownDtds[absoluteUri.OriginalString]; 
      Assembly assembly = Assembly.GetAssembly(typeof(LocalXhtmlXmlResolver)); 
      return assembly.GetManifestResourceStream(resourceName); 
     } 

     return base.GetEntity(absoluteUri, role, ofObjectToReturn); 
    } 
} 
Powiązane problemy