How to create/parse SOAP MTOM/XOP, XML, and binary attachments

The code applies to Clever Internet Suite v9.3 and higher.
 
1. How to create SOAP MTOM/XOP attachments.
procedure TForm1.BuildSoapXopAttachments;
var
  soap: TclSoapMessage;
  s: string;
begin
  soap := TclSoapMessage.Create(nil);
  try
    soap.OnLoadAttachment := DoLoadXopAttachment;

    soap.Clear();
    soap.AddXmlData('<root><data name="some-data-id"/></root>', 'start-content-id');
    soap.AddAttachment('text/xml', 'content-id-1');
    soap.AddAttachment('image/png', 'content-id-2');

    //returns the request header as Delphi string list
    //soap.HeaderSource;

    //returns the request body as Delphi string list
    //soap.RequestSource;

    //returns the request body as a stream
    //soap.RequestStream;

    //You can use the TclSoapMessage instance together with TclHttp for sending the request:
    //http.Post('http...', soap, response);

  finally
    soap.Free();
  end;
end;

procedure TForm1.DoLoadXopAttachment(Sender: TObject; AItem: TclAttachmentItem;
  const AContentID: string; var AData: TStream);
begin
  //TclSoapMessage will automatically close all instances of created streams
  //after composing the request source
  if (AContentID = 'content-id-1') then
  begin
    AData := TStringStream.Create('<xml>an xml attachment content</xml>');
  end else
  if (AContentID = 'content-id-2') then
  begin
    AData := TFileStream.Create('c:\images\pict.png', fmOpenRead);
  end;
end;
2. How to parse SOAP attachments.
procedure TForm1.ParseSoapXopAttachments;
var
  soap: TclSoapMessage;
  root: TclXmlItem;
  attachment: TclAttachmentItem;
begin
  soap := TclSoapMessage.Create(nil);
  try
    soap.OnSaveAttachment := DoSaveAttachment;
    soap.OnAttachmentSaved := DoAttachmentSaved;

    //Loading request data from files.
    soap.LoadHeader('c:\data\request-header.txt');
    soap.LoadRequest('c:\data\request-body.txt');

    //Alternatively, you can load request data from a stream, or a string list:
    //http.Post('http...', request, responseHeader, responseBody);
    //soap.RequestHeader := responseHeader;
    //soap.RequestStream := responseBody;

    //After loading:

    //returns 'multipart/related'
    //soap.Header.ContentType

    //returns 'application/xop+xml'
    //soap.Header.SubType

    //returns a content id of the root XML part
    //soap.Header.Start

    //returns a number of message parts, including the root XML and attachments
    //soap.Items.Count

    root := soap.Items[0] as TclXmlItem;

    //returns XML string
    root.XmlData

    attachment := soap.Items[1] as TclAttachmentItem;

    //There is no specific property to store the attachment content.
    //The attachments are saved to stream instances.
  finally
    soap.Free();
  end;
end;

procedure TForm1.DoSaveAttachment(Sender: TObject; AItem: TclAttachmentItem;
  const AContentID: string; var AData: TStream);
begin
  //The attachment will be saved to this filestream.
  //The stream will be automatically closed after parsing the SOAP message.
  AData := TFileStream.Create('c:\attachments\' + AContentID + '.dat', fmOpenRead);

  //If you want to save an attachment to a memory stream, or to a string stream,
  //you need to add a handler for the OnAttachmentSaved event, as well.
  //AData := TStringStream.Create();
end;

procedure TForm1.DoAttachmentSaved(Sender: TObject; AItem: TclAttachmentItem;
  const AContentID: string; AData: TStream);
var
  xml: string;
begin
  //This event handler allows you to access extracted attachment before closing the stream.
  xml := (AData as TStringStream).DataString;
end;

Add Feedback