27

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

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

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

  • Error: User Rate Limit ExceededpError: User Rate Limit ExceededcorrectError: User Rate Limit ExceedednormalizesError: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • 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 ExceededcheckHTML("<p>Test<P>test")Error: User Rate Limit ExceededinnerHTML.

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Ixx
  • Error: User Rate Limit Exceededthat ternary operator after the return...

    от
7 ответов
  • 1

    Code:

    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');
    }
    

  • 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;
    }
    

  • 15

    Ну, этот код:

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

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

  • 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
    

    .

  • 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 вернет ложь. Браузеры также нормализуют регистры тегов и изменяют пробелы. Вы должны знать об этих пределах при принятии решения об использовании этого подхода.

  • 0

    Это зависит от js-библиотеки, которую вы используете.

    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;
    }
    

  • 0

    Используя чистый JavaScript

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

    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.