IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

NodeJS Discussion :

Transform Stream et htmlparser2


Sujet :

NodeJS

  1. #1
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut Transform Stream et htmlparser2
    Bonjour à tous,

    Je connais assez mal l'API Stream de Node.js et j'ai quelques difficultés à l'utiliser pour venir transformer des fichiers HTML analysés avec la lib htmlparser2: https://github.com/fb55/htmlparser2

    Mon objectif est de récupérer les éléments <t> texte à traduire </t> et les attributs <img t-src="url à traduire"> pour venir remplacer leur contenu par une traduction et écrire le tout dans le répertoire de la langue correspondante.

    Je sais déjà récupérer et lister ces éléments, mais je bute sur la manière la plus efficace de venir remplacer ces textes au moment du parsing et écrire le tout dans un fichier de destination.

    Voilà où j'en suis:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    const    htmlParser = require('htmlparser2'),
        promisify = require("promisify-node"),
        fs = promisify("fs-extra"),
        log = require("../logger")
     
     
    module.exports = function parseHTML(filepaths){
        var tElements = [],
            tAttributes = [],
            buffer;
     
     
        const parser = new htmlParser.Parser({
            onopentag: (tagname, attrs) => {
                if(tagname === "t"){
                    buffer="";
                }
                Object.keys(attrs).filter(attr=>attr.startsWith("t-")).forEach(attr => {
                    tAttributes.push(attrs[attr]);
                })
            },
            ontext: (text) => {
                if(buffer != null){
                    buffer+=text;
                }
            },
            onclosetag: (tagname) => {
                if(tagname === "t"){
                    tElements.push(buffer);
                    buffer = null;
                }
            }
        });
     
     
        return Promise.all(filepaths.map(filepath => fs.readFile(filepath).then(data => {
            buffer= null;
            parser.write(data)
            parser.end()
            log.debug("HTML parsing done")
     
            fs.writeFileSync("destination/"+ filepath, data) // <-- comment relier le stream d'entrée et de sortie ? Stream.Transform ? Pipes ?
     
     
            return { elements: tElements, attributes: tAttributes }
        }).catch(log.error)
     
     
    }
    J'utilise donc de bêtes String en guise de buffer de fortune pour venir y écrire le contenu de mes éléments. Je pourrais sans doute faire une série de replace() sur le contenu pour réécrire le tout avec fs.writeFile, mais j'imagine qu'il y a une façon plus propre et performante de faire ça. L'API Stream.Transform semble tout indiquée mais je ne vois pas comment l'interfacer avec htmlparser2. J'ai mon stream d'entrée avec fs.readFile, mon stream de sortie fs.writeFile, comment relier les deux au moment du parsing ?
    One Web to rule them all

  2. #2
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2016
    Messages
    223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2016
    Messages : 223
    Points : 561
    Points
    561
    Par défaut
    bonjour,

    même si le topic est un peu vieu, une réponse.

    tldr; htmlparser2 peut recevoir un stream, mais ne peut être chainé en sortie. C'est une interface type SAX qui émet des évènements.
    Ce que tu veux faire correspond à ce ticket, https://github.com/fb55/htmlparser2/issues/101

    L'exemple qui montre bien qu'il n'implémente pas l'interface Readable stream,


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
     
    var through2 = require('through2')
     
    var htmlparser = require("htmlparser2");
    var parser = new htmlparser.Parser({
        onopentag: function(name, attribs){
            if(name === "script" && attribs.type === "text/javascript"){
                console.log("JS! Hooray!");
            }
        },
        ontext: function(text){
            console.log("-->", text);
        },
        onclosetag: function(tagname){
            if(tagname === "script"){
                console.log("That's it?!");
            }
        }
    }, {decodeEntities: true});
    // parser.write("Xyz <script type='text/javascript'>var foo = '<<bar>>';</ script>");
    // parser.end();
     
    var resumer = require('resumer'); // un stream sur lequel on peut ecrire du texte (source)
    var s = resumer();
     
    s.pipe(through2(function(d,e,cb){ // though2 pour montrer les donnes qui traversent le stream (transform)
      console.log(d+'');
      cb(null, d);
    }))
    .pipe(parser) // le parser html qui est branché en sortie de stream (sink)
    .pipe(through2(function(c,e,cb){ // une autre transform branché en sink, mais qui provoque une erreur car parser n'est pas stream readable, documenter pour voir l'exemple fonctionner
      console.log(c);
      cb(null, c)
    }))
     
     
    s.write("Xyz <script type='text/javascript'>var foo = '<<bar>>';</ script>") // envoyer des données dans le stream
    Ici j'ai utilisé
    https://github.com/substack/resumer pour faire un stream source, dans lequel j'écris des données
    https://github.com/rvagg/through2 pour faire des streams transforms, je reçoit des chunks de données qui traversent le stream, et les poussent dans le stream sink

    Pour aller plus loin
    https://github.com/calvinmetcalf/noms pour implémenter des streams readable
    https://github.com/calvinmetcalf/streams-a-love-story
    https://github.com/substack/stream-handbook
    https://github.com/substack/stream-adventure

  3. #3
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut
    Merci pour la réponse, mieux vaut tard que jamais

    Dommage que l'auteur de htmlparser2 ne veut même pas en discuter, ça serait une belle optimisation. Tant pis, je n'ai pas le temps de forker son module pour ajouter ça moi-même, je me contenterais de la solution lente et dégueu.
    One Web to rule them all

  4. #4
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2016
    Messages
    223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2016
    Messages : 223
    Points : 561
    Points
    561
    Par défaut
    Des alternatives qui me sont revenues en tête plus tard,

    https://github.com/substack/node-trumpet
    https://github.com/cheeriojs/cheerio

    notamment trumpet qui me semble correspondre à ton besoin initial.

    hth

  5. #5
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut
    Hmm oui ça peut marcher avec trumpet et la notation E[attr^=prefix]

    Merci, j'étais passé à autre chose depuis le temps mais je vais essayer ça à l'occasion.
    One Web to rule them all

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] Transformer StreamWriter en Stream
    Par pitite dans le forum VB.NET
    Réponses: 4
    Dernier message: 30/04/2012, 13h10
  2. Réponses: 8
    Dernier message: 10/07/2008, 17h44
  3. Réponses: 4
    Dernier message: 05/09/2007, 15h32
  4. [VB.net] transformation d'image en stream
    Par damyrid dans le forum VB.NET
    Réponses: 2
    Dernier message: 29/12/2005, 18h51
  5. [Stream] Transformer un OutputStream en InputStream
    Par kevredon dans le forum Entrée/Sortie
    Réponses: 6
    Dernier message: 18/06/2005, 13h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo