Problema com Parser XML

Tire suas dúvidas sobre programação em AutoHotkey

Moderator: Gio

pedro45_vs
Posts: 7
Joined: 28 Jun 2020, 18:46

Problema com Parser XML

07 Aug 2020, 14:12

Boa tarde,

Estou com alguma dificuldade em parsear arquivos XML da Nota fiscal eletrônica. O que acontece é que há vários nodes em que não existe uma certa tag, como por exemplo, <vICMS>. Por isso eu preciso utilizar o método SelectSingleNodes.

O problema é que na hora de fazer o Loop, eu não consigo fazer o script resolver a váriavel para ir puxando os campos.

Code: Select all

FileRead, arq, *p65001 arq.xml

doc := ComObjCreate("Msxml2.DOMDocument.3.0")
doc.async := false
doc.loadXML(arq)

Valor_ICMS := doc.selectSingleNode("//det[0]/imposto/ICMS/*/vICMS") ; meu problema é não conseguir iterar para ir selecionando os próximo nodes, det[1], det[2]
Valor_ICMS := Valor_ICMS.text

MsgBox, % Valor_ICMS
Como faço para fazer um Loop para selecionar o det[0], det[1], det[2], etc...?

Obs. Eu até tentei o método selectNodes, mas aí quando um produto não tiver a chave, ele vai simplesmente pular ao invés de me retornar um valor vazio por exemplo.

Será que alguem sabe como posso resolver?
User avatar
Gio
Posts: 1057
Joined: 30 Sep 2013, 10:54
Location: Brazil

Re: Problema com Parser XML

07 Aug 2020, 18:02

Boa tarde Pedro45_vs.

Eu tenho alguns scripts que fazem exatamente isso (ler dados de XMLs de notas fiscais). Fiz da seguinte forma para entrar nos itens da nota:

1. Primeiro, crio uma variável para ser um contador de itens da nota e inicio ela com valor 0 (zero).
2. Depois, faço um Loop com 1000 iterações. Esse loop vai descobrir cada item da nota (o número 1000 não é exatamente aleatório: a nota fiscal eletrônica aceita no máximo 990 itens diferentes).
3. No corpo do loop, o código usa o método selectSingleNode para buscar os dados da tag <xProd> que esteja dentro da tag Det[%A_Index%]. Logo, esse código vai pegar um-a-um todos os valores de <xProd> dentro de <det[número]> que existirem no XML da nota (a tag <xProd> é obrigatória para todos os itens da nota fiscal e não pode conter valor em branco, senão a nota não foi aprovada).
4. Logo em seguida, ainda dentro do corpo do loop, testo o valor encontrado em cada iteração. Se não for em branco, aumento o contador de itens em 1. Se for em branco, termino o loop (porque na verdade não precisa iterar 1000 vezes toda vez).
5. A partir daí a variável do contador de itens vai ter a exata quantidade de itens da nota, então posso usar ela para buscar qualquer informação de item pela ordem do item. Também posso usar ela para criar outros loops que extraiam os dados específicos de cada item.
6. Portanto, caso um determinado item EXISTA e ao mesmo NÃO TENHA ESPECIFICAMENTE A TAG <vICMS>, podemos saber facilmente: se o número do det[] for menor que o total do contador de itens esse item existe. E se mesmo assim a tag vICMS retornar em branco, então de fato é um item que não tem a tag vICMS.

Exemplo:

Code: Select all

FileSelectFile, XML_FILE,,,Selecione os arquivo de XML da nota, Arquivos de XML (*.xml;)
If (ErrorLevel)
{
	msgbox, 0x10, Erro, Falha ao ler o arquivo. Por favor, reinicie o programa e selecione o arquivo XML novamente.
	SB_SetText("Aguardando XML")
	Return
}

FileRead, XML_FILE_CONTENTS, %XML_FILE%

If ((ErrorLevel) OR (XML_FILE_CONTENTS = ""))
{
	msgbox, 0x10, Erro, Falha ao ler o arquivo. Por favor, reinicie o programa e selecione o arquivo XML novamente.
	SB_SetText("Aguardando XML")
	Return
}

ns = xmlns=".*?"
xmldata := RegExReplace(XML_FILE_CONTENTS, ns, "")

xmlA := ComObjCreate("MSXML2.DOMDocument.6.0")
xmlA.async := false
xmlA.loadXML(xmldata)


TOTAL_DE_ITENS := 0
Loop 1000
{
	DESC_PROD := xmlA.selectSingleNode("//det[" . A_Index . "]/prod/xProd").text
	If !(DESC_PROD = "")
	{
		TOTAL_DE_ITENS++
	}
	else ; Esse ELSE é opcional, caso você queira terminar o loop no primeiro item cuja TAG não exista (ao invés de efetivamente iterar até 1000).
	{
		Break
	}
}

Loop % TOTAL_DE_ITENS ; A partir daqui eu posso usar a variável para indicar uma iteração por item da nota.
{
	PROD := CD_FABR_PROD := xmlA.selectSingleNode("//det[" . A_Index . "]/prod/xProd").text
	EAN_PROD := xmlA.selectSingleNode("//det[" . A_Index . "]/prod/cEAN").text
	VALOR_UNIT_NF := xmlA.selectSingleNode("//det[" . A_Index . "]/prod/vUnCom").text
	
	vICMS := xmlA.selectSingleNode("//det[" . A_Index . "]/imposto/ICMS/ICMS00/vICMS").text ; OBSERVAR SEMPRE O CAMINHO DAS TAGS!
	
	msgbox, 0, Aviso, Total de Itens: %TOTAL_DE_ITENS%`n`nItem %A_index%:`n`nDESCRIÇÃO: %PROD%`nEAN: %EAN_PROD%`nVALOR UNITARIO: %VALOR_UNIT_NF%`nvICMS: %vICMS%
}
pedro45_vs
Posts: 7
Joined: 28 Jun 2020, 18:46

Re: Problema com Parser XML

08 Aug 2020, 10:32

Em primeiro lugar gostaria de agradecer sua atenção.

Segundo, vc acredita que depois de chegar em casa, enquanto eu tomava um banho eu tive a seguinte ideia:

Usar o SelectNodes para selecionar todos os produtos e determinar a quantidade de vezes que o Loop será feito.
Depois criar uma variável para manipular a expressão XPath antes de aplicar o método selectSingleNode.
E não é que deu certo? :dance: Veja o que eu fiz:

Code: Select all

Node0 := doc.selectNodes("//det/prod") ; faço isso apenas para determinar a quantidade de Loops necessários para cada arquivo XML
For key in Node0 {

iNode1 := "//det[" (A_Index - 1) "]/imposto/ICMS/*/vICMS"  ; fazendo assim eu consigo resolver a expressão XPath antes de aplicar o método SelectSingleNodes
vICMS :=  doc.selectSingleNode(iNode1).text 

if (vICMS = "") {
vICMS := 0
}

MsgBox, %vICMS%
}

Ps. Engraçado como às vezes a gente empaca em um problema e depois, em momentos que a gente nem imagina, vem uma ideia para resolver. :lol:

Return to “Ajuda e Suporte Geral”

Who is online

Users browsing this forum: No registered users and 7 guests