Tá na sefazclass, com funções que podem faltar.
Aqui só pra ilustrar.
Basicamente verifica se está abrindo/fechando tudo na ordem certa.
Código: Selecionar todos
STATIC FUNCTION SingleXmlValidate( cXml, cIgnoreList )
LOCAL nPos, aTagsAbre := {}, cTmp, oElement, cLetra, cTxt := ""
hb_Default( @cIgnoreList, "" )
DO WHILE .T.
nPos := hb_At( "<", cXml, nPos )
IF nPos < 1
EXIT
ENDIF
IF Substr( cXml, nPos + 1, 1 ) == "/"
IF ! ProcFecha( Substr( cXml, nPos, hb_At( ">", cXml, nPos ) - nPos ), aTagsAbre, @cTxt )
EXIT
ENDIF
ELSE
cTmp := Substr( cXml, nPos, hb_At( ">", cXml, nPos ) - nPos + 1 )
IF ! "/>" $ cTmp .AND. ! "/ >" $ cTmp
AAdd( aTagsAbre, cTmp )
//? "Abriu " + Atail( aTagsAbre )
ENDIF
ENDIF
nPos := nPos + 3
ENDDO
IF Len( aTagsAbre ) != 0
cTxt += "Em aberto" + Space(3)
FOR EACH oElement IN aTagsAbre
cTxt += oElement + Space(3)
NEXT
RETURN "*ERRO* " + cTxt
ENDIF
FOR EACH cLetra IN cXml
DO CASE
CASE cLetra $ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
CASE cLetra $ "abcdefghijklmnopqrstuvwxyz"
CASE cLetra $ "0123456789"
CASE cLetra $ " <>=:/.,-+#$()_@;%"
CASE cLetra == ["]
CASE cLetra $ cIgnoreList
OTHERWISE
cTxt += "Caractere " + cLetra + " posição " + Ltrim( Str( cLetra:__EnumIndex ) ) + ;
" aproximadamente aqui " + Substr( cXml, Max( 0, cLetra:__EnumIndex - 10 ), 20 ) + ", "
ENDCASE
NEXT
IF " <" $ cXml .OR. "> " $ cXml
cTxt += "espaços em branco antes de < ou depois de >"
ENDIF
IF Len( cTxt ) > 0
RETURN "*ERRO* " + cTxt
ENDIF
RETURN "OK"
STATIC FUNCTION ProcFecha( cTag, aTagsAbre, cTxt )
LOCAL oElement
FOR EACH oElement IN aTagsAbre
IF " " $ oElement
oElement := Substr( oElement, 1, At( " ", oElement ) - 1 )
ENDIF
IF ">" $ oElement
oElement := Substr( oElement, 1, At( ">", oElement ) - 1 )
ENDIF
IF "<" $ oElement
oElement := Trim( Substr( oElement, 2 ) )
ENDIF
NEXT
cTag := Substr( cTag, 3 )
IF ">" $ cTag
cTag := Substr( cTag, 1, At( ">", cTag ) - 1 )
ENDIF
IF cTag == Atail( aTagsAbre )
//? "fechou " + cTag
hb_ADel( aTagsAbre, Len( aTagsAbre ), .T. )
ELSE
IF Len( aTagsAbre ) != 0
cTxt += "erro fechada " + cTag + " esperada " + Atail( aTagsAbre ) + Space(3)
ENDIF
RETURN .F.
ENDIF
RETURN .T.