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).
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.
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.
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:
<br/>
et normalisations d'attributs vides =""
ne sont pas ignorésRetour
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
image
et les autres balises avec un attribut src
sont "désarmés" pendant le rendu<br/>
>> <br>
conversion<p disabled>
>> <p disabled="">
).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(/&/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(/&/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##/, "&");
}
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
.
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');
}
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;
}
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 .
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!