错误:使用 Microsoft WebService.dll 通过 Delphi7 规范化 XML

问题描述 投票:0回答:2

我正在使用 Delphi7 修改旧项目以添加使用证书和签名。经过一些搜索后,我发现了XML规范化函数,但我无法让这些函数中的任何一个起作用:

  • WsStartReaderCanonicalization / WsEndReaderCanonicalization
  • WsStartWriterCanonicalization / WsEndWriterCanonicalization

这些函数包含在 Microsoft WebServices.dll 中,我在其中找到了它的标头翻译 Github但我仍然没有运气。这是我测试的代码:


{$APPTYPE CONSOLE}
program XmlBufferExample;

//This example shows some use of the xml buffer APIs.
//Original C++ code from Microsoft :
//https://msdn.microsoft.com/en-us/library/windows/desktop/dd819131(v=vs.85).aspx

uses
  Windows, Sysutils, Classes,
  webservices in 'webservices.pas';

Procedure PrintError(errorCode:HRESULT; error:PWS_ERROR);
var
  hr:HRESULT;
  errorCount,i:ULONG;
  str:WS_STRING;
  s:string;
begin
  writeln(Format('Failure: errorCode=0x8%.x',[errorCode]));

  if (errorCode=E_INVALIDARG) or (errorCode=WS_E_INVALID_OPERATION) then
  begin
    // Correct use of the APIs should never generate these errors
    writeln('The error was due to an invalid use of an API. This is likely due to a bug in the program.');
    exit;
  end;

  hr:=NOERROR;
  if (error<>nil) then
  begin
    hr:=WsGetErrorProperty(error, WS_ERROR_PROPERTY_STRING_COUNT, @errorCount, sizeof(errorCount));
    if (hr=NOERROR) and (errorCount>0) then
      for i:=0 to errorCount-1 do
      begin
        hr:=WsGetErrorString(error, i, @str);
        if (hr=NOERROR) then
        begin
          s:=copy(str.chars,1,str.length);
          writeln(s);
        end else
          errorCount:=i; //exit for
      end;
  end;
  if (hr<>NOERROR) then
    writeln(Format('Could not get error string (errorCode=0x8%.x)',[hr]));
end;

var
  MyCallbackStatus : Cardinal;
  Found : BOOL;
  Mybuffer:PWS_XML_BUFFER = nil;
const
  HeapSize = 24 * 1024;  //24 kb

function MyCallback(callbackState : pointer; buffer : PWS_BYTES; count : ULONG;
                     asyncContext : PWS_ASYNC_CONTEXT; error : PWS_ERROR):HRESULT; stdcall;
var
  S : AnsiString;
begin
//debuging start
  Writeln('Inside MyCallback :');
  Writeln('MyCallbackStatus :', IntToStr(MyCallbackStatus));
  if Assigned(error) then PrintError(0, error);
//debuging end

  if Assigned(buffer) then
    SetString(S, PAnsiChar(buffer.bytes), buffer.length);

  Writeln(s);
end;

var
  hr:HRESULT;
  error:PWS_ERROR;
  heap:PWS_HEAP;
  buffer:PWS_XML_BUFFER;
  writer:PWS_XML_WRITER;
  reader:PWS_XML_READER;
  newXml:pointer;
  newXmlLength:ULONG;
  xml:ansistring;
  ExitCode:integer;
  Stream : TMemoryStream;
begin
  error:=nil;
  heap:=nil;
  buffer:=nil;
  writer:=nil;
  reader:=nil;
  newXml:=nil;
  newXmlLength:=0;

  // Create an error object for storing rich error information
  hr := WsCreateError(nil,
                      0,
                      @error);

  if (hr=NOERROR) then
  begin
    // Create a heap to store deserialized data
    hr := WsCreateHeap(2048,   //maxSize
                       512,    //trimSize
                       nil,
                       0,
                       @heap,
                       error);
  end;

  if hr=NOERROR then
  begin
    // Create an XML writer
    hr := WsCreateWriter(nil,
                         0,
                         @writer,
                         error);
  end;

  if hr=NOERROR then
  begin
    // Create an XML reader
    hr := WsCreateReader(nil,
                         0,
                         @reader,
                         error);
  end;

  // Some xml to read and write
  xml:='<a><b>1</b><c>2</c></a>';

  if hr=NOERROR then
  begin
    hr:=WsReadXmlBufferFromBytes(reader,
                                 nil,
                                 nil,
                                 0,
                                 PAnsiChar(xml), //@xml[1],
                                 length(xml),
                                 heap,
                                 @buffer,
                                 error);

  end;

  if hr=NOERROR then
  begin
    hr:=WsWriteXmlBufferToBytes(writer,
                                buffer,
                                nil,
                                nil,
                                0,
                                heap,
                                @newXml,
                                @newXmlLength,
                                error);
  end;

  if hr=NOERROR then
  begin
    writeln('new xml :');
    writeln(copy(PAnsiChar(newXml),1,newXmlLength));
    writeln;
    ExitCode:=0;
  end;

  //----------------------------------------
  //My test start
  //----------------------------------------
  if hr=NOERROR then
  begin
    if Assigned(reader) then
    begin
      WsFreeReader(reader);
      reader := nil;
    end;
    hr := WsCreateReader(nil, 0, @reader, error);

    if Assigned(heap) then
    begin
      WsFreeHeap(heap);
      heap := nil;
    end;
    hr := WsCreateHeap(3 * HeapSize, 512, nil, 0, @heap, error);

    if hr=NOERROR then
    begin
      //load xml file
      Stream := TMemoryStream.Create();
      try
        Stream.LoadFromFile('Z:\zatca-einvoicing-sdk\test\100030.xml');
        SetString(xml, PChar(Stream.Memory), Stream.Size);
        Writeln;
        Writeln('-------------------------------');
        Writeln('XML File size is ' + IntToStr(Stream.Size) + ' Bytes');
      finally
        Stream.Free();
      end;

      hr:=WsReadXmlBufferFromBytes(reader, nil, nil, 0, PAnsiChar(xml), length(xml), heap, @buffer, error);
    end;

(*
according to https://learn.microsoft.com/en-us/windows/win32/api/webservices/nf-webservices-wsstartreadercanonicalization
The usage pattern for canonicalization is:
  1)  Move the Reader to the element where canonicalization begins.
  2)  Call WsStartReaderCanonicalization.
  3)  Move the Reader forward to the end position.
  4)  Call WsEndReaderCanonicalization.

*)
// Step1: Move the Reader to the element where canonicalization begins.  [this gives an error]
    if hr=NOERROR then
      hr := WsMoveReader(reader, WS_MOVE_TO_PARENT_ELEMENT, @Found, error);

// Step2 : Call WsStartReaderCanonicalization.
    MyCallbackStatus := 0;
    if hr=NOERROR then
      hr:=WsStartReaderCanonicalization(reader, MyCallback, @MyCallbackStatus, nil, 0, error);

// Step3: Move the Reader forward to the end position.  [this gives an error]
    if hr=NOERROR then
      hr := WsMoveReader(reader, WS_MOVE_TO_EOF, @Found, error);

// Step4 : Call WsEndReaderCanonicalization  [this will call MyCallback]
    if hr=NOERROR then
      hr := WsEndReaderCanonicalization(reader, error);
  end;

  //----------------------------------------
  //My test End
  //----------------------------------------

  if hr <> NOERROR then
  begin
    PrintError(hr,error);
    ExitCode:=-1;
  end;


  if writer<>nil then WsFreeWriter(writer);
  if reader<>nil then WsFreeReader(reader);
  if heap<>nil then WsFreeHeap(heap);
  if error<>nil then WsFreeError(error);

  Readln;
  halt(exitcode);
end.

正如您在代码中看到的,函数 WsMoveReader() 给出了错误。当我删除对 WsMoveReader() 的调用时,代码完整且没有错误,但当调用 MyCallback 时,缓冲区参数为零。任何帮助将不胜感激。

xml web-services delphi
2个回答
0
投票

经过多次尝试,我终于找到了问题的答案。该解决方案有些原始,但它执行了所需的功能。这是我的代码。

以下是一个虚拟函数,但如果没有它,代码将无法运行。我尝试使用

{$APPTYPE CONSOLE}
program XmlBufferExample;

//This example shows some use of the xml buffer APIs.
//Original C++ code from Microsoft :
//https://msdn.microsoft.com/en-us/library/windows/desktop/dd819131(v=vs.85).aspx

uses
  Windows, Sysutils, Classes,
  webservices in 'webservices.pas';

Procedure PrintError(errorCode:HRESULT; error:PWS_ERROR);
var
  hr:HRESULT;
  errorCount,i:ULONG;
  str:WS_STRING;
  s:string;
begin
  writeln(Format('Failure: errorCode=0x8%.x',[errorCode]));

  if (errorCode=E_INVALIDARG) or (errorCode=WS_E_INVALID_OPERATION) then
  begin
    // Correct use of the APIs should never generate these errors
    writeln('The error was due to an invalid use of an API. This is likely due to a bug in the program.');
    exit;
  end;

  hr:=NOERROR;
  if (error<>nil) then
  begin
    hr:=WsGetErrorProperty(error, WS_ERROR_PROPERTY_STRING_COUNT, @errorCount, sizeof(errorCount));
    if (hr=NOERROR) and (errorCount>0) then
      for i:=0 to errorCount-1 do
      begin
        hr:=WsGetErrorString(error, i, @str);
        if (hr=NOERROR) then
        begin
          s:=copy(str.chars,1,str.length);
          writeln(s);
        end else
          errorCount:=i; //exit for
      end;
  end;
  if (hr<>NOERROR) then
    writeln(Format('Could not get error string (errorCode=0x8%.x)',[hr]));
end;

var
  MyCallbackStatus : Cardinal;
  Found : BOOL;
  Mybuffer:PWS_XML_BUFFER = nil;
const
  HeapSize = 24 * 1024;  //24 kb

function MyCallback(callbackState : pointer; buffer : PWS_BYTES; count : ULONG;
                     asyncContext : PWS_ASYNC_CONTEXT; error : PWS_ERROR):HRESULT; stdcall;
var
  S : AnsiString;
begin
//debuging start
  Writeln('Inside MyCallback :');
  Writeln('MyCallbackStatus :', IntToStr(MyCallbackStatus));
  if Assigned(error) then PrintError(0, error);
//debuging end

  if Assigned(buffer) then
    SetString(S, PAnsiChar(buffer.bytes), buffer.length);

  Writeln(s);
end;

var
  hr:HRESULT;
  error:PWS_ERROR;
  heap:PWS_HEAP;
  buffer:PWS_XML_BUFFER;
  writer:PWS_XML_WRITER;
  reader:PWS_XML_READER;
  newXml:pointer;
  newXmlLength:ULONG;
  xml:ansistring;
  ExitCode:integer;
  Stream : TMemoryStream;
begin
  error:=nil;
  heap:=nil;
  buffer:=nil;
  writer:=nil;
  reader:=nil;
  newXml:=nil;
  newXmlLength:=0;

  // Create an error object for storing rich error information
  hr := WsCreateError(nil,
                      0,
                      @error);

  if (hr=NOERROR) then
  begin
    // Create a heap to store deserialized data
    hr := WsCreateHeap(2048,   //maxSize
                       512,    //trimSize
                       nil,
                       0,
                       @heap,
                       error);
  end;

  if hr=NOERROR then
  begin
    // Create an XML writer
    hr := WsCreateWriter(nil,
                         0,
                         @writer,
                         error);
  end;

  if hr=NOERROR then
  begin
    // Create an XML reader
    hr := WsCreateReader(nil,
                         0,
                         @reader,
                         error);
  end;

  // Some xml to read and write
  xml:='<a><b>1</b><c>2</c></a>';

  if hr=NOERROR then
  begin
    hr:=WsReadXmlBufferFromBytes(reader,
                                 nil,
                                 nil,
                                 0,
                                 PAnsiChar(xml), //@xml[1],
                                 length(xml),
                                 heap,
                                 @buffer,
                                 error);

  end;

  if hr=NOERROR then
  begin
    hr:=WsWriteXmlBufferToBytes(writer,
                                buffer,
                                nil,
                                nil,
                                0,
                                heap,
                                @newXml,
                                @newXmlLength,
                                error);
  end;

  if hr=NOERROR then
  begin
    writeln('new xml :');
    writeln(copy(PAnsiChar(newXml),1,newXmlLength));
    writeln;
    ExitCode:=0;
  end;

  //----------------------------------------
  //My test start
  //----------------------------------------
  if hr=NOERROR then
  begin
    if Assigned(reader) then
    begin
      WsFreeReader(reader);
      reader := nil;
    end;
    hr := WsCreateReader(nil, 0, @reader, error);

    if Assigned(heap) then
    begin
      WsFreeHeap(heap);
      heap := nil;
    end;
    hr := WsCreateHeap(3 * HeapSize, 512, nil, 0, @heap, error);

    if hr=NOERROR then
    begin
      //load xml file
      Stream := TMemoryStream.Create();
      try
        Stream.LoadFromFile('Z:\zatca-einvoicing-sdk\test\100030.xml');
        SetString(xml, PChar(Stream.Memory), Stream.Size);
        Writeln;
        Writeln('-------------------------------');
        Writeln('XML File size is ' + IntToStr(Stream.Size) + ' Bytes');
      finally
        Stream.Free();
      end;

      hr:=WsReadXmlBufferFromBytes(reader, nil, nil, 0, PAnsiChar(xml), length(xml), heap, @buffer, error);
    end;

(*
according to https://learn.microsoft.com/en-us/windows/win32/api/webservices/nf-webservices-wsstartreadercanonicalization
The usage pattern for canonicalization is:
  1)  Move the Reader to the element where canonicalization begins.
  2)  Call WsStartReaderCanonicalization.
  3)  Move the Reader forward to the end position.
  4)  Call WsEndReaderCanonicalization.

*)
// Step1: Move the Reader to the element where canonicalization begins.  [this gives an error]
    if hr=NOERROR then
      hr := WsMoveReader(reader, WS_MOVE_TO_PARENT_ELEMENT, @Found, error);

// Step2 : Call WsStartReaderCanonicalization.
    MyCallbackStatus := 0;
    if hr=NOERROR then
      hr:=WsStartReaderCanonicalization(reader, MyCallback, @MyCallbackStatus, nil, 0, error);

// Step3: Move the Reader forward to the end position.  [this gives an error]
    if hr=NOERROR then
      hr := WsMoveReader(reader, WS_MOVE_TO_EOF, @Found, error);

// Step4 : Call WsEndReaderCanonicalization  [this will call MyCallback]
    if hr=NOERROR then
      hr := WsEndReaderCanonicalization(reader, error);
  end;

  //----------------------------------------
  //My test End
  //----------------------------------------

  if hr <> NOERROR then
  begin
    PrintError(hr,error);
    ExitCode:=-1;
  end;


  if writer<>nil then WsFreeWriter(writer);
  if reader<>nil then WsFreeReader(reader);
  if heap<>nil then WsFreeHeap(heap);
  if error<>nil then WsFreeError(error);

  Readln;
  halt(exitcode);
end.

代替它,但失败了。

nil

规范函数。

uses
  Windows, Sysutils, Classes, webservices, wcrypt2, ncrypt;

//   A user-defined callback used by the WS_XML_WRITER to write a buffer to some destination.
function MyCallback(callbackState : pointer; buffer : PWS_BYTES; count : ULONG;
                     asyncContext : PWS_ASYNC_CONTEXT; error : PWS_ERROR):HRESULT; stdcall;
begin
  Result := 0;
end; 

注:
在某些情况下,该函数在实际结果之前和之后返回“#10”,因此必须像这样修改结果:

function CanonicalXML(xml : string; Exclusive:Boolean=True; WithComment:Boolean=True) : string;
const
  HeapSize = 128 * 1024;  //128 KB for test
  Exclusives : array[Boolean, Boolean] of Integer = (
    (WS_INCLUSIVE_XML_CANONICALIZATION_ALGORITHM, WS_INCLUSIVE_WITH_COMMENTS_XML_CANONICALIZATION_ALGORITHM),
    (WS_EXCLUSIVE_XML_CANONICALIZATION_ALGORITHM, WS_EXCLUSIVE_WITH_COMMENTS_XML_CANONICALIZATION_ALGORITHM)
  );
  
var
  hr:HRESULT;
  heap:PWS_HEAP;
  buffer:PWS_XML_BUFFER;
  writer:PWS_XML_WRITER;
  reader:PWS_XML_READER;
  newXml:pointer;
  newXmlLength :ULONG;
  MyCallbackStatus : Cardinal;
  CanProp : WS_XML_CANONICALIZATION_PROPERTY;
  PtrCanProp : PWS_XML_CANONICALIZATION_PROPERTY;
  Algorithm : ULONG;
begin
  buffer := nil;
  writer := nil;
  reader := nil;
  
  //Setup algorithm used in canonicalization. 
  Algorithm := Exclusives[Exclusive, WithComment];
  CanProp.id := WS_XML_CANONICALIZATION_PROPERTY_ALGORITHM ;
  CanProp.value := @Algorithm;
  CanProp.valueSize := SizeOf(Algorithm);
  PtrCanProp := @CanProp;   
   
  hr := WsCreateReader(nil, 0, @reader, nil);     // Create an XML reader

  if hr=NOERROR then
    hr := WsCreateWriter(nil, 0, @writer, nil);   // Create an XML writer

  if (hr=NOERROR) then
    hr := WsCreateHeap(HeapSize, 512, nil, 0, @heap, nil); // Create a heap to store data

  if hr=NOERROR then    //read data into buffer
    hr:=WsReadXmlBufferFromBytes(reader, nil, nil, 0, PAnsiChar(xml), length(xml), heap, @buffer, nil);

  if hr=NOERROR then
    hr:=WsWriteXmlBufferToBytes(writer, buffer, nil, nil, 0, heap, @newXml, @newXmlLength, nil);

  if hr=NOERROR then
    hr := WsStartWriterCanonicalization(writer, MyCallback, @MyCallbackStatus, PtrCanProp, 1, nil);
  if hr=NOERROR then
    hr := WsEndWriterCanonicalization(writer, nil);

  if hr=NOERROR then
    SetString(Result, PAnsiChar(newXml), newXmlLength);

  //Free created objects
  if Assigned(writer) then WsFreeWriter(writer);
  if Assigned(reader) then WsFreeReader(reader);
  if Assigned(heap) then WsFreeHeap(heap);
end;

0
投票

我知道答案来晚了,但由于我还没有找到使用 WWSAPI 规范化的工作示例,所以我在这里留下了执行不同类型规范化的函数的完整代码。

解决方案是使用功能

SetString(Result, PAnsiChar(newXml), newXmlLength);
Result := Trim(Result);
前进。 另外,回调函数获取缓冲区数组

WsReadNode

使用示例:

uses
  Webservices, StrUtils, Math;


function MyCallback(callbackState: Pointer; buffer: PWS_BYTES; count: ULONG;
                     asyncContext: PWS_ASYNC_CONTEXT; error: PWS_ERROR): HRESULT; stdcall;
var
  s: AnsiString;
begin
  while count > 0 do // repeat for each item of buffer array
  begin
    if Assigned(buffer) then
      SetString(s, PAnsiChar(buffer.bytes), buffer.length);

    string(callbackState^) := string(callbackState^) + string(s);

    Inc(buffer);
    Dec(count);
  end;

  Result := 0;
end;

function CanonicalXML(XmlString: string;
                      Exclusive: Boolean;
                      WithComment: Boolean;
                      SubsetByTag: string;
                      PrefixList: array of string): string;
var
  wsError: PWS_ERROR;

  // translate string to WS_XML_STRING
  function WS_XML_STRING_VALUE(s: string): WS_XML_STRING;
  begin
    Result.length := Length(s);
    Result.bytes := PByte(UTF8String(s));
    Result.dictionary := nil;
    Result.id := 0;
  end;

  // Translate WS_XML_STRING to string
  function GetXmlString(wsString: WS_XML_STRING): string;
  begin
    SetString(Result, PAnsiChar(wsString.bytes), wsString.length);
  end;

  function GetXmlElementName(wsElement: WS_XML_ELEMENT_NODE): string;
  begin
    Result := GetXmlString(wsElement.prefix^);

    if Result <> '' then
      Result := Result + ':';

    Result := Result + GetXmlString(wsElement.localName^)
  end;

  // Raise a detailed error if needed
  procedure CheckError(r: HRESULT);
  var
    s: string;
    i,
    errorCount: ULONG;
    errorString: WS_STRING;
  begin
    if r = NOERROR then
      Exit;

    s := Format('Error code: 0x%x'#13, [r]);
    if (r = E_INVALIDARG) or (r = WS_E_INVALID_OPERATION) then
      raise Exception.Create(s + 'Invalid operation')
    else if WsGetErrorProperty(wsError, WS_ERROR_PROPERTY_STRING_COUNT, @errorCount, sizeof(errorCount)) = NOERROR then
    begin
      for i := 0 to errorCount - 1 do
      if WsGetErrorString(wsError, i, @errorString) = NOERROR then
        s := s + WideCharLenToString(errorString.chars, errorString.length) + #13;

      raise Exception.Create(s);
    end;
  end;

const
  Exclusives : array [Boolean, Boolean] of Integer = (
    (WS_INCLUSIVE_XML_CANONICALIZATION_ALGORITHM, WS_INCLUSIVE_WITH_COMMENTS_XML_CANONICALIZATION_ALGORITHM),
    (WS_EXCLUSIVE_XML_CANONICALIZATION_ALGORITHM, WS_EXCLUSIVE_WITH_COMMENTS_XML_CANONICALIZATION_ALGORITHM)
  );
var
  wsHeap: PWS_HEAP;
  wsBuffer: PWS_XML_BUFFER;
  wsReader: PWS_XML_READER;
  wsNode: PWS_XML_NODE;
  CanProp: array [0..1] of WS_XML_CANONICALIZATION_PROPERTY;
  Algorithm: ULONG;
  wsPrefixes: WS_XML_CANONICALIZATION_INCLUSIVE_PREFIXES;
  wsPrefixesXmlStrings: array of WS_XML_STRING;
  Xml: UTF8String;
  Found: BOOL;
  XmlCanon: string;
  i: Integer;
begin
  XmlCanon := '';

  wsError := nil;
  wsHeap := nil;
  wsReader := nil;
  wsBuffer := nil;
  wsNode := nil;

  Xml := UTF8String(XmlString);

  try
    CheckError(WsCreateError(nil, 0, @wsError));

    CheckError(WsCreateReader(nil, 0, @wsReader, wsError));
    CheckError(WsCreateHeap(128 * 1024, 512, nil, 0, @wsHeap, wsError));

    // read from xml to buffer
    CheckError(WsReadXmlBufferFromBytes(wsReader, nil, nil, 0, PAnsiChar(Xml), length(Xml), wsHeap, @wsBuffer, wsError));

    // set reader to use buffer
    CheckError(WsSetInputToBuffer(wsReader, wsBuffer, nil, 0, wsError));
    // move to BOF
    CheckError(WsMoveReader(wsReader, WS_MOVE_TO_BOF, @Found, wsError));

    if Found then
    begin
      // if exclusive, you can canonicalize only a subset, move to it
      if Exclusive then
      if SubsetByTag <> '' then
      begin
        CheckError(WsGetReaderNode(wsReader, @wsNode, wsError));
        while wsNode.nodeType <> WS_XML_NODE_TYPE_EOF do
        begin
          if wsNode.nodeType = WS_XML_NODE_TYPE_ELEMENT  then
          if SubsetByTag <> '' then
          begin
            if GetXmlElementName(PWS_XML_ELEMENT_NODE(wsNode)^) = SubsetByTag then
              Break;
          end;

          // move to next node
          CheckError(WsReadNode(wsReader, wsError));
          CheckError(WsGetReaderNode(wsReader, @wsNode, wsError));
        end;
      end;

      CheckError(WsGetReaderNode(wsReader, @wsNode, wsError));

      // if reader position is ok starts canonicalization
      if wsNode.nodeType <> WS_XML_NODE_TYPE_EOF then
      begin
        // param algorithm
        Algorithm := Exclusives[Exclusive, WithComment];
        CanProp[0].id := WS_XML_CANONICALIZATION_PROPERTY_ALGORITHM;
        CanProp[0].value := @Algorithm;
        CanProp[0].valueSize := SizeOf(Algorithm);

        // Param included prefix list
        if Length(PrefixList) > 0 then
        begin
          wsPrefixes.prefixCount := Length(PrefixList);
          SetLength(wsPrefixesXmlStrings, wsPrefixes.prefixCount);
          for i := 0 to wsPrefixes.prefixCount - 1 do
            wsPrefixesXmlStrings[i] := WS_XML_STRING_VALUE(PrefixList[i]);
          wsPrefixes.prefixes := @wsPrefixesXmlStrings[0];

          CanProp[1].id := WS_XML_CANONICALIZATION_PROPERTY_INCLUSIVE_PREFIXES;
          CanProp[1].value := @wsPrefixes;
          CanProp[1].valueSize := SizeOf(wsPrefixes);
        end;

        // start
        CheckError(WsStartReaderCanonicalization(wsReader, MyCallback, @XmlCanon, @CanProp[0], IfThen(Length(PrefixList) = 0, 1, 2), wsError));

        // if starts at BOF move node by node until ends
        if wsNode.nodeType = WS_XML_NODE_TYPE_BOF then
        begin
          while wsNode.nodeType <> WS_XML_NODE_TYPE_EOF do
          begin
            CheckError(WsReadNode(wsReader, wsError));
            CheckError(WsGetReaderNode(wsReader, @wsNode, wsError));
          end;
        end
        else // sub node, only move from this node to the next, skipping childs
          CheckError(WsSkipNode(wsReader, wsError));

        // ends
        CheckError(WsEndReaderCanonicalization(wsReader, wsError));
      end;
    end;

    // callback function wrote to XmlCanon variable
    Result := XmlCanon;
  finally
    if Assigned(wsReader) then WsFreeReader(wsReader);
    if Assigned(wsHeap) then WsFreeHeap(wsHeap);
    if Assigned(wsError) then WsFreeError(wsError);
  end;
end;
© www.soinside.com 2019 - 2024. All rights reserved.