jXmlVali

Проверка строки на соответствие XML с помощью JavaScript и регулярных выражений. Версия 2.1.1

Версия 2.1.1

Требуется проверить строку на соответствие XML.

Версия 2.0 выложена на сайте Студии Лебедева

Пример проверки XML

 

Ответ:

Код HTML и инициализация

<form name="example" onsubmit="return false" action="./">
	<textarea id="UserData" style="width:100%; height:10em;" rows="5" cols="30"></textarea>
	<div style="margin:0.5em 0;">
		<input id="FragmentTrue" type="checkbox" />
		<label for="FragmentTrue">фрагмент XML</label>
	</div>
	<input type="button" value="Проверить" onclick="CheckXml(); return false;" />
	<p id="Answer"></p>
</form>

<script type="text/javascript" src="./jxmlvali.js"></script>

<script type="text/javascript">
	var sMessage = [
		'Все верно (All right)', // 0
		'Нет корневой ноды (No root node)', // 1
		'Незакрытый комментарий (Unfinalized comment)', // 2
		'Незакрытый блок CDATA (Unfinalized unit CDATA)', // 3
		'Неожиданный Instruction (Unexpected Instruction)', // 4
		'Неожиданный DocType (Unexpected DocType)', // 5
		'Текст в начале строки выходит за пределы тега (Text before the first tag)', // 6
		'Текст в конце строки выходит за пределы тега (Text after the last tag)', // 7
		'Неожиданная entity (Unexpected entity)', // 8
		'Больше одной корневой ноды или неожиданный тег (More than one root node, or an unexpected tag)', // 9
		'Незакрытый тег (Unclosed tag)', // 10
		'Дублирование атрибутов (Duplicate attribute)']; // 11

	function CheckXml(){
		var my_oXmlValidator = new oXmlValidator.Object(oUserData.value);
		if ( oFragmentTrue.checked ) my_oXmlValidator.hParams.bFragment = true;
		if ( my_oXmlValidator.valid() ) oAnswer.innerHTML = "Это XML (This is XML). ";
			else oAnswer.innerHTML = "Это не XML (This is not XML). " + sMessage[my_oXmlValidator.nCode] + ".";
	};
	var oUserData = document.getElementById('UserData');
	var oAnswer = document.getElementById('Answer');
	var oFragmentTrue = document.getElementById('FragmentTrue');
</script>

Объект jxmlvali.js

/*
 * @Author Denis Khripkov | denisx@ya.ru | denisx.ru
 */
var oXmlValidator = {
	oTab: new RegExp(/[\n\t\r]+/g),
	oCommentAndCdata: new RegExp(/<!(?:--(?:[^-]|-[^-])*--|\[CDATA\[(?:[^\]]|\][^\]]|\]+[^\>\]])*]{2,})>/g),
	oInstruction: new RegExp(/<\?.*?\?>/),
	oDocType: new RegExp(/<\!DocType.*?>/i),
	oOutTagTextBegin: new RegExp(/^\s*[^<\s]+/),
	oEntityFull: new RegExp(/&(?:#(?:x[a-f\d]{1,4}|\d{2,5})|[a-z][\w\-]*);/gi),
	oAttribute: new RegExp(/(<[a-z_][\w:-]*)((?:\s+[a-z_][\w:-]*\s*=\s*(?:'[^<>']*'|"[^<>"]*"))*)\s*(\/?>)/gi),
	oAttributeUnique: new RegExp(/([a-z_][\w:-]*)\s*=\s*(?:'[^<>']*'|"[^<>"]*")/gi),
	oAttributeMatch: new RegExp(/[a-z_][\w:-]*/gi),
	oSingleTag: new RegExp(/<[a-z_][\w:-]*\/>/gi),
	oDoubleTag: new RegExp(/<([a-zA-Z_][\w:-]*)>[^<]*<\/\1\s*>/g)
};
oXmlValidator.Object = function(sValue){
	this.sValue = sValue;
	this.nCode = 0;
	this.nBugPlace = 0;
	this.hParams = {
		bFragment: false // true - проверяемый код не целый xml, а только его часть
	}
};
oXmlValidator.Object.prototype = {
	valid: function(){
		var sValue = this.sValue;
		var hParams = this.hParams;
		if ( sValue ){
			// вырезаем табуляцию и переносы строк
			sValue = sValue.replace( oXmlValidator.oTab, ' ' );
			// вырезаем комменты и CDATA
			sValue = sValue.replace( oXmlValidator.oCommentAndCdata, '' );
			if ( sValue.indexOf( '<!--' ) != -1 ) {
				this.nCode = 2; return false;
			}
			if ( sValue.indexOf( ']]>' ) != -1 ) {
				this.nCode = 3; return false;
			}
			// вырезаем инструкции
			if ( !hParams.bFragment )
				sValue = sValue.replace( oXmlValidator.oInstruction, '' );
				if ( sValue.search( oXmlValidator.oInstruction ) != -1 ) {
					this.nCode = 4; return false;
				}
			// вырезаем DocType
			if ( !hParams.bFragment )
				sValue = sValue.replace( oXmlValidator.oDocType, '' );
			if ( sValue.search( oXmlValidator.oDocType ) != -1 ) {
				this.nCode = 5; return false;
			}
			// ищем текст в начале и в конце строки, выходящий за пределы тегов
			if ( !hParams.bFragment ) {
				if ( sValue.search( oXmlValidator.oOutTagTextBegin ) != -1 ) {
					this.nCode = 6; return false;
				}
				// конец строки.
				var nValueLength = sValue.length;
				var bIsSpace = true;
				do {
					nValueLength--;
					if ( sValue.charAt( nValueLength ) != ' ' ) bIsSpace = false;
				} while ( bIsSpace && nValueLength > 0 )
				if ( !bIsSpace && sValue.charAt( nValueLength ) != '>' ){
					this.nCode = 7; return false;
				}
				else if ( nValueLength == 0 ){
					this.nCode = 1; return false;
				}
			}
			// вырезаем Entities
			sValue = sValue.replace( oXmlValidator.oEntityFull, '' );
			if ( sValue.indexOf( '&' ) != -1 ){
				this.nCode = 8; return false;
			}
			// вырезаем аттрибуты и проверяем на дублирование
			var bAttributeUnique = true;
			sValue = sValue.replace( oXmlValidator.oAttribute,
				function a($0, $1, $2 ,$3){
					$2 = $2.replace( oXmlValidator.oAttributeUnique, '$1' );
					var aAttribute = $2.match( oXmlValidator.oAttributeMatch );
					if ( aAttribute ){
						var nMatchCount = aAttribute.length;
						if ( nMatchCount > 1 ){
							var i = 0; var j;
							while ( bAttributeUnique && i < nMatchCount-1 ){
								j = i + 1;
								while ( bAttributeUnique && j < nMatchCount ){
									if ( aAttribute[i] != aAttribute[j] ){
										j++;
									}else{
										bAttributeUnique = false;
									}
								}
								i++;
							}
						}
					}
					return $1 + $3;
				});
			if ( !bAttributeUnique ){
				this.nCode = 11; return false;
			}
			// параметр для вырезания тэгов
			var sTagReplaceTo = '';
			if ( !hParams.bFragment ) sTagReplaceTo = '&';
			// вырезаем одинарные тэги
			sValue = sValue.replace( oXmlValidator.oSingleTag, sTagReplaceTo );
			// вырезаем двойные тэги
			var nPrevLen; var nLen = 0;
			do {
				nPrevLen = nLen;
				sValue = sValue.replace( oXmlValidator.oDoubleTag, sTagReplaceTo );
				nLen = sValue.length;
			} while ( nLen != nPrevLen );
			if ( !hParams.bFragment ) {
				if ( sValue.indexOf(sTagReplaceTo) != sValue.lastIndexOf(sTagReplaceTo) ) {
					this.nCode = 9; return false;
				}
			}
			if( sValue.indexOf( '<' ) != -1 ){
				this.nCode = 10; return false;
			}
			this.nCode = 0; return true;
		} else { // пустая строка
			if ( !hParams.bFragment ){
				this.nCode = 1; return false;
			}
			else {
				this.nCode = 0; return true;
			}
		}
	}
};

Репозиторий

Актуальная версия также доступна на jxmlvali - Google Code (en)

v2.1.1

03.03.2009

Посмотреть

Скачать

Посмотреть (en)

Скачать (en)

Ещё версии

v2.1

02.03.2009

Посмотреть

Скачать

v2.0

25.09.2008

Посмотреть

Скачать

Описание

2.1.1

Текст ошибок вынесен из объекта в обший код.

Добавлен скверный дубляж ошибок на англйском.

2.1

Добавлена проверка дублирующихся атрибутов.

Скорость обработки тестового мегабайтного xsl-файла выросла в два раза до 0,4 секунд. Кому критично — можно сделать через параметр, на основе примера с bFragment.

2.0

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

Объект имеет единственный параментр bFragment для указания типа XML.

Скорость обработки тестового мегабайтного xsl-файла примерно равна 0,2 секунды.