Автор: slavw 
Я не утвержаю, что в Delphi нет средств для каноникализации XML... я констатирую этот факт. Если у кого то есть сомнения по этому поводу, что ж...
Можно написать и самому, но для этого надо знать как оно должно работать... именно с этой целью я и выложил программу c14n.exe... если вы не сможете вручную преобразовать XML к каноническому виду, то тем более не сможете "научить" этому свою процедуру...
А исходники конечно будут, если будет интерес к этому вопросу...
но не будет толка от процедур для получения хеша и подписи пока не будет возможности передать им "нужный" XML...
После прочтения утверждения Slavw специально провел тестирование основных парсеров для среды Delphi XE4-XE5 на основе примеров приведенных на сайте
http://www.w3.org/TR/xml-c14n11/: - MSXML2_TLB - методов каноникализации для среды нет;
- Встроенные средства Delphi (компонент TXMLDocument)- методов каноникализации нет;
- Библиотека NativeXML - средства каноникализации к виду с14n есть, но тестирование по примерам не проходит (подробности опускаю, можете сами протестировать);
- libxml2 - средства каноникализации к виду с14n есть, но тестирование по примерам не проходит.
- uXMLHelper от slavw канонизирует XML, но тестирование по примерам, указанным в рекомендациях консорциума W3C Canonical c14n показало также многие несоответствия.
В результате пришел к выводу - 100% согласен с утверждением "в Delphi нет средств для каноникализации XML... ". По крайней мере в соответствии с рекомендациями консорциума.
Полное соответствие дает каноникализация в программе c14n.exe (текст ), причем если в C# используются версия FrameWork 3.5 и ниже, то полного соответствия также нет (если в XML используются ссылки на несуществующие файлы). Так, что необходима версия FrameWork 4.0 и выше.
В Delphi можно использовать средства, применяемые для каноникализации XML к виду c14n в C#.
Для этого с помощью MS VS создать DLL с COM интерфейсом. В DLL используется единственная функция для каноникализации XML, например:
private XmlDsigExcC14NTransform xmlTransform;
public string[] TransformStringToC14n(string Input)
{
xmlTransform = new XmlDsigExcC14NTransform(false);
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = true;
xmlDocument.LoadXml(Input.Replace("\r\n", '\n'.ToString()));
xmlTransform.LoadInput((object)xmlDocument);
return Encoding.UTF8.GetString(((System.IO.MemoryStream)xmlTransform.GetOutput()).ToArray()).Split('\n');
}
У нас DLL после компиляции в MS VS 2015 имеет размер 6144 байт )))
Далее необходимо зарегистрировать COM объект в системе, где установлена Delphi среда, да и вообще где будет проводиться каноникализация с использованием этой DLL.
Делается это просто: утилита из состава MS FrameWork Regasm.exe.
Выполняется так:
- запустить командную строку в режиме Администратор;
- перейти в директорию, содержащую DLL Com объекта.
- выполнить команду: c:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe canonicalization_c14n_4.5.dll /tlb
Данная команда выполняет регистрацию COM объекта в системе Windows, а также создает библиотеку описания типов canonicalization_c14n_4.5.tlb, котарая необходима для генерации библиотеки типов в Delphi.
- В среде Delphi необходимо сгенерировать библиотеку типов canonicalization_c14n_4.5_tlb.pas
Для этого необходимо выполнить команду меню Component - Import Component - Import a Type Library.
Выбрать из списка необходимую библиотеку типов (в нашем случае canonicalization_c14n_4.5) и импортировать ее. В результате будет создан canonicalization_c14n_4.5_tlb.pas, который помещается в каталог среды Imports.
- В модуле рабочего проекта подключить canonicalization_c14n_4.5_tlb.pas в Uses и воспользоваться функцией каноникализации в Delphi:
procedure TForm3.Button2Click(Sender: TObject);
var ;
Canonicalization_c14n:TransformToC14n;
xml_C14n:PSafeArray;
begin
Canonicalization_c14n:= CoTransformToC14n.Create;
xml_C14n:=Canonicalization_c14n.TransformStringToC14n(XMLDoc.xml);
end;
- Тип PSafeArray переводится в String просто:
...
var index, Count, Max:integer;
str:string;
getResult : HRESULT;
Count:=SafeArrayGetDim(xml_C14n);
SafeArrayGetUBound(xml_C14n, Count, Max);
for index:=0 to Max do begin
getResult:=SafeArrayGetElement(xml_C14n, Index, str);
case getResult of
S_OK : ShowMessage('Success.');
DISP_E_BADINDEX : ShowMessage('The specified index was invalid.');
E_INVALIDARG : ShowMessage('One of the arguments is invalid.');
E_OUTOFMEMORY : ShowMessage('Memory could not be allocated for the element.');
end;
Memo2.Lines.Add(str); //Вывод каждой строки в Memo компонент.
end;
Вот собственно и все. Каноникализация будет проходить в полном соответствии с рекомендациями w3c.