.net 打开外部DTD(w3.org,xhtml1 transitional.DTD)时出错。503服务器不可用
我正在尝试对xhtml文档执行xpath查询。使用.NET3.5 该文档如下所示:.net 打开外部DTD(w3.org,xhtml1 transitional.DTD)时出错。503服务器不可用,.net,xml,xhtml,w3c,dtd,.net,Xml,Xhtml,W3c,Dtd,我正在尝试对xhtml文档执行xpath查询。使用.NET3.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">
<!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>
var s = File.OpenRead(fileToRead)
var reader = XmlReader.Create(s, new XmlReaderSettings{ ProhibitDtd=false });
// 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())
{
...
}
但当我运行它时,它会返回
打开外部DTD“”时出错:远程服务器返回错误:(503)服务器不可用
现在,我知道为什么会出现503错误了
我见过“变通方法”,人们只是禁用DTD。这就是prohibidtd=true
所能做的,它消除了503错误
但在我的例子中,这会导致其他问题——应用程序没有实体定义,因此不是格式良好的XML。如何在不访问w3.org网站的情况下使用DTD进行验证并获取实体定义
我认为.NET4.0有一个漂亮的内置功能来处理这种情况:。但是我需要一个.NET3.5的解决方案
相关:
-答案是,我必须提供我自己的。我不认为这是.NET3.5内置的。这真令人费解。同样令人困惑的是,我花了这么长时间才偶然发现这个问题。同样令人困惑的是,我找不到其他人已经解决了这个问题 好吧,那么。。XmlResolver。我创建了一个新类,该类派生自XmlResolver,并超越了三个关键因素:凭证(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
我想做的是只解析XHTML1.0中DTD的URI。因此,我编写了ResolveUri和GetEntity来查找那些特定的DTD,并只对它们做出肯定的响应
对于带有DTD语句的XHTML文档,流程如下:
“-//W3C//DTD XHTML 1.0//EN”
。如果XmlResolver可以解析,它应该返回。。。有效的URI。如果它不能解决,它应该抛出。我的实现只是抛出公共URI”http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“
。在本例中,XhtmlResolver返回一个有效的Uri这对我有用。它应该适用于从.NET在XHTML上进行XML处理的任何人。如果您想在自己的应用程序中使用它。zip包含完整的源代码。根据 您可以将其插入到您的XML应用程序中,这些应用程序可以处理XHTML。像这样使用它:
<!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>
var s = File.OpenRead(fileToRead)
var reader = XmlReader.Create(s, new XmlReaderSettings{ ProhibitDtd=false });
// 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())
{
...
}
通过将XmlReaderSettings.XmlResolver属性设置为null,可以禁止XmlReader打开任何外部资源
System.Xml.XmlReaderSettings xmlReaderSettings = new System.Xml.XmlReaderSettings ();
xmlReaderSettings.XmlResolver = null;
System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(myUrl, xmlReaderSettings);
当您的
ResolveUri
方法获得对类似-//W3C//ELEMENTS XHTML Images 1.0//EN
的URI的“公共”形式的请求时,您的方法是否会抛出并等待以http://
开头的后续类似web的URI
我没有抛出,而是将公共URI解析为相应的http://
URI(然后在GetEntity
方法中拦截对http://
URI的请求)
因此,我从来不需要扔东西,我认为这是正确的解决办法
这是一个聪明的方法。你的字典有多大?我向您指出的库只处理XHTML1.0,并且只需要映射一个公共URI库 我使用的是“模块化”的XHTML1.1,所以我必须映射大约40个文件 请注意,框架的行为可能已经改变!我有一个库(包括我的XHTMLResolver类),它是用.NET Framework 2构建的,但是调用它的方式不同,这取决于应用程序(使用库的)是为.NET 2还是.NET 4构建的 对于.NET 2,当我的ResolveUri方法始终仅透明地委托给XmlUrlResolver时,它将:
- 请求解析子资源(例如,
文件)的公共URI,我的实现刚刚委托给XMLURLSolver*.mod
- 要求获取子资源的“已解析”公共实体,该子资源是