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 | www.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)
Ещё версии
Описание
2.1.1
Текст ошибок вынесен из объекта в обший код.
Добавлен скверный дубляж ошибок на англйском.
2.1
Добавлена проверка дублирующихся атрибутов.
Скорость обработки тестового мегабайтного xsl-файла выросла в два раза до 0,4 секунд. Кому критично — можно сделать через параметр, на основе примера с bFragment.
2.0
Проверка XML осуществляется ступенчато, методом вырезания из копии исходной строки валидных участков с помощью регулярных выражений с дальнейшей проверкой. Есть вывод кодов ошибок, а в примере, для наглядности, и комментарии.
Объект имеет единственный параментр bFragment для указания типа XML.
Скорость обработки тестового мегабайтного xsl-файла примерно равна 0,2 секунды.