Parseando valores ${campo}

24 respostas
D

opa…
pessoal… to fazendo uma linguagem de script pra interpretar o template da saída de um programa…

é o seguinte… incialmente to fazendo tudo na mao… acho que nao valerá a pena usar alguma API só pra fazer esse parse… pq vai ser usado numa classe só…
só se tiver uma API free, simples e pequena… pq to tendo que usar aqui na empresa… e eles nunca compram API… e nem precisam :mrgreen:

um arquivo de template seria mais ou menos assim:
Citação:

Olá ${nome}, vc tem ${idade} anos!

to parseando isso no braço mesmo… usando indexOf(), subString() e replaceFirst()

talvez essa nao é a melhor maneira… mas pelo menos agora como testes, to fazendo assim mesmo…

o problema é quando tento fazer o replace de ${campo} por o valor correspondete no HashMap…
o erro acontece pq caracteres $,.{}; e outros são inválidos para esse tipo de operação…

alguem tem uma ideia de como eu posso fazer um replace disso?

abraços

24 Respostas

Mauricio_Linhares

Porque em vez de fazer você não usa o que já está pronto, como o Velocity ou o FreeMarker?

danieldestro

Já ouviu falar de “regular expression”?

D

ja… só que a aplicação nao rola em ambiente web…
nao sei se funcionaria fora de um ambiente web… mas mesmo que funcionasse, eu gostaria de tratar isso na mão mesmo… pra servir também como forma de aprendizado… um desafio mesmo… gosto disso

ja… só que pelo jeito eu nao to sabendo usar…
pq qdo eu faço, por exemplo, um [i]replaceFirst("${nome}",“Badawi”)[i] aparece o seguinte erro…

sei que é por causa desses esquemas dos escapes…

alguem pode me ajudar com isso?

abraços

Mauricio_Linhares

Nenhum dos dois esquemas de templates que eu citei precisam de um sistema web, os dois podem ser utilizados normalmente em uma aplicação desktop.

D

opa… valeu ae pela resposta…
mas eu to querendo fazer isso no braço mesmo… eu sei que Velocity faz isso muito bem e tal… mas eu quero fazer isso na mao mesmo… pra aprendizado…
e tb pq nao sei se valeria a pena o uso de uma poderosa ferramenta pra tratar um parse de template… que nao é nem 5% do que a aplicão faz.

to querendo isso, pq a aplicação gera como se fosse um relatório (mas nao é relatório) e envia ao cliente por email… o que quero é fazer uma funcionalidade pro admin da aplicação poder mudar o template do email…

sei que poderia usar até o Jasper… mas nao gosto do jasper… e como ja disse, quero fazer o gerenciador de templates na mão mesmo… pelo simples fato de gostar de fazer isso

abraços e valeu pelas respostas! :smiley:

andgonca

Já que vc quer aprender, baixa o código do Velocity e dá uma olhada. O melhor jeito de aprender é vendo como se faz.

D

to fazendo isso…
mas como o FreeMaker

mas agredeceria se alguem pudesse me ajudar como fazer o replace disso ${nome} por isso Daniel

abraços

_fs

tada-da-da
http://www.guj.com.br/posts/list/19118.java

D

valeu Lipe! :smiley: :smiley:

pcalcado

Para casos simples, leia a documentação aqui java.text.MessageFormat

Shoes

D

aeeeeeeeeeeeee!!!

consegui!!
fiz assim:

Map map = new HashMap();
        map.put("nomeUser", "Daniel Badawi");
        map.put("nomeProjeto", "TaskNotifier");

        StringBuffer str = new StringBuffer("bla bla bla ${nomeUser} bla bla bla ${nomeProjeto}");
       
        while (str.indexOf("${") != -1) {
            String tag = str.substring(str.indexOf("${"),
                    (str.indexOf("}") + 1));
            String valueTag = str.substring((str.indexOf("${") + 2), str
                    .indexOf("}"));

            str.replace(str.indexOf("${"), str.indexOf("}") + 1, map.get(
                    valueTag).toString());

        }

        System.out.println(str.toString());

recebe como entrada a String bla bla bla ${nomeUser} bla bla bla ${nomeProjeto}
e a saída fica assim:
bla bla bla Daniel Badawi bla bla bla TaskNotifier

abraços!

urubatan

para duvidas sobre expressões regulares, sempre consulte: http://guia-er.sourceforge.net/

hehehe, tem o guia todo de gratis na net :smiley:

danieldestro

String pattern = “${[w]+}”;

Acho que isso funfa!

D

galera!
consegui fazer uma engine bem legal…
inclusive com controle de fluxo!! (por enquanto só co for)
mas isso ja é um bom caminho!

abraços e valeu ae!

renatosilva

Interessante Daniel, eu tenho um troço desses, por enquanto num é Java, mas a idéia é a mesma. No meu caso, em vez de catar cada ${ como tu faz, eu faço diferente. Em Java seria equivalente a percorrer cada elemento do Map, chamando então um relpaceAll(nome, valor) no template.

Tua abordagem me parece mais rápida, e isso vai ajudar pacas pra mim, porque geralmente os templates são grandes…

danieldestro

Daniel, o seu método ainda pode ser melhorado para ser “um pouco mais” performático, já que ele sempre vai procurar o índice do ‘${’ desde o início do SringBuffer. Você poderia manter a última posição alcançada e percorrer a partir dela.

D

sim sim!
estou melhorando cada vez mais…
meu chefe curtiu muito essa ideia, pq ele vai poder mudar o template a hora que quiser, via browser mesmo…
aí ele ja quis ficar programando nessas tagzinhas, só que ainda nao tava muito legal… entao decidi tocar o projeto pra frente…

ja dei umas pequenas melhoradas… principalmente na tag de Looping… agora eu to fazendo a estruta dela assim:

[loop id="users"]
${users.nome}
[/loop]

saida:

outra melhoria:

[bean id="project"/]
${project.nomeProjeto}

saida:

só que ainda to com um pé atrás com essa… pq uma vez que o o objeto é passado para a view através de um Map, nao tem muito a utilidade de se se ter uma tag [bean]…

outra melhoria (que ja tinha feito desde o inicio mas que ainda nao tava 100%):
no método de Bussines, Action… o que for que seja que jogue os dados para a View…

SimpleTag.setAttribute("users",umListDeUsers);

o Attribute no caso é um unico Map que será enviado para a View…
e é com a chave desse atributo que as tags encontram…

ta até ficando bunitinho isso aí! eheheh

só preciso melhorar a engine de parser… ja modifiquei legal ela em relação ao ultimo post… nada perto do ideal, mas ta bem melhor que antes…
só que tag com atributos ex: [loop id=“xxx”] ainda ta bem porco o parser dela… mas com o tempo eu vo melhorando…

comentários, críticas (construtivas), opniões, sujestões, são sempre bem vindas! :smiley:
abraços!

D

heehehehe!!
to curtindo pra caralho programar essses esquemas de script… eheh
e tá até rapidinho o processamento delas!
por ser totalmente interpretado, tem um desempenho legal até…

acabei de colocar em produção aqui na empresa… e ele processou e gerou um arquivo texto de 30kb… com 15 tags de loops e com aproximadamente 70 tags de valor (referente aos loopings)

e a sáida foi instânea… jogando toda a saída no System.out.println(), a velocidade foi muito boa (considerando que eu nao nenhum expert em algoritmos de performance) que parece até que ta imprimindo o um monte de System.out.println() de Strings puras e tratadas…

minha mae ia ficar orgulhosa de mim! hehehe (se ela conhecesse java, é claro) :smiley: :smiley: :lol: :lol:

pcalcado

Pergunta: por que não utilizar uma linguagem de script como Groovy, BeanShell ou VTL diretamente mesmo?

D

eu ia usar alguma coisa pronta mesmo…

só que, no inicio, qdo decidi fazer um jeito de ter template e tal… era só alguns campos coisa pouca, pequena… acho que nao valeria o custo benefício de ter um coisa granda servindo uma coisa pequena…
só q durante o dev, eu gostei bastante de programar isso e o projeto foi crescendo…
serviu mais como aprendizado e desafio pessoal mesmo… :wink:

abraços

K

Aí badawan...eu implementei a tag for assim:

package talentos;

import java.util.HashMap;
import java.lang.StringBuffer;

public class Teste {

    public static void main(String args[]){
        
    HashMap map = new HashMap();
    map.put("nameUser","João Java");
    map.put("nameProject","TestProject");
    map.put("loopTimes",new Integer(5));
        
    StringBuffer str 	 = new StringBuffer("${nameUser} -- ${nameProject}");
    StringBuffer strLoop = new StringBuffer("${loopTimes}");
       
    while(str.indexOf("${") != -1){
        String tag = str.substring(str.indexOf("${"),(str.indexOf("}") + 1));        
        String valueTag = str.substring((str.indexOf("${") + 2), str.indexOf("}"));
        str.replace(str.indexOf("${"), str.indexOf("}") + 1, map.get(valueTag).toString());        
    }
    
    while(strLoop.indexOf("${") != -1){
        String tagLopp = strLoop.substring(strLoop.indexOf("${"),(strLoop.indexOf("}") + 1));
        String valueTagLopp = strLoop.substring((strLoop.indexOf("${") + 2), strLoop.indexOf("}"));
        strLoop.replace(strLoop.indexOf("${"), strLoop.indexOf("}") + 1, map.get(valueTagLopp).toString());                
    }       
    
    for(int i = 0; i < Integer.parseInt(strLoop.toString()); i++){
        System.out.println(strLoop.toString());
    }

    System.out.println(strLoop.toString());
    System.out.println("\n");
    System.out.println(str.toString());
        
    }
}

e vc?

Valeu!

:D

D

opa!
blz?

ta assim o looping da primeira versão que eu fiz ontem, que itera um List fixo..
eu nao postei ainda o novo looping, pq eu ainda to terminando de fazer a tag que aceita argumentos.. e ainda nao ta funcional...

//bloco que procura os loopings com o numero de vezes do tamanho de um List que recebe..

while (str.indexOf("[LOOP_TASK]") != -1) {
            int inicio = str.indexOf("[LOOP_TASK]");
            int fim = str.indexOf("[/LOOP_TASK]")+12;
            String tag = str.substring(inicio,fim-12);
            String valueTag = str.substring(inicio+11,fim-12);
            str.replace(inicio,fim,appendaLoopTask(valueTag));     
            
        }


/método appendaLoopTask, que appenda todo locl de looping, inclusive com novas tags de valores..

private String appendaLoopTask(String tags) {
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<listTasks.size();i++) {
            sb.append(tags + "${LOOP}\n");
        }
        return sb.toString();
    }

esse código ta até rapidinho, apesar dessa segunda versao que eu to fazendo ta entre 20 a 30% mais rapido pois instancia menos objetos e faz menos redundancias e ainda segui a dica do danielDestro em marcar aonde o código parou para nao varrer sempre desde o começo...

e mesmo assim com tudos esses defeitos, esse código parseia, interpreta e faz consultas no banco, troca os valores das tags, e ainda escreve um arquivo texto de tudo isso em apenas 298 milissegundos de um arquivo com 43kb com váááárias, eu disse várias tags a ser tartadas..

obs: a nova versao que eu to fazendo nao ta parecendo nada com esse código... pq esse código ta bem amarrado com a aplicação que usa..

agora, segue o código a ser parseado:
<!DOCTYPE HTML PUBLIC ""-//IETF//DTD HTML//EN"">
<html>
<head>
<meta http-equiv=""Content-Type""
content=""text/html; charset=iso-8859-1"">
<TITLE>TaskNotifier - Tarefas abertas de ${user.nomeCompleto}</TITLE></HEAD><BODY><BR>
<b>${user.nomeCompleto}</b>, <br>
Segue a lista de tarefas abertas: <br><br>
<ul>
[LOOP_TASK]
<li>
<b>${task.nomeProjeto}</b> - <i>${task.nomeTask}</i><br>
Tarefa criada em: ${task.dataCriacaoTask}<br>
Data de início da tarefa: ${task.dataInicioTask}<br>
Data de término: ${task.dataFimTask}<br>
Delegado a: ${user.nomeCompleto}<br>
Descrição: <i>${task.descricaoTask}</i><br>
</li><br>
task id: ${task.id}
[/LOOP_TASK]
user id: ${user.id}	
user login ${user.userName}
</ul>
</body>
</html>
Obs: a tag de looping acaba rodando aproximandamente 15 vezes por usuário.. ou seja, esse código aí é parseado 18 vezes(numero de usuários) sendo que pra cada parse, o looping roda em média 15 vezes por usuário.. e pra cada aqruivo desse gerado, é enviado um email para o usuário..

abraços!
qdo eu terminar a segunda versao que eu to fazendo, eu passo pra quem quiser.

pcalcado

Oi
Sem querer estragar a brincadeira, eu recomendo expressamente o usod e uma linguagem de script já existente numa aplicação real que vá para a produção.

Mas se for pra brincar, testar e aprender ( :mrgreen: ), deem uma olahda nas ferramentas clássicas para isso:

https://javacc.dev.java.net

Shoes

D

pcalcado:
Oi
Sem querer estragar a brincadeira, eu recomendo expressamente o usod e uma linguagem de script já existente numa aplicação real que vá para a produção.

Mas se for pra brincar, testar e aprender ( :mrgreen: ), deem uma olahda nas ferramentas clássicas para isso:

https://javacc.dev.java.net

Shoes

opa!
realmente uma linguagem de script existente seria beeem mais proveitoso e muito mais… muito mais suporte e tal… trocentas vantagens a mais…
mas, isso aí é só um detatlha na aplicação… e poderia nem exister… nem tava na especificação… eu fiz a feature por escolha propria pra testar os esquemas… e meu chefe acabou gostando pra caralho… e pediu pra ir junto pra produção… e foi… e ta funcionando… ehaehehae…

como essa parte do script nao tente a crescer nem ter mais requisições, é bem capaz que fique daquele jeito mesmo… pq tenho quase certeza que qdo quiserem trocar o template dos arquivos gerados, eles vao pedir pra eu fazer mesmo… o que daria no mesmo se o template tivesse amarrado no código… hehahaeea…
mas é lógico, nao vou ser radical… assim que essa linguagenzinha pequenininha e nada flexivel começar a nao dar conta, com certeza eu vo trocar por alguma coisa que pode mesmo ser chamada de liguagem de script…

valeu a dica do Javacc! vo dar uma olhada pra aprender mais sobre isso… acho que ja encontrei um tema pro meu TCC… ehehhehe

é isso ae!
abraços!
bom é isso é… gostei dessa área… quero me aprofundar

Criado 30 de junho de 2005
Ultima resposta 1 de jul. de 2005
Respostas 24
Participantes 9