Solved

Delphi: send XML schema parameter in SOAP request

Posted on 2013-10-31
9
5,096 Views
Last Modified: 2016-02-26
Hello,
I have already developed some interfaces with soap using xml content.

With one vendor I have a problem by understanding how send a SOAP request in following situation:

Here the webservice:
http://xml.unione.ch/Ph4stdWebServices/ArtQueries.asmx?WSDL

And the xml content to be send:
http://xml.unione.ch/XSD/ProductAvailabilityRequestSchema.xsd

And an example of sended xml:
http://xml.unione.ch/XML/ProductAvailabilityRequest.xml
My question is about this part of the WDSL:
...
<s:element name="[b]LoadStockInfos[/b]">
    <s:complexType>
        <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="dsRequest">
                  <s:complexType>
                       <s:sequence>
                           <s:element ref="s:schema"/>
                    <s:any/>
             </s:sequence>
...

Open in new window

The WDSL imported in Delphi for this part above looks like this:
...
  dsRequest = class(TRemotable)
  private
    Fschema: TXMLData;
  public
    destructor Destroy; override;
  published
    property schema: TXMLData  Index (IS_REF) read Fschema write Fschema;
  end;
..

Open in new window


I create the xml request file and I send the soap request
with THTTPRIO component:
 var xData: TXMLData;
     Stock: LoadStockInfosResult;
begin
daufArtRequest := dsRequest.Create;
xData := TXMLData.Create;
xData.LoadFromXML(Memo1.Lines.text);  // here is the xml content to send

daufArtRequest.schema := xData;
Stock := (httprio1 as ArtQueriesSoap).LoadStockInfos(daufArtRequest);
...

Open in new window

The Server answer with:

This operation can not be performed with a node of type XMLDEC

If I delete the first line "<?xml version="1.0" standalone="yes"?>"
Then the error is:

Server was unable to read request There is an error in XML Document.., then 'ProductAvailabilityRequest' element is not supperted in this context.

Surely I am doing something wrong or the imported type TXMLData is wrong.

Any suggestion would be very appreciated.

Peter

P.S.: here the webservice description:
Requests Unione Farmaceutica products stock informations
0
Comment
Question by:eustachio
  • 5
  • 3
9 Comments
 
LVL 25

Expert Comment

by:Sinisa Vuk
ID: 39618729
First, similar like you did import wdsl - try import Request shema xsd (from link you gave) in Delphi's New/Other/Xml Data Binding (paste link to ProductAvailabilityRequestSchema.xsd). You will get something like ProductAvailabilityRequestSchema.pas. This way you will get data request interface and you can create request in code.

So, your code looks like now:
procedure TForm1.Button7Click(Sender: TObject);
var
  art: dsRequest;
  lsRes: LoadStockInfosResult;
  Product: IXMLProductAvailabilityRequest;
  Cust: IXMLCustomer;
  prod: IXMLProducts;
begin
  try
    art := dsRequest.Create;
    Product:= NewProductAvailabilityRequest;
    try
      //fill art info
      art.schema := TXMLData.Create;

      Cust := Product.Customer.Add;
      Cust.Number := 'test code';
      Cust.SoftwareType := 'Software_name';
      Cust.SoftwareVersion := '1.0';
      Cust.Password := 'test password';

      prod := Product.Products.Add;
      prod.PharmaCode := '1875976';
      prod.EANCode := '';
      prod.Quantity := '1';

      prod := Product.Products.Add;
      prod.PharmaCode := '0166700';
      prod.EANCode := '';
      prod.Quantity := '1';

      art.schema.LoadFomXML(Product.XML);

      //request
      lsRes := GetArtQueriesSoap.LoadStockInfos(art);

      if Assigned(lsRes) and Assigned(lsRes.schema) and Assigned(lsRes.schema.XMLNode) then
      begin
        ...
      end;
    finally
      Product := nil;
      FreeAndNil(art);
    end;
  except
    on E: Exception do
    begin
      ShowMessage(E.Message);
    end;
  end;
end;

Open in new window


after all, I got same error like you. There is something wrong with this web service.
Will try later...
0
 

Author Comment

by:eustachio
ID: 39619120
Hello,
thanks a lot for your suggestion! I have already imported the Request shema xsd, and
generated the xml code with this schema.
I regret you obtain the same errors from the webservice.

I used your code with user and password delivered from vendor
but with the same error.

I will contact Monday the IT departement of this webervice asking more
example code.

Is there a way to have the exact complete string sended from the
Thttprio component to webservice ? I had difficulty finding how obtain this,..

Thanks in the meantime

Peter
0
 
LVL 25

Expert Comment

by:Sinisa Vuk
ID: 39620139
I use Fiddler to catch soap request.Then analyze request and compare it with web service example. Think that there is something wrong. Yes, try to contact their support service.
0
 

Author Comment

by:eustachio
ID: 39632056
for info I am waiting answer of the IT departement of this webservice.
Petet
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 

Author Comment

by:eustachio
ID: 39659756
Hello
the webservice vendors tell me I should add some parts to the request, marked in Bold


<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SOAP-ENV:Body>
    <LoadStockInfos xmlns="http://xml.unione.ch">
      <dsRequest>
        <xs:schema id="ProductAvailabilityRequest" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
          <xs:element name="ProductAvailabilityRequest">
            <xs:complexType>
              <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element name="Customer">
                  <xs:complexType>
                    <xs:sequence>
                      <xs:element name="Number" type="xs:string" minOccurs="0" />
                      <xs:element name="SoftwareType" type="xs:string" minOccurs="0" />
                      <xs:element name="SoftwareVersion" type="xs:string" minOccurs="0" />
                      <xs:element name="Password" type="xs:string" minOccurs="0" />
                    </xs:sequence>
                  </xs:complexType>
                </xs:element>
                <xs:element name="Products">
                  <xs:complexType>
                    <xs:sequence>
                      <xs:element name="PharmaCode" type="xs:string" minOccurs="0" />
                      <xs:element name="Quantity" type="xs:string" minOccurs="0" />
                    </xs:sequence>
                  </xs:complexType>
                </xs:element>
              </xs:choice>
            </xs:complexType>
          </xs:element>
        </xs:schema>

        <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
          <ProductAvailabilityRequest xmlns="">
            <Customer>
              <Number>099987</Number>
              <SoftwareType>MySoftware</SoftwareType>
              <SoftwareVersion>4.5</SoftwareVersion>
              <Password>abc</Password>
            </Customer>
            <Products>
              <PharmaCode>4461407</PharmaCode>
              <Quantity>1</Quantity>
            </Products>
          </ProductAvailabilityRequest>
        </diffgr:diffgram>
      </dsRequest>
    </LoadStockInfos>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>



This means I should change the Interface strutucture that was automatically generated ? Or is they a way to simple manually add the nodes to the request ?
The other generated parts are okay

Thanks in advance for a suggestion

Peter
0
 
LVL 25

Expert Comment

by:Sinisa Vuk
ID: 39665442
Delphi have some issues using diffgrams. (internal preparing of TXMLData makes exception)
Using suggestions from:
http://www.gekko-software.nl/DotNet/Art07.htm
http://www.gekko-software.nl/DotNet/Art09.htm
http://www.agnisoft.com/white_papers/soap1.asp

made following (osing Rio event onBeforeExecute)..
procedure TForm1.RioUnhandledNode(const Name: string; NodeXML: WideString);
begin
  //
end;

function GetArtRequest: String;
var
  xml: TStringList;
  Product: IXMLProductAvailabilityRequest;
  Cust: IXMLCustomer;
  prod: IXMLProducts;
  Xdoc, XSchema: IXMLDocument;
  Idiffgram: IXMLNode;
begin
  Result := '';
  try
    xml := TStringList.Create;
    Product:= NewProductAvailabilityRequest;
    try
      //fill art info
      try
        Cust := Product.Customer.Add;
        Cust.Number := 'test code';
        Cust.SoftwareType := 'Software_name';
        Cust.SoftwareVersion := '1.0';
        Cust.Password := 'test password';

        prod := Product.Products.Add;
        prod.PharmaCode := '1875976';
        prod.EANCode := '';
        prod.Quantity := '1';

        prod := Product.Products.Add;
        prod.PharmaCode := '0166700';
        prod.EANCode := '';
        prod.Quantity := '1';

        xml.Text := Product.XML;
        xml.SaveToFile('d:\xm.txt');
        //schema
        xml.LoadFromFile('D:\Work\ProductAvailabilityRequestSchema.xsd.xml');

        XSchema := LoadXMLdata(xml.Text);
        XSchema.Active := True;
        XSchema.StandAlone := '';
        //remove xml node
        if XSchema.ChildNodes.First.NodeType = ntProcessingInstr then  
          XSchema.ChildNodes.Remove(XSchema.ChildNodes.First);

        Xdoc := NewXMLDocument;
        Xdoc.Active := True;

        // Diffgram data
        Idiffgram:= Xdoc.AddChild('diffgr:diffgram');
        //Idiffgram.Attributes['xmlns']:= '';
        Idiffgram.Attributes['xmlns:msdata']:= 'urn:schemas-microsoft-com:xml-msdata';
        Idiffgram.Attributes['xmlns:diffgr']:= 'urn:schemas-microsoft-com:xml-diffgram-v1';

        Idiffgram.ChildNodes.Add(Product.CloneNode(True));
        Idiffgram.ChildNodes[0].Attributes['xmlns']:= '';

        //remove xml node
        if Xdoc.ChildNodes.First.NodeType = ntProcessingInstr then
          Xdoc.ChildNodes.Remove(Xdoc.ChildNodes.First);

        Result := XSchema.XML.Text + #13#10 + Xdoc.XML.Text;
      finally
      end;
    finally
      Product := nil;
      FreeAndNil(xml);
    end;
  except
    on E: Exception do
    begin
      ShowMessage(E.Message);
    end;
  end;
end;

procedure TForm1.RioBeforeExecute(const MethodName: string; var SOAPRequest: InvString);
var
  StrStrm : TStringStream;
  xml: TStringList;
begin
  StrStrm := TStringStream.Create(SOAPRequest);
  xml := TStringList.Create;
  try
    xml.Text := SOAPRequest;
    xml.SaveToFile('d:\xm4.txt');
    SOAPRequest := StringReplace(SOAPRequest, '<xsd:schema/>', GetArtRequest, []);
    xml.Text := SOAPRequest;
    xml.SaveToFile('d:\xm5.txt');
  finally
    xml.Free;
    StrStrm.Free;
  end;
end;

procedure TForm1.RioAfterExecute(const MethodName: string; SOAPResponse: TStream);
begin
  //
end;

function GetArtQueriesSoapExt(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO;
  evt_unhandle: TUnhandledNodeEvent; evt_before: TBeforeExecuteEvent;
  evt_after: TAfterExecuteEvent): ArtQueriesSoap;
const
  defWSDL = 'http://xml.unione.ch/Ph4stdWebServices/ArtQueries.asmx?WSDL';
  defURL  = 'http://xml.unione.ch/Ph4stdWebServices/ArtQueries.asmx';
  defSvc  = 'ArtQueries';
  defPrt  = 'ArtQueriesSoap';
var
  RIO: THTTPRIO;
begin
  Result := nil;
  if (Addr = '') then
  begin
    if UseWSDL then
      Addr := defWSDL
    else
      Addr := defURL;
  end;
  if HTTPRIO = nil then
    RIO := THTTPRIO.Create(nil)
  else
    RIO := HTTPRIO;
  try
    Result := (RIO as ArtQueriesSoap);
    if UseWSDL then
    begin
      RIO.WSDLLocation := Addr;
      RIO.Service := defSvc;
      RIO.Port := defPrt;
    end else
      RIO.URL := Addr;

    RIO.Converter.OnUnhandledNode := evt_unhandle;
    RIO.OnAfterExecute := evt_after;
    RIO.OnBeforeExecute := evt_before;
  finally
    if (Result = nil) and (HTTPRIO = nil) then
      RIO.Free;
  end;
end;

procedure TForm1.Button11Click(Sender: TObject);
var
  art: dsRequest;
  lsRes: LoadStockInfosResult;
begin
  try
    art := dsRequest.Create;
    try
      art.schema := TXMLData.Create;
      //request
      lsRes := GetArtQueriesSoapExt(False, '', nil, RioUnhandledNode,
        RioBeforeExecute, RioAfterExecute).LoadStockInfos(art);

      if Assigned(lsRes) and Assigned(lsRes.schema) and Assigned(lsRes.schema.XMLNode) then
      begin
        ....
      end;
    finally
      FreeAndNil(art);
    end;
  except
    on E: Exception do
    begin
      ShowMessage(E.Message);
    end;
  end;
end;

Open in new window

(remove all "debug" stuff like saving to file because I wan to know what happens in each step)
This is working with downloaded schema file and stored to disk. This schema is append in request as recommended.
0
 

Accepted Solution

by:
eustachio earned 0 total points
ID: 39674695
Hello Sinisav,

thanks a lot for your very interesting and professional answer !!

Last week I had to hurry to find a solution and at the end I composed a little bit manually
the xml to send. And is working now. My solution is not so elegant as yours, the final
code that send the request looks like this:

procedure TfrmUnione.RequestUnioneSend;
var err, str: string;
    req: TStringStream;
    strings: TStringList;
    recieveID: integer;
    request, response: TStringStream;
begin
strings := TStringList.Create;
strings.Text := RequestHeader + RequestArticle + RequestFooter;

request := TStringStream.Create(strings.GetText);
response := TStringStream.Create('');

Rio.HTTPWebNode.SoapAction := 'http://xml.unione.ch/LoadStockInfos';

recieveID := SOAP.HTTPWebNode.Send(request);           //Request

Rio.HTTPWebNode.Receive(recieveID,response,false);    //Response

response.Position := 0;
listg.LoadFromStream(response, TEncoding.UTF8);

                                                      listg.SaveToFile('UnioneResponse.xml');
strings.Free;
request.Free;
response.Free;
end;

Open in new window

RequestHeader and RequestFooter string are always the same. I generate the
RequestArticle string with the Interfaces.

Very Interesting your links suggestions. Perhaps I can use the component
GekkoDotNetDataSet for help me to read the received data.

Regards

Peter
0
 

Author Closing Comment

by:eustachio
ID: 39686638
I appreciate the lot of work to understand and solve the problem
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
word0 challenge 3 58
firstChar challenge 13 83
API Soap Calls 4 58
PHP connection to remote AWS MySQL RDS 4 36
This is about my first experience with programming Arduino.
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
An introduction to basic programming syntax in Java by creating a simple program. Viewers can follow the tutorial as they create their first class in Java. Definitions and explanations about each element are given to help prepare viewers for future …
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now