Ошибка произошла вводный экстерн DTD (w3.org, xhtml1-transitional.dtd). 503 Недоступные Сервера

Я пытаюсь сделать запросы xpath по xhtml документу. Используя.NET 3.5.

Документ похож на это:




  
   ....
  
  
    ...
  

Поскольку документ включает различные символьные объекты (  и так далее), я должен использовать DTD для загрузки его XmlReader. Таким образом, мой код похож на это:

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

Но когда я выполняю это, это возвращается

Ошибка произошла при открытии внешнего DTD 'http://www.w3.org/TR/xhtml1-transitional.dtd': удаленный сервер возвратил ошибку: (503) Недоступный Сервер.

Теперь, я знаю, почему я получаю 503 ошибки. W3C объяснил это очень ясно.

Я видел "обходные решения", где люди просто отключают DTD. Это что ProhibitDtd=true может сделать, и это устраняет 503 ошибки.

Но в моем случае, который приводит к другим проблемам - приложение не получает определения объекта и так не является правильно построенным XML. Как я могу проверить с DTD и получить определения объекта, не поражая веб-сайт w3.org?


Я думаю, что.NET 4.0 имеет изящную встроенную возможность обработать эту ситуацию: XmlPreloadedResolver. Но мне нужно решение для.NET 3.5.


похожие страницы:
- java.io. IOException: Сервер возвратил код ответа HTTP: 503

10
задан Community 23 May 2017 в 12:09
поделиться

2 ответа

Ответ заключается в том, что я должен предоставить свой собственный 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.

Моя идея состоит в том, чтобы встроить локальные копии DTD и его зависимостей для XHTML1.0 в сборку, используя опцию csc.exe /resource, а затем получить поток для этого ресурса.

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 в открытом виде.

Я хотел разрешить только URI для DTD из Xhtml 1.0. Поэтому я написал ResolveUri и GetEntity для поиска этих конкретных DTD и утвердительного ответа только для них.

Для документа XHTML с утверждением DTD поток выглядит следующим образом;

  1. XmlReader вызывает ResolveUri с публичным URI для DTD XHTML, который является "-//W3C//DTD XHTML 1.0 Transitional//EN". Если XmlResolver может разрешить, он должен вернуть... правильный URI. Если он не может разрешить, он должен бросить. Моя реализация просто бросает для публичного URI.

  2. XmlReader затем вызывает ResolveUri с системным идентификатором DTD, который в данном случае "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd". В этом случае XhtmlResolver возвращает правильный Uri.

  3. XmlReader затем вызывает GetEntity с этим URI. XhtmlResolver захватывает поток встроенного ресурса и возвращает его.

То же самое происходит для зависимостей - xhtml_lat1.ent, и так далее. Для того чтобы резольвер работал, все эти вещи должны быть встроены.

И да, если резольвер не может разрешить URI, он должен выбросить исключение. Насколько я могу судить, это официально не документировано. Это кажется немного удивительным. (Вопиющее нарушение принципа наименьшего удивления). Если вместо этого ResolveUri вернет null, XmlReader вызовет GetEntity на нулевом URI, что .... безнадежно.


Это работает для меня. Это должно работать для любого, кто делает обработку XML на XHTML из .NET. Если вы хотите использовать это в своих собственных приложениях, возьмите DLL. В zip-архив включен полный исходный код. Лицензируется по MS Public License.

Вы можете подключить его к своим XML-приложениям, которые работают с XHTML. Используйте его следующим образом:

// 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())
    {
     ...
    }
7
ответ дан 4 December 2019 в 00:23
поделиться

Вы можете запретить XmlReader открывать любые внешние ресурсы, установив для свойства XmlReaderSettings.XmlResolver значение null.

System.Xml.XmlReaderSettings xmlReaderSettings = new System.Xml.XmlReaderSettings ();
xmlReaderSettings.XmlResolver = null;
System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(myUrl, xmlReaderSettings);
3
ответ дан 4 December 2019 в 00:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: