.net – 打开extern DTD(w3.org,xhtml1-transitional.dtd)时发生错误. 503服务器不可用

前端之家收集整理的这篇文章主要介绍了.net – 打开extern DTD(w3.org,xhtml1-transitional.dtd)时发生错误. 503服务器不可用前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试通过xhtml文档执行xpath查询.使用.NET 3.5.

该文档如下所示:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
   ....
  </head>
  <body>
    ...
  </body>
</html>

因为文档包含各种char实体(& nbsp;等等),所以我需要使用DTD,以便加载一个XmlReader.所以我的代码如下所示:

var s = File.OpenRead(fileToRead)
var reader = XmlReader.Create(s,new XmlReaderSettings{ ProhibitDtd=false });

但是当我运行它时,它返回

An error has occurred while opening external DTD ‘07001’: The remote server returned an error: (503) Server Unavailable.

现在,我知道为什么我得到503错误. W3C explained it very clearly.

我看到“解决方法”,人们只是禁用DTD.这是ProhibitDtd = true可以做的,它消除了503错误.

但是在我的情况下,导致其他问题 – 应用程序没有获得实体定义,因此XML格式格式不正确.如何使用DTD进行验证,并获取实体定义,而不必打到w3.org网站?

我认为.NET 4.0有一个漂亮的内置功能来处理这种情况:XmlPreloadedResolver.但是我需要一个.NET 3.5的解决方案.

有关:
java.io.IOException: Server returned HTTP response code: 503

解决方法

答案是,我必须提供自己的 XmlResolver.我不认为这是内置的.NET 3.5.这真让人困惑这也让我感到困惑,这使我长久以来绊倒了这个问题.这也是令人困惑的,我找不到已经解决了这个问题的其他人?

好的,所以.. XmlResolver.我创建了一个新类,派生自XmlResolver,并且覆盖了三个关键的事情:Credentials(set),ResolveUri和GetEntity.

public sealed class XhtmlResolver : XmlResolver
{
    public override System.Net.ICredentials Credentials
    {
        set { throw new NotSupportedException();}
    }

    public override object GetEntity(Uri absoluteUri,string role,Type t)
    {
       ...
    }

    public override Uri ResolveUri(Uri baseUri,string relativeUri)
    {
      ...
    }
}

关于这个东西的文件很简单,所以我会告诉你我学到了什么.这个类的操作是这样的:XmlReader首先调用ResolveUri,然后给定一个已解决的Uri,然后调用GetEntity.该方法预期返回类型t的对象(作为参数传递).我只看过它请求一个System.IO.Stream.

我的想法是使用csc.exe / resource选项将DTD的本地副本及其XHTML1.0的依赖项嵌入到程序集中,然后检索该资源的流.

private System.IO.Stream GetStreamForNamedResource(string resourceName)
{
    Assembly a = Assembly.GetExecutingAssembly();
    return  a.GetManifestResourceStream(resourceName);
}

很简单这从GetEntity()调用.

但我可以改善这一点.我们首先将它们以简明的方式嵌入DTD中,然后修改上述方法,如下所示:

private System.IO.Stream GetStreamForNamedResource(string resourceName)
{
    Assembly a = Assembly.GetExecutingAssembly();
    return  new System.IO.Compression.GZipStream(a.GetManifestResourceStream(resourceName),System.IO.Compression.CompressionMode.Decompress);
}

代码打开嵌入式资源的流,并返回配置为解压缩的GZipStream.读者得到明文DTD.

我想做的只是解决Xhtml 1.0中DTD的URI.所以我写了ResolveUri和GetEntity来寻找这些特定的DTD,并且只对他们作出肯定的回应.

对于具有DTD语句的XHTML文档,流程是这样的;

> XmlReader调用ResolveUri与XHTML DTD的公共URI,它是“ – // W3C // DTD XHTML 1.0 Transitional // EN”.如果XmlResolver可以解析,它应该返回一个有效的URI.如果不能解决,应该抛出.我的实现只是抛出公共URI.
> XmlReader然后使用DTD的系统标识符调用ResolveUri,在这种情况下,它是“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”.在这种情况下,XhtmlResolver返回一个有效的Uri.
> XmlReader然后使用该URI调用GetEntity. XhtmlResolver抓住嵌入的资源流并返回.

对于依赖项 – xhtml_lat1.ent等也是一样的事情.为了使解析器工作,所有这些事情都需要嵌入.

是的,如果Resolver无法解析URI,那么预计会抛出异常.据我所知,这并没有正式记录.这似乎有点令人惊讶(严重违反the principle of least astonishment).如果相反,ResolveUri返回null,XmlReader将调用GetAntity的空URI,哪个….啊,是绝望的.

这对我有用它应该适用于从.NET处理XHTML的任何人.如果你想在你自己的应用程序中使用这个,grab the DLL.该zip包含完整的源代码.根据@L_502_7@许可.

您可以将其插入到XHTML中的XML应用程序中.使用它像这样:

// for an XmlDocument...
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.XmlResolver = new Ionic.Xml.XhtmlResolver();
doc.Load(xhtmlFile);

// for an XmlReader...
var xmlReaderSettings = new XmlReaderSettings
    {
        ProhibitDtd = false,XmlResolver = new XhtmlResolver()
    };
using (var stream = File.OpenRead(fileToRead))
{
    XmlReader reader = XmlReader.Create(stream,xmlReaderSettings);
    while (reader.Read())
    {
     ...
    }

猜你在找的HTML相关文章