Domanda

Ho un messaggio soap in arrivo che è TStream (Delphi7), il server che invia questo soap è in modalità di sviluppo e aggiunge un'intestazione html al messaggio per scopi di debug. Ora ho bisogno di ritagliare la parte di intestazione html da esso prima di poterlo passare al convertitore di sapone. Inizia dall'inizio con il tag 'pre' e termina con il tag '/ pre'. Sto pensando che dovrebbe essere abbastanza facile, ma non l'ho mai fatto prima in Delphi7, quindi qualcuno può aiutarmi?

È stato utile?

Soluzione

Penso che il seguente codice farebbe quello che vuoi, supponendo che tu ne abbia solo uno < pre > blocco nel documento.

function DepreStream(Stm : tStream):tStream;
var
  sTemp : String;
  oStrStm : tStringStream;
  i : integer;
begin
  oStrStm := tStringStream.create('');
  try
    Stm.Seek(0,soFromBeginning);
    oStrStm.copyfrom(Stm,Stm.Size);
    sTemp := oStrStm.DataString;
    if (Pos('<pre>',sTemp) > 0) and (Pos('</pre>',sTemp) > 0) then
      begin
        delete(sTemp,Pos('<pre>',sTemp),(Pos('</pre>',sTemp)-Pos('<pre>',sTemp))+6);
        oStrStm.free;
        oStrStm := tStringStream.Create(sTemp);
      end;
    Result := tMemoryStream.create;
    oStrStm.Seek(0,soFromBeginning);
    Result.CopyFrom(oStrStm,oStrStm.Size);
    Result.Seek(0,soFromBeginning);
  finally
    oStrStm.free;
  end;
end;

Un'altra opzione che credo sarebbe quella di utilizzare una trasformazione XML per rimuovere i tag indesiderati, ma non faccio molto in termini di trasformazioni, quindi se qualcun altro vuole quella torcia ...

MODIFICA: codice corretto affinché funzioni. Mi insegna per la codifica direttamente in SO anziché prima nell'IDE.

Altri suggerimenti

Un'altra soluzione, più in linea con il suggerimento di Lars e in qualche modo più elaborata.
È più veloce, specialmente quando la dimensione dello Stream è superiore a 100, e ancora di più su quelli veramente grandi. Evita di copiare su una stringa intermedia.
FilterBeginStream è più semplice e segue le " specifiche " nel rimuovere tutto fino alla fine dell'intestazione.
FilterMiddleStream fa lo stesso di DepreStream, lasciando ciò che è prima e dopo l'intestazione.

Avviso : questo codice è per Delphi fino a D2007, non D2009.

// returns position of a string token (its 1st char) into a Stream. 0 if not found
function StreamPos(Token: string; AStream: TStream): Int64;
var
  TokenLength: Integer;
  StringToMatch: string;
begin
  Result := 0;
  TokenLength := Length(Token);
  if TokenLength > 0 then
  begin
    SetLength(StringToMatch, TokenLength);
    while AStream.Read(StringToMatch[1], 1) > 0 do
    begin
      if (StringToMatch[1] = Token[1]) and
         ((TokenLength = 1) or
          ((AStream.Read(StringToMatch[2], Length(Token)-1) = Length(Token)-1) and
           (Token = StringToMatch))) then
      begin
        Result := AStream.Seek(0, soCurrent) - (Length(Token) - 1); // i.e. AStream.Position - (Length(Token) - 1);
        Break;
      end;
    end;
  end;
end;

// Returns portion of a stream after the end of a tag delimited header. Works for 1st header.
// Everything preceding the header is removed too. Returns same stream if no valid header detected.
// Result is True if valid header found and stream has been filtered.
function FilterBeginStream(const AStartTag, AEndTag: string; const AStreamIn, AStreamOut: TStream): Boolean;
begin
  AStreamIn.Seek(0, soBeginning); // i.e. AStreamIn.Position := 0;
  Result := (StreamPos(AStartTag, TStream(AStreamIn)) > 0) and (StreamPos(AEndTag, AStreamIn) > 0);
  if Result then
    AStreamOut.CopyFrom(AStreamIn, AStreamIn.Size - AStreamIn.Position)
  else
    AStreamOut.CopyFrom(AStreamIn, 0);
end;

// Returns a stream after removal of a tag delimited portion. Works for 1st encountered tag.
// Returns same stream if no valid tag detected.
// Result is True if valid tag found and stream has been filtered.
function FilterMiddleStream(const AStartTag, AEndTag: string; const AStreamIn, AStreamOut: TStream): Boolean;
var
  StartPos, EndPos: Int64;
begin
  Result := False;
  AStreamIn.Seek(0, soBeginning); // i.e. AStreamIn.Position := 0;
  StartPos := StreamPos(AStartTag, TStream(AStreamIn));
  if StartPos > 0 then
  begin
    EndPos := StreamPos(AEndTag, AStreamIn);
    Result := EndPos > 0;
  end;
  if Result then
  begin
    if StartPos > 1 then
    begin
      AStreamIn.Seek(0, soBeginning); // i.e. AStreamIn.Position := 0;
      AStreamOut.CopyFrom(AStreamIn, StartPos - 1);
      AStreamIn.Seek(EndPos - StartPos + Length(AEndTag), soCurrent);
    end;
    AStreamOut.CopyFrom(AStreamIn, AStreamIn.Size - AStreamIn.Position);
  end
  else
    AStreamOut.CopyFrom(AStreamIn, 0);
end;

Crea un nuovo TStream (usa TMemoryStream) e sposta tutti gli elementi che desideri mantenere da uno stream all'altro con i metodi TStream.CopyFrom o TStream.ReadBuffer / WriteBuffer.

Un'espressione XPath di " //pre[1][1] " estrarrà il primo nodo del primo < pre > tag nel messaggio XML: dalla tua descrizione, dovrebbe contenere il messaggio SOAP che desideri.

Sono passati molti anni dall'ultima volta che l'ho usato, ma penso che la libreria OpenXML di Dieter Koehler XPath.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top