5

我正在尝试验证 XML 文件。我正在使用此代码

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.ValidationType = ValidationType.DTD;

settings.ValidationEventHandler += new ValidationEventHandler(validationError);        

XmlSchemaSet schemas = new XmlSchemaSet();
settings.Schemas = schemas;
XmlReader reader = XmlReader.Create(lblXmlPath.Text, settings);

reader.Settings.Schemas.Add(null, lblDTDPath.Text);
while (reader.Read())
{ 
          // empty by now
}
reader.Close();

但在“reader.Settings.Schemas.Add(null, lblDTDPath.Text);”这一行 Visual Studio 向我显示错误“出于安全原因,此 XML 文档中禁止 DTD。要启用 DTD 处理,请将 XmlReaderSettings 上的 ProhibitDtd 属性设置为 false 并将设置传递给 XmlReader.Create 方法”

正如您在代码中看到的,ProhibitDtd 设置为 false(我也在调试期间进行了验证)。我还尝试在调用 XmlReader.Create() 之前添加架构,但没有成功。

4

4 回答 4

3

我之前为验证 RSS 提要做过此操作。通过本地存储的 DTD 进行验证的方法是将自定义插入XmlResolverXmlReader

XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.ValidationType = ValidationType.DTD;
readerSettings.ProhibitDtd = false;
readerSettings.XmlResolver = new XmlFakeDtdResolver();

这将为读者提供本地 DTD(对于已知格式),而不是从 DOCTYPE 中给出的 URL 下载它。

class XmlFakeDtdResolver : XmlUrlResolver
{
    public static Dictionary<Uri, byte[]> dtdMap = new Dictionary<Uri, byte[]>();
    public static Dictionary<string, Uri> uriMap = new Dictionary<string, Uri>();
    static XmlFakeDtdResolver()
    {
        Uri rss091uri = new Uri("http://fake.uri/rss091");
        uriMap["-//Netscape Communications//DTD RSS 0.91//EN"] = rss091uri;
        uriMap["http://my.netscape.com/publish/formats/rss-0.91.dtd"] = rss091uri;
        dtdMap[rss091uri] = Encoding.ASCII.GetBytes(Resources.rss_0_91dtd);
    }

    public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
    {
        if (dtdMap.ContainsKey(absoluteUri) && ofObjectToReturn == typeof(Stream))
        {
            return new MemoryStream(dtdMap[absoluteUri]);
        }
        return base.GetEntity(absoluteUri, role, ofObjectToReturn);
    }

    public override Uri ResolveUri(Uri baseUri, string relativeUri)
    {
        if (uriMap.ContainsKey(relativeUri))
            return uriMap[relativeUri];
        return base.ResolveUri(baseUri, relativeUri);
    }
}

最后,我决定最终不使用 DTD 验证,而是通过 XML 模式进行验证,原因之一是许多提要不包含 DOCTYPE

于 2012-03-23T17:36:21.900 回答
0

我有一个类似的问题。对我来说,答案是 DTD 不需要通过模式连接,因为 XML 文件指出,通过模式添加导致了我的问题。

于 2009-11-03T16:46:41.233 回答
0

根据我的探索,我可以让它工作的唯一方法是不要将模式添加到XmlReader. xml 文档中指定的 DTD 必须是有效的 url,并且XmlReader每次都会下载它。

如果您需要 shema 是本地的,您可以更改 DTD 的 url 以使用正则表达式指向本地文件,这样它看起来像

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.3//EN" "file:C:\wml.dtd">

注意文件:在网址中。在将其传递给 XmlReader 之前在内存中执行此操作,这样您就不必修改 xml 文件来验证它是否正确。

于 2009-10-02T11:30:29.590 回答
0

尝试在调用 XmlReader.Create 之前将 DTD 架构添加到架构集合。

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.ValidationType = ValidationType.DTD;

settings.ValidationEventHandler += new ValidationEventHandler(validationError);        

XmlSchemaSet schemas = new XmlSchemaSet();

schemas.Add(null, lblDTDPath.Text);
settings.Schemas = schemas;

XmlReader reader = XmlReader.Create(lblXmlPath.Text, settings);

while (reader.Read())
{ 
          // empty by now
}
reader.Close();
于 2009-10-02T11:52:25.757 回答