web-dev-qa-db-fra.com

Vérifiez si l'extrait de code HTML est valide avec Javascript

J'ai besoin d'une bibliothèque/fonction Javascript fiable pour vérifier si un extrait de code HTML est valide que je peux appeler à partir de mon code. Par exemple, il doit vérifier que les balises ouvertes et les guillemets sont fermés, l'imbrication est correcte, etc.

Je ne veux pas que la validation échoue car quelque chose n'est pas 100% standard (mais fonctionnerait de toute façon).

31
Ixx

pdate: cette réponse est limitée - veuillez voir la modification ci-dessous.

En développant la réponse de @ kolink, j'utilise:

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

C'est-à-dire que nous créons un div temporaire avec le HTML. Pour ce faire, le navigateur créera une arborescence DOM basée sur la chaîne HTML, ce qui peut impliquer la fermeture de balises, etc.

La comparaison du contenu HTML du div avec le HTML d'origine nous dira si le navigateur avait besoin de changer quoi que ce soit.

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

Renvoie false.

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

Renvoie vrai.

Edit: Comme @Quentin le note ci-dessous, c'est excessivement strict pour diverses raisons: les navigateurs corrigent souvent les balises de fermeture omises, même si les balises de fermeture sont facultatives pour cette balise. Par exemple:

<p>one para
<p>second para

... est considéré comme valide (puisque Ps est autorisé à omettre les balises de fermeture) mais checkHTML retournera false. Les navigateurs normaliseront également les cas de balises et modifieront les espaces blancs. Vous devez être conscient de ces limites lorsque vous décidez d'utiliser cette approche.

31
mikemaccana

Eh bien, ce code:

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

Cela "corrigera" le HTML mal formé au mieux de la capacité du navigateur. Si cela vous aide, c'est beaucoup plus facile que d'essayer de valider le HTML.

18

Aucune des solutions présentées jusqu'à présent ne répond bien à la question initiale, en particulier en ce qui concerne

Je ne veux pas que la validation échoue car quelque chose n'est pas 100% standard (mais fonctionnerait de toute façon).

tldr >> vérifier le JSFiddle

J'ai donc utilisé l'entrée des réponses et des commentaires sur ce sujet et créé une méthode qui fait ce qui suit:

  • vérifie la balise de chaîne HTML par balise si elle est valide
  • essaie de rendre la chaîne html
  • compare théoriquement le nombre de balises créées avec le nombre de balises html dom réellement rendues
  • si coché 'strict', <br/> et normalisations d'attributs vides ="" ne sont pas ignorés
  • compare le rendu innerHTML avec une chaîne html donnée (tout en ignorant les espaces et les guillemets)

Retour

  • true si le rendu html est identique à la chaîne html donnée
  • false si l'une des vérifications échoue
  • chaîne html normalisée si le rendu html semble valide mais n'est pas égal à la chaîne html donnée

normalisé signifie que lors du rendu, le navigateur ignore ou répare parfois des parties spécifiques de l'entrée (comme l'ajout de balises de fermeture manquantes pour <p> et convertit les autres (comme les guillemets simples en doubles ou l'encodage des esperluettes). Faire une distinction entre "échoué" et "normalisé" permet de signaler le contenu à l'utilisateur comme "cela ne sera pas rendu comme vous pourriez vous y attendre".

La plupart du temps normalisé renvoie une version légèrement modifiée de la chaîne html originale - encore, parfois le résultat est assez différent. Cela devrait donc être utilisé par exemple pour marquer l'entrée utilisateur pour un examen plus approfondi avant de l'enregistrer dans une base de données ou de la restituer à l'aveugle. (voir JSFiddle pour des exemples de normalisation)

Les contrôles tiennent compte des exceptions suivantes

  • ignorer la normalisation des guillemets simples en guillemets doubles
  • image et les autres balises avec un attribut src sont "désarmés" pendant le rendu
  • (si non stricte) ignorant <br/> >> <br> conversion
  • (si non strict) ignorant la normalisation des attributs vides (<p disabled> >> <p disabled="">)
  • encodage des esperluettes initialement non encodées lors de la lecture de .innerHTML, par exemple. dans les valeurs d'attribut

.

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

Ici vous pouvez le trouver dans un JSFiddle https://jsfiddle.net/abernh/twgj8bev/ , avec différents cas de test, y compris

"<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

.

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

Cela dépend de js-library que vous utilisez.

Html validatod pour node.js https://www.npmjs.com/package/html-validator

Validateur HTML pour jQuery https://api.jquery.com/jquery.parsehtml/

Mais, comme mentionné précédemment, utiliser le navigateur pour valider le HTML cassé est une excellente idée:

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

En utilisant du JavaScript pur, vous pouvez vérifier si un élément existe en utilisant la fonction suivante:

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

En utilisant le code suivant, nous pouvons tester cela en action:

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

Il peut être trouvé sur JSFiddle .

0
Leviscus Tempris
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;
}

Bonne chance!

0
David Castro