• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 7200
  • Last Modified:

Delphi: send XML schema parameter in SOAP request

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
eustachio
Asked:
eustachio
  • 5
  • 3
1 Solution
 
Sinisa VukCommented:
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
 
eustachioAuthor Commented:
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
 
Sinisa VukCommented:
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
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
eustachioAuthor Commented:
for info I am waiting answer of the IT departement of this webservice.
Petet
0
 
eustachioAuthor Commented:
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
 
Sinisa VukCommented:
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
 
eustachioAuthor Commented:
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
 
eustachioAuthor Commented:
I appreciate the lot of work to understand and solve the problem
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 5
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now