Вопрос по html, javascript, validation – Проверьте, допустим ли фрагмент HTML с Javascript

27

Мне нужна надежная библиотека / функция Javascript, чтобы проверить, верен ли фрагмент HTML, который я могу вызвать из своего кода. Например, он должен проверить, что открытые теги и кавычки закрыты, правильность вложенности и т. Д.

Я не хочу, чтобы проверка завершилась неудачей, потому что что-то не соответствует 100% (но все равно будет работать).

Ваш Ответ

7   ответов
29

Update: этот ответ ограничен - см. редактирование ниже.

Расширяя ответ @ kolink, я использую:

var checkHTML = function(html) {
  var doc = document.createElement('div');
  doc.innerHTML = html;
  return ( doc.innerHTML === html );
}

Т.е. мы создаем временный div с HTML. Для этого браузер создаст дерево DOM на основе строки HTML, что может включать закрывающие теги и т. Д.

Сравнение содержимого HTML div с исходным HTML покажет нам, нужно ли браузеру что-либо изменить.

checkHTML('<a>hell<b>o</b>')

Возвращает ложь.

checkHTML('<a>hell<b>o</b></a>')

Возвращает истину.

Edit: Как отмечает @Quentin ниже, этоexcessively strict по разным причинам: браузеры часто исправляют пропущенные закрывающие теги, даже если закрывающие теги являются необязательными для этого тега. Например:

<p>one para
<p>second para

... считается действительным (поскольку Ps разрешено пропускать закрывающие теги), ноcheckHTML вернет ложь. Браузеры также нормализуют регистры тегов и изменяют пробелы. Вы должны знать об этих пределах при принятии решения об использовании этого подхода.

Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededcheckHTML("<p>Test<P>test")Error: User Rate Limit ExceededinnerHTML.
Error: User Rate Limit Exceeded<P>Error: User Rate Limit Exceeded</p>Error: User Rate Limit ExceededlotsError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededpError: User Rate Limit ExceededcorrectError: User Rate Limit ExceedednormalizesError: User Rate Limit Exceeded
0

вы можете проверить, существует ли элемент, используя следующую функцию:

if (typeof(element) != 'undefined' && element != null)

Используя следующий код, мы можем проверить это в действии:

HTML:

<input type="button" value="Toggle .not-undefined" onclick="toggleNotUndefined()">
<input type="button" value="Check if .not-undefined exists" onclick="checkNotUndefined()">
<p class=".not-undefined"></p>

CSS:

p:after {
    content: "Is 'undefined'";
    color: blue;
}
p.not-undefined:after {
    content: "Is not 'undefined'";
    color: red;
}

JavaScript:

function checkNotUndefined(){
    var phrase = "not ";
    var element = document.querySelector('.not-undefined');
    if (typeof(element) != 'undefined' && element != null) phrase = "";
    alert("Element of class '.not-undefined' does "+phrase+"exist!");
    // $(".thisClass").length checks to see if our elem exists in jQuery
}

function toggleNotUndefined(){
    document.querySelector('p').classList.toggle('not-undefined');
}

Это можно найти наJSFiddle.

0

Html validatod для node.jshttps://www.npmjs.com/package/html-validator

HTML-валидатор для jQueryhttps://api.jquery.com/jquery.parsehtml/

Но, как упоминалось ранее, использование браузера для проверки поврежденного HTML - отличная идея:

function tidy(html) {
    var d = document.createElement('div');
    d.innerHTML = html;
    return d.innerHTML;
}
2

й вопрос, особенно когда речь идет о

I don't want the validation to fail because something is not 100% standard (but would work anyways).

tldr & gt; & gt; проверитьJSFiddle

Поэтому я использовал ввод ответов и комментариев по этой теме и создал метод, который делает следующее:

checks html string tag by tag if valid trys to render html string compares theoretically to be created tag count with actually rendered html dom tag count if checked 'strict', <br/> and empty attribute normalizations ="" are not ignored compares rendered innerHTML with given html string (while ignoring whitespaces and quotes)

Возвращает

true if rendered html is same as given html string false if one of the checks fails normalized html string if rendered html seems valid but is not equal to given html string

normalized означает, что при рендеринге браузер игнорирует или восстанавливает иногда определенные части ввода (например, добавляя отсутствующие закрывающие теги для<p> и преобразует другие (такие как одинарные к двойным кавычки или кодирование амперсандов). Различение «не удалось» и "нормализованный" позволяет помечать контент пользователю как «это не будет отображаться так, как вы этого ожидаете».

Большую часть времениnormalized возвращает только слегка измененную версию исходной строки html, но иногда результат совсем другой. Так что это должно быть использовано, например. пометить пользовательский ввод для дальнейшего просмотра, прежде чем сохранять его в БД или делать вслепую. (увидетьJSFiddle за примеры нормализации)

Проверки учитывают следующие исключения

ignoring of normalization of single quotes to double quotes image and other tags with a src attribute are 'disarmed' during rendering (if non strict) ignoring of <br/> >> <br> conversion (if non strict) ignoring of normalization of empty attributes (<p disabled> >> <p disabled="">) encoding of initially un-encoded ampersands when reading .innerHTML, e.g. in attribute values

.

function simpleValidateHtmlStr(htmlStr, strictBoolean) {
  if (typeof htmlStr !== "string")
    return false;

  var validateHtmlTag = new RegExp("<[a-z]+(\s+|\"[^\"]*\"\s?|'[^']*'\s?|[^'\">])*>", "igm"),
    sdom = document.createElement('div'),
    noSrcNoAmpHtmlStr = htmlStr
      .replace(/ src=/, " svhs___src=") // disarm src attributes
      .replace(/&amp;/igm, "#svhs#amp##"), // 'save' encoded ampersands
    noSrcNoAmpIgnoreScriptContentHtmlStr = noSrcNoAmpHtmlStr
      .replace(/\n\r?/igm, "#svhs#nl##") // temporarily remove line breaks
      .replace(/(<script[^>]*>)(.*?)(<\/script>)/igm, "$1$3") // ignore script contents
      .replace(/#svhs#nl##/igm, "\n\r"),  // re-add line breaks
    htmlTags = noSrcNoAmpIgnoreScriptContentHtmlStr.match(/<[a-z]+[^>]*>/igm), // get all start-tags
    htmlTagsCount = htmlTags ? htmlTags.length : 0,
    tagsAreValid, resHtmlStr;


  if(!strictBoolean){
    // ignore <br/> conversions
    noSrcNoAmpHtmlStr = noSrcNoAmpHtmlStr.replace(/<br\s*\/>/, "<br>")
  }

  if (htmlTagsCount) {
    tagsAreValid = htmlTags.reduce(function(isValid, tagStr) {
      return isValid && tagStr.match(validateHtmlTag);
    }, true);

    if (!tagsAreValid) {
      return false;
    }
  }


  try {
    sdom.innerHTML = noSrcNoAmpHtmlStr;
  } catch (err) {
    return false;
  }

  // compare rendered tag-count with expected tag-count
  if (sdom.querySelectorAll("*").length !== htmlTagsCount) {
    return false;
  }

  resHtmlStr = sdom.innerHTML.replace(/&amp;/igm, "&"); // undo '&' encoding

  if(!strictBoolean){
    // ignore empty attribute normalizations
    resHtmlStr = resHtmlStr.replace(/=""/, "")
  }

  // compare html strings while ignoring case, quote-changes, trailing spaces
  var
    simpleIn = noSrcNoAmpHtmlStr.replace(/["']/igm, "").replace(/\s+/igm, " ").toLowerCase().trim(),
    simpleOut = resHtmlStr.replace(/["']/igm, "").replace(/\s+/igm, " ").toLowerCase().trim();
  if (simpleIn === simpleOut)
    return true;

  return resHtmlStr.replace(/ svhs___src=/igm, " src=").replace(/#svhs#amp##/, "&amp;");
}

Здесь вы можете найти его в JSFiddlehttps://jsfiddle.net/abernh/twgj8bev/ вместе с различными тест-кейсами, включая

"<a href='blue.html id='green'>missing attribute quotes</a>" // FAIL
"<a>hell<B>o</B></a>"                                        // PASS
'<a href="test.html">hell<b>o</b></a>'                       // PASS
'<a href=test.html>hell<b>o</b></a>',                        // PASS
"<a href='test.html'>hell<b>o</b></a>",                      // PASS
'<ul><li>hell</li><li>hell</li></ul>',                       // PASS
'<ul><li>hell<li>hell</ul>',                                 // PASS
'<div ng-if="true && valid">ampersands in attributes</div>'  // PASS

.

15

function tidy(html) {
    var d = document.createElement('div');
    d.innerHTML = html;
    return d.innerHTML;
}

Это будет "правильно" искаженный HTML в меру возможностей браузера. Если это полезно для вас, это намного проще, чем пытаться проверить HTML.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Ixx
0
function isHTML(str)
{
 var a = document.createElement('div');
 a.innerHTML = str;
 for(var c= a.ChildNodes, i = c.length; i--)
 {
    if (c[i].nodeType == 1) return true;
 }
return false;
}

1
function validHTML(html) {
  var openingTags, closingTags;

  html        = html.replace(/<[^>]*\/\s?>/g, '');      // Remove all self closing tags
  html        = html.replace(/<(br|hr|img).*?>/g, '');  // Remove all <br>, <hr>, and <img> tags
  openingTags = html.match(/<[^\/].*?>/g) || [];        // Get remaining opening tags
  closingTags = html.match(/<\/.+?>/g) || [];           // Get remaining closing tags

  return openingTags.length === closingTags.length ? true : false;
}

var htmlContent = "<p>your html content goes here</p>" // Note: String without any html tag will consider as valid html snippet. If it’s not valid in your case, in that case you can check opening tag count first.

if(validHTML(htmlContent)) {
  alert('Valid HTML')
}
else {
  alert('Invalid HTML');
}
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededthat ternary operator after the return...

Похожие вопросы