Проблемы с разрешением DOCTYPE и ASP.Net
Вопрос
В предыдущий вопрос Я упомянул некоторую работу со сторонней DLL, интерфейс которой использует ряд входных данных XML, определенных с помощью DTD.До сих пор все шло гладко, но у меня все еще есть неприятная проблема с разрешением объявления типа документа в сгенерированных входных значениях.
Чего я не могу понять, так это того, что является решающим фактором при определении того, где искать указанный файл DTD.Если у меня есть объявление, которое выглядит так:
<!DOCTYPE ElementName SYSTEM "ElementName.dtd">
Первоначально я думал, что текущий путь выполнения приложения — это место, где анализатор будет искать DTD.Однако, когда я пытаюсь использовать XML-элемент управления в ASP.Net ошибка, которую я получаю, сбивает меня с толку...
Не удалось найти File 'C: Program Files Microsoft Visual Studio 9.0 common7 ide elementName.dtd'
Почему он ищет там DTD?
Есть ли какие-нибудь гуру XML, которые могут мне помочь в этом вопросе.Я действительно не имею никакого контроля над XML, возвращаемым из этой DLL, так что мне делать?Есть ли способ «зарегистрировать» DTD в операционной системе?Нравится GAC?
Решение
К сожалению, библиотека, сгенерировавшая XML, использовала относительный URL-адрес для dtd, а не полный.Таким образом, XmlDocument XmlControl использует XmlResolver class для преобразования относительного пути в полный.По умолчанию он использует XmlUrlResolver (это конкретный XmlResolver).При этом будет предпринята попытка сопоставить расположение dtd с местоположением, которое, по его мнению, находится относительно документа Xml.Проблема в том, где находится XmlDocument?Вероятно, в памяти, которая не связана ни с чем, и XmlUrlResolver вместо этого использует местоположение процесса, которым в вашем случае является Visual Studio, которая находится по адресу «c:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe».
Так что ты можешь сделать?Ну, я полагаю, вам нужно создать собственный XmlResolver, который наследует от XmlUrlResolver, переопределяет метод ResolveUri и делает что-то подходящее.Сделав это, вам придется:
- Создайте класс XmlReaderSettings и задайте для свойства XmlReolver только что созданный класс.
- Создайте XmlReader, используя XmlReader.Create(), передав документ и объект XmlSettings.
- Создайте XmlDocument и вызовите передачу Load в XmlReader и, наконец.
- Установите для свойства XmlDocument вашего XmlControl значение XmlDocument.
Честно говоря, все это немного муторно, поэтому, если бы это было так, я бы просто использовал string.Replace, чтобы удалить объявление DTD из документа перед его обработкой в XML.
Если вы действительно смелы, вы можете создать преобразователь, который наследуется непосредственно от XmlResolver.Как только вы это сделаете, вы можете переопределить GetEntity метод, а затем вы сможете получить документ dtd откуда угодно.Однажды я написал один, который получал dtds из файлов, встроенных в файлы ресурсов, но, к сожалению, у меня больше нет кода :-(
Другие советы
Если вас на самом деле не заботит проверка каждого документа на соответствие его DTD, вы можете установить для свойства XmlResolver значение null в вашем XmlTextReader (или XmlDocument), чтобы полностью игнорировать DTD.