Embora nos ultimos tempos tenha sido dificil de podermos em nossos sistemas puxar os XMLs direto da receita e fazendo-se valer a lei de que o emissor é
obrigado a enviar o XML ao seu cliente, cabe à nós receber este arquivo e armazená-lo em local ou pasta que nossos sistemas possam catalogar e manipular.
Para criarmos um XML, não existe segredo, basta umar concatenação e umas funções de escrita e pronto.
Para recuperar o conteúdo é outra história.
No meu caso, andei por tempos batendo a cabeça para recuperar dados em XMLs e muitas vezes algo falhava.
Um exemplo é o caso da busca de tags em nós onde, hora existem, ora não, exemplo:
Dois itens na sessão produtos onde em um exista a tag IPI em apenas um dos conjuntos.
Buscar por AT(), RAT(), $ ou outra função de pesquisa de string nos faz rodar demais.
No meu caso, desde o inicio no trato com XML sempre apostei no uso dos motores do S.O. para este intuito em conjunto com OLE.
Código: Selecionar todos
cEDXFile := "35..-nfe.xml"
// Caminhos
cPathDados := "C:\Sistema"
cEDXFile := cPathDados+"\NF-e\remessa\ent\"+cFileName( cEDXFile )
// Puxa o conteúdo do arquivo para manipulação
cXMLDoc := MemoRead( cEDXFile )
Código: Selecionar todos
// Usa motor XML da Microsoft
oXMLDoc := TOLEAUTO():New( "Microsoft.XMLDOM" )
oXMLDoc:async := .f.
lSuccess := oXMLDoc:load( cEDXFile )
if lSuccess // se abriu com sucesso...
Para capturar dados de uma tag simples bastaria:
Código: Selecionar todos
oXMLDoc:getElementsByTagName( "xNome" ):Text
Código: Selecionar todos
// Traz todo o conjunto para dentro de um unico objeto
xProds := oXMLDoc:getElementsByTagName( "det" )
// Faço uma contagem de quantidade de subconjuntos
nProds := xProds:length // length retorna quantidade a contar
// Executo o laço
for iProds = 1 to nProds
// Para cada subconjunto/nó mais interno crio o suporte
oTAGProd := oXMLDoc:getElementsByTagName( "prod" )
oTAGImposto := oXMLDoc:getElementsByTagName( "imposto" )
oTAGPIS := oXMLDoc:getElementsByTagName( "PIS" )
oTAGCOFINS := oXMLDoc:getElementsByTagName( "COFINS" )
// Pego o XML somente do conjunto que desejo
cXMLProd := oTAGProd:Item(iProds-1):xml
cXMLImposto := oTAGImposto:Item(iProds-1):xml
cXMLPIS := oTAGPIS:Item(iProds-1):xml
cXMLCOFINS := oTAGCOFINS:Item(iProds-1):xml
Código: Selecionar todos
// Caso exista a tag processo/pego seu conteúdo
lRESUMIDO := iif( ValidaXMLField( "cProd" , cXMLProd ), .t., .f. )
lDESCRICAO := iif( ValidaXMLField( "xProd" , cXMLProd ), .t., .f. )
Código: Selecionar todos
M->RESUMIDO := iif( lRESUMIDO , oXMLDoc:getElementsByTagName( "cProd" ):Item(iProds-1):Text , "" )
M->DESCRICAO := iif( lDESCRICAO , oXMLDoc:getElementsByTagName( "xProd" ):Item(iProds-1):Text , "" )
Código: Selecionar todos
<det nItem="1">
<prod>
<cProd>120088</cProd>
<cEAN/>
<xProd>PORTA CARTAO</xProd>
<NCM>39095029</NCM>
<CFOP>5101</CFOP>
<uCom>BL</uCom>
<qCom>1.0000</qCom>
<vUnCom>3597.6000</vUnCom>
<vProd>3597.60</vProd>
<cEANTrib/>
<uTrib>BL</uTrib>
<qTrib>1.0000</qTrib>
<vUnTrib>3597.6000</vUnTrib>
<indTot>1</indTot>
</prod>
<imposto>
<ICMS>
<ICMSSN202>
<orig>0</orig>
<CSOSN>202</CSOSN>
<mobBCST>4</mobBCST>
<pMVAST>57.0000</pMVAST>
<pRedBCST>0.00</pRedBCST>
<vBCST>5648.23</vBCST>
<pICMSST>12.0000</pICMSST>
<vICMSST>109.01</vICMSST>
</ICMSSN202>
</ICMS>
<IPI>
<IPITrib>
<CST>53</CST>
<vBC>0.00</vBC>
<pIPI>0.00</pIPI>
<vIPI>0.00</vIPI>
</IPITrib>
</IPI>
<PIS>
<PISOutr>
<CST>99</CST>
<vBC>0.00</vBC>
<pPIS>0.00</pPIS>
<vPIS>0.00</vPIS>
</PISOutr>
</PIS>
<COFINS>
<COFINSOutr>
<CST>99</CST>
<vBC>0.00</vBC>
<pCOFINS>0.00</pCOFINS>
<vCOFINS>0.00</vCOFINS>
</COFINSOutr>
</COFINS>
</imposto>
</det>
Código: Selecionar todos
<prod>
<cProd>120088</cProd>
<cEAN/>
<xProd>PORTA CARTAO</xProd>
<NCM>39095029</NCM>
<CFOP>5101</CFOP>
<uCom>BL</uCom>
<qCom>1.0000</qCom>
<vUnCom>3597.6000</vUnCom>
<vProd>3597.60</vProd>
<cEANTrib/>
<uTrib>BL</uTrib>
<qTrib>1.0000</qTrib>
<vUnTrib>3597.6000</vUnTrib>
<indTot>1</indTot>
</prod>
Código: Selecionar todos
<imposto>
<ICMS>
...
</ICMS>
<IPI>
...
</IPI>
<PIS>
...
</PIS>
<COFINS>
...
</COFINS>
</imposto>
Ao executar oTAGPIS := oXMLDoc:getElementsByTagName( "PIS" ) trago somente o conteúdo do nó PIS:
Código: Selecionar todos
<PIS>
<PISOutr>
<CST>99</CST>
<vBC>0.00</vBC>
<pPIS>0.00</pPIS>
<vPIS>0.00</vPIS>
</PISOutr>
</PIS>
Lógico que o que foi aqui apresentado é somente um rascunho esclarecedor mas parcial do que seria preciso para captar adequadamente todo o conteúdo de um XML como o de uma nota fiscal eletronica. Mas a idéia é conhecer como chegar mais fundo nos XML mais complexos.
A postagem apresentada tratou somente da obtenção de trechos em nós e não tratou atributos.
Para isto bastará buscar informações sobre os métodos attribute do objeto XMLDOM
Algumas funções usadas:
Código: Selecionar todos
Function CriticaTagName( _tagName_, oXMLDoc, cXMLDoc )
if upper( "<"+_tagName_+">" ) $ upper( cXMLDoc )
_cTagName_ := oXMLDoc:getElementsByTagName( _tagName_ ):Item(0):Text
else
_cTagName_ := ""
endif
return _cTagName_
function ValidaXMLField( _XMLField_, _XMLFile_ )
return iif( AT( "<"+_XMLField_+">", _XMLFile_ ) > 0, .t., .f. )
function XMLTagInsert( cTag, cConteudo, nSpaces )
DEFAULT nSpaces := 0
return space(nSpaces)+[<]+cTag+[>] + cConteudo + [</]+cTag+[>]
function getXMLValue( cXML, cTAG )
LOCAL nPosIni := At( [<]+cTag+[>], cXML ) + len( [<]+cTag+[>] )
LOCAL nPosFim := At( [</]+cTag+[>], cXML ) - ( len([</]+cTag+[>]) + 1 )
return substr( cXML, nPosIni, nPosFim-nPosIni )


