Проблема проверки XML-файла с локальным DTD-файлом в C # - PullRequest
5 голосов
/ 02 октября 2009

Я пытаюсь проверить 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 показывает мне эту ошибку: «Из соображений безопасности DTD запрещен в этом документе XML. Чтобы включить обработку DTD, установите для свойства ProhibitDtd объекта XmlReaderSettings значение false и передайте настройки в метод XmlReader.Create»

Как видно из кода, для ProhibitDtd установлено значение false (я проверял и во время отладки). Я также попытался добавить схему перед вызовом XmlReader.Create (), но безуспешно.

Ответы [ 4 ]

3 голосов
/ 23 марта 2012

Я сделал это некоторое время назад для проверки RSS-каналов. Метод для проверки с помощью локально сохраненного DTD заключался в вставке пользовательского XmlResolver в XmlReader

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

, который даст читателю локальное DTD (для известных форматов) вместо загрузки его с URL-адреса, указанного в DOCTYPE.

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

0 голосов
/ 02 октября 2009

Попробуйте добавить свою схему DTD в коллекцию схем перед вызовом XmlReader.Create.

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();
0 голосов
/ 03 ноября 2009

У меня была похожая проблема. Для меня ответ состоял в том, что DTD не нужно подключать через схемы, поскольку XML-файл указывает на это, добавление через схемы вызвало у меня проблему.

0 голосов
/ 02 октября 2009

Из-за того, что я возился, единственный способ заставить его работать - не добавлять схему к XmlReader. DTD, указанный в документе xml, должен быть действительным URL-адресом, и XmlReader будет загружать его каждый раз.

Если вам нужно, чтобы shema была локальной, вы можете изменить URL DTD, чтобы он указывал на локальный файл с помощью регулярного выражения, чтобы он выглядел примерно так:

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

Обратите внимание на файл : в URL. Сделайте это в памяти перед передачей его в XmlReader, и вам не нужно будет изменять файл xml только для того, чтобы изменить его на правильность.

...