Transformação de XML para TXT [RESOLVIDO]

13. Re: Transformação de XML para TXT [RESOLVIDO]

Alexandre Rios
alex_tj

(usa Outra)

Enviado em 09/07/2023 - 18:20h


msoliver escreveu:


alex_tj escreveu:

msoliver escreveu:

alex_tj escreveu:


msoliver escreveu:

Boa noite Alexandre.
Vamos por partes....
Com o comando:
grep -o '<ObterResultadosInicioResult>.*</ObterResultadosInicioResult>' response.xml | sed -n 's/<ObterResultadosInicioResult>\(.*\)<\/ObterResultadosInicioResult>/\1/p' 

Vc "pega" todo o arquivo, eliminando "<ObterResultadosInicioResult>" e "</ObterResultadosInicioResult>"
É isso?
----------------------------------------------------------------------------------------------------------------
Realmente, o maior problema são os campos inexistentes ....
Vejo que o ideal é padronizar o arquivo.
Sugestão:
Checar os campos a partir da var "$header"...
Fiz um teste, e o resultado foi satisfatório.
Por hora, a saída é essa:
./script.sh
-------------------------
Checar campos do Reg:1 Cmp:14
-------------------------
NomeCandidato: ok
CPF: ok
NomeExame: ok
DataProcessamento: ok
SituacaoFinal: ok
GrauObtido: ok
StatusLiberacao: ok
IDModulo: ok
NumeroAcertos: ok
TempoRestante: ok
CooperativaCentral: ok
CooperativaSingular: not
IDInscricao: ok
DataExame: ok

Reg:00002 Campos:15 Okay
-------------------------
Checar campos do Reg:3 Cmp:13
-------------------------
NomeCandidato: ok
CPF: ok
NomeExame: ok
DataProcessamento: ok
SituacaoFinal: ok
GrauObtido: not
StatusLiberacao: ok
IDModulo: ok
NumeroAcertos: ok
TempoRestante: ok
CooperativaCentral: ok
CooperativaSingular: ok
IDInscricao: not
DataExame: ok


______________________________________________________________________
Att.: Marcelo Oliver
______________________________________________________________________


Marcelo no XML existe uma tag que é essa: ObterResultadosInicioResult que determina o início e o fim da action, pq o SOAP ele traz várias informações na string do XML aí eu restrinjo pra pegar tudo o que está dentro disso --> <ObterResultadosInicioResult> ..... </ObterResultadosInicioResult> que é efetivamente os dados que preciso trabalhar.

E minha ideia é justamente tentar comparar linha a linha com o cabeçalho, mesmo sabendo que pode ser que isso deixe o processo lento, mas o desafio realmente é marcar o vazio na linha com o ||

Em python eu fazia isso e funcionava perfeitamente:
......
Só que em ambiente corporativo existem algumas bibliotecas que usava que não poderia ser instaladas e por isso estou migrando o código para shell script.
Obrigado pela ajuda!


Alexandre, boa noite.
Entendi sobre a 'tag' ObterResultadosInicioResult,
fiz os testes sem ela, e com um registro por linha,conforme arquivo abaixo.
"Parece" que funcionou.....
cat response.xml
<NomeCandidato>AAAA</NomeCandidato><CPF>12345678900</CPF><IDInscricao>8523690</IDInscricao><DataExame>2009-10-02T00:00:00</DataExame><NomeExame>Ouvidores</NomeExame><DataProcessamento>2009-10-05T15:50:15.447</DataProcessamento><SituacaoFinal>R</SituacaoFinal><GrauObtido>63.00</GrauObtido><StatusLiberacao>Resultado Fornecido/Liberado</StatusLiberacao><IDModulo>0</IDModulo><NumeroAcertos>25</NumeroAcertos><TempoRestante>2000-01-01T01:15:46</TempoRestante><CooperativaCentral>0000 - Instituição A</CooperativaCentral>
<NomeCandidato>BBBB</NomeCandidato><CPF>14785236900</CPF><IDInscricao>9874561</IDInscricao><DataExame>2023-05-12T00:00:00</DataExame><NomeExame>CPC-S100</NomeExame><DataProcessamento>2023-05-14T21:52:16.367</DataProcessamento><SituacaoFinal>A</SituacaoFinal><GrauObtido>77.00</GrauObtido><StatusLiberacao>Resultado Fornecido/Liberado</StatusLiberacao><IDModulo>0</IDModulo><NumeroAcertos>46</NumeroAcertos><TempoRestante>2000-01-01T01:03:12</TempoRestante><CooperativaCentral>9999 - Instituição B</CooperativaCentral><CooperativaSingular>Singular 2</CooperativaSingular>
<NomeCandidato>CCCC</NomeCandidato><CPF>78523654100</CPF><DataExame>2023-05-12T00:00:00</DataExame><NomeExame>CPC-S100</NomeExame><DataProcessamento>2023-05-14T21:52:16.367</DataProcessamento><SituacaoFinal>A</SituacaoFinal><StatusLiberacao>Resultado Fornecido/Liberado</StatusLiberacao><IDModulo>0</IDModulo><NumeroAcertos>46</NumeroAcertos><TempoRestante>2000-01-01T01:03:12</TempoRestante><CooperativaCentral>Coop 1</CooperativaCentral><CooperativaSingular>Singular 3</CooperativaSingular>
<NomeCandidato>DDDD</NomeCandidato><CPF>14785236900</CPF><IDInscricao>9874561</IDInscricao><DataExame>2023-05-12T00:00:00</DataExame><DataProcessamento>2023-05-14T21:52:16.367</DataProcessamento><SituacaoFinal>A</SituacaoFinal><GrauObtido>77.00</GrauObtido><StatusLiberacao>Resultado Fornecido/Liberado</StatusLiberacao><IDModulo>0</IDModulo><NumeroAcertos>46</NumeroAcertos><TempoRestante>2000-01-01T01:03:12</TempoRestante><CooperativaCentral>9999 - Instituição B</CooperativaCentral><CooperativaSingular>Singular 4</CooperativaSingular>
<NomeCandidato>ABCD</NomeCandidato><CPF>78523654100</CPF><DataExame>2023-05-12T00:00:00</DataExame><NomeExame>CPC-ABCD</NomeExame><DataProcessamento>2023-05-14T21:52:16.367</DataProcessamento><SituacaoFinal>A</SituacaoFinal><StatusLiberacao>Resultado Fornecido/Liberado</StatusLiberacao><IDModulo>0</IDModulo><NumeroAcertos>46</NumeroAcertos><TempoRestante>2000-01-01T01:03:12</TempoRestante><CooperativaCentral>Coop 1</CooperativaCentral><CooperativaSingular>Singular 5</CooperativaSingular>
<NomeCandidato>WXYZ</NomeCandidato><CPF>78523654100</CPF>


Script:

#!/usr/bin/env bash
NR=0;
header="NomeCandidato|CPF|IDInscricao|DataExame|NomeExame|DataProcessamento|SituacaoFinal|GrauObtido|StatusLiberacao|IDModulo|NumeroAcertos|TempoRestante|CooperativaCentral|CooperativaSingular"
arr=(${header//|/ });
arqen='response.xml';
arqsa=$(printf 'ARQUIVO_FINAL_%(%Y%m%d)T.txt');

#Llimpa arq
sed -i.bak 's/<[[:alpha:]]\+>//g;' ${arqen}

#altera formato da data:
sed -ri 's/T[0-9:.]+//g' ${arqen}

#Insere Cabeçalho
echo $header > ${arqsa};

while read line;do
NC=$(awk -F"</[[:alpha:]]+>" '{print NF}' <<< "$line");
echo "Reg:$((++NR)) Campos:$NC";
if (($NC == 15));then
awk -F"</[[:alpha:]]+>" '{OFS="|"; print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14}' <<< "$line" >> ${arqsa}
else
unset res ttr;
for ((n=0;n<${#arr[@]};n++));do
res=$(grep -Eo "[[:alnum:]._-]+</${arr[$n]}>" <<< "$line");
ttr+="${res/<\/${arr[$n]}>/}|";
done
echo "${ttr}" >> ${arqsa}
fi
done<${arqen}

sed -i 's/|$//' ${arqsa}

Arquivo_final
NomeCandidato|CPF|IDInscricao|DataExame|NomeExame|DataProcessamento|SituacaoFinal|GrauObtido|StatusLiberacao|IDModulo|NumeroAcertos|TempoRestante|CooperativaCentral|CooperativaSingular
AAAA|12345678900|8523690|2009-10-02|Ouvidores|2009-10-05|R|63.00|Liberado|0|25|2000-01-01|A|
BBBB|14785236900|9874561|2023-05-12|CPC-S100|2023-05-14|A|77.00|Resultado Fornecido/Liberado|0|46|2000-01-01|9999 - Instituição B|Singular 2
CCCC|78523654100||2023-05-12|CPC-S100|2023-05-14|A||Liberado|0|46|2000-01-01|1|3
DDDD|14785236900|9874561|2023-05-12||2023-05-14|A|77.00|Liberado|0|46|2000-01-01|B|4
ABCD|78523654100||2023-05-12|CPC-ABCD|2023-05-14|A||Liberado|0|46|2000-01-01|1|5
WXYZ|78523654100||||||||||||

-----------------------------------------
É isso.....


______________________________________________________________________
Att.: Marcelo Oliver
______________________________________________________________________



Opa Marcelo, beleza?

Antes de tudo muito obrigado está realmente MUITO próximo da saída que imaginava, ficou incrível essa lógica, mas queria só tirar uma dúvida.

Percebi que nas linhas em que ele entra no else para fazer a inserção dos espaços encontrados que são vazios ele não preserva por completo os campos que tem valor, vou pegar 2 linhas do arquivo response.xml do seu exemplo:

<NomeCandidato>AAAA</NomeCandidato><CPF>12345678900</CPF><IDInscricao>8523690</IDInscricao><DataExame>2009-10-02T00:00:00</DataExame><NomeExame>Ouvidores</NomeExame><DataProcessamento>2009-10-05T15:50:15.447</DataProcessamento><SituacaoFinal>R</SituacaoFinal><GrauObtido>63.00</GrauObtido><StatusLiberacao>Resultado Fornecido/Liberado</StatusLiberacao><IDModulo>0</IDModulo><NumeroAcertos>25</NumeroAcertos><TempoRestante>2000-01-01T01:15:46</TempoRestante><CooperativaCentral>0000 - Instituição A</CooperativaCentral>
<NomeCandidato>BBBB</NomeCandidato><CPF>14785236900</CPF><IDInscricao>9874561</IDInscricao><DataExame>2023-05-12T00:00:00</DataExame><NomeExame>CPC-S100</NomeExame><DataProcessamento>2023-05-14T21:52:16.367</DataProcessamento><SituacaoFinal>A</SituacaoFinal><GrauObtido>77.00</GrauObtido><StatusLiberacao>Resultado Fornecido/Liberado</StatusLiberacao><IDModulo>0</IDModulo><NumeroAcertos>46</NumeroAcertos><TempoRestante>2000-01-01T01:03:12</TempoRestante><CooperativaCentral>9999 - Instituição B</CooperativaCentral><CooperativaSingular>Singular 2</CooperativaSingular>

A primeira linha falta uma coluna que é a CooperativaSingular.
Já na linha2 todas as colunas estão OK, com isso a saída da primeira linha do arquivo final ficou:

AAAA|12345678900|8523690|2009-10-02|Ouvidores|2009-10-05|R|63.00|Liberado|0|25|2000-01-01|A|

Se a gente comparar a coluna <StatusLiberacao> do arquivo response.xml ele tem valor = Resultado Fornecido/Liberado

Porém no arquivo final ele ficou apenas como Liberado

Na linha 2 como ela estava completa, veja que a linha preservou o nome completo dessa coluna:
BBBB|14785236900|9874561|2023-05-12|CPC-S100|2023-05-14|A|77.00|Resultado Fornecido/Liberado|0|46|2000-01-01|9999 - Instituição B|Singular 2


Outra coisa que percebi é que quando ocorre a alteração na linha qualquer string que tenha uma separação por um espaço em branco também sofre esse tipo de alteração, por exemplo:

Se a coluna <NomeCandidato> for igual a Fulano Beltrano da Silva no arquivo final fica somente Silva
Se a coluna <CooperativaCentral> for igual a Cooperativa ABC no arquivo final fica somente ABC e assim sucessivamente...

Ou seja, ele pega apenas o último valor de uma string composta.

Poderia me auxiliar com esse questão?
Fiz um ajuste no seu código e acredito que assim funcione, mas espero que não tenha mudado demais a lógica do processo:

while read -r line; do
NC=$(awk -F"</[[:alpha:]]+>" '{print NF}' <<< "$line")
if (($NC == 15)); then
awk -F"</[[:alpha:]]+>" '{OFS="|"; print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14}' <<< "$line" >> "${arquivo_saida}"
else
unset res ttr
for ((n = 0; n < ${#arr[@]}; n++)); do
res=$(grep -Eo "[^<>]+</${arr[$n]}>" <<< "$line")
res=${res%<\/${arr[$n]}>}
ttr+=("${res}")
done
ttr_line=$(IFS="|"; echo "${ttr[*]}")
echo "${ttr_line}" >> "${arquivo_saida}"
fi
done < "${arquivo_temp}"

sed -i -E "/^($(printf '[|]'%.0s {1.."$quantidade"}))$|^([|]{$quantidade})$/d" "${arquivo_saida}"

dos2unix "${arquivo_saida}" > /dev/null 2>&1



Mas novamente, obrigado mesmo pela ajuda esse código já foi um norte pra mim gigantesco.
Abraço!


Boa tarde Alexandre.
Obrigado pela melhor resposta....

O fato de "não pegar o valor completo do campo", ocorre devido a um pequeno "descuido" na regex do grep.
Note que não tem espaço:
res=$(grep -Eo "[[:alnum:]._-]+</${arr[$n]}>" <<< "$line"); 

Correção: Altere a linha acima, para:
res=$(grep -Eo "[[:alnum:]._/ -]+</${arr[$n]}>" <<< "$line") 

Coloquei espaço e barra.
-----------------------------------------------------------------------------------------------------------------
A sua regex funciona perfeitamente:
res=$(grep -Eo "[^<>]+</${arr[$n]}>" <<< "$line")
Só que demora um pouco mais que a minha sugestão....
Como são muitas linhas.... Faz diferença
----------------------------------------------------------------------------------------------------------------
Quanto ao seu script:

Deleta as linhas que tem somente "|" do arquivo_saida
sed -i -E "/^($(printf '[|]'%.0s {1.."$quantidade"}))$|^([|]{$quantidade})$/d" "${arquivo_saida}"
Não encontrei a definição da var "quantidade".
Em que parte do script essas linhas foram inseridas no arquivo_saida?
-----------------------------------------------------------------------------------------------------------------
É isso...
______________________________________________________________________
Att.: Marcelo Oliver
______________________________________________________________________


Marcelo, vou fazer o teste então com esse ajuste, muito obrigado!

No meu arquivo original ao final gerou uma linha com |||||||||||||
Então $quantidade eu criei baseado nesse comando --> quantidade=$(echo "$header" | tr -cd '|' | wc -c)

Porém eu acredito que isso se deu porque nessa linha do script:
echo "${retorno}" | sed -e 's|<DadosAgendamento>||g' -e 's|<Dados>||g' -e 's|</DadosAgendamento>|\n|g' >> "${arquivo_temp}"

Eu esqueci de colocar tbm essa condição --> -e 's|</Dados>||g'

E aí faz sentido ele gerar vários pipelines pq como o valor da última linha ficou </Dados>, para informar o fim da string XML esse valor não bate com nenhuma coluna do cabeçalho.

Mas aqui foi desatenção minha mesmo e não erro no script que vc sugeriu.

MTO obrigado meu amigo, ontem mesmo testei em ambiente corporativo e funcionou perfeitamente!!!




  


14. Re: Transformação de XML para TXT [RESOLVIDO]

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 09/07/2023 - 19:01h

Alexandre, acabei de editar a minha postagem anterior....
------------------------------------------------------------------------
Em tempo....
Para a var quantidade:
qtdd=${#arr[@]} 



______________________________________________________________________
Att.: Marcelo Oliver
______________________________________________________________________




01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts