2009-10-29 5 views
9

मैं एक XDocument में एक XHTML दस्तावेज़ लोड करने के लिए कोशिश कर रहा हूँ, लेकिन मैं मुझ पर फेंक दिया अपवाद "अघोषित इकाई के संदर्भ में" हो रही है। मैं ® और » तरह संस्थाओं को हल करने की जरूरत है।मैं कैसे जब एक XDocument में लोड संस्थाओं को हल करते हैं?

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

जब मैं एक XDocument.Load(<StringReader>) करना है जब मैं इन अपवादों फेंक दिया हो रही है:

मेरा मानना ​​है कि मेरे दस्तावेज़ ठीक से बनाई है, यहाँ सिर है।

उत्तर

10

यह MSDN और ब्लॉग पोस्टिंग के एक सहयोग है।

 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

हल वेब से DTDs आम तौर पर एक बुरा विचार है अनुरोध के साथ, यह काफी धीमी है, और इंटरनेट कनेक्शन पर निर्भर करता है और विश्वसनीय है। एक बहुत बेहतर दृष्टिकोण संसाधनों के रूप में उन DTDs की स्थानीय कॉपी की दुकान, और 'Assembly.GetManifestResourceStream' के माध्यम से उन्हें लोड करने के लिए है, या स्थानीय फाइलों के रूप में एक ही निर्देशिका में आपके निष्पादन योग्य के रूप में। अंतर्दृष्टि के लिए –

+0

@ पावेल धन्यवाद! – Dave

8

मुझे डेव के समान समस्या थी और इस सवाल पर आया जिसने मुझे बहुत मदद की। डेव के जवाब और अनुकूलन के लिए पावेल के सुझाव के आधार पर मैंने कक्षा को अद्यतन किया। अब डीटीडी को एम्बेडेड संसाधनों के रूप में संग्रहीत किया जा सकता है और यदि आवश्यक हो तो लोड किया जा सकता है। मुझे पता है कि यह पोस्ट कुछ साल पुरानी है लेकिन शायद यह किसी की मदद कर सकती है।

उदाहरण उपयोग:

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

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

LocalXhtmlXmlResolver वर्ग: - तथ्य यह है कि आप अनावश्यक रूप से W3C सर्वर कम पड़ रहा है से अलग

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); 
    } 
} 
संबंधित मुद्दे