Página 2 de 3

GEr

Enviado: 22 Ago 2021 07:23
por JoséQuintas
Só pra não errar no json... a fonte do json agora é o resultado de hb_jsonDecode()

Código: Selecionar todos

REQUEST HB_CODEPAGE_PTISO

PROCEDURE Main

   LOCAL xValue, xTeste, cTxt

   Set( _SET_CODEPAGE, "PTISO" )
   SetMode( 40, 100 )

   xTeste := {}
   AAdd( xTeste, 123 )
   AAdd( xTeste, .F. )
   AAdd( xTeste, .T. )
   AAdd( xTeste, Nil )
   AAdd( xTeste, "testando" )
   AAdd( xTeste, { 1, 2, 3 } )
   AAdd( xTeste, { { 1, 2 } } )

   cTxt := hb_JsonEncode( xTeste )

   Altd()
   xValue := ze_JsonDecode( cTxt )
   ( xValue )
   Altd()
   Inkey(0)

   RETURN
Agora vou poder testar DATE.
Deixando o hash pro final, porque eu também não tenho prática com hash kkkk

GEr

Enviado: 22 Ago 2021 07:34
por JoséQuintas
jsondate.png
Olhem uma coisa interessante, que vai resultar em problema.
Data é salva no json como Dtos()

Sabem qual é o problema?

A string "20210822" vai ser o mesmo que 22/08/2021.
Se existir um número de documento igual a esse, ele vai ser convertido pra DATE.
Tô achando esquisito isso, mas é o que vai acontecer.

GEr

Enviado: 22 Ago 2021 07:38
por JoséQuintas
json.png
Olhem aí, é isso mesmo, uma data e uma string, mas em json estão exatamente iguais.
Será que a rotina do Harbour tem bug?

GEr

Enviado: 22 Ago 2021 07:47
por JoséQuintas
json.png
Olhem aí: mesmo resultado pra tipos diferentes
Com certeza, na decodificação o resultado vai ser um só.

GEr

Enviado: 22 Ago 2021 08:08
por JoséQuintas
json.png
Aproveitei pra alguns testes mais.
Chr(13) é traduzido pra \r
Chr(10) é traduzido pra \n
Aspas é traduzida pra \", este último tinha colocado lá.

Tem esses na rotina em C, e outros mais.

O da data, é depois de traduzir a string, testar se Stod() consegue converter pra tipo date.

Código: Selecionar todos

            IF Len( xValue2 ) == 8 .AND. Dtos( Stod( xValue2 ) ) == xValue2
               xValue := Stod( xValue2 )
            ELSE
               xValue := xValue2
            ENDIF

GEr

Enviado: 22 Ago 2021 08:29
por JoséQuintas
No fonte em C tem esta parte:

Código: Selecionar todos

       case '\"':
                  *szHead++ = '\"';
                  break;
               case '\\':
                  *szHead++ = '\\';
                  break;
               case '/':
                  *szHead++ = '/';
                  break;
               case 'b':
                  *szHead++ = '\b';
                  break;
               case 'f':
                  *szHead++ = '\f';
                  break;
               case 'n':
                  *szHead++ = '\n';
                  break;
               case 'r':
                  *szHead++ = '\r';
                  break;
               case 't':
                  *szHead++ = '\t';
                  break;
Parece que tem mais além de Chr(13) e Chr(10) (\r e \n)

GEr

Enviado: 22 Ago 2021 08:39
por JoséQuintas
desvendando:

\r chr(13) return
\n Chr(10) new line
\f Chr(12) line feed
\b Chr(8) backspace
\t Chr(9) tab

GEr

Enviado: 22 Ago 2021 08:50
por JoséQuintas
jsn.png
Chegou a vez do hash.
Parece moleza, parece o que eu havia previsto.
Ao terminar de decodificar a string, verificar se tem ":"
Se tiver, é usar como chave, e o próximo valor como conteúdo.

GEr

Enviado: 22 Ago 2021 09:10
por JoséQuintas
json.png
E não é que foi moleza mesmo, mais fácil do que eu pensava.

Código: Selecionar todos

      CASE Left( cTxt, 1 ) == "{"
         xValue := hb_Hash()
         cTxt := Substr( cTxt, 2 )
         DO WHILE ze_JsonDecodeValue( @cTxt, @xValue )
         ENDDO
         lReturn := .T.
         EXIT
Se encontra "{" começa a variável hash, notem que passa a variável como parâmetro.

Código: Selecionar todos

         IF Left( cTxt, 1 ) == ":"
            xValue[ xValue2 ] := Nil
            cTxt := Substr( cTxt, 2 )
            ze_JsonDecodeValue( @cTxt, @xValue[ xValue2 ] )
            lReturn := .T.
            EXIT
Se encontrou ":" após o término da string, significa que é hash, então a string se torna a chave do hash, e o próximo valor é o conteúdo

Ainda falta.... TimeStamp
E testar tudo junto e misturado.

Código: Selecionar todos

REQUEST HB_CODEPAGE_PTISO

PROCEDURE Main

   LOCAL xValue, xTeste, cTxt

   Set( _SET_CODEPAGE, "PTISO" )
   SET DATE BRITISH
   SetMode( 40, 100 )

   xTeste := hb_Hash()
   xTeste[ "codigo" ] := 1
   xTeste[ "nome" ] := "Jose Quintas"

   cTxt := hb_JsonEncode( xTeste )

   Altd()
   xValue := ze_JsonDecode( cTxt )
   ( xValue )
   Altd()
   Inkey(0)

   RETURN

FUNCTION ze_JsonDecode( cTxt )

   LOCAL xValue

   ze_JsonDecodeValue( cTxt, @xValue )

   RETURN xValue

FUNCTION ze_JsonDecodeValue( cTxt, xValue )

   LOCAL xValue2, lReturn := .F.

   DO WHILE Len( cTxt ) > 0
      DO WHILE Left( cTxt, 1 ) $ " " + Chr(13) + Chr(10) .AND. Len( cTxt ) > 0
         cTxt := Substr( cTxt, 2 )
      ENDDO
      DO CASE
      CASE Left( cTxt, 1 ) $ "]}"
         lReturn := .F.
         cTxt := Substr( cTxt, 2 )
         EXIT
      CASE Left( cTxt, 1 ) == "["
         xValue := {}
         cTxt := Substr( cTxt, 2 )
         DO WHILE ze_JsonDecodeValue( @cTxt, @xValue2 )
            AAdd( xValue, xValue2 )
            xValue2 := Nil
         ENDDO
         lReturn := .T.
         EXIT
      CASE Left( cTxt, 1 ) == "{"
         xValue := hb_Hash()
         cTxt := Substr( cTxt, 2 )
         DO WHILE ze_JsonDecodeValue( @cTxt, @xValue )
         ENDDO
         lReturn := .T.
         EXIT
      CASE Left( cTxt, 1 ) $ "-123456789"
         xValue := ""
         DO WHILE Left( cTxt, 1 ) $ "-0123456789." .AND. Len( cTxt ) > 0
            xValue += Left( cTxt, 1 )
            cTxt := Substr( cTxt, 2 )
         ENDDO
         xValue := Val( xValue )
         lReturn := .T.
         EXIT
      CASE Left( cTxt, 5 ) == "false"
         xValue := .F.
         cTxt := Substr( cTxt, 6 )
         lReturn := .T.
         EXIT
      CASE Left( cTxt, 4 ) == "null"
         xValue := Nil
         cTxt := Substr( cTxt, 5 )
         lReturn := .T.
         EXIT
      CASE Left( cTxt, 4 ) == "true"
         xValue := .T.
         cTxt := Substr( cTxt, 5 )
         lReturn := .T.
         EXIT
      CASE Left( cTxt, 1 ) == ["]
         // pode ser string ou item hash
         xValue2 := ""
         cTxt := Substr( cTxt, 2 )
         DO WHILE Len( cTxt ) > 0
            DO CASE
            CASE Left( cTxt, 2 ) == [\"]
               xValue2 += ["]
               cTxt := Substr( cTxt, 3 )
               LOOP
            CASE Left( cTxt, 2 ) == "\\"
               xValue2 += "\"
               cTxt := Substr( cTxt, 3 )
               LOOP
            CASE Left( cTxt, 2 ) == "\r" // return
               xValue2 += Chr(13)
               cTxt := Substr( cTxt, 3 )
               LOOP
            CASE Left( cTxt, 2 ) == "\n" // newline
               xValue2 += Chr(10)
               cTxt := Substr( cTxt, 3 )
               LOOP
            CASE Left( cTxt, 2 ) == "\f" // formfeed
               xValue2 += Chr(12)
               cTxt := Substr( cTxt, 3 )
               LOOP
            CASE Left( cTxt, 2 ) == "\b" // backspace
               xValue2 += Chr(8)
               cTxt := Substr( cTxt, 3 )
               LOOP
            CASE Left( cTxt, 2 ) == "\t" // tab
               xValue2 += Chr(9)
               cTxt := Substr( cTxt, 3 )
               LOOP
            ENDCASE
            IF Left( cTxt, 1 ) == ["]
               cTxt := Substr( cTxt, 2 )
               EXIT
            ENDIF
            xValue2 += Left( cTxt, 1 )
            cTxt := Substr( cTxt, 2 )
         ENDDO
         IF Left( cTxt, 1 ) == ":"
            xValue[ xValue2 ] := Nil
            cTxt := Substr( cTxt, 2 )
            ze_JsonDecodeValue( @cTxt, @xValue[ xValue2 ] )
            lReturn := .T.
            EXIT
         ELSE
            IF Len( xValue2 ) == 8 .AND. Dtos( Stod( xValue2 ) ) == xValue2
               xValue := Stod( xValue2 )
            ELSE
               xValue := xValue2
            ENDIF
            lReturn := .T.
            EXIT
         ENDIF
      ENDCASE
      cTxt := Substr( cTxt, 2 )
   ENDDO
   DO WHILE Left( cTxt, 1 ) $ ", " + Chr(13) + Chr(10) .AND. Len( cTxt ) > 0
      cTxt := Substr( cTxt, 2 )
   ENDDO

   RETURN lReturn
Bom... talvez xHarbour não tenha STOD(), mas dá pra criar alternativa.

Stod() converte ano-mes-dia pra data, seria aaaammdd
Dá pra usar Ctod() mas vai ficar dependente de formato de data BRITISH por exemplo.

Código: Selecionar todos

FUNCTION Stod( cAnoMesDia )

   SET DATE BRITISH
   RETURN Ctod( Substr( cAnoMesDia, 7, 2 ) + "/" + Substr( cAnoMesDia, 5, 2 ) + "/" + Substr( cAnoMesDia, 1, 2 ) )

GEr

Enviado: 22 Ago 2021 09:20
por JoséQuintas
Só comentário:

Acho que é aquele tal negócio que já mencionei aqui: não preciso disso, não tive pressa, pude pensar devagar e tranquilo.
Alterei totalmente a lógica inicial, ficou até mais incompleto que antes, mas continuei sem pressa, devagar e tranquilo.
Fui resolvendo um tipo de cada vez.
E... parece que saiu.
Talvez agora até dê pra identificar partes comuns entre esse fonte e o fonte C.

Ainda acho estranho o que mencionei, se converter a string "20210822" pra json, e depois decodificar, vai trazer Date() e não string. Mas é assim com Harbour, esta rotina ficou igual.

GEr

Enviado: 22 Ago 2021 09:46
por JoséQuintas
Convém ressaltar:

Não faço idéia do que vai acontecer num texto "não json", ou se tiver formatação errada.
Não fiz nenhum tratamento pra conteúdo inválido, então não sei o que pode acontecer.
Não fiz nem mesmo tratamento de vírgulas, tá aceitando até com espaço em branco entre valores ao invés de vírgula.
Vai aceitar [ 1 2 3 ] ou [ 1, 2, 3 ]
Mas foi o que deu pra fazer...

GEr

Enviado: 22 Ago 2021 15:07
por JoséQuintas
mysqljson.png
Uia.
No MySQL data é diferente, mas, dois tipos de variável diferente com mesmo resultado.
Apesar que no MySQL data é assim mesmo.

Mas isso significa alterar a rotina ze_jsonDecode pra datas nesse estilo também.
Confuso isso, então json não é padrão, ou segue o padrão SQL.
Agora não sei dizer se no Harbour está certo fazer diferente ou não, data sem separação.

GEr

Enviado: 23 Ago 2021 10:49
por frazato
Bom dia!
Ta ficando muito legal mesmo, no meu caso já me resolvou o problema! Mais ta sendo um aula acompanhar a evolução do codigo!

Frazato

GEr

Enviado: 23 Ago 2021 11:01
por JoséQuintas
Agora é ir ajustando conforme o que for aparecendo de diferente.
O caso das datas, por exemplo, nem testei se hb_JsonDecode() entende "2021-08-22" como data.
Pelo menos pra codificar, o Harbour faz diferente do MySQL.

GEr

Enviado: 28 Set 2021 11:04
por JoséQuintas
Só pra constar
O que mencionei aqui sobre campo que pode ser date ou string, postei no fórum harbour-users.
A novidade é que outro usuário acaba de mencionar sobre isso.
Hello.
I have the same question.
Now this code prints "C"

aData := {'date'=>0d20220101}
jData := hb_jsonEncode(aData)
aData := hb_jsonDecode(jData)
? ValType(aData['date'])

can hb_jsonDecode() convert data to date?

thanks!

El domingo, 22 de agosto de 2021 a las 12:43:30 UTC+2, jmcqu...@gmail.com escribió:

"20210822" and Stod( "20210822" )

One is string and another is date.

When using hb_jsonEncode(), result is the same.

Is this correct?

On hb_jsonDecode(), both will return a date.
Parece que json não é tão padronizado como parecia.