Einzelnen Beitrag anzeigen

mytbo

Registriert seit: 8. Jan 2007
461 Beiträge
 
#12

AW: Soap-Service: XML-Fehler

  Alt 1. Feb 2023, 23:59
Auf der DHL Hilfe Seite bekommt man für 18 Sprachen, für einige auch mehrere Lösungswege, den vollständigen Quellcode zum Copy&Pasten. Alle Eingabe- und Ausgabeparameter sind en detail aufgeführt und ausführlich beschrieben.

Wenn ich es mit mORMot umsetze, stehen mir viele Wege offen. Von holzschnittartig bis fein ziseliert. Deine Daten bekommst du am einfachsten mit einem TWinHttp.Get Aufruf. mORMot beherrscht SSL/TLS. Im Folgenden verwende ich Curl, weil der Quellcode aus dem DHL Beispiel kopiert werden kann. Der JSON Response wird mit der Funktion RecordLoadJson in eine Record Struktur deserialisiert. Möglich wäre auch ein Objekt, oder ohne vorherige Definition einer Struktur mit der Funktion InitJson ein DocVariant. Dies ist vorteilhaft, wenn nur einige Werte von Interesse sind. Mit der Funktion GetValueByPath ist ein Direktzugriff möglich. Informationen zu mORMot mit Curl findest du im Forum hier.

Abgebildet ist der Fall Rating GET /rates (Retrieve Rates for a one piece Shipment):
Delphi-Quellcode:
uses
  mormot.core.base,
  mormot.core.data,
  mormot.core.text,
  mormot.core.json,
  mormot.core.buffers,
  mormot.core.variants,
  mormot.core.os,
  mormot.lib.curl,
  mormot.net.client;

type
  TRateRequestResult = packed record
    products: array of record
      productName: RawUtf8;
      productCode: RawUtf8;
      localProductCode: RawUtf8;
      localProductCountryCode: RawUtf8;
      networkTypeCode: RawUtf8;
      isCustomerAgreement: Boolean;
      weight: record
        volumetric: Double;
        provided: Double;
        unitOfMeasurement: RawUtf8;
      end;
      totalPrice: array of record
        currencyType: RawUtf8;
        priceCurrency: RawUtf8;
        price: Currency;
      end;
      totalPriceBreakdown: array of record
        currencyType: RawUtf8;
        priceCurrency: RawUtf8;
        priceBreakdown: array of record
          typeCode: RawUtf8;
          price: Currency;
        end;
      end;
      detailedPriceBreakdown: array of record
        currencyType: RawUtf8;
        priceCurrency: RawUtf8;
        breakdown: array of record
          name: RawUtf8;
          serviceCode: RawUtf8;
          localServiceCode: RawUtf8;
          typeCode: RawUtf8;
          serviceTypeCode: RawUtf8;
          price: Currency;
          isCustomerAgreement: Boolean;
          isMarketedService: Boolean;
          isBillingServiceIndicator: Boolean;
          priceBreakdown: array of record
            priceType: RawUtf8;
            typeCode: RawUtf8;
            price: Currency;
            rate: Double;
            basePrice: Currency;
          end;
        end;
      end;
      pickupCapabilities: record
        nextBusinessDay: Boolean;
        localCutoffDateAndTime: TDateTime;
        GMTCutoffTime: TDateTime;
        pickupEarliest: TDateTime;
        pickupLatest: TDateTime;
        originServiceAreaCode: RawUtf8;
        originFacilityAreaCode: RawUtf8;
        pickupAdditionalDays: Integer;
        pickupDayOfWeek: Integer;
      end;
      deliveryCapabilities: record
        deliveryTypeCode: RawUtf8;
        estimatedDeliveryDateAndTime: TDateTime;
        destinationServiceAreaCode: RawUtf8;
        destinationFacilityAreaCode: RawUtf8;
        deliveryAdditionalDays: Integer;
        deliveryDayOfWeek: Integer;
        totalTransitDays: Integer;
      end;
      items: array of record
        number: Integer;
        breakdown: array of record
          name: RawUtf8;
          serviceCode: RawUtf8;
          localServiceCode: RawUtf8;
          typeCode: RawUtf8;
          serviceTypeCode: RawUtf8;
          price: Currency;
          priceCurrency: RawUtf8;
          isCustomerAgreement: Boolean;
          isMarketedService: Boolean;
          isBillingServiceIndicator: Boolean;
          priceBreakdown: array of record
            priceType: RawUtf8;
            typeCode: RawUtf8;
            price: Currency;
            rate: Double;
            basePrice: Currency;
          end;
        end;
      end;
      pricingDate: TDateTime;
    end;
    exchangeRates: array of record
      currentExchangeRate: Double;
      currency: RawUtf8;
      baseCurrency: RawUtf8;
    end;
    warnings: array of RawUtf8;
  end;

var
  hnd: TCurl;
  res: TCurlResult;
  headers: Pointer;
  responseData: RawByteString;
  responseSize: Int64;
  requestResult: TRateRequestResult;
begin
  if not CurlIsAvailable then Exit; //=>

  hnd := curl.easy_init;
  if hnd <> Nil then
  begin
    curl.easy_setopt(hnd, coSSLVerifyPeer, 0);
    curl.easy_setopt(hnd, coSSLVerifyHost, 0);
    curl.easy_setopt(hnd, coWriteFunction, @CurlWriteRawByteString);
    curl.easy_setopt(hnd, coWriteData, @responseData);

    var docQuery: TDocVariantData;
    docQuery.Init(JSON_FAST_EXTENDED, dvObject);
    docQuery.U['accountNumber'] := '123456789';
    docQuery.U['originCountryCode'] := 'CZ';
    docQuery.U['originCityName'] := 'Prague';
    docQuery.U['destinationCountryCode'] := 'CZ';
    docQuery.U['destinationCityName'] := 'Prague';
    docQuery.I['weight'] := 5;
    docQuery.I['length'] := 15;
    docQuery.I['width'] := 10;
    docQuery.I['height'] := 5;
    docQuery.U['plannedShippingDate'] := '2020-02-26';
    docQuery.B['isCustomsDeclarable'] := False;
    docQuery.U['unitOfMeasurement'] := 'metric';
    curl.easy_setopt(hnd, coURL, Pointer(docQuery.ToUrlEncode('https://api-mock.dhl.com/mydhlapi/rates')));

    var docHeader: TDocVariantData;
    docHeader.Init(JSON_FAST_EXTENDED, dvObject);
    docHeader.U['Message-Reference'] := 'd0e7832e-5c98-11ea-bc55-0242ac13';
    docHeader.U['Message-Reference-Date'] := 'Wed, 21 Oct 2015 07:28:00 GMT';
    docHeader.U['Plugin-Name'] := '';
    docHeader.U['Plugin-Version'] := '';
    docHeader.U['Shipping-System-Platform-Name'] := '';
    docHeader.U['Shipping-System-Platform-Version'] := '';
    docHeader.U['Webstore-Platform-Name'] := '';
    docHeader.U['Webstore-Platform-Version'] := '';

    headers := Nil;
    var headerField: TDocVariantFields;
    headers := curl.slist_append(headers, Pointer(FormatUtf8('accept: %', [JSON_CONTENT_TYPE])));
    headers := curl.slist_append(headers, Pointer(FormatUtf8('Authorization: Basic %', ['ZGVtby1rZXk6ZGVtby1zZWNyZXQ='])));
    for headerField in docHeader.Fields do
    begin
      if headerField.Value <> Nil then
        headers := curl.slist_append(headers, Pointer(FormatUtf8('%: %', [headerField.Name^, headerField.Value^])));
    end;
    curl.easy_setopt(hnd, coHttpHeader, headers);

    curl.easy_setopt(hnd, coCustomRequest, RawUtf8('GET'));
    res := curl.easy_perform(hnd);
    if res = crOk then
    begin
      FileFromString(responseData, MakePath([Executable.ProgramFilePath, 'ResponseData.json']));

      curl.easy_getinfo(hnd, ciSizeDownloadT, responseSize);
      ShowMessage(Format('Download completed: %s', [KB(responseSize)]));

      if RecordLoadJson(requestResult, responseData, TypeInfo(TRateRequestResult)) then
        ShowMessage(Utf8ToString(RawUtf8ArrayToCsv(requestResult.warnings, sLineBreak)));
    end
    else
      ShowMessage(Format('Curl told us %d (%s)', [Ord(res), curl.easy_strerror(res)]));

    curl.slist_free_all(headers);
    curl.easy_cleanup(hnd);
  end;
end;
Disclaimer: ohne Gewähr

Auch für Query und Header Teil musst du keinen DocVariant verwenden, sondern kannst es als Record oder Objekt abbilden und mit UrlEncode/ToCSV Funktionen aufbereiten.

Bis bald...
Thomas
  Mit Zitat antworten Zitat