Como gerar documento do word, sem ser via modelo dot

Hoje vou mostrar uma forma diferente de integrar com Word, através da extensão XML.

Quem já precisou fazer integração com Word, sabe que o meio mais fácil de se fazer é através de modelos com extensão .dot e .dotx. Inclusive eu já fiz artigos abordando isso.

Porém, teve uma situação em um cliente, onde o documento do Word possuía umas 30 páginas, e centenas de variáveis, o que fazia o usuário ficar esperando um tempinho para a população dos dados.

Para otimizar essa questão, o que foi desenvolvido foi uma integração via XML, dessa forma ficou muito mais rápido, pois basicamente é realizado a leitura de um arquivo XML base e trocado as variáveis em um For de um array.

Abaixo irei detalhar como fazer esse procedimento. Mas ressalto, trabalhar com XML no Word pode ser bem chato a longo prazo (se precisar dar manutenções no arquivo, por causa das quebras de tags).

Obs.: Pré requisito para esse tutorial é ter instalado o Notepad++ e o plugin XML Tools, veja como instalar no artigo Como Indentar um arquivo XML utilizando o Notepad++

  1. Abra o Word e onde for as variáveis, escreva VAR e o restante do nome (evite escrever underline ou outros caracteres especiais, pois pode impactar na tags XML)

Exemplo do Word

  1. Clique em Salvar Como, e escolha o tipo Documento XML do Word

Gravando o documento como xml

  1. Clique com o botão direito no arquivo, depois em Edit with Notepad++ e acione o Pretty Print no XML Tools

Quebrando o XML via Notepad++

  1. Copie o arquivo para a Protheus_Data, por exemplo para a subpasta x_dots
  2. Agora desenvolva um código fonte que leia o conteúdo do arquivo, substitua as variáveis com StrTran e depois abra o arquivo modificado (o fonte esta depois do passo 6)
  3. Por último, basta ver o resultado gerado quando o Word abrir o arquivo

Exemplo da geração do documento

Abaixo o código fonte desenvolvido:

//Bibliotecas
#Include "TOTVS.ch"

/*/{Protheus.doc} User Function zTstXML
Função de integração com o Word, através de um XML
@type  Function
@author Atilio
@since 08/06/2021
/*/

User Function zTstXML()
	Processa({|| fGera()})
Return

Static Function fGera()
    Local cConteudo := ""
	Local aVariaveis
	Local nAtual := 0
	Local nTotal := 0
	Local cDocVar
	Local xDocSubst
	Local cPasta := GetTempPath()
	Local cArquivo := "arquivo_" + dToS(Date()) + "_" + StrTran(Time(), ':', '-') + ".doc"
    Local cXMLArquivo := "\x_dots\exemplo.xml"

    //Se o arquivo existir
    If File(cXMLArquivo)

        //Lê todo o conteúdo do arquivo, joga para a memória
        cConteudo := fMemoRead(cXMLArquivo)

        //Adiciona as variaveis e conteudos
        aVariaveis := {}
        aAdd(aVariaveis, {"VARNOME", "Daniel"})
        aAdd(aVariaveis, {"VARDIA",  Date()})
        aAdd(aVariaveis, {"VARHORA", Time()})

        //Substitui todas as variáveis
        nTotal := Len(aVariaveis)
        ProcRegua(nTotal)
        For nAtual := 1 To nTotal
            IncProc("Analisando variável " + cValToChar(nAtual) + " de " + cValToChar(nTotal) + "...")

            //Busca a variavel e o conteúdo, conforme eVal do fonte GPEWORD2
            cDocVar   := aVariaveis[nAtual][1]
            xDocSubst := aVariaveis[nAtual][2]
            If ValType(xDocSubst) == "D"
                xDocSubst := dToC(xDocSubst)
            EndIf
            If ValType(xDocSubst) == "N"
                xDocSubst := cValToChar(xDocSubst)
            EndIf

            //Retira caracteres especiais para não impactar no XML
            xDocSubst := StrTran(xDocSubst, '>', '')
            xDocSubst := StrTran(xDocSubst, '<', '')
            xDocSubst := StrTran(xDocSubst, '&', '')
            xDocSubst := StrTran(xDocSubst, '¡', '')
            xDocSubst := Alltrim(xDocSubst)

            //Faz a substituição
            cConteudo := StrTran(cConteudo, cDocVar, xDocSubst)
        Next

        //Grava o conteúdo do arquivo, na temporária do sistema, com a extensão .doc
        MemoWrite(cPasta + cArquivo, cConteudo)

        //Abre o arquivo gerado
        ShellExecute("OPEN", cArquivo, "", cPasta, 1)

    Else
        MsgStop("Arquivo XML não foi encontrado na origem!", "Atenção")
    EndIf
Return

//Mais que 65535 bytes
Static Function fMemoRead(cArquivo)
	Local cConteudo := ""
	Local oFile := FWFileReader():New(cArquivo)
	Local aLinhas
	Local cLinAtu

	//Se o arquivo pode ser aberto
	If (oFile:Open())

		//Se não for fim do arquivo
		If ! (oFile:EoF())
			//Definindo o tamanho da régua
			aLinhas := oFile:GetAllLines()
			ProcRegua(Len(aLinhas))

			//Método GoTop não funciona, deve fechar e abrir novamente o arquivo
			oFile:Close()
			oFile := FWFileReader():New(cArquivo)
			oFile:Open()

			//Enquanto houver linhas a serem lidas
			While (oFile:HasLine())
				//Buscando o texto da linha atual
				cLinAtu := oFile:GetLine()
				cConteudo += cLinAtu
			EndDo
		EndIf

		//Fecha o arquivo e finaliza o processamento
		oFile:Close()
	EndIf

Return cConteudo

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

Deixe uma resposta