Hola a todos,
Ya se tienen algunas piezas del puzzle.
Creo que falta una, ¿Cómo leen Ustedes un XML?
Yo tengo una función pero creo que no es una solución muy ortodoxa, aunque funciona muy bien. El único requisito es saber a priori que Tag son iterativos.
Ya que usar la clase para crear un XML me costó entenderla, pensé que para leerlo me costaría también, por lo que opté por lo que me es fácil, y cuando quiero leer un XML paso su contenido a una array.
Me creé una función LoadXML() que devuelve una Array de arrays tridimensionales, cada array de esta array tiene:
-una cadena del path del tag completo
-el valor que tiene ese tag
-una array de arrays bidimensionales con el atributo y su valor (si tiene atributos)
Defino previamente aTagIter (son los Tags iterativos) que és una array de array bidimensionales, para Verifactu:
Code: Select all | Expand
Local aTagIter := { { "/env:Envelope/env:Body/tikR:RespuestaRegFactuSistemaFacturacion/tikR:RespuestaLinea/", 0 }, ;
{ "/env:Envelope/env:Body/tikR:RespuestaRegFactuSistemaFacturacion/tikR:RespuestaLinea/tikR:CodigoErrorRegistro/", 0 }, ;
{ "/env:Envelope/env:Body/tikR:RespuestaRegFactuSistemaFacturacion/tikR:RespuestaLinea/tikR:DescripcionErrorRegistro/", 0 } ;
}
Así es como leo la respuesta a los envíos que hago a Verifactu:
Code: Select all | Expand
//----------------------------------------------------------------------------/
FUNCTION LoadXml( hFile, cBDPathFull, aTagIter )
Local oXmlDoc, oXmlIter
Local lAbreaqui := .F.
//Local oTagActual, oTagLast, aRoots := {}
Local oTagActual, oTagLast := {}
Local litetagA := ""
Local litetagB := ""
Local nContador := 0
Local aXml := {}
Local cDummy := ""
/* Tag iteratius i sumatori de iteracions trovades.
L'estructura de l'array es:
- 1er. element el tag que pot ser iteratiu
- 2on. element el número de iteració del tag.
*/
/*
Local aTagIter := { {"/Document/CstmrDrctDbtInitn/PmtInf/", 0}, ;
{"/Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf/", 0}, ;
{"/Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf/Dbtr/PstlAdr/AdrLine/", 0} }
*/
//Msgnowait( AMPAarra, GetTrad("Atenció!"), GetTrad("Llegint el fitxer: ") + cBDPathFull )
// Cal ordenar la array per a que es puguin controlar correctament les iteracions.
aTagIter := Asort( aTagIter,,, { |x, y| x[1] < y[1] } )
If hFile = 0
hFile = FOpen( cBDPathFull )
lAbreaqui := .T.
EndIf
oXmlDoc = TXmlDocument():New( hFile )
oXmlIter = TXmlIterator():New( oXmlDoc:oRoot )
oTagActual := oTagLast := Nil
litetagA := "/"
while ( oTagActual := oXmlIter:Next() ) != nil
//Traza( 1, "oTagActual:Depth()-oTagActual:cName=", oTagActual:Depth(), "-", oTagActual:cName )
If oTagLast != nil
if oTagLast:Depth() < oTagActual:Depth()
litetagA := litetagA + oTagActual:cName + "/"
endif
if oTagLast:Depth() > oTagActual:Depth()
//Traza( 1, "litetagA=", litetagA )
litetagB := "/"
For nContador := 1 To ( oTagActual:Depth() - 1 )
litetagB := litetagB + StrToken( litetagA, nContador, "/" ) + "/"
EndFor
litetagA := litetagB
If Empty(oTagActual:cName)
litetagA := litetagA + "/"
Else
litetagA := litetagA + oTagActual:cName + "/"
EndIf
//litetagA := CheckItera( litetagA, aTagIter )
endif
if oTagLast:Depth() == oTagActual:Depth()
//Traza( 1, "litetagA=", litetagA )
litetagB := "/"
For nContador := 1 To ( oTagActual:Depth() - 1 )
litetagB := litetagB + StrToken( litetagA, nContador, "/" ) + "/"
EndFor
litetagA := litetagB
If Empty(oTagActual:cName)
litetagA := litetagA + "/"
Else
litetagA := litetagA + oTagActual:cName + "/"
EndIf
//litetagA := CheckItera( litetagA, aTagIter )
endif
litetagA := CheckItera( litetagA, aTagIter )
else
If .Not. Empty(oTagActual:cName)
litetagA := litetagA + oTagActual:cName + "/"
EndIf
//Traza( 1, "litetagA=", litetagA )
endif
//litetagA := CheckItera( litetagA, aTagIter )
// Aquí es captura el TAG, el seu valor y els atributs si en té.
// exemple: { "/Document/CstmrDrctDbtInitn/PmtInf<1>/DrctDbtTxInf<2>/Dbtr/PstlAdr/AdrLine<1>/", "BARCINO, 29 P-D - SELVA NEGRA", {} }
// { "/Document/CstmrDrctDbtInitn/PmtInf<1>/DrctDbtTxInf<2>/Dbtr/PstlAdr/AdrLine<2>/", "08750 Vallirana", {} }
// Es captura el TAG si té data o si hi han atributs del TAG.
If .Not. Empty( oTagActual:cData ) .or. Len( oTagActual:aAttributes ) > 0
AADD( aXml, { litetagA, oTagActual:cData, {} } )
HEval( oTagActual:aAttributes,;
{ | cKey, cData | AADD( ATail( aXml )[3], { cKey, cData } ) } )
EndIf
/* En aquesta traza s'enregistren els TAG i els seus valors.
------------------------------------------------------ */
/*
cDummy := ""
HEval( oTagActual:aAttributes,;
{ | cKey, cData | cDummy := cDummy + cKey + ":" + cData + "-" } )
If .Not. Empty( oTagActual:cData ) .or. Len( oTagActual:aAttributes ) > 0
Traza( 1, "litetagA=", litetagA, "..", oTagActual:cData, "..", cDummy, "..", Len( ATail( aXml )[3]) )
EndIf
*/
//Traza( 1, "" )
oTagLast = oTagActual
end
If lAbreaqui
FClose( hFile )
EndIf
//EndMsgNoWait( AMPAarra )
// Podem ordenar l'array... però crec que no serà necessari.
//aXml := Asort( aXml,,, { |x, y| x[1] < y[1] } )
//Traza( 1 , aXml )
Return aXml
//----------------------------------------------------------------------------//
FUNCTION CheckItera( litetagA, aTagIter )
/* litetagA es reb acabat en '/'.
Aquesta funció es llença al moment d'afegir un node de XML a litetagA, i
es comprova si aquest nou node afegit és iteratiu, i si és el cas s'el
numera. A la resta de nodes que arriberien a 'penjar' d'ell s'els posa
el numeral a '0', doncs es tractaria d'una nova captura de nodes iteratius.
Per a que la possada a zero de les iteracions que penjen de la que
estem examinant, cal que aTagIter estigui ordenada ascendentment.
------------------------------------------------------------------------ */
Local cCadena := litetagA
Local nContadorA := 0
Local nContadorB := 0
Local PosA := 0
Local PosB := 0
Local LenaTagIter := 0
Local LencCadena := 0
Do While (PosA := AT( "<", cCadena) ) > 0
//Traza( 1 , "a-cCadena=", cCadena )
PosB := AT( ">", cCadena )
cCadena := Left( cCadena, PosA - 1 ) + SubStr( cCadena, PosB + 1 )
//Traza( 1 , "b-cCadena=", cCadena )
End
If ( nContadorA := ASCan( aTagIter, { |aVal| aVal[1] = cCadena } ) ) > 0
/* Poso la resta d'elements iteratius que penjen del que estem examinant a zero (0).
------------------------------------------------------------------------------ */
LenaTagIter := Len(aTagIter)
LencCadena := Len(cCadena)
For nContadorB := ( nContadorA + 1 ) To LenaTagIter
If cCadena = Left( aTagIter[nContadorB][1], LencCadena )
aTagIter[nContadorB][2] := 0
EndIf
EndFor
aTagIter[ nContadorA ][2] ++
cCadena := Left( litetagA, Len(litetagA) - 1 ) + "<" + AllTrim(Str(aTagIter[ nContadorA ][2], 10,0)) + ">/"
Else
cCadena := litetagA
EndIf
Return cCadena
//----------------------------------------------------------------------------//
Prueben a pasarle a LoadXML() un fichero XML y vean el array que les devuelve, hacer un AT() nos facilita recuperar el valor que lleva ese Tag.
Con mucho gusto compartiría mi código, pero no lo tengo tan bien estructurado para aislarlo del programa donde se utiliza, hay demasiadas llamadas a funciones que utilizo para otras cosas.
Si que puedo compartir parte de él y como he resuelto situaciones que voy detectando.
Saludos,