Send xml via post to API

I need to send an xml via post to an api, but it gets the following error:

String could not be parsed as XML

It gets sending a string, instead of actually sending the XML.

The code to create XML:

        //Monta o XML
        cXML +=  "<?xml version='1.0' encoding='UTF-8' ?>" + SL     
        cXML +=  "<maxfrota>"+ SL       
        cXML +=  "<usuario>"+Alltrim('123')+"</usuario>" + SL   
        cXML +=  "<chave>"+Alltrim('123')+"</chave>" + SL
        cXML +=  "<opcoes>" + SL
        cXML +=  "<reordenar_entregas>"+Alltrim('0')+"</reordenar_entregas>" + SL //NAO PRECISA
        cXML +=  "</opcoes>" + SL           
        cXML +=  "<acao>"+Alltrim('adicionar')+"</acao>" + SL       
        While !QRY_SB1->(EoF())    
            cXML +=  "  <dados>"+ SL
            cXML +=  "  <entregas>"+ SL
            cXML +=  "      <entrega>"+ SL
            cXML +=  "          <origem>"+ SL
            cXML +=  "              <codigo>"+Alltrim('')+"</codigo>" + SL 
            cXML +=  "              <codigo_externo>"+Alltrim('1')+"</codigo_externo>" + SL
            cXML +=  "          </origem>"+ SL
            cXML +=  "  <lote>"+Alltrim(cCarga)+"</lote>" + SL
            cXML +=  "  <lote_principal>"+Alltrim('')+"</lote_principal>" + SL  //NAO VAMOS COLOCAR
            cXML +=  "  <numero>"+Alltrim(MOTORI->PEDIDO)+"</numero>" + SL 
            cXML +=  "  <data_pedido>"+Alltrim('2014-10-24 08:00:00')+"</data_pedido>" + SL
            cXML +=  "  <nota_fiscal>"+Alltrim(QRY_SB1->F2_DOC)+"</nota_fiscal>" + SL //NOTA FISCAL {OK}
            cXML +=  "  <data_emissao>"+Alltrim(QRY_SB1->F2_EMISSAO)+"</data_emissao>" + SL
            cXML +=  "  <chave_nota_fiscal>"+Alltrim('76278164782364781269879')+"</chave_nota_fiscal>" + SL 
            cXML +=  "  <valor>"+Alltrim('5549.99')+"</valor>" + SL
            cXML +=  "          <cliente>"+ SL
            cXML +=  "              <codigo>"+Alltrim(QRY_SB1->F2_CLIENT)+"</codigo>" + SL
            cXML +=  "              <nome>"+Alltrim(QRY_SB1->A1_NOME)+"</nome>" + SL
            cXML +=  "              <endereco>"+Alltrim(QRY_SB1->A1_ENDENT)+"</endereco>" + SL      
            cXML +=  "                  <endereco_detalhado>"+ SL
            cXML +=  "                      <logradouro>"+Alltrim(QRY_SB1->A1_ENDENT)+"</logradouro>" + SL
            cXML +=  "                      <numero>"+Alltrim(QRY_SB1->A1_YNUMT)+"</numero>" + SL
            cXML +=  "                      <bairro>"+Alltrim(QRY_SB1->A1_BAIRROE)+"</bairro>" + SL     
            cXML +=  "                      <cidade>"+Alltrim(QRY_SB1->A1_MUN)+"</cidade>" + SL 
            cXML +=  "                      <uf>"+Alltrim(QRY_SB1->A1_EST)+"</uf>" + SL
            cXML +=  "                      <cep>"+Alltrim(QRY_SB1->A1_CEP)+"</cep>" + SL
            cXML +=  "                      <informacao_adicional>"+Alltrim(QRY_SB1->A1_REFEREN)+"</informacao_adicional>" + SL
            cXML +=  "                  </endereco_detalhado>"+ SL  
            cXML +=  "              <telefone>"+Alltrim(QRY_SB1->A1_TEL)+"</telefone>" + SL
            cXML +=  "              <email>"+Alltrim(QRY_SB1->A1_EMAIL)+"</email>" + SL 
            cXML +=  "              <cidade>"+Alltrim(QRY_SB1->A1_MUN)+"</cidade>" + SL 
            cXML +=  "              <latitude>"+Alltrim('-5.9115545')+"</latitude>" + SL //NO MOMENTO NAO BOTAREMOS
            cXML +=  "              <longitude>"+Alltrim('-35.2713164')+"</longitude>" + SL //NO MOMENTO NAO BOTAREMOS
            cXML +=  "              <consultor>"+Alltrim('1')+"</consultor>" + SL   //ID DO CONSULTOR DO SEU SISTEMA
            cXML +=  "          </cliente>"+ SL
            cXML +=  "          <janela>"+ SL
            cXML +=  "              <data_hora_inicial>"+Alltrim('')+"</data_hora_inicial>" + SL //NAO COLOCAREMOS NO MOMENTO
            cXML +=  "              <data_hora_final>"+Alltrim('')+"</data_hora_final>" + SL    //NAO COLOCAREMOS NO MOMENTO
            cXML +=  "          </janela>"+ SL
            cXML +=  "      <tempo_estimado>"+Alltrim('40')+"</tempo_estimado>" + SL //NAO COLOCAREMOS NO MOMENTO
            cXML +=  "      <data_limite>"+Alltrim('')+"</data_limite>" + SL //PROCURAR SABER
            cXML +=  "      <hora_limite>"+Alltrim('23:59:59')+"</hora_limite>" + SL //PROCURAR SABER
            cXML +=  "      <tolerancia>"+Alltrim('0')+"</tolerancia>" + SL 
            cXML +=  "      <posicao>"+Alltrim('1')+"</posicao>" + SL   //NAO COLOCAREMOS NO MOMENTO
            cXML +=  "      <distancia_prevista>"+Alltrim('1')+"</distancia_prevista>" + SL //NAO COLOCAREMOS NO MOMENTO
            cXML +=  "          <veiculo>"+ SL
            cXML +=  "              <codigo>"+Alltrim('')+"</codigo>" + SL     
            cXML +=  "              <codigo_externo>"+Alltrim('PFX-5099')+"</codigo_externo>" + SL      
            cXML +=  "          </veiculo>"+ SL
            cXML +=  "          <motorista>"+ SL
            cXML +=  "              <nome>"+Alltrim(MOTORI->DA4_NOME)+"</nome>" + SL
            cXML +=  "              <cpf>"+Alltrim('')+"</cpf>" + SL    //NAO TEMOS O CPF, SÓ O CÓDIGO
            cXML +=  "          </motorista>"+ SL
            cXML +=  "          <rota>"+ SL
            cXML +=  "              <codigo>"+Alltrim('')+"</codigo>" + SL //DEVERÁ VIM VAZIO
            cXML +=  "              <codigo_externo>"+Alltrim('1')+"</codigo_externo>" + SL //PROCURAR SE TIVERMOS
            cXML +=  "          </rota>"+ SL
            cXML +=  "      <peso>"+Alltrim('0')+"</peso>" + SL //NAO TEMOS
            cXML +=  "      <volume>"+Alltrim('0')+"</volume>" + SL //NAO TEMOS
            cXML +=  "      <ocupacao>"+Alltrim('12.5')+"</ocupacao>" + SL  //PROCURAR SABER        
            cXML +=  "          <itens>"+ SL
            cXML +=  "              <item>"+ SL
            cXML +=  "                  <codigo_externo>"+Alltrim('00021759250001')+"</codigo_externo>" + SL //PROCURAR SABER SE TEMOS (Código de barras do Volume a ser conferido)
            cXML +=  "              </item>"+ SL
            cXML +=  "          </itens>"+ SL           
            cXML +=  "</entrega>" + SL
            cXML +=  "</entregas>" + SL

            cXML +=  "          <rotas>"+ SL
            cXML +=  "              <rota>"+ SL
            cXML +=  "                  <codigo_externo>"+Alltrim('')+"</codigo_externo>" + SL //PROCURAR SABER SE TEMOS
            cXML +=  "                  <lote>"+Alltrim(cCarga)+"</lote>" + SL
            cXML +=  "                  <polilinha>"+Alltrim('_p~iF~ps|U_ulLnnqC_mqNvxq`@')+"</polilinha>" + SL //NAO TEMOS
            cXML +=  "                  <ocupacao_total>"+Alltrim('83.75')+"</ocupacao_total>" + SL //PROCURAR SABER SE TEMOS
            cXML +=  "                  <distancia_prevista_total>"+Alltrim('30816')+"</distancia_prevista_total>" + SL //NAO TEMOS
            cXML +=  "              </rota>"+ SL
            cXML +=  "          </rotas>"+ SL

            cXML +=  "</dados>" + SL   

            nAtu++
            QRY_SB1->(DbSkip())


        EndDo




        QRY_SB1->(DbCloseArea())    

        cXML +=  "</maxfrota>" + SL

the + SL is to skip line Then I send the XML as a parameter to the static function that makes the post

eApi(cXML)

Then I do the XML reading

    Static Function fLeXML(aCarga)
    Local oLido    := Nil
    Local cReplace := "_"
    Local cErros   := ""
    Local cAvisos  := ""
    Local cMsg     := ""
    Local cCar  := aCarga

    //Se o arquivo existir
    If File(cDirect+cArquivo+cCar+cValtoChar(nElem)+".xml")
        //Lendo o arquivo com XMLParser (lê a string), caso queira ler o arquivo direto, utilize o XMLParserFile (o arquivo deve estar dentro da system)
        oLido := XmlParser(MemoRead(cDirect+cArquivo+cCar+cValtoChar(nElem)+".xml"), cReplace, @cErros, @cAvisos)


        //Se tiver erros, mostra ao usuário
        If !Empty(cErros)
            Aviso('Atenção', "Erros: "+cErros, {'Ok'}, 03)
        EndIf

        //Se tiver avisos, mostra ao usuário
        If !Empty(cAvisos)
            Aviso('Atenção', "Avisos: "+cAvisos, {'Ok'}, 03)
        EndIf


        //Mensagem de sucesso
            MSGALERT( "XML criado com sucesso!" )

        //Mostrando a mensagem do xml lido
        Aviso('Atenção', cMsg, {'Ok'}, 03)

    EndIf
Return

Post Code:

Static Function eApi(cXML)

nTimeOut := 120 
    aHeadOut := {} 
    cHeadRet := "" 
    sPostRet := ""                   

    aAdd(aHeadOut,'User-Agent: Mozilla/4.0 (compatible; Protheus '+GetBuild()+')') 
    aadd(aHeadOut,'Content-Type: application/xml') 

    cUrl1 := ("API AQUI")



    sPostRet := HttpPost(cUrl1,,,nTimeOut,aHeadOut,@cHeadRet, cXML) 

    ALERT(sPostRet)

return

Only he lives giving the error of ser string.

 0
Author: Maria, 2018-12-05

1 answers

You are passing the arguments in Changed order. According to the documentation of the function in the TDN , the arguments are as follows, in this order:

  1. cUrl - the endpoint (only required argument)
  2. cGetParms - parameters GET, those that comes after the ? in the URL
  3. cPostParms - the payload you want to send
  4. nTimeOut - time to give "connection failure" for time exceeded
  5. aHeadStr - vector with the HTTP headers to be sent
  6. @cHeaderGet - reference to a string where the headers received from the server

Your third argument is empty, so ADVPL puts nil during the call (see more ).

The correction would be to change the order of the arguments:

sPostRet := HttpPost(cUrl1,,cXML,nTimeOut,aHeadOut,@cHeadRet)

There is no documentation that explains what the seventh argument is, where in your code is cXML.

Also has the function HttpPostXml, only he does not allows you to place arbitrary headers and works with the path of an XML file. I never felt the need to use it, however, since I avoid XMLs and files when I have everything in memory.

 1
Author: Jefferson Quesado, 2018-12-05 16:20:06