Componentes.Terceros.RemObj.../internal/5.0.23.613/1/RemObjects SDK for Delphi/Source/uROXMLSerializer.pas
david 2824855ea7 - Modificación del paquete RemObjects_Core_D10 para que sea un paquete de runtime/designtime (antes era designtime sólo)
- Recompilación en Delphi10 de todos los paquetes de RO para generar las DCU's en Lib\D10
- Recompilación en Delphi10 de todos los paquetes de DA para generar las DCU's en Lib\D10

git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.RemObjects@9 b6239004-a887-0f4b-9937-50029ccdca16
2007-09-10 14:06:19 +00:00

1871 lines
62 KiB
ObjectPascal

unit uROXMLSerializer;
{----------------------------------------------------------------------------}
{ RemObjects SDK Library - Core Library }
{ }
{ compiler: Delphi 5 and up, Kylix 2 and up }
{ platform: Win32, Linux }
{ }
{ (c)opyright RemObjects Software. all rights reserved. }
{ }
{ Using this code requires a valid license of the RemObjects SDK }
{ which can be obtained at http://www.remobjects.com. }
{----------------------------------------------------------------------------}
{$I RemObjects.inc}
interface
uses
{$IFDEF REMOBJECTS_TRIAL}uROTrial,{$ENDIF}
Classes, uROSerializer, TypInfo, uROXMLIntf, uROTypes, SysUtils, FMTBcd;
const
// SOAP specifics
tag_Envelope = 'Envelope';
tag_Body = 'Body';
tag_Header = 'Header';
tag_Fault = 'Fault';
ns_Envelope = 'SOAP-ENV';
ns_Standard = 'xs';
ns_Custom = 'ro';
ns_xsi = 'xsi';
ns_xsd = 'xsd';
tag_HRef = 'href';
tag_Nil = 'xsi:nil';
tag_NilValue = 'true';
tag_Id = 'id';
// Misc
SOAP_DecimalSeperator = '.';
SOAP_BoolValues: array [Boolean] of string = ('false', 'true');
SOAP_DateFormat = 'yyyy-mm-dd';
SOAP_DateFormatLength = 10;
SOAP_DateTimeFormat = 'yyyy-mm-dd"T"hh":"nn":"ss';
SOAP_DateTimeFormatLength = 19;
SOAP_TimeFormat = 'hh":"nn":"ss';
SOAP_TimeFormatLength = 8;
// Data types signatures
dts_Array = 'SOAP-ENC:Array';
dts_Array2 = 'soapenc:Array';
dts_base64Binary = 'base64Binary';
type
{ Misc }
TROXMLSerializationOption = (
xsoWriteMultiRefArray, // for literal, use false
xsoWriteMultiRefObject, // for literal, use false
xsoSendUntyped, // for literal, use true
xsoStrictStructureFieldOrder,
xsoIgnoreStructureType,
xsoEncodedXML, // for literal, use false
xsoClientIdInWsdl,
xsoDocument, // for document, use true; if both doc & literal are true it uses wrapped arguments
xsoSplitServiceWsdls,
xsoExternalTypesAsReferences // This will emit "import" references to external resources in the wsdl and namespace references in the body of messages.
);
TROXMLSerializationOptions = set of TROXMLSerializationOption;
TXMLSerializationOption = TROXMLSerializationOption {$IFDEF DELPHI10UP}deprecated{$ENDIF};
TXMLSerializationOptions = TROXMLSerializationOptions {$IFDEF DELPHI10UP}deprecated{$ENDIF};
{ TROXMLSerializer }
TROXMLSerializer = class(TROSerializer)
private
fNode: IXMLNode;
fSerializationOptions: TROXMLSerializationOptions;
fBodyNode : IXMLNode;
fMaxRef : integer;
fRespNode : IXMLNode;
function BodyNode : IXMLNode;
function FindNode(const aName: string; ArrayElementId : integer): boolean;
function GetObject(const aName: string; ArrayElementId : integer): IXMLNode;
function FindSoapReference(subnode: IXMLNode): IXMLNode;
protected
{ Internal }
function GetRecordStrictOrder: Boolean; override;
procedure BeginWriteObject(const aName: string; aClass : TClass; anObject: TObject; var LevelRef : IUnknown;
var IsValidType : boolean; out IsAssigned:Boolean; ArrayElementId : integer = -1); override;
procedure EndWriteObject(const aName: string; aClass : TClass; anObject: TObject; const LevelRef : IUnknown); override;
procedure CustomWriteObject(const aName : string; aClass : TClass; const Ref; ArrayElementId : integer = -1); override;
procedure CustomReadObject(const aName: string; aClass: TClass;var Ref; ArrayElementId: integer);override;
procedure BeginReadObject(const aName : string; aClass : TClass; var anObject : TObject; var LevelRef : IUnknown;
var IsValidType : boolean; ArrayElementId : integer = -1); override;
procedure EndReadObject(const aName : string; aClass : TClass; var anObject : TObject; const LevelRef : IUnknown); override; public
{ Writers }
procedure WriteInteger(const aName : string; anOrdType : TOrdType; const Ref; ArrayElementId : integer = -1); override;
procedure WriteInt64(const aName : string; const Ref; ArrayElementId : integer = -1); override;
procedure WriteEnumerated(const aName : string; anEnumTypeInfo : PTypeInfo; const Ref; ArrayElementId : integer = -1); override;
procedure WriteUTF8String(const aName : string; const Ref; ArrayElementId : integer = -1); override;
procedure WriteWideString(const aName : string; const Ref; ArrayElementId : integer = -1); override;
procedure WriteDateTime(const aName : string; const Ref; ArrayElementId : integer = -1); override;
procedure WriteDouble(const aName : string; aFloatType : TFloatType; const Ref; ArrayElementId : integer = -1); override;
procedure WriteVariant(const aName : string; const Ref; ArrayElementId : integer = -1); override;
procedure WriteDecimal(const aName: String; const Ref; ArrayElementId: Integer = -1); override;
procedure WriteGuid(const aName: String; const Ref; ArrayElementId: Integer = -1); override;
procedure WriteXml(const aName: String; const Ref; ArrayElementId: Integer = -1); override;
procedure WriteBinary(const aName : string; const Ref; ArrayElementId : integer = -1);override;
procedure WriteStruct(const aName : string; const Ref; ArrayElementId : integer = -1);override;
procedure WriteArray(const aName : string; const Ref; ArrayElementId : integer = -1);override;
procedure WriteException(const aName : string; const Ref; ArrayElementId : integer = -1); override;
{ Readers }
procedure ReadInteger(const aName : string; anOrdType : TOrdType; var Ref; ArrayElementId : integer = -1); override;
procedure ReadInt64(const aName : string; var Ref; ArrayElementId : integer = -1); override;
procedure ReadEnumerated(const aName : string; anEnumTypeInfo : PTypeInfo; var Ref; ArrayElementId : integer = -1); override;
procedure ReadUTF8String(const aName : string; var Ref; ArrayElementId : integer = -1; iMaxLength:integer=-1); override;
procedure ReadWideString(const aName : string; var Ref; ArrayElementId : integer = -1; iMaxLength:integer=-1); override;
procedure ReadDateTime(const aName : string; var Ref; ArrayElementId : integer = -1); override;
procedure ReadDouble(const aName : string; aFloatType : TFloatType; var Ref; ArrayElementId : integer = -1); override;
procedure ReadVariant(const aName : string; var Ref; ArrayElementId : integer = -1); override;
procedure ReadDecimal(const aName: String; var Ref; ArrayElementId: Integer = -1); override;
procedure ReadGuid(const aName: String; var Ref; ArrayElementId: Integer = -1); override;
procedure ReadXml(const aName: String; var Ref; ArrayElementId: Integer = -1); override;
procedure ReadBinary(const aName : string; var Ref; ArrayElementId : integer = -1);override;
function ReadStruct(const aName : string; aClass : TClass; var Ref; ArrayElementId : integer = -1): Boolean; override;
function ReadArray(const aName : string; aClass : TClass; var Ref; ArrayElementId : integer = -1): Boolean; override;
procedure ReadException(const aName : string; var Ref; ArrayElementId : integer = -1); override;
public
constructor Create(aStorageRef:pointer);
procedure SetStorageRef(aStorageRef:pointer);
function GetArrayElementName(anItemType : PTypeInfo; anItemReference: pointer): string; override;
property SerializationOptions : TROXMLSerializationOptions read fSerializationOptions write fSerializationOptions;
end;
const
RESERVED_WORD_PREFIX = '___';
function Unprefix(const AStr: String; const APrefix: String = RESERVED_WORD_PREFIX): String;
function XMLToObject(const someXML : string) : TROComplexType;
function ObjectToXML(anObject : TROComplexType;
const anObjectName : string = '') : string;
procedure SplitNodeName(const aNode : IXMLNode; out aNameSpace, aLocalName : string);
function SOAPDateTimeToDateTime(const aSOAPDate : string) : TDateTime;
function DateTimeToSOAPDateTime(aDateTime : TDateTime) : string;
function ExtractServerURL(const aFullURL : string) : string;
function SOAPStrToFloat(const aString: string): Extended;
function AddXMLChildNode(aParent : IXMLNode; const aName : string; const aNamespace: WideString = '') : IXMLNode;
function AddXMLAttribute(aNode : IXMLNode; const aName: string; const aValue : WideString) : IXMLNode;
procedure AddXMLTextValue(aNode : IXMLNode; const aValue : WideString);
function FindChildNode(aParent : IXMLNode; const aName : string; StartFrom : integer; IsOnlyLocalName : boolean = FALSE) : IXMLNode;
function FindChildNodeByAttribute(aParent : IXMLNode; const anAttributeName, anAttributeValue : string) : IXMLNode;
function FindParentNode(aNode : IXMLNode; const aName : string; IsOnlyLocalName : boolean = FALSE) : IXMLNode;
function FindAttribute(aNode : IXMLNode; const aName : string; IsOnlyLocalName : boolean = FALSE) : IXMLNode;
function GetXMLTextValue(aNode : IXMLNode) : widestring;
{$IFDEF DELPHI7UP}
const SOAPLocale = 1033;
var SOAPFormatSettings : TFormatSettings;
{$ENDIF DELPHI7}
implementation
uses
{$IFDEF DELPHI5}Windows, {$ENDIF}
Math, uRORes, uROCompression, uROClasses, Variants, uROBinaryHelpers;
function ObjectToXML(anObject : TROComplexType;
const anObjectName : string = '') : string;
var objname : string;
doc : IXMLDocument;
begin
result := '';
if (anObjectName='') then objname := 'Object'
else objname := anObjectName;
doc := NewROXmlDocument;
doc.New(anObject.ClassName);
with TROXMLSerializer.Create(pointer(doc.DocumentNode)) do try
//with TROXMLSerializer.Create(doc.DocumentNode) do try
SerializationOptions := [xsoSendUntyped];
Write(anObject.ClassName, anObject.ClassInfo, anObject);
{$IFDEF RemObjects_OpenXML}
result := doc.XML; //mej - OpenXML seems to not behave the same way as MSDOM
{$ELSE}
result := doc.DocumentNode.XML;
{$ENDIF}
finally
Free;
end;
end;
function XMLToObject(const someXML : string) : TROComplexType;
var clsname : string;
cls : TROComplexTypeClass;
doc : IXMLDocument;
ss : TStringStream;
begin
ss := TStringStream.Create(someXML);
ss.Position := 0;
try
doc := NewROXmlDocument;
doc.New;
doc.LoadFromStream(ss);
finally
ss.Free;
end;
clsname := doc.DocumentNode.Name;
cls := FindROClass(clsname);
if (cls=NIL) then RaiseError(err_UnknownClass, [clsname]);
with TROXMLSerializer.Create(pointer(doc.DocumentNode)) do try
//with TROXMLSerializer.Create(doc.DocumentNode) do try
Read(clsname, cls.ClassInfo, result);
finally
Free;
end;
end;
procedure SplitName(const aName : string; out aNameSpace, aLocalName : string);
var idx : integer;
begin
aNameSpace := '';
if (aName='') then begin
aLocalName := '';
Exit;
end
else aLocalName := aName;
idx := Pos(':', aName);
if (idx>0) then begin
aNameSpace := Copy(aName, 1, idx-1);
aLocalName := Copy(aName, idx+1, Length(aName)-idx);
end;
end;
// Required for a bug in OpenXML which never assigns correctly LocalName
procedure SplitNodeName(const aNode : IXMLNode; out aNameSpace, aLocalName : string);
begin
// SplitName(aNode.nodeName, aNameSpace, aLocalName)
SplitName(aNode.Name, aNameSpace, aLocalName)
end;
function SOAPStrToFloat(const aString: string): Extended;
begin
{$IFDEF DELPHI7UP}
Result := StrToFloat(aString,SOAPFormatSettings);// then
{$ELSE}
Result := StrToFloat(StringReplace(aString, '.', DecimalSeparator, []));
{$ENDIF}
//RaiseError(err_ErrorConvertingFloat, [aString]);
//Val(aString, Result, e);
//if (e<>0) then RaiseError(err_ErrorConvertingFloat, [aString, e]);
end;
function SOAPDateTimeToDateTime(const aSOAPDate : string) : TDateTime;
var year, month, day, hour, min, sec : word;
msec: double;
ldummy, i: Integer;
s: string;
begin
// This probabily will all change. See W3C specs for date/time
case Length(aSOAPDate) of
SOAP_DateFormatLength : begin {yyyy-mm-dd}
year := StrToInt(Copy(aSOAPDate,1,4));
month := StrToInt(Copy(aSOAPDate,6,2));
day := StrToInt(Copy(aSOAPDate,9,2));
result := EncodeDate(year, month, day);
end;
SOAP_TimeFormatLength : begin {hh:nn:ss}
hour := StrToInt(Copy(aSOAPDate,1,2));
min := StrToInt(Copy(aSOAPDate,4,2));
sec := StrToInt(Copy(aSOAPDate,7,2));
result := EncodeTime(hour, min, sec, 0);
end;
else {SOAP_DateTimeFormatLength : } begin {yyyy-mm-ddThh:nn:ss}
year := StrToInt(Copy(aSOAPDate,1,4));
month := StrToInt(Copy(aSOAPDate,6,2));
day := StrToInt(Copy(aSOAPDate,9,2));
hour := StrToInt(Copy(aSOAPDate,12,2));
min := StrToInt(Copy(aSOAPDate,15,2));
sec := StrToInt(Copy(aSOAPDate,18,2));
s := copy(aSOAPDate, 20, MaxInt);
if (Length(s) > 1) and (s[1] = '.') then begin
i := LastDelimiter('+-Z', s);
if i > 0 then begin
Val(Copy(s, 1, i -1), msec, ldummy);
delete(s, 1, i-1);
end else begin
Val(s, msec, ldummy);
s := '';
end;
msec := msec * (1.0 / 60.0 / 60.0 / 24);
end else
msec := 0;
result := EncodeDate(year, month, day);
// The code below is required! Do not adjust
if (result<0) then begin
result := result-EncodeTime(hour, min, sec, 0);
result := result - msec;
end else begin
result := result+EncodeTime(hour, min, sec, 0);
result := result + msec;
end;
if (Length(s) > 0) and ((s[1] = '+') or (s[1] = '-')) then begin
if s[1] = '-' then i := -1 else i := 1;
Delete(s,1,1);
if pos(':', s) > 0 then begin
hour := StrToInt(copy(s,1,Pos(':', s)-1));
delete(s,1,pos(':', s));
min := StrToInt(s);
end else begin
hour := StrToInt(s);
min := 0;
end;
if i = 1 then
Result := Result - (1.0 / 86400.0) * (min + 60 * hour) * 60
else
Result := Result + (1.0 / 86400.0) * (min + 60 * hour) * 60;
end;
end;
end;
end;
function DateTimeToSOAPDateTime(aDateTime : TDateTime) : string;
begin
result := FormatDateTime(SOAP_DateTimeFormat, aDateTime);
end;
function ExtractServerURL(const aFullURL : string) : string;
const ProtocolID = 'http://';
var p : integer;
begin
result := Trim(StringReplace(aFullURL, ProtocolID, '', [rfReplaceAll, rfIgnoreCase]));
p := LastDelimiter('/', result);
if (p>0)
then result := ProtocolID+Copy(result, 1, p)
else result := ProtocolID+result;
end;
function AddXMLChildNode(aParent : IXMLNode; const aName : string; const aNamespace: WideString = '') : IXMLNode;
begin
{result := aParent.ownerDocument.createElement(aName);
aParent.appendChild(result);}
result := aParent.Add(aName, aNamespace)
end;
function AddXMLAttribute(aNode : IXMLNode; const aName: string; const aValue : WideString) : IXMLNode;
begin
{result := aNode.ownerDocument.createAttribute(aName);
result.nodeValue := aValue;
aNode.attributes.setNamedItem(result);}
result := aNode.AddAttribute(aName, aValue);
end;
procedure AddXMLTextValue(aNode : IXMLNode; const aValue : widestring);
begin
//aNode.appendChild(aNode.ownerDocument.createTextNode(aValue));
aNode.Value := aValue
end;
function FindParentNode(aNode : IXMLNode; const aName : string; IsOnlyLocalName : boolean = FALSE) : IXMLNode;
var ns, locname : string;
parent : IXMLNode;
begin
result := NIL;
while (aNode.Parent<>NIL) do begin
parent := aNode.Parent;
if IsOnlyLocalName then begin
SplitNodeName(parent, ns, locname);
if (CompareText(locname, aName)=0) then begin
result := parent;
Exit;
end;
end
else if (parent.Name=aName) then begin
result := parent;
Exit;
end;
aNode := parent;
end;
end;
function FindChildNode(aParent : IXMLNode; const aName : string; StartFrom : integer; IsOnlyLocalName : boolean = FALSE) : IXMLNode;
var i, startidx : integer;
locname, ns : string;
item : IXMLNode;
begin
result := NIL;
with aParent do begin
// fix for arrays. I was always using the first item...
if (StartFrom>=0) then startidx := StartFrom
else startidx := 0;
for i := startidx to (childrenCount-1) do begin
item := Children[i];
if IsOnlyLocalName then begin
SplitNodeName(item, ns, locname);
if (CompareText(locname, aName)=0) then begin // I am ignoring XML case sensitivity here...
result := item;
Exit;
end;
// Moved down by AleF. This "patch" actually breaks regular webservices
// processing. Let's keep it here as an extreme measure for Amazon alike web services
{if (ns = '') and SameText(locname, 'return') then begin
Result := FindChildNode(item, aName, StartFrom, IsOnlyLocalName);
Exit;
end;}
end
else begin
if (item.Name=aName) then begin
result := item;
Exit;
end;
end
end
end;
end;
function FindChildNodeByAttribute(aParent : IXMLNode; const anAttributeName, anAttributeValue : string) : IXMLNode;
var i : integer;
//attr : IXMLNode;
item, item2 : IXMLNode;
//list : IXMLNodeList;
begin
result := NIL;
with aParent do
for i := 0 to (ChildrenCount-1) do begin
item := Children[i];
item2 := item.GetNodeByAttribute(anAttributeName, anAttributeValue);
if (item2<>NIL) then begin
result := item;
Exit;
end;
end
end;
function FindAttribute(aNode : IXMLNode; const aName : string; IsOnlyLocalName : boolean = FALSE) : IXMLNode;
//var i : integer;
//locname, ns : string;
begin
result := NIL;
result := aNode.GetAttributeByName(aName);
{with aNode do
for i := 0 to (AttributeCount-1) do begin
if IsOnlyLocalName then begin
SplitNodeName(attributes.item(i), ns, locname);
if (locname=aName) then begin
result := attributes.item(i);
Exit;
end;
end
else begin
if (attributes.item(i).nodeName=aName) then begin
result := attributes.item(i);
Exit;
end;
end
end}
end;
function GetXMLTextValue(aNode : IXMLNode) : WideString;
//var textnode : IXMLNode;
begin
//textnode := aNode.childNodes.item(0);
{if Assigned(textnode) and (textnode.hasChildNodes) and (textnode.nodeName='#text')
then result := textnode.textContent
else result := '';}
result := aNode.Value
end;
function SameText(A, B : string) : boolean;
begin
result := CompareText(a,b)=0
end;
function TypeInfoNameToSOAPType(aTypeInfo : PTypeInfo) : string;
begin
case aTypeInfo^.Kind of
tkEnumeration : begin
if (aTypeInfo=TypeInfo(boolean))
then result := ns_xsd+':boolean'
else result := ns_Custom+':'+aTypeInfo^.Name;
end;
tkInteger : begin
case GetTypeData(aTypeInfo)^.OrdType of
otSByte : result := ns_xsd+':byte';
otUByte : result := ns_xsd+':unsignedByte';
otSWord : result := ns_xsd+':short';
otUWord : result := ns_xsd+':unsignedShort';
otSLong : result := ns_xsd+':int';
otULong : result := ns_xsd+':unsignedInt';
end;
end;
tkInt64 : result := ns_xsd+':long';
// TODO: this wont work for DateTime's inside records or arrays
tkFloat : if (aTypeInfo=TypeInfo(TDateTime)) then result := ns_xsd+':dateTime'
else begin
case GetTypeData(aTypeInfo)^.FloatType of
ftSingle : result := ns_xsd+':float';
ftDouble : result := ns_xsd+':double';
ftExtended : result := ns_xsd+':double';
ftComp : result := ns_xsd+':double';
ftCurr : result := ns_xsd+':double';
end;
end;
tkWString,
tkLString,
tkString : result := ns_xsd+':string';
tkClass :
begin
if aTypeInfo = typeinfo(Binary) then
result := ns_xsd+':'+dts_base64Binary
else
result := ns_Custom+':'+aTypeInfo^.Name;
end;
tkVariant:
begin
if aTypeInfo = typeinfo(TDecimalVariant) then result := ns_xsd+':decimal' else
result := ns_xsd+':anyType';
end;
tkInterface:
result := ns_xsd+':any';
end;
end;
function VarTypeNameToSOAPType(aVarType : TVarType) : string;
begin
result := '';
case aVarType of
varBoolean : result := ns_xsd+':boolean';
varInteger : result := ns_xsd+':int';
varWord : result := ns_xsd+':unsignedShort';
varSmallInt : result := ns_xsd+':short';
varByte : result := ns_xsd+':unsignedByte';
varShortInt : result := ns_xsd+':byte';
varSingle : result := ns_xsd+':float';
varDouble,
varCurrency : result := ns_xsd+':double';
varDate : result := ns_xsd+':dateTime';
varOleStr,
varString : result := ns_xsd+':string';
varLongWord : result := ns_xsd+':unsignedInt';
varInt64 : result := ns_xsd+':long';
varEmpty,
varNull: result := ns_xsd+':null';
else
if aVarType = VarFMTBcd then
result := ns_xsd +':decimal'
else
result := ns_Custom+':unknown';
end;
end;
function Unprefix(const AStr, APrefix: String): String;
var
L: Integer;
begin
L := Length(APrefix);
if StrLIComp(PChar(AStr), PChar(APrefix), Min(Length(AStr), L)) = 0 then
Result :=Copy(AStr, L + 1, MaxInt)
else
Result := AStr;
end;
{ TROXMLSerializer }
constructor TROXMLSerializer.Create(aStorageRef: pointer);
begin
inherited Create;
SetStorageRef(aStorageRef);
fSerializationOptions := [xsoWriteMultiRefArray, xsoWriteMultiRefObject];
end;
{$IFDEF DELPHI5}
function Supports(const Instance: IUnknown; const Intf: TGUID): Boolean; overload;
var lDummyInst:IUnknown;
begin
result := Supports(Instance, Intf, lDummyInst);
end;
{$ENDIF DELPHI5}
procedure TROXMLSerializer.SetStorageRef(aStorageRef : pointer);
begin
fNode := nil;
if Supports(IUnknown(aStorageRef), IXMLNode) then begin
//RaiseError('TROXMLSerializer: Not a valid IXMLNode reference',[]);
fBodyNode := NIL;
fRespNode := NIL;
fMaxRef := 0;
fNode := IXMLNode(aStorageRef);
end;
{fNode := aStorageRef;}
end;
procedure TROXMLSerializer.EndReadObject(const aName: string;
aClass : TClass; var anObject: TObject; const LevelRef : IUnknown);
begin
fNode := IXMLNode(pointer(LevelRef));
end;
procedure TROXMLSerializer.EndWriteObject(const aName: string;
aClass : TClass; anObject: TObject; const LevelRef : IUnknown);
begin
fNode := IXMLNode(pointer(LevelRef));
end;
procedure TROXMLSerializer.ReadDateTime(const aName: string; var Ref; ArrayElementId : integer = -1);
var subnode : IXMLNode;
begin
subnode := GetObject(aName, ArrayElementId);
subnode := FindSoapReference(subnode);
if (subnode<>NIL)
then TDateTime(Ref) := SOAPDateTimeToDateTime(GetXMLTextValue(subnode))
else TDateTime(Ref) := 0;
//else RaiseError(err_ParameterNotFound, [aName]);
end;
procedure TROXMLSerializer.ReadEnumerated(const aName: string;
anEnumTypeInfo: PTypeInfo; var Ref; ArrayElementId : integer = -1);
var subnode : IXMLNode;
s, lTypeName : string;
lIndexInEnum: Integer;
begin
subnode := GetObject(aName, ArrayElementId);
subnode := FindSoapReference(subnode);
if (subnode<>NIL)
then begin
s := GetXMLTextValue(subnode);
lIndexInEnum := GetEnumValue(anEnumTypeInfo, s);
if lIndexInEnum = -1 then begin
lIndexInEnum := GetEnumValue(anEnumTypeInfo, anEnumTypeInfo.Name+'_'+s);
if lIndexInEnum = -1 then begin
lTypeName := anEnumTypeInfo^.Name;
if anEnumTypeInfo = typeinfo(Boolean) then begin
if s = '1' then begin
byte(Ref) := 1;
exit;
end
else if s = '0' then begin
byte(Ref) := 0;
exit;
end;
end;
RaiseError(Format('The value "-1" for parameter "%s" of "%s" type is invalid', [aName, lTypeName]));
end;
end;
byte(Ref) := lIndexInEnum;
end else begin
byte(Ref) := 0;
end;
//else RaiseError(err_ParameterNotFound, [aName]);
end;
procedure TROXMLSerializer.ReadDouble(const aName: string;
aFloatType: TFloatType; var Ref; ArrayElementId : integer = -1);
var
subnode : IXMLNode;
text: string;
begin
subnode := GetObject(aName, ArrayElementId);
subnode := FindSoapReference(subnode);
if (subnode<>NIL) then begin
text := GetXMLTextValue(subnode);
{$IFNDEF DELPHI7UP}
if DecimalSeparator <> '.' then
ReplaceChar(text, ['.'], DecimalSeparator);
{$ENDIF}
case aFloatType of
ftSingle : single(Ref) := SOAPStrToFloat(text);
ftDouble : double(Ref) := SOAPStrToFloat(text);
ftExtended : extended(Ref) := SOAPStrToFloat(text);
ftComp : comp(Ref) := SOAPStrToFloat(text);
ftCurr : currency(Ref) := SOAPStrToFloat(text);
end;
end else begin
case aFloatType of
ftSingle : single(Ref) := 0;
ftDouble : double(Ref) := 0;
ftExtended : extended(Ref) := 0;
ftComp : comp(Ref) := 0;
ftCurr : currency(Ref) := 0;
end;
end;
//else RaiseError(err_ParameterNotFound, [aName]);
end;
procedure TROXMLSerializer.ReadInt64(const aName: string; var Ref; ArrayElementId : integer = -1);
var subnode : IXMLNode;
begin
subnode := GetObject(aName, ArrayElementId);
subnode := FindSoapReference(subnode);
if (subnode<>NIL)
then int64(Ref) := StrToInt64(GetXMLTextValue(subnode))
else int64(Ref) := int64(0);
//else RaiseError(err_ParameterNotFound, [aName]);
end;
procedure TROXMLSerializer.ReadInteger(const aName: string;
anOrdType: TOrdType; var Ref; ArrayElementId : integer = -1);
var subnode : IXMLNode;
begin
subnode := GetObject(aName, ArrayElementId);
subnode := FindSoapReference(subnode);
if (subnode<>NIL) then
case anOrdType of
otSByte,
otUByte : byte(Ref) := StrToInt(GetXMLTextValue(subnode));
otSWord,
otUWord : word(Ref) := StrToInt(GetXMLTextValue(subnode));
otSLong,
otULong : integer(Ref) := StrToInt(GetXMLTextValue(subnode));
end
else
case anOrdType of
otSByte,
otUByte : byte(Ref) := 0;
otSWord,
otUWord : word(Ref) := 0;
otSLong,
otULong : integer(Ref) := 0;
end
//else RaiseError(err_ParameterNotFound, [aName]);
end;
procedure TROXMLSerializer.ReadUTF8String(const aName: string; var Ref; ArrayElementId : integer = -1; iMaxLength:integer=-1);
var subnode : IXMLNode;
begin
subnode := GetObject(aName, ArrayElementId);
subnode := FindSoapReference(subnode);
if (subnode<>NIL) then
string(Ref) := GetXMLTextValue(subnode)
else
string(Ref) := '';
//else RaiseError(err_ParameterNotFound, [aName]);
end;
procedure TROXMLSerializer.ReadWideString(const aName: string; var Ref; ArrayElementId : integer = -1; iMaxLength:integer=-1);
var subnode : IXMLNode;
begin
subnode := GetObject(aName, ArrayElementId);
subnode := FindSoapReference(subnode);
if (subnode<>NIL) then
widestring(Ref) := GetXMLTextValue(subnode)
else
widestring(Ref) := '';
//else RaiseError(err_ParameterNotFound, [aName]);
end;
procedure TROXMLSerializer.WriteDateTime(const aName: string; const Ref; ArrayElementId : integer = -1);
var newnode : IXMLNode;
begin
newnode := AddXMLChildNode(fNode, Unprefix(aName));
if not (xsoSendUntyped in SerializationOptions) then
AddXMLAttribute(newnode, 'xsi:type', 'xsd:dateTime');
AddXMLTextValue(newnode, DateTimeToSOAPDateTime(TDateTime(Ref)));
end;
procedure TROXMLSerializer.WriteEnumerated(const aName: string;
anEnumTypeInfo: PTypeInfo; const Ref; ArrayElementId : integer = -1);
var newnode : IXMLNode;
isbool : boolean;
val : string;
lEnumName: String;
begin
newnode := AddXMLChildNode(fNode, Unprefix(aName));
isbool := (anEnumTypeInfo.Name='Boolean');
lEnumName := anEnumTypeInfo^.Name;
if not (xsoSendUntyped in SerializationOptions) then begin
if isbool
then AddXMLAttribute(newnode, 'xsi:type', 'xsd:boolean')
else AddXMLAttribute(newnode, 'xsi:type', ns_Custom+':'+lEnumName);
end;
val := GetEnumName(anEnumTypeInfo, Ord(byte(Ref)));
if (Length(val) > Length(lEnumName) + 2) and
(Copy(val, 1, Length(lEnumName) + 1) = lEnumName + '_') then begin
val := Copy(val, Length(lEnumName) + 2, MaxInt);
end;
if isbool then val := LowerCase(val);
AddXMLTextValue(newnode, val); // TODO: check enums bigger than a byte!
end;
procedure TROXMLSerializer.WriteDouble(const aName: string;
aFloatType: TFloatType; const Ref; ArrayElementId : integer = -1);
var src : pointer;
text, dtype : string;
newnode : IXMLNode;
begin
src := @Ref;
case aFloatType of
ftSingle : begin
text := FloatToStr(single(src^){$IFDEF DELPHI7UP},SOAPFormatSettings{$ENDIF});
{$IFNDEF DELPHI7UP}text := StringReplace(text, DecimalSeparator, '.', []);{$ENDIF}
dtype := 'float';
end;
ftDouble : begin
text := FloatToStr(double(src^){$IFDEF DELPHI7UP},SOAPFormatSettings{$ENDIF});
{$IFNDEF DELPHI7UP}text := StringReplace(text, DecimalSeparator, '.', []);{$ENDIF}
dtype := 'double';
end;
ftExtended : begin
text := FloatToStr(extended(src^){$IFDEF DELPHI7UP},SOAPFormatSettings{$ENDIF});
{$IFNDEF DELPHI7UP}text := StringReplace(text, DecimalSeparator, '.', []);{$ENDIF}
dtype := 'double';
end;
ftComp : begin
text := FloatToStr(comp(src^){$IFDEF DELPHI7UP},SOAPFormatSettings{$ENDIF});
{$IFNDEF DELPHI7UP}text := StringReplace(text, DecimalSeparator, '.', []);{$ENDIF}
dtype := 'double';
end;
ftCurr : begin
text := FloatToStr(currency(src^){$IFDEF DELPHI7UP},SOAPFormatSettings{$ENDIF});
{$IFNDEF DELPHI7UP}text := StringReplace(text, DecimalSeparator, '.', []);{$ENDIF}
dtype := 'double';
end;
end;
newnode := AddXMLChildNode(fNode, Unprefix(aName));
if not (xsoSendUntyped in SerializationOptions) then
AddXMLAttribute(newnode, 'xsi:type', 'xsd:'+dtype);
AddXMLTextValue(newnode, text);
end;
procedure TROXMLSerializer.WriteInt64(const aName: string; const Ref; ArrayElementId : integer = -1);
var src : pointer;
text : string;
newnode : IXMLNode;
begin
src := @Ref;
text := IntToStr(int64(src^));
newnode := AddXMLChildNode(fNode, Unprefix(aName));
if not (xsoSendUntyped in SerializationOptions) then
AddXMLAttribute(newnode, 'xsi:type', 'xsd:long');
AddXMLTextValue(newnode, text);
end;
procedure TROXMLSerializer.WriteInteger(const aName: string;
anOrdType: TOrdType; const Ref; ArrayElementId : integer = -1);
var src : pointer;
text, dtype : string;
newnode : IXMLNode;
begin
src := @Ref;
case anOrdType of
otSByte : begin
text := IntToStr(shortint(src^));
dtype := 'byte';
end;
otUByte : begin
text := IntToStr(byte(src^));
dtype := 'unsignedByte';
end;
otSWord : begin
text := IntToStr(smallint(src^));
dtype := 'short';
end;
otUWord : begin
text := IntToStr(word(src^));
dtype := 'unsignedShort';
end;
otSLong : begin
text := IntToStr(integer(src^));
dtype := 'int';
end;
otULong : begin
text := IntToStr(integer(src^));
dtype := 'unsignedInt';
end;
end;
newnode := AddXMLChildNode(fNode, Unprefix(aName));
if not (xsoSendUntyped in SerializationOptions) then
AddXMLAttribute(newnode, 'xsi:type', 'xsd:'+dtype);
AddXMLTextValue(newnode, text);
end;
procedure TROXMLSerializer.WriteUTF8String(const aName: string; const Ref; ArrayElementId : integer = -1);
var newnode : IXMLNode;
begin
newnode := AddXMLChildNode(fNode, Unprefix(aName));
if not (xsoSendUntyped in SerializationOptions) then
AddXMLAttribute(newnode, 'xsi:type', 'xsd:string');
AddXMLTextValue(newnode, string(Ref));
end;
procedure TROXMLSerializer.WriteWideString(const aName: string; const Ref; ArrayElementId : integer = -1);
var newnode : IXMLNode;
begin
newnode := AddXMLChildNode(fNode, Unprefix(aName));
if not (xsoSendUntyped in SerializationOptions) then
AddXMLAttribute(newnode, 'xsi:type', 'xsd:string');
AddXMLTextValue(newnode, WideString(Ref));
newnode.Value := newnode.Value;
end;
procedure TROXMLSerializer.BeginReadObject(const aName: string;
aClass : TClass; var anObject: TObject; var LevelRef : IUnknown; var IsValidType : boolean; ArrayElementId : integer = -1);
var cnt : integer;
lNilAttr, hrefattr : IXMLNode;
id : string;
clsnme, namespc, clstype : string;
lActualClass : TROComplexTypeClass;
begin
inherited;
if fRespNode = nil then
fRespNode := fNode;
LevelRef := fNode;
fnode := GetObject(aName, ArrayElementId);
fnode := FindSoapReference(fnode);
if (fNode=NIL) then begin
// No such node found
anObject := NIL;
Exit;
end;
lNilAttr := fNode.GetAttributeByName(tag_Nil);
if Assigned(lNilAttr) and (lNilAttr.Value = tag_NilValue) then begin
anObject := NIL;
Exit;
end;
hrefattr := fNode.GetAttributeByName(tag_HRef);
if (hrefattr<>NIL) then begin
id := Copy(hrefattr.Value, 2, Length(hrefattr.Value)); // Removes the '#'
fNode := FindChildNodeByAttribute(BodyNode, tag_Id, id);
if fNode = nil then
fNode := FindChildNodeByAttribute(fRespNode, tag_Id, id);
end;
if aClass.InheritsFrom(TStream) then begin
anObject := TROBinaryMemoryStream.Create;
IsValidType := TRUE;
end
else if aClass.InheritsFrom(EROException) then begin
// Does nothing here
IsValidType := TRUE;
end
else if IsValidType then begin
clstype := VarToStr(fNode.GetAttributeValue('xsi:type', aClass.ClassName));
if (clstype = dts_Array) or (clstype = dts_Array2) then begin
//For arrays this attribute does't contain actual class name.
anObject := TROComplexTypeClass(aClass).Create;
end else begin
if xsoIgnoreStructureType in fSerializationOptions then begin
anObject := TROComplexTypeClass(aClass).Create;
end
else begin
SplitName(clstype, namespc, clsnme);
lActualClass := FindROClass(clsnme);
if not Assigned(lActualClass) then RaiseError(err_UnknownClassInStream,[clsnme]);
if not lActualClass.InheritsFrom(aClass) then RaiseError(err_UnexpectedClassInStream,[clsnme,aClass.ClassName]);
anObject := lActualClass.Create;
end;
end;
if (anObject is TROArray) then begin
cnt := fNode.ChildrenCount;
TROArray(anObject).Resize(cnt);
end;
end;
end;
function GetNamespace(aClass: TClass; aInst: Tobject): string;
var
i: Integer;
begin
if aInst is TROComplexType then aClass := aInst.ClassType;
if (aClass <> nil) and (aClass.InheritsFrom(TROComplexType)) or (aClass = TROComplexType) then begin
for i := TROComplexTypeClass(aClass).GetAttributeCount -1 downto 0 do begin
if TROComplexTypeClass(aClass).GetAttributeName(i) = 'ImportedFromNamespace' then begin
result := TROComplexTypeClass(aClass).GetAttributeValue(i);
exit;
end;
end;
end;
result := '';
end;
procedure TROXMLSerializer.BeginWriteObject(const aName: string;
aClass : TClass; anObject: TObject; var LevelRef : IUnknown; var IsValidType : boolean; out IsAssigned:Boolean; ArrayElementId : integer = -1);
var id : string;
refnode : IXMLNode;
xsiattr : IXMLNode;
lName: String;
begin
lName := Unprefix(aName);
inherited BeginWriteObject(lName, aClass, anObject, LevelRef, IsValidType, IsAssigned, ArrayElementId);
if fRespNode = nil then
fRespNode := fNode;
IsAssigned := Assigned(anObject);
if aClass.InheritsFrom(TStream) then begin
LevelRef := fNode;
fNode := AddXMLChildNode(fNode, lName);
if Assigned(anObject) then begin
if not (xsoSendUntyped in SerializationOptions) then
xsiattr := AddXMLAttribute(fNode, 'xsi:type', 'xsd:'+dts_base64Binary);
IsValidType := TRUE;
end
else begin
AddXMLAttribute(fNode, tag_Nil, tag_NilValue);
end;
end
else if IsValidType then begin // It is then a TROComplexType
LevelRef := fNode;
if ((aClass.InheritsFrom(TROArray) and (xsoWriteMultiRefArray in SerializationOptions)) or
(not aClass.InheritsFrom(TROArray)) and (xsoWriteMultiRefObject in SerializationOptions)) then begin
if Assigned(anObject) then begin
id := IntToStr(fMaxRef);
Inc(fMaxRef);
{refnode := fNode;
fNode := AddXMLChildNode(fRespNode, ns_Custom+':'+anObject.ClassName);
AddXMLAttribute(fNode, tag_Id, id);
refnode := AddXMLChildNode(refnode, lName);
AddXMLAttribute(refnode, tag_href, '#'+id);}
if xsoExternalTypesAsReferences in SerializationOptions then
refnode := AddXMLChildNode(fNode, lName, GetNamespace(aClass, AnObject))
else
refnode := AddXMLChildNode(fNode, lName);
AddXMLAttribute(refnode, tag_href, '#'+id);
fNode := AddXMLChildNode(BodyNode, ns_Custom+':'+anObject.ClassName);
AddXMLAttribute(fNode, tag_Id, id);
if not (xsoSendUntyped in SerializationOptions) then
if (anObject is TROArray) then begin
xsiattr := AddXMLAttribute(fNode, 'xsi:type', dts_Array);
//id := ns_Custom+':'+anObject.ClassName+'['+IntToStr(TROArray(anObject).Count)+']';
id := TypeInfoNameToSOAPType(TROArray(anObject).GetItemType)+'['+IntToStr(TROArray(anObject).Count)+']';
AddXMLAttribute(fNode, 'SOAP-ENC:arrayType', id);
end
else xsiattr := AddXMLAttribute(fNode, 'xsi:type', ns_Custom+':'+anObject.ClassName);
end
else begin
if xsoExternalTypesAsReferences in SerializationOptions then
refnode := AddXMLChildNode(fNode, lName, GetNamespace(aClass, anObject))
else
refnode := AddXMLChildNode(fNode, lName);
AddXMLAttribute(refnode, tag_Nil, tag_NilValue);
end;
end
else begin
if xsoExternalTypesAsReferences in SerializationOptions then
fnode := AddXMLChildNode(fNode, lName, GetNamespace(aClass, anObject))
else
fNode := AddXMLChildNode(fNode, lName);
if not (xsoSendUntyped in SerializationOptions) then begin
if (anObject is TROArray) then begin
xsiattr := AddXMLAttribute(fNode, 'xsi:type', dts_Array);
//id := ns_Custom+':'+anObject.ClassName+'['+IntToStr(TROArray(anObject).Count)+']';
id := TypeInfoNameToSOAPType(TROArray(anObject).GetItemType)+'['+IntToStr(TROArray(anObject).Count)+']';
AddXMLAttribute(fNode, 'SOAP-ENC:arrayType', id);
end
else xsiattr := AddXMLAttribute(fNode, 'xsi:type', ns_Custom+':'+anObject.ClassName);
end
end
end;
//if (fNode<>NIL) and not IsAssigned
//then AddXMLAttribute(fNode, 'xsi:nil', 'true');
end;
procedure TROXMLSerializer.CustomReadObject(const aName: string;
aClass : TClass; var Ref; ArrayElementId: integer);
var obj : TObject absolute Ref;
ss : TStringStream;
begin
inherited;
if Assigned(obj) then begin
if (obj is TStream) then begin
ss := TStringStream.Create(fNode.Value);
try
DecodeStream(ss, TMemoryStream(obj));
TMemoryStream(obj).Position := 0;
finally
ss.Free;
end;
end;
end;
end;
procedure TROXMLSerializer.CustomWriteObject(const aName: string;
aClass : TClass; const Ref; ArrayElementId : integer = -1);
var obj : TObject absolute Ref;
ss : TStringStream;
begin
inherited CustomWriteObject(Unprefix(aName), aClass, Ref, ArrayElementId);
if Assigned(obj) then begin
if (obj is TStream) then begin
ss := TStringStream.Create('');
try
TStream(obj).Position := 0;
EncodeStream(TStream(obj), ss);
AddXMLTextValue(fNode, ss.DataString);
finally
ss.Free;
end;
end;
end;
end;
function TROXMLSerializer.BodyNode: IXMLNode;
begin
if (fBodyNode=NIL) then fBodyNode := FindParentNode(fNode, tag_Body, TRUE);
result := fBodyNode;
end;
procedure TROXMLSerializer.ReadVariant(const aName: string; var Ref;
ArrayElementId: integer);
var s,
vartypestr,
varnamespcstr : string;
subnode : IXMLNode;
lIntegerValue:integer;
{$IFNDEF DELPHI5}
lShortIntValue:shortint;
lSmallIntValue: Smallint;
//lInt64Value:Int64;
{$ENDIF DELPHI5}
lByteValue:byte;
lBoolValue: boolean;
lDoubleValue:double;
lSingleValue:single;
//lCurrencyValue:currency;
lWordValue : word;
lStringValue: widestring;
lDateTimeValue : TDateTime;
begin
subnode := GetObject(aName, ArrayElementId);
subnode := FindSoapReference(subnode);
if (subnode<>NIL) then begin
// Determines the type of the value, if specified. Defaults to string.
s := subnode.GetAttributeValue('xsi:empty', '');
if s = '1' then begin
Variant(ref) := Unassigned;
exit;
end;
s := subnode.GetAttributeValue('xsi:null', '');
if s = '1' then begin
Variant(ref) := null
end
else begin
s := subnode.GetAttributeValue('xsi:type', 'xsd:string');
SplitName(s, varnamespcstr, vartypestr);
// Returns the right type of variant
if SameText(vartypestr, 'string') then begin
ReadWideString(aName, lStringValue, ArrayElementId);
Variant(Ref) := lStringValue;
end
else if SameText(vartypestr, 'float') then begin
ReadDouble(aName, ftSingle, lSingleValue, ArrayElementId);
Variant(Ref) := lSingleValue;
end
else if SameText(vartypestr, 'double') then begin
ReadDouble(aName, ftDouble, lDoubleValue, ArrayElementId);
Variant(Ref) := lDoubleValue;
end
else if SameText(vartypestr, 'byte') then begin
ReadInteger(aName, otSByte, lShortIntValue, ArrayElementId);
Variant(Ref) := lShortIntValue;
end
else if SameText(vartypestr, 'unsignedByte') then begin
ReadInteger(aName, otUByte, lByteValue, ArrayElementId);
Variant(Ref) := lByteValue;
end
else if SameText(vartypestr, 'short') then begin
ReadInteger(aName, otSWord, lSmallIntValue, ArrayElementId);
Variant(Ref) := lSmallIntValue;
end
else if SameText(vartypestr, 'unsignedShort') then begin
ReadInteger(aName, otUWord, lWordValue, ArrayElementId);
Variant(Ref) := lWordValue;
end
else if (SameText(vartypestr, 'int') or SameText(vartypestr, 'unsignedInt')) then begin
ReadInteger(aName, otSLong, lIntegerValue, ArrayElementId);
Variant(Ref) := lIntegerValue;
end
else if SameText(vartypestr, 'boolean') then begin
ReadEnumerated(aName, TypeInfo(boolean), lBoolValue, ArrayElementId);
Variant(Ref) := lBoolValue;
end
else if SameText(vartypestr, 'dateTime') then begin
ReadDateTime(aName, lDateTimeValue, ArrayElementId);
Variant(Ref) := lDateTimeValue;
end
end;
end
else RaiseError(err_ParameterNotFound, [aName]);
end;
procedure TROXMLSerializer.WriteVariant(const aName: string; const Ref;
ArrayElementId: integer);
var vtype : integer;
varvalue : Variant;
lIntegerValue:integer;
{$IFNDEF DELPHI5}
lShortIntValue:shortint;
lSmallIntValue: Smallint;
//lInt64Value:Int64;
{$ENDIF DELPHI5}
lByteValue:byte;
lBoolValue: boolean;
lDoubleValue:double;
lSingleValue:single;
lCurrencyValue:currency;
lWideString: widestring;
newnode: IXMLNode;
begin
varvalue := Variant(Ref);
vtype := VarType(Variant(Ref));
{ Simple types }
case vtype of
varEmpty:
begin
newnode := AddXMLChildNode(fNode, Unprefix(aName));
AddXMLAttribute(newnode, 'xsi:empty', '1');
end;
varNull,varError:begin
newnode := AddXMLChildNode(fNode, Unprefix(aName));
AddXMLAttribute(newnode, 'xsi:null', '1');
end;
{$IFNDEF DELPHI5}
varShortInt:begin { 2, 10, 12 }
lShortIntValue := varvalue;
WriteInteger(aName, otSByte, lShortIntValue, ArrayElementId);
end;
varSmallInt,
varWord : begin
lSmallIntValue := varvalue;
WriteInteger(aName, otSWord, lSmallIntValue, ArrayElementId); // Suspicious... This might be wrong
end;
{$ENDIF DELPHI5}
{$IFNDEF DELPHI5}varLongWord,{$ENDIF DELPHI5}
varInteger:begin { 3, 13 }
lIntegerValue := varvalue;
WriteInteger(aName, otSLong, lIntegerValue, ArrayElementId);
end;
varSingle:begin { 4 }
lSingleValue := varvalue;
WriteDouble(aName, ftSingle, lSingleValue, ArrayElementId);
end;
varDouble:begin { 5 }
lDoubleValue := varvalue;
WriteDouble(aName, ftDouble, lDoubleValue, ArrayElementId);
end;
varDate:begin { 7 } // This must be handled differently in SOAP!
lDoubleValue := varvalue;
WriteDateTime(aName, lDoubleValue, ArrayElementId);
end;
varCurrency:begin { 6 }
lCurrencyValue := varvalue;
WriteDouble(aName, ftCurr, lCurrencyValue, ArrayElementId);
end;
varBoolean:begin { B }
lBoolValue:= varvalue;
WriteEnumerated(aName, TypeInfo(boolean), lBoolValue, ArrayElementId);
end;
varByte:begin { 11 }
lByteValue := varvalue;
WriteInteger(aName, otUByte, lByteValue, ArrayElementId);
end;
{$IFNDEF DELPHI5}
(* varInt64:begin { 14 }
NotSupported('');
end;*)
{$ENDIF DELPHI5}
varOleStr,varString:begin { 8, 100 }
lWideString := varvalue;
WriteWideString(aName, lWideString, ArrayElementId);
end;
else NotSupported(Format(err_UnsupportedVariantType, [VarType(varvalue)]));
end;
end;
function TROXMLSerializer.GetArrayElementName(
anItemType: PTypeInfo; anItemReference: pointer): string;
var tn: string;
begin
case anItemType.Kind of
tkClass : begin
if anItemReference = nil then result := anItemType^.Name else result := TObject(anItemReference).ClassName;
end;
tkVariant :
begin
tn := VarTypeNameToSOAPType(VarType(Variant(anItemReference^)));
result := Copy(tn, Pos(':', tn)+1, MaxInt);
end;
else begin
tn := TypeInfoNameToSOAPType(anItemType);
result := Copy(tn, Pos(':', tn)+1, MaxInt);
end;
end;
end;
function TROXMLSerializer.GetRecordStrictOrder: Boolean;
begin
Result := xsoStrictStructureFieldOrder in fSerializationOptions;
end;
function TROXMLSerializer.FindSoapReference(subnode: IXMLNode): IXMLNode;
var
hrefattr: IXMLNode;
id: string;
begin
result := subnode;
if subnode = nil then
exit;
hrefattr := subnode.GetAttributeByName(tag_HRef);
if (hrefattr<>NIL) then begin
id := Copy(hrefattr.Value, 2, Length(hrefattr.Value)); // Removes the '#'
while subnode <> nil do begin
result := FindChildNodeByAttribute(subnode, tag_Id, id);
if result <> nil then break;
subnode := subnode.Parent;
end;
end;
end;
function TROXMLSerializer.GetObject(const aName: string; ArrayElementId : integer): IXMLNode;
begin
if (ArrayElementId>=0)
then result := fNode.Children[ArrayElementId]
else result := FindChildNode(fNode, Unprefix(aName), ArrayElementId,TRUE);
end;
procedure TROXMLSerializer.ReadXml(const aName: String; var Ref;
ArrayElementId: Integer);
var
w: WideString;
doc: IXMLDocument;
node: IXMLNode;
begin
node := GetObject(aName, ArrayElementID);
if (xsoEncodedXML in SerializationOptions) or (node = nil) or (node.FirstChild = nil) or (Node.FirstChild.name = '#text') then begin
ReadWideString(aName, w, ArrayElementId);
if w = '' then
IXMLNode(Ref) := nil
else begin
doc := NewROXmlDocument;
doc.New;
doc.XML := w;
IXMLNode(Ref) := doc.DocumentNode;
end;
end else begin
if node = nil then IXMLNode(Ref) := nil else begin
node := Node.FirstChild;
if node = nil then begin
IXMLNode(Ref) := nil;
end else begin
doc := NewROXmlDocument;
doc.New;
doc.XML := node.XML;
IXMLNode(Ref) := doc.DocumentNode;
end;
end;
end;
end;
procedure TROXMLSerializer.WriteXml(const aName: String; const Ref;
ArrayElementId: Integer);
var
w: WideString;
newnode: IXMLNode;
begin
if (xsoEncodedXML in SerializationOptions) then begin
if IXMLNode(Ref) = nil then
w := ''
else
w := IXMLNode(Ref).XML;
WriteWideString(aName, w, ArrayElementId);
end else begin
newnode := AddXMLChildNode(fNode, Unprefix(aName));
if IXMLNode(Ref) <> nil then begin
newnode.AddXml(IXMLNode(Ref).XML);
end;
end;
end;
procedure TROXMLSerializer.ReadDecimal(const aName: String; var Ref;
ArrayElementId: Integer);
var
s: string;
begin
ReadUTF8String(aName, s, ArrayElementId);
if DecimalSeparator <> '.' then s := StringReplace(s, '.', DecimalSeparator, []);
Variant(Ref) := BCDToVariant(StrToBcd(s));
end;
procedure TROXMLSerializer.ReadGuid(const aName: String; var Ref;
ArrayElementId: Integer);
var
s: string;
begin
ReadUTF8String(aName, s, ArrayElementId);
if Copy(s,1,1) <> '{' then s := '{'+s+'}';
string(Ref) := s;
end;
procedure TROXMLSerializer.WriteDecimal(const aName: String; const Ref;
ArrayElementId: Integer);
var
s: string;
begin
s := BcdToStr(VariantToBCD(variant(Ref)));
if DecimalSeparator <> '.' then s := StringReplace(s, DecimalSeparator, '.', []); // delphi has no way to format a bcd with a specific format
WriteUTF8String(aName, s, ArrayElementId);
end;
procedure TROXMLSerializer.WriteGuid(const aName: String; const Ref;
ArrayElementId: Integer);
var
s: string;
begin
s := GuidToString(StringToGUID(string(Ref)));
s := copy(s,2,length(s) -2); // remove curlies
WriteUTF8String(aName, s, ArrayElementId);
end;
procedure TROXMLSerializer.ReadBinary(const aName: string; var Ref;
ArrayElementId: integer);
var
obj : Binary absolute Ref;
ss : TStringStream;
LevelRef: IXMLNode;
begin
LevelRef := fNode;
try
if FindNode(aName, ArrayElementId) then begin
if not Assigned(obj) then obj:= Binary.Create;
ss := TStringStream.Create(fNode.Value);
try
obj.Clear;
DecodeStream(ss, TMemoryStream(obj));
TMemoryStream(obj).Position := 0;
finally
ss.Free;
end;
end
else
Obj := nil;
finally
fNode := LevelRef;
end;
end;
procedure TROXMLSerializer.WriteBinary(const aName: string; const Ref;
ArrayElementId: integer);
var
obj : Binary absolute Ref;
ss : TStringStream;
LevelRef: IXMLNode;
begin
LevelRef := fNode;
//BeginWriteObject
{ TODO -oek : BeginWriteObject }
fNode := AddXMLChildNode(fNode, Unprefix(aName));
if Assigned(obj) then begin
if not (xsoSendUntyped in SerializationOptions) then AddXMLAttribute(fNode, 'xsi:type', 'xsd:'+dts_base64Binary);
ss := TStringStream.Create('');
try
obj.Position := 0;
EncodeStream(obj, ss);
AddXMLTextValue(fNode, ss.DataString);
finally
ss.Free;
end;
end
else
AddXMLAttribute(fNode, tag_Nil, tag_NilValue);
fNode := LevelRef;
end;
procedure TROXMLSerializer.WriteArray(const aName: string; const Ref;
ArrayElementId: integer);
var
obj : TROArray absolute Ref;
LevelRef: IXmlNode;
id : string;
refnode : IXMLNode;
xsiattr : IXMLNode;
lName: String;
begin
LevelRef := fNode;
try
lName := Unprefix(aName);
if fRespNode = nil then fRespNode := fNode;
LevelRef := fNode;
if (xsoWriteMultiRefArray in SerializationOptions) then begin
if Assigned(obj) then begin
id := IntToStr(fMaxRef);
Inc(fMaxRef);
refnode := AddXMLChildNode(fNode, lName);
AddXMLAttribute(refnode, tag_href, '#'+id);
fNode := AddXMLChildNode(BodyNode, ns_Custom+':'+obj.ClassName);
AddXMLAttribute(fNode, tag_Id, id);
if not (xsoSendUntyped in SerializationOptions) then begin
xsiattr := AddXMLAttribute(fNode, 'xsi:type', dts_Array);
id := TypeInfoNameToSOAPType(obj.GetItemType)+'['+IntToStr(obj.Count)+']';
AddXMLAttribute(fNode, 'SOAP-ENC:arrayType', id);
end;
end
else begin
refnode := AddXMLChildNode(fNode, lName);
AddXMLAttribute(refnode, tag_Nil, tag_NilValue);
end;
end
else begin
fNode := AddXMLChildNode(fNode, lName);
if not (xsoSendUntyped in SerializationOptions) then begin
xsiattr := AddXMLAttribute(fNode, 'xsi:type', dts_Array);
id := TypeInfoNameToSOAPType(obj.GetItemType)+'['+IntToStr(obj.Count)+']';
AddXMLAttribute(fNode, 'SOAP-ENC:arrayType', id);
end
end;
if Assigned(Obj) then Obj.WriteComplex(Self);
finally
fNode := IXMLNode(LevelRef);
end;
end;
procedure TROXMLSerializer.WriteStruct(const aName: string; const Ref;
ArrayElementId: integer);
var
obj : TROComplexType absolute Ref;
LevelRef: IXmlNode;
id : string;
refnode : IXMLNode;
xsiattr : IXMLNode;
lName: String;
begin
LevelRef:=fNode;
try
lName := Unprefix(aName);
if fRespNode = nil then fRespNode := fNode;
LevelRef := fNode;
if (xsoWriteMultiRefObject in SerializationOptions) then begin
if Assigned(obj) then begin
id := IntToStr(fMaxRef);
Inc(fMaxRef);
refnode := AddXMLChildNode(fNode, lName);
AddXMLAttribute(refnode, tag_href, '#'+id);
fNode := AddXMLChildNode(BodyNode, ns_Custom+':'+obj.ClassName);
AddXMLAttribute(fNode, tag_Id, id);
if not (xsoSendUntyped in SerializationOptions) then
xsiattr := AddXMLAttribute(fNode, 'xsi:type', ns_Custom+':'+obj.ClassName);
end
else begin
refnode := AddXMLChildNode(fNode, lName);
AddXMLAttribute(refnode, tag_Nil, tag_NilValue);
end;
end
else begin
fNode := AddXMLChildNode(fNode, lName);
if not (xsoSendUntyped in SerializationOptions) then
xsiattr := AddXMLAttribute(fNode, 'xsi:type', ns_Custom+':'+obj.ClassName);
end;
if Assigned(Obj) then Obj.WriteComplex(Self);
finally
fNode := LevelRef;
end;
end;
function TROXMLSerializer.ReadArray(const aName: string; aClass: TClass;
var Ref; ArrayElementId: integer): Boolean;
var
obj : TROArray absolute Ref;
LevelRef: IXmlNode;
cnt : integer;
lNilAttr, hrefattr : IXMLNode;
id : string;
clsnme, namespc, clstype : string;
lActualClass : TROArrayClass;
begin
Result := False;
LevelRef := fNode;
try
if fRespNode = nil then fRespNode := fNode;
fnode := GetObject(aName, ArrayElementId);
fnode := FindSoapReference(fnode);
if (fNode=NIL) then begin
// No such node found
Obj := NIL;
Exit;
end;
lNilAttr := fNode.GetAttributeByName(tag_Nil);
if Assigned(lNilAttr) and (lNilAttr.Value = tag_NilValue) then begin
obj := NIL;
Exit;
end;
hrefattr := fNode.GetAttributeByName(tag_HRef);
if (hrefattr<>NIL) then begin
id := Copy(hrefattr.Value, 2, Length(hrefattr.Value)); // Removes the '#'
fNode := FindChildNodeByAttribute(BodyNode, tag_Id, id);
if fNode = nil then fNode := FindChildNodeByAttribute(fRespNode, tag_Id, id);
end;
clstype := VarToStr(fNode.GetAttributeValue('xsi:type', aClass.ClassName));
if (clstype = dts_Array) or (clstype = dts_Array2) then begin
//For arrays this attribute does't contain actual class name.
obj := TROArrayClass(aClass).Create;
end else begin
if xsoIgnoreStructureType in fSerializationOptions then begin
obj := TROArrayClass(aClass).Create;
end
else begin
SplitName(clstype, namespc, clsnme);
lActualClass := TROArrayClass(FindROClass(clsnme));
if not Assigned(lActualClass) then RaiseError(err_UnknownClassInStream,[clsnme]);
if not lActualClass.InheritsFrom(aClass) then RaiseError(err_UnexpectedClassInStream,[clsnme,aClass.ClassName]);
Obj := lActualClass.Create;
end;
end;
cnt := fNode.ChildrenCount;
Obj.Resize(cnt);
obj.ReadComplex(Self);
finally
fNode := LevelRef;
end;
end;
function TROXMLSerializer.ReadStruct(const aName: string; aClass: TClass;
var Ref; ArrayElementId: integer): Boolean;
var
obj : TROComplexType absolute Ref;
LevelRef: IXmlNode;
lNilAttr, hrefattr : IXMLNode;
id : string;
clsnme, namespc, clstype : string;
lActualClass : TROComplexTypeClass;
begin
Result:=False;
LevelRef:=fNode;
try
if fRespNode = nil then fRespNode := fNode;
fnode := GetObject(aName, ArrayElementId);
fnode := FindSoapReference(fnode);
if (fNode=NIL) then begin
// No such node found
obj := NIL;
Exit;
end;
lNilAttr := fNode.GetAttributeByName(tag_Nil);
if Assigned(lNilAttr) and (lNilAttr.Value = tag_NilValue) then begin
obj := NIL;
Exit;
end;
hrefattr := fNode.GetAttributeByName(tag_HRef);
if (hrefattr<>NIL) then begin
id := Copy(hrefattr.Value, 2, Length(hrefattr.Value)); // Removes the '#'
fNode := FindChildNodeByAttribute(BodyNode, tag_Id, id);
if fNode = nil then
fNode := FindChildNodeByAttribute(fRespNode, tag_Id, id);
end;
clstype := VarToStr(fNode.GetAttributeValue('xsi:type', aClass.ClassName));
if (clstype = dts_Array) or (clstype = dts_Array2) then begin
//For arrays this attribute does't contain actual class name.
obj := TROComplexTypeClass(aClass).Create;
end else begin
if xsoIgnoreStructureType in fSerializationOptions then begin
obj := TROComplexTypeClass(aClass).Create;
end
else begin
SplitName(clstype, namespc, clsnme);
lActualClass := FindROClass(clsnme);
if not Assigned(lActualClass) then RaiseError(err_UnknownClassInStream,[clsnme]);
if not lActualClass.InheritsFrom(aClass) then RaiseError(err_UnexpectedClassInStream,[clsnme,aClass.ClassName]);
obj := lActualClass.Create;
end;
end;
Obj.ReadComplex(Self);
finally
fNode := LevelRef;
end;
end;
function TROXMLSerializer.FindNode(const aName: string;
ArrayElementId: integer): Boolean;
var
lNilAttr, hrefattr : IXMLNode;
id : string;
begin
Result:=False;
if fRespNode = nil then fRespNode := fNode;
fnode := FindSoapReference(GetObject(aName, ArrayElementId));
if (fNode=NIL) then Result:=False; // No such node found
lNilAttr := fNode.GetAttributeByName(tag_Nil);
if Assigned(lNilAttr) and (lNilAttr.Value = tag_NilValue) then Exit;
Result := True;
hrefattr := fNode.GetAttributeByName(tag_HRef);
if (hrefattr<>NIL) then begin
id := Copy(hrefattr.Value, 2, Length(hrefattr.Value)); // Removes the '#'
fNode := FindChildNodeByAttribute(BodyNode, tag_Id, id);
if fNode = nil then fNode := FindChildNodeByAttribute(fRespNode, tag_Id, id);
end;
end;
procedure TROXMLSerializer.ReadException(const aName: string; var Ref;
ArrayElementId: integer);
var
obj: EROException absolute Ref;
LevelRef,
lNilAttr, hrefattr : IXMLNode;
id : string;
begin
if fRespNode = nil then fRespNode := fNode;
LevelRef := fNode;
try
fnode := GetObject(aName, ArrayElementId);
fnode := FindSoapReference(fnode);
if (fNode=NIL) then begin
// No such node found
obj := NIL;
Exit;
end;
lNilAttr := fNode.GetAttributeByName(tag_Nil);
if Assigned(lNilAttr) and (lNilAttr.Value = tag_NilValue) then begin
obj := NIL;
Exit;
end;
hrefattr := fNode.GetAttributeByName(tag_HRef);
if (hrefattr<>NIL) then begin
id := Copy(hrefattr.Value, 2, Length(hrefattr.Value)); // Removes the '#'
fNode := FindChildNodeByAttribute(BodyNode, tag_Id, id);
if fNode = nil then fNode := FindChildNodeByAttribute(fRespNode, tag_Id, id);
end;
Obj.ReadException(Self);
finally
fNode := LevelRef;
end;
end;
procedure TROXMLSerializer.WriteException(const aName: string; const Ref;
ArrayElementId: integer);
var
obj: EROException absolute Ref;
LevelRef,
xsiattr : IXMLNode;
begin
if fRespNode = nil then fRespNode := fNode;
LevelRef := fNode;
try
fNode := AddXMLChildNode(fNode, Unprefix(aName));
if not (xsoSendUntyped in SerializationOptions) then
xsiattr := AddXMLAttribute(fNode, 'xsi:type', ns_Custom+':'+obj.ClassName);
if Assigned(obj) then Obj.WriteException(Self);
finally
fNode := LevelRef;
end;
end;
initialization
{$IFDEF DELPHI7UP}
GetLocaleFormatSettings(SOAPLocale,SOAPFormatSettings);
//ToDo: fix this for D6
{$ENDIF}
end.