Заглавная страница

Проверка XML на стороне клиента

30 сентября 2008

Вы все еще не осознали всю прелесть отделения логики представления от содержимого? Тогда мы идем к вам!

Мысли вслух. Всем кто в танке посвящается

Обратите внимание, данный вид проверки подразумевает использование XML в качестве текстовых ресурсов (кусочков кода), которые затем будут использоваться для построения XML-дерева перед преобразованием процессором XSLT.

Чтобы не ждать, пока процессор XSLT на сервере создаст исключительную ситуацию мы будем проверять XML, попадающий в базу данных, на стороне клиента с помощью ява-скрипта. Естественно, валидацию на стороне сервера отменять не будем.

В то время пока технологи Студии изобретают велосипеды по мотивам Джеффри Фридла (первый велосипед, второй), которые при проверке XML пропускают неопределенные сущности (например, &google;), простые парни используют объектную модель документа XML DOM для проверки кода.

Итак, начнем

Напишем функцию checkXML(), которая будет проверять нужный нам XML. Значения, возвращаемые функцией проверки, определим так: −1 (возможность проверки корректности XML в данном браузере отсутствует), 0 (некорректный XML), 1 (корректный). Единственным аргументом нашей функции будет строковое значение XML.

Если у вас чудесный эксплорер, будем использовать объект ActiveXObject с параметром Microsoft.XMLDOM, для остальных — объект DOMParser.

Т. к. наш проверяемый код впоследствии будет обрабатываться шаблонизатором (в моем случае, XSLT) нам необходимо, как минимум, проверять на валидность сущности (ссылки). Воспользуемся для этого включением внутренней схемы DTD и определим в ней необходимые нам сущности. Вы можете сделать это динамически, т. е. собрать значение для переменной sEntities прочитав и обработав файл, используемый в ваших шаблонах, например, entities.dtd.

var sEntities = '<!ENTITY nbsp "&#160;"><!ENTITY euro "&#8364;">';

Проверяемый код (единственный аргумент нашей функции) обернем в корневой элемент. Также добавим объявление XML и внутреннюю схему DTD для ссылок (имя DOCTYPE должно соответствовать имени корневого элемента): sXML = '<?xml version="1.0"?><!DOCTYPE element [' + sEntities + ']><element>' + sXML + '<\/element>';

Объекту oIEParser (для IE) установим значение validateOnParse равное false, чтобы он не умер при валидации кода с применением внутренней схемы DTD.

Ошибки парсера

Наша функция возвращает значение валидации (мы его определили выше). Метод loadXML объекта ActiveXObject в IE возвратит значение false в случае неудачи. С DOMParser дела обстоят несколько иначе. В браузере Opera, метод parseFromString возбудит исключительную ситуацию (не только в Opera, см. баг Mozilla № 45566), в Mozilla Firefox проверим свойство nodeName на значение parsererror. В Safari, для отлова ошибки, сначала нужно проверить свойство firstChild на значение отличное от null, а затем преобразовать его в строковое представление и проверить на значение [object HTMLElement].

function checkXML(sXML)
{
	var sEntities = '<!ENTITY nbsp "&#160;"><!ENTITY euro "&#8364;">';
	var sXML = '<?xml version="1.0"?><!DOCTYPE element [' + sEntities + ']><element>' + sXML + '<\/element>';

	if (window.DOMParser) {
		var oParser = new DOMParser();
		try {
			var oElement = oParser.parseFromString(sXML, 'text/xml').documentElement;
		} catch (oException) {
			return 0;
		}
		if (oElement.nodeName == 'parsererror') {
			return 0;
		}
		if (oElement.firstChild !== null) {
			if (oElement.firstChild.toString() == '[object HTMLElement]') {
				return 0;
			}
		}
	} else if (window.ActiveXObject) {
		try {
			var oIEParser = new ActiveXObject('Microsoft.XMLDOM');
		} catch (oException) {
			return -1;
		}
		oIEParser.async = false;
		oIEParser.validateOnParse = false;
		if (false === oIEParser.loadXML(sXML)) {
			return 0;
		}
	} else {
		return -1;
	}

	return 1;
}

Вроде все, ага. Кстати, продолжение последовало.

Исходный файл xml-validator.js 1 КБ

Неужели работает

Проверяется только фрагмент XML (если нужно другое, дополните по необходимости дюжиной регекспов). Как было сказано выше, в данном примере «пройдут» только две ссылки: &nbsp; и &euro; (добавить по вкусу).

Буду признателен за отзывы и комментарии.

Отдельной строкой

Спасибо Денису Селезневу (ака webfilin) за вдохновление на написание этой работы, а также за предпосылки к ней.

Комментарии читателей

Компьютерщик 11/4/2009 04:44
Благодарю за информацию. Всего хорошего Вам!
Андрей 14/8/2009 16:32
спасибо! очень помог!
Zmed 2/10/2011 14:26
Спасибо большое, очень полезно. Мне помогло!

29