web-dev-qa-db-fra.com

Analyser une chaîne HTML avec JS

J'ai cherché une solution mais rien n'était pertinent, voici donc mon problème:

Je veux analyser une chaîne qui contient du texte HTML. Je veux le faire en JavaScript.

J'ai essayé cette bibliothèque mais il semble que cela analyse le code HTML de ma page actuelle, pas à partir d'une chaîne. Parce que quand j'essaye le code ci-dessous, ça change le titre de ma page:

var parser = new HTMLtoDOM("<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>", document);

Mon objectif est d'extraire des liens d'une page externe HTML que je lis comme une chaîne.

Connaissez-vous une API pour le faire?

216
stage

Créez un élément DOM factice et ajoutez-lui la chaîne. Ensuite, vous pouvez le manipuler comme n'importe quel élément du DOM.

var el = document.createElement( 'html' );
el.innerHTML = "<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>";

el.getElementsByTagName( 'a' ); // Live NodeList of your anchor elements

Edit: ajouter une réponse jQuery pour faire plaisir aux fans!

var el = $( '<div></div>' );
el.html("<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>");

$('a', el) // All the anchor elements
332
Florian Margaine

C'est assez simple:

var parser = new DOMParser();
var htmlDoc = parser.parseFromString(txt, 'text/html');
// do whatever you want with htmlDoc.getElementsByTagName('a');

Selon MDN , pour ce faire dans chrome, vous devez analyser en XML comme suit:

var parser = new DOMParser();
var htmlDoc = parser.parseFromString(txt, 'text/xml');
// do whatever you want with htmlDoc.getElementsByTagName('a');

Actuellement, il n'est pas pris en charge par webkit et vous devrez suivre la réponse de Florian. Il est inconnu de travailler dans la plupart des cas sur les navigateurs mobiles.

Edit: maintenant largement supporté

187
Cilan

EDIT: La solution ci-dessous concerne uniquement les "fragments" HTML, car html, head et body ont été supprimés. Je suppose que la solution à cette question est la méthode parseFromString () de DOMParser.


Pour les fragments HTML, les solutions répertoriées ici fonctionnent pour la plupart des HTML, mais dans certains cas, cela ne fonctionne pas.

Par exemple, essayez d'analyser <td>Test</td>. Celui-ci ne fonctionnera pas sur la solution div.innerHTML, ni sur la solution DOMParser.prototype.parseFromString ni sur la gamme range.createContextualFragment. La balise td disparaît et il ne reste que le texte.

Seul jQuery gère bien ce cas.

La solution future (MS Edge 13+) consiste donc à utiliser la balise template:

function parseHTML(html) {
    var t = document.createElement('template');
    t.innerHTML = html;
    return t.content.cloneNode(true);
}

var documentFragment = parseHTML('<td>Test</td>');

Pour les navigateurs plus anciens, j'ai extrait la méthode parseHTML () de jQuery dans un Gist indépendant - https://Gist.github.com/Munawwar/6e6362dbdf77c7865a99

16
Munawwar
var $doc = new DOMParser().parseFromString($html, "text/html");
$As = $('a', $doc);
7
Mathieu

La fonction suivante parseHTML renverra soit:

  • a Document lorsque votre fichier commence par un doctype.

  • a DocumentFragment lorsque votre fichier ne commence pas par un doctype.


Le code :

function parseHTML(markup) {
    if (markup.toLowerCase().trim().indexOf('<!doctype') === 0) {
        var doc = document.implementation.createHTMLDocument("");
        doc.documentElement.innerHTML = markup;
        return doc;
    } else if ('content' in document.createElement('template')) {
       // Template tag exists!
       var el = document.createElement('template');
       el.innerHTML = markup;
       return el.content;
    } else {
       // Template tag doesn't exist!
       var docfrag = document.createDocumentFragment();
       var el = document.createElement('body');
       el.innerHTML = markup;
       for (i = 0; 0 < el.childNodes.length;) {
           docfrag.appendChild(el.childNodes[i]);
       }
       return docfrag;
    }
}

Comment utiliser :

var links = parseHTML('<!doctype html><html><head></head><body><a>Link 1</a><a>Link 2</a></body></html>').getElementsByTagName('a');
6
John Slegers

Le moyen le plus rapide d’analyser le code HTML dans Chrome et Firefox est le suivant: Range # createContextualFragment:

var range = document.createRange();
range.selectNode(document.body); // required in Safari
var fragment = range.createContextualFragment('<h1>html...</h1>');
var firstNode = fragment.firstChild;

Je recommanderais de créer une fonction d'assistance qui utilise createContextualFragment si disponible et retourne à innerHTML sinon.

Indice de référence: http://jsperf.com/domparser-vs-createelement-innerhtml/

5
Joel Richard

Si vous êtes ouvert à l’utilisation de jQuery, il dispose de quelques outils Nice pour créer des éléments DOM détachés à partir de chaînes HTML. Ceux-ci peuvent ensuite être interrogés par les moyens habituels, par exemple:

var html = "<html><head><title>titleTest</title></head><body><a href='test0'>test01</a><a href='test1'>test02</a><a href='test2'>test03</a></body></html>";
var anchors = $('<div/>').append(html).find('a').get();

Edit - vient de voir la réponse de @ Florian qui est correcte. C'est fondamentalement exactement ce qu'il a dit, mais avec jQuery.

2
jmar777