Валидация XML в ЧтениеXML - не работает!

1. andrewks 1370 06.10.12 17:48 Сейчас в теме
вот код:

	Попытка
		ТекСхема=Новый СхемаXML;
		ТекСхема.РасположениеСхемы=ИмяФайлаСхемы;
		НаборСхем=Новый НаборСхемXML;
		НаборСхем.Добавить(ТекСхема);
	
		ХМЛ=Новый ЧтениеXML;
		ХМЛ.ОткрытьФайл(ИмяФайла,Новый ПараметрыЧтенияXML(,,,ТипПроверкиXML.СхемаXML),НаборСхем);
		Пока ХМЛ.Прочитать() Цикл
		КонецЦикла;
		
		ХМЛ.Закрыть();
		
	Исключение
		ТекстОшибки=ОписаниеОшибки();
		Сообщить(ТекстОшибки);
	КонецПопытки;

Показать


если верить СП, всё должно работать. но не работает, выдаёт ошибку:

Ошибка при вызове метода контекста (Прочитать): Ошибка разбора XML: - [2,32]
Ошибка:
Element 'Файл': No matching global declaration available for the validation root.

в инете не нашёл ни одного рабочего примера валидации файла по схеме штатными методами 1С - ни через ЧтениеXML, ни через ФабрикаXDTO (здесь файл с ошибками спокойно грузится безо всяких сообщений о несоответствии схеме)

у кого-нибудь есть пример рабочего кода для валидации штатными средствами 1С? (если что, через msxml я знаю, как, интересуют именно штатные )
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
7. kasper076 104 03.02.17 06:36 Сейчас в теме
(1) А файл выгружался средствами 1С по этой же схеме?
2. pumbaE 06.10.12 18:13 Сейчас в теме
У тебя случаем в схеме не прописано, что для определенных объектов проверку брать из другой схемы?

это вопрос для проверки, удаляюсь до понедельника.
3. andrewks 1370 06.10.12 18:38 Сейчас в теме
4. andrewks 1370 06.10.12 19:19 Сейчас в теме
платформа 8.2.15.319, если что. но, судя по обилию в инете старых веток с аналогичными проблемами, баян играет уже давно.

или тут есть какой-то нюанс, или это просто тупо не работает, а в СП враньё. (вообще, по моим личным наблюдениям, что касательно конкретно объектов в 1С, связанных с XML, то около четверти того, что прописано в СП, не работает, работает не всегда, или работает не так, как, казалось бы, должно работать исходя из описания)
5. andrewks 1370 08.10.12 20:23 Сейчас в теме
неужели в 1С нет ни одного рабочего штатного метода?
6. olenkaKOT 2 02.02.17 20:17 Сейчас в теме
смотри обработку
Проверка по схеме XML-файла (валидация по XSD)
http://infostart.ru/public/202643/
успехов
8. a.x 13.05.18 06:25 Сейчас в теме
Процедура ВалидацияXML(СтрокаXML)
	
	Попытка
		
		// Для начала получим все пространства имен, которые встречаются в строке XML,
		// и заполним множество URL пространств имен.
		МножествоПИ_ = Новый Соответствие;
		
		// Для этого нам потребуются разделители, чтобы определить начала директив xmlns.
		Разделители_ = " " + Символы.ПС + Символы.ВК + Символы.Таб;
		// Для удобства запомним строку xmlns
		Строка_xmlns_ = "xmlns";
		// и ее длину.
		Длина_xmlns_ = СтрДлина(Строка_xmlns_);
		
		// Начнем искать подстроки "xmlns" в строке XML.
		Поз_ = СтрНайти(СтрокаXML, Строка_xmlns_);
		Пока Не 0 = Поз_ Цикл
			
			// Вместо GOTO. Прервать означает GOTO за конец цикла.
			Пока Истина Цикл
				
				// Будем считать, что URL пространств имен заключены в двойные кавычки,
				// хотя стандарт XML допускает и одинарные. Также не будем разрешать разделители
				// перед и после знака "=". Надо уточнить, допустимы ли они по стандарту XML.
				НачалоURL_ = СтрНайти(СтрокаXML, "=""", , Поз_ + Длина_xmlns_);
				Если 0 = НачалоURL_ Тогда
					Прервать;
				КонецЕсли;
				
				КонецURL_ = СтрНайти(СтрокаXML, """", , НачалоURL_ + 2);
				Если 0 = КонецURL_ Тогда
					Прервать;
				КонецЕсли;
				
				// Имя пространства имен - это часть строки между концом подстроки "xmlns" и началом URL.
				// Будем считать, что двоеточие также относится к имени.
				ИмяПИ_ = Сред(СтрокаXML, Поз_ + Длина_xmlns_, НачалоURL_ - Поз_ - Длина_xmlns_);
				
				// Имя не должно содержать разделителей, символов "<", ">" и двойной кавычки.
				Если Не 0 = СтрНайти(Разделители_ + "<"">", ИмяПИ_) Тогда
					Прервать;
				КонецЕсли;
				
				// Если имя не пусто, оно должно начинаться с двоеточия.
				Если ЗначениеЗаполнено(ИмяПИ_) И Не СтрНачинаетсяС(ИмяПИ_, ":") Тогда
					Прервать;
				КонецЕсли;
				
				// URL пространства имен - это часть строки после xmlns:ИмяПИ=, заключенная в кавычки.
				URLПИ_ = Сред(СтрокаXML, НачалоURL_ + 2, КонецURL_ - НачалоURL_ - 2);
				
				// URL не должен содержать разделителей, символов "<", ">" и двойной кавычки.
				Если Не 0 = СтрНайти(Разделители_ + "<"">",URLПИ_) Тогда
					Прервать;
				КонецЕсли;
				
				// Добавим найденный url пространства имен в множество пространств имен.
				МножествоПИ_.Вставить(URLПИ_, Истина);
				
				// Не забудем перейти за конец цикла, поскольку это вовсе и не цикл,
				// а завуалированный оператор GOTO.
				Прервать;
			КонецЦикла;
			
			// Переходим к следующему вхождению подстроки "xmlns".
			Поз_ = СтрНайти(СтрокаXML, Строка_xmlns_, , Поз_ + Длина_xmlns_);
		КонецЦикла;
		
		// Теперь на основе найденных URL пространств имен создадим набор схем XML.
		НаборСхем_ = Новый НаборСхемXML;
		МассивПИ_ = Новый Массив;
		Для Каждого КлючИЗначение_ Из МножествоПИ_ Цикл
			МассивПИ_.Добавить(КлючИЗначение_.Ключ);
			// Получать схему можно разными путями, например, извлечь её из описания wsdl веб-сервиса.
			// Обратим внимание, что если схема содержит тег <xs:include/>, то предложенный здесь
			// алгоритм не работает, поскольку в этом случае схема для одного пространства имен
			// задается в нескольких файлах.
			СхемаXML_ = ПолучитьСхемуXMLИзWSDL(КлючИЗначение_.Ключ);
			НаборСхем_.Добавить(СхемаXML_);
		КонецЦикла;
		
		// По какой-то непонятной причине мы не можем напрямую использовать набор схем.
		// Возможно, это ошибка платформы.
		// Поэтому прогоним набор схем через фабрику XDTO.
		ФабрикаСервиса_ = Новый ФабрикаXDTO(НаборСхем_);
		НаборСхем_ = ФабрикаСервиса_.ЭкспортСхемыXML(МассивПИ_);
		
		// Проверим, что набор схем корректен.
		НаборСхем_.Проверить();
		
		// Теперь прочитаем XML, с учетом набора схем.
		ЧтениеXML_ = Новый ЧтениеXML;
		ПараметрыЧтенияXML_ = Новый ПараметрыЧтенияXML(,,,ТипПроверкиXML.СхемаXML);
		ЧтениеXML_.УстановитьСтроку(СтрокаXML, ПараметрыЧтенияXML_, НаборСхем_);
		// Вот здесь, собственно, выполняется валидация xml.
		ЧтениеXML_.Прочитать();
		ЧтениеXML_.Закрыть();
		
	Исключение
		
		// Если валидация по какой-то причине не прошла, то запишем это в журнал регистрации.
		// Работу программы прерывать не будем.
		Ошибка_ = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписьЖурналаРегистрации(
			"ВалидацияXML.Ошибка",
			УровеньЖурналаРегистрации.Ошибка,
			,
			СтрокаXML,
			Ошибка_
		);
		
	КонецПопытки;
	
КонецПроцедуры

Функция ПолучитьСхемуXMLИзWSDL(ПространствоИмен) Экспорт
	
	// Предположим, что описание wsdl веб-сервиса находится в макете.
	ОписаниеWSDL_ = ПолучитьОбщийМакет("МакетОписанияWSDL").ПолучитьТекст();
	
	// Для выполнения запросов XPath нам потребуется разыменователь с пространством имен xs.
	// Его будем строить на основе следующего соответствия.
	СоответствиеПИ_ = Новый Соответствие;
	СоответствиеПИ_.Вставить("xs", xmlns.xs());
	РазыменовательПИ_ = Новый РазыменовательПространствИменDOM(СоответствиеПИ_);
	
	// Также нам потребуется следующий тип результата XPath.
	ТипРезультата_ = ТипРезультатаDOMXPath.ЛюбойНеупорядоченныйУзел;
	
	// Для выбора схемы будем использовать такой запрос XPath.
	XPath_ = СтрШаблон("//xs:schema[@targetNamespace='%1']", ПространствоИмен);
	
	// Преобразуем описание WSDL в DOM для выполнения запросов XPath.
	ЧтениеXML_ = Новый ЧтениеXML;
	ЧтениеXML_.УстановитьСтроку(ОписаниеWSDL_);
	ПостроительDOM_ = Новый ПостроительDOM;
	ДокументDOM_ = ПостроительDOM_.Прочитать(ЧтениеXML_);
	ЧтениеXML_.Закрыть();
	
	// Выполним запрос XPath.
	РезультатXPath_ =
		ДокументDOM_.ВычислитьВыражениеXPath(XPath_, ДокументDOM_, РазыменовательПИ_, ТипРезультата_)
	;
	// Результатом запроса XPath должен быть корневой узел схемы.
	КорневойУзелСхемы_ = РезультатXPath_.ОдиночныйУзелЗначение;
	
	// В схеме могут встречаться теги <xs:import> и <xs:include>, в которых атрибут
	// schemaLocation ссылается на недоступное место. Когда платформа 1С:Предприятие выполняет
	// проверку на соответствие xml схеме, она пытается загрузить внешние схемы, указанные в
	// этих тегах. Подождав некоторое время (несколько десятков секунд) и не получив ответ,
	// платформа выдает ошибку. Чтобы этого не происходило, удалим теги <xs:import> и
	// <xs:include> из схемы. Для этого также используем XPath.
	ШаблонXPath_ = "./*[(local-name()='import' or local-name()='include') and namespace-uri()='%1']";
	XPath_ = СтрШаблон(ШаблонXPath_, xmlns.xs());
	Пока Истина Цикл
		РезультатXPath_ =
			ДокументDOM_.ВычислитьВыражениеXPath(XPath_, КорневойУзелСхемы_, РазыменовательПИ_, ТипРезультата_)
		;
		Узел_ = РезультатXPath_.ОдиночныйУзелЗначение;
		Если Неопределено = Узел_ Тогда
			Прервать;
		КонецЕсли;
		Узел_.РодительскийУзел.УдалитьДочерний(Узел_);
	КонецЦикла;
	
	
	// Для создания схемы используем построитель схем.
	ПостроительСхем_ = Новый ПостроительСхемXML;
	// Собственно, создаем схему.
	СхемаXML_ = ПостроительСхем_.СоздатьСхемуXML(КорневойУзелСхемы_);
	
	// И вернем её в вызывающий метод.
	Возврат СхемаXML_;
	
КонецФункции
Показать
9. a.x 15.05.18 10:20 Сейчас в теме
Исправленный вариант без фильтрации через фабрику XDTO.
Процедура ВалидацияXML(СтрокаXML)
	
	Попытка
		
		// Для начала получим все пространства имен, которые встречаются в строке XML,
		// и заполним множество URL пространств имен.
		МножествоПИ_ = "";
		
		// Для этого нам потребуются разделители, чтобы определить начала директив xmlns.
		Разделители_ = " " + Символы.ПС + Символы.ВК + Символы.Таб;
		// Для удобства запомним строку xmlns
		Строка_xmlns_ = "xmlns";
		// и ее длину.
		Длина_xmlns_ = СтрДлина(Строка_xmlns_);
		
		// Начнем искать подстроки "xmlns" в строке XML.
		Поз_ = СтрНайти(СтрокаXML, Строка_xmlns_);
		Пока Не 0 = Поз_ Цикл
			
			// Вместо GOTO. Прервать означает GOTO за конец цикла.
			Пока Истина Цикл
				
				// Будем считать, что URL пространств имен заключены в двойные кавычки,
				// хотя стандарт XML допускает и одинарные. Также не будем разрешать разделители
				// перед и после знака "=". Надо уточнить, допустимы ли они по стандарту XML.
				НачалоURL_ = СтрНайти(СтрокаXML, "=""", , Поз_ + Длина_xmlns_);
				Если 0 = НачалоURL_ Тогда
					Прервать;
				КонецЕсли;
				
				КонецURL_ = СтрНайти(СтрокаXML, """", , НачалоURL_ + 2);
				Если 0 = КонецURL_ Тогда
					Прервать;
				КонецЕсли;
				
				// Имя пространства имен - это часть строки между концом подстроки "xmlns" и началом URL.
				// Будем считать, что двоеточие также относится к имени.
				ИмяПИ_ = Сред(СтрокаXML, Поз_ + Длина_xmlns_, НачалоURL_ - Поз_ - Длина_xmlns_);
				
				// Имя не должно содержать разделителей, символов "<", ">" и двойной кавычки.
				Если Не 0 = СтрНайти(Разделители_ + "<"">", ИмяПИ_) Тогда
					Прервать;
				КонецЕсли;
				
				// Если имя не пусто, оно должно начинаться с двоеточия.
				Если ЗначениеЗаполнено(ИмяПИ_) И Не СтрНачинаетсяС(ИмяПИ_, ":") Тогда
					Прервать;
				КонецЕсли;
				
				// URL пространства имен - это часть строки после xmlns:ИмяПИ=, заключенная в кавычки.
				URLПИ_ = Сред(СтрокаXML, НачалоURL_ + 2, КонецURL_ - НачалоURL_ - 2);
				
				// URL не должен содержать разделителей, символов "<", ">" и двойной кавычки.
				Если Не 0 = СтрНайти(Разделители_ + "<"">",URLПИ_) Тогда
					Прервать;
				КонецЕсли;
				
				// Добавим найденный url пространства имен в множество пространств имен.
				Если 0 = СтрНайти(МножествоПИ_, URLПИ_) Тогда
					МножествоПИ_ = МножествоПИ_ + Символы.ПС + URLПИ_;
				КонецЕсли;
				
				// Не забудем перейти за конец цикла, поскольку это вовсе и не цикл,
				// а завуалированный оператор GOTO.
				Прервать;
			КонецЦикла;
			
			// Переходим к следующему вхождению подстроки "xmlns".
			Поз_ = СтрНайти(СтрокаXML, Строка_xmlns_, , Поз_ + Длина_xmlns_);
		КонецЦикла;
		
		// Теперь на основе найденных URL пространств имен создадим набор схем XML.
		НаборСхем_ = ПолучитьНаборСхемXML(МножествоПИ_);
		
		// Проверим, что набор схем корректен.
		НаборСхем_.Проверить();
		
		// Теперь прочитаем XML, с учетом набора схем.
		ЧтениеXML_ = Новый ЧтениеXML;
		ПараметрыЧтенияXML_ = Новый ПараметрыЧтенияXML(,,,ТипПроверкиXML.СхемаXML);
		ЧтениеXML_.УстановитьСтроку(СтрокаXML, ПараметрыЧтенияXML_, НаборСхем_);
		// Вот здесь, собственно, выполняется валидация xml.
		ЧтениеXML_.Прочитать();
		ЧтениеXML_.Закрыть();
		
	Исключение
		
		// Если валидация по какой-то причине не прошла, то запишем это в журнал регистрации.
		// Работу программы прерывать не будем.
		Ошибка_ = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписьЖурналаРегистрации(
			"ВалидацияXML.Ошибка",
			УровеньЖурналаРегистрации.Ошибка,
			,
			СтрокаXML,
			Ошибка_
		);
		
	КонецПопытки;
	
КонецПроцедуры

Функция ПолучитьНаборСхемXML(ПространстваИменЧерезСимволПС)
	
	МассивПространствИмен_ = СтрРазделить(ПространстваИменЧерезСимволПС, Символы.ПС, Ложь);
	НаборСхем_ = Новый НаборСхемXML;
	
	// Не используем цикл Для, поскольку размер массива может измениться из-за директив
	// <xs:import> в схемах.
	Индекс_ = 0;
	Пока Индекс_ < МассивПространствИмен_.Количество() Цикл
		ДобавитьВНаборСхем(НаборСхем_, МассивПространствИмен_, Индекс_);
		Индекс_ = Индекс_ + 1;
	КонецЦикла;
	
	Возврат НаборСхем_;
	
КонецФункции

// В МассивПространствИмен могут быть добавлены пространства имен из директивы <xs:import>
Процедура ДобавитьВНаборСхем(НаборСхем, МассивПространствИмен, ИндексВМассиве) Экспорт
	
	// Выбираем искомое пространство имен из массива.
	ПространствоИмен_ = МассивПространствИмен[ИндексВМассиве];
	
	// Текстом файла со схемой может быть содержимое xsd файла, описание wsdl или содержимое
	// любого другого документа XML, содержащего тег <xs:schema>.
	ТекстФайлаСоСхемой_ = ПолучитьТекстФайлаСоСхемой(ПространствоИмен_);
	
	// Для выполнения запросов XPath нам потребуется разыменователь с пространством имен xs.
	// Его будем строить на основе следующего соответствия.
	СоответствиеПИ_ = Новый Соответствие;
	СоответствиеПИ_.Вставить("xs", xmlns.xs());
	РазыменовательПИ_ = Новый РазыменовательПространствИменDOM(СоответствиеПИ_);
	
	// Также нам потребуется следующий тип результата XPath.
	ТипРезультата_ = ТипРезультатаDOMXPath.ЛюбойНеупорядоченныйУзел;
	
	// Для выбора схемы будем использовать такой запрос XPath.
	XPath_ = СтрШаблон("//xs:schema[@targetNamespace='%1']", ПространствоИмен_);
	
	// Преобразуем описание WSDL в DOM для выполнения запросов XPath.
	ЧтениеXML_ = Новый ЧтениеXML;
	ЧтениеXML_.УстановитьСтроку(ОписаниеWSDL_);
	ПостроительDOM_ = Новый ПостроительDOM;
	ДокументDOM_ = ПостроительDOM_.Прочитать(ЧтениеXML_);
	ЧтениеXML_.Закрыть();
	
	// Выполним запрос XPath.
	РезультатXPath_ =
		ДокументDOM_.ВычислитьВыражениеXPath(XPath_, ДокументDOM_, РазыменовательПИ_, ТипРезультата_)
	;
	// Результатом запроса XPath должен быть корневой узел схемы.
	КорневойУзелСхемы_ = РезультатXPath_.ОдиночныйУзелЗначение;
	
	// В схеме могут встречаться теги <xs:import> и <xs:include>, в которых атрибут
	// schemaLocation ссылается на недоступное место. Когда платформа 1С:Предприятие выполняет
	// проверку на соответствие xml схеме, она пытается загрузить внешние схемы, указанные в
	// этих тегах. Подождав некоторое время (несколько десятков секунд) и не получив ответ,
	// платформа выдает ошибку. Чтобы этого не происходило, удалим из тегов <xs:import> и
	// <xs:include> атрибут schemaLocation. Для этого также используем XPath.
	ШаблонXPath_ = "./*[(local-name()='import' or local-name()='include') and namespace-uri()='%1']";
	XPath_ = СтрШаблон(ШаблонXPath_, xmlns.xs());
	РезультатXPath_ =
		ДокументDOM_.ВычислитьВыражениеXPath(
			XPath_, КорневойУзелСхемы_, РазыменовательПИ_, ТипРезультатаDOMXPath.НеупорядоченныйИтераторУзлов
		)
	;
	Узел_ = РезультатXPath_.ПолучитьСледующий();
	Пока Не Неопределено = Узел_ Цикл
		Если Узел_.ЕстьАтрибут("namespace") Тогда
			// Заодно добавим импортируемое пространство имен в массив пространств имен.
			ДополнительноеПИ_ = Узел_.ПолучитьАтрибут("namespace");
			Если Неопределено = МассивПространствИмен.Найти(ДополнительноеПИ_) Тогда
				МассивПространствИмен.Добавить(ДополнительноеПИ_);
			КонецЕсли;
		КонецЕсли;
		Если Узел_.ЕстьАтрибут("schemaLocation") Тогда
			Узел_.УдалитьАтрибут("schemaLocation");
		КонецЕсли;
		Узел_ = РезультатXPath_.ПолучитьСледующий();
	КонецЦикла;
	
	
	// Для создания схемы используем построитель схем.
	ПостроительСхем_ = Новый ПостроительСхемXML;
	// Собственно, создаем схему.
	СхемаXML_ = ПостроительСхем_.СоздатьСхемуXML(КорневойУзелСхемы_);
	
	// Теперь нужно обновить ДОМ схемы, иначе манипуляции с тегами <xs:import> и <xs:include>
	// не будут учтены. Можно просто удалить его.
	СхемаXML_.ДокументDOM = Неопределено;
	
	// Добавляем схему в набор.
	НаборСхем.Добавить(СхемаXML_);
	
КонецПроцедуры
Показать
10. victorypopova1 18.10.18 05:32 Сейчас в теме
Упрощённый вариант валидации файла XML по схеме XSD.
Процедура ВалидацияXML(ПутьКФайлуXML, ПутьКФайлуСхемы)
	
	// Читаем схему и записываем её в объектную модель документа (DOM).
	ЧтениеXML_ = Новый ЧтениеXML;
	ЧтениеXML_.ОткрытьФайл(ПутьКФайлуСхемы);
	ПостроительDOM_ = Новый ПостроительDOM;
	ДокументDOM_ = ПостроительDOM_.Прочитать(ЧтениеXML_);
	ЧтениеXML_.Закрыть();

	// Для построения схемы получаем корневой элемент документа.
	КорневойЭлементДокумента_ = ДокументDOM_.documentElement;

	// Для создания схемы используем построитель схем.
	ПостроительСхем_ = Новый ПостроительСхемXML;
	// Cоздаем схему.
	СхемаXML_ = ПостроительСхем_.СоздатьСхемуXML(КорневойЭлементДокумента_);

	// Теперь нужно обновить DOM схемы, иначе действия с тегами <xs:import> и <xs:include>
	// не будут учтены. 
	// Для этого просто удалим документ DOM.
	СхемаXML_.ДокументDOM = Неопределено;

	// Добавляем схему в набор.
	НаборСхем_ = Новый НаборСхемXML;
	НаборСхем_.Добавить(СхемаXML_);

	// Проверим, что набор схем корректен.
	НаборСхем_.Проверить();

	// Теперь прочитаем XML, с учетом набора схем.
	ЧтениеXML_ = Новый ЧтениеXML;
	ПараметрыЧтенияXML_ = Новый ПараметрыЧтенияXML(,,,ТипПроверкиXML.СхемаXML);
	ЧтениеXML_.ОткрытьФайл(ПутьКФайлуXML, ПараметрыЧтенияXML_, НаборСхем_);
	
	// При вызове метода Прочитать() выполняется валидация файла XML по схеме.
	ЧтениеXML_.Прочитать();
	ЧтениеXML_.Закрыть();
	
КонецПроцедуры
Показать
Восьмой; +1 Ответить
11. Восьмой 88 19.11.18 14:23 Сейчас в теме
(10) Благослави тебя будда!!!!
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот