unit uRODLToWSDL; {----------------------------------------------------------------------------} { RemObjects SDK Library - CodeGen } { } { 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. } {----------------------------------------------------------------------------} {$IFNDEF MSWINDOWS} {$I ../RemObjects.inc} {$ELSE} {$I ..\RemObjects.inc} {$ENDIF} interface uses Classes, uRODL, uROTypes, uROClasses, uROXMLSerializer; const SOAPDataTypes : array[TRODataType] of string = ( 'int', 'dateTime', 'double', 'double', 'string', 'string', 'long', 'boolean', 'anyType', dts_base64Binary, 'any', 'string', 'decimal', 'string', 'dateTime', '???'); type { TRODLToWSDL } TRODLToWSDL = class(TRODLConverter) private fLocation: string; fShowClientId: Boolean; fUseLiteral: Boolean; fUseDocument: Boolean; fTargetEntity, fTargetNamespace: string; fExternalTypesAsReferences: Boolean; fHasXsdData: Boolean; fExternalRefs, // namespace fExternalUrls: TStrings; // uri fXsdTns, fTargetXSD: string; procedure SetLocation(const Value: string); function GetPrefix(const aType, aNs: string): String; procedure WriteEnum(anEnum : TRODLEnum); procedure WriteStruct(const aLibrary: TRODLLibrary; aStruct : TRODLStruct); procedure WriteArray(anArray : TRODLArray); procedure WriteExceptionElement(anException : TRODLException); procedure WriteMessages(aLibrary: TRODLLibrary; aService : TRODLService); procedure WriteExceptionMessage(anException: TRODLException); procedure WriteLiteralParameters(aLibrary: TRODLLibrary; aService : TRODLService); procedure WriteBindings(aLibrary: TRODLLibrary; aService : TRODLService); procedure WritePorts(aLibrary: TRODLLibrary; aService : TRODLService); procedure WriteExceptionParts(aMeth: TRODLOperation); procedure WriteService(aLibrary: TRODLLibrary; aService : TRODLService); function GetAnchestor(aLibrary: TRODLLibrary; aService: TRODLService): TRODLService; procedure WriteAnnotation(aDocString: string; aIndentation: Integer = 0; aNs: string = 'xs:'); procedure WriteDocumentation(aDocString: string; aIndentation: Integer = 0; aNs: string = 'xs:'); function ExtSOAPDataType(aLibrary: TRODLLibrary; const aDataTypeName : string) : string; procedure ResolveExternalReferences(aLibrary: TRODLLibrary); function ReplaceSpecialChars(aText: String): String; protected procedure IntConvert(const aLibrary : TRODLLibrary; const aTargetEntity : string = ''); override; procedure AddExternal(aNode: TRODLEntity); overload; procedure AddExternal(const aNs,aUrl: string); overload; public constructor Create(const aLibraryFile: string; const aTargetEntity: string = ''); overload; override; constructor Create(const aLibrary: TRODLLibrary; const aTargetEntity: string = ''); overload; override; destructor Destroy; override; property TargetXsd: string read fTargetXSD write fTargetXSD; property Location : string read fLocation write SetLocation; property TargetNamespace: string read fTargetNamespace write fTargetNamespace; property ShowClientId : Boolean read fShowClientId write fShowClientId; property UseLiteral : Boolean read fUseLiteral write fUseLiteral; property UseDocument : Boolean read fUseDocument write fUseDocument; property ExternalTypesAsReferences : Boolean read fExternalTypesAsReferences write fExternalTypesAsReferences; end; function SOAPDataType(const aDataTypeName : string; IncludeNamespace : boolean = TRUE) : string; implementation uses SysUtils; function SOAPDataType(const aDataTypeName : string; IncludeNamespace : boolean = TRUE) : string; var dt : TRODataType; begin dt := StrToDataType(aDataTypeName); if (dt=rtUserDefined) then result := aDataTypeName else result := SOAPDataTypes[dt]; if IncludeNamespace then begin if (dt=rtUserDefined) then result := 'tns:'+result else result := ns_Standard+':'+result; end; end; { TRODLToWSDL } const definitions_ns : array[0..5] of string = ('xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" ', 'xmlns:xs="http://www.w3.org/2001/XMLSchema" ', 'name="%s" ', 'xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" ', 'xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" ', 'xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"'); procedure TRODLToWSDL.IntConvert(const aLibrary: TRODLLibrary; const aTargetEntity: string); var s, i: integer; lService: TRODLService; begin if pos(':', fTargetNamespace) = 0 then fTargetNamespace := 'urn:'+fTargetNamespace; fTargetEntity := aTargetEntity; with aLibrary do begin if (aTargetEntity<>'') then begin lService := aLibrary.FindService(aTargetEntity); if (lService <> nil) then if lService.isPrivate then Exit; end else lService := NIL; fExternalRefs.Clear; fExternalUrls.Clear; fXsdTns := ''; if fExternalTypesAsReferences then begin ResolveExternalReferences(aLibrary); end; if fXsdTns = '' then fXsdTns := fTargetNamespace; Write(''); if fTargetXSD <> '' then begin if not fHasXsdData then raise Exception.Create('No xsd by that name'); Write(' fXsdTns then write('xmlns:ns'+IntToStr(i)+'="'+fExternalRefs[i]+'" ', 3); end; Write('>'); end else begin Write(''); WriteAnnotation(aLibrary.Documentation); {Giovanni} // Write types Write('', 3); Write(Format('', [fTargetNamespace]), 6); end; for i := 0 to fExternalRefs.Count -1 do begin if ((fTargetXSD ='') and (fExternalRefs[i] = fTargetNamespace)) or ((fTargetXSD <> '') and (fExternalRefs[i] = fXsdTns)) then Write(Format('',[flocation, fExternalUrls[i]] ), 3) else Write(Format('',[fExternalRefs[i], fLocation, fExternalUrls[i]] ), 3); end; for i := 0 to (EnumCount-1) do WriteEnum(Enums[i]); for i := 0 to (StructCount-1) do WriteStruct(aLibrary, Structs[i]); for i := 0 to (ArrayCount-1) do WriteArray(Arrays[i]); for i := 0 to (ExceptionCount-1) do WriteExceptionElement(Exceptions[i]); if fUseLiteral and fUseDocument then begin if (aTargetEntity<>'') then WriteLiteralParameters(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WriteLiteralParameters(aLibrary, lService); end; if fShowClientId then begin Write('', 3); Write('', 6); Write('', 9); Write('', 6); Write('', 9); Write('', 6); Write('', 3); end; end; Write('', 6); if fTargetXSD = '' then begin Write('', 3); // Writes messages if (aTargetEntity<>'') then WriteMessages(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WriteMessages(aLibrary, lService); end; for s := 0 to aLibrary.ExceptionCount -1 do begin WriteExceptionMessage(aLibrary.Exceptions[s]); end; if fShowClientId and fUseLiteral and fUseDocument then begin Write('', 3); Write('', 3); Write('', 3); end; // Writes port and operations if (aTargetEntity<>'') then WritePorts(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WritePorts(aLibrary, lService); end; // Write bindings if (aTargetEntity<>'') then WriteBindings(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WriteBindings(aLibrary, lService); end; // Writes services if (aTargetEntity<>'') then WriteService(aLibrary, lService) else for s := 0 to (ServiceCount-1) do begin lService := Services[s]; WriteService(aLibrary, lService); end; Write(''); end; end; end; procedure TRODLToWSDL.SetLocation(const Value: string); begin fLocation := Value; end; procedure TRODLToWSDL.WriteArray(anArray: TRODLArray); var lMin, lMax: Integer; begin if fExternalTypesAsReferences and (anArray.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then exit; Write(Format('', [anArray.Name]), 9); WriteAnnotation(anArray.Documentation, 9); if fUseDocument then begin Write('', 12); lMax := StrToIntDef(anArray.Attributes.Values['MaxOccurs'], -1); lMin := StrToIntDef(anArray.Attributes.Values['MinOccurs'], 0); if lMax = -1 then begin Write(Format('', [Unprefix(SOAPDataType(anArray.ElementType, false)), lMin, ExtSOAPDataType(anArray.OwnerLibrary, anArray.ElementType)]), 15); end else begin Write(Format('', [Unprefix(SOAPDataType(anArray.ElementType, false)), lMin, lMax, ExtSOAPDataType(anArray.OwnerLibrary, anArray.ElementType)]), 15); end; Write('', 12); end else begin Write('', 12); Write('', 15); Write('', 18); Write(Format('', [Unprefix(ExtSOAPDataType(anArray.OwnerLibrary, anArray.ElementType))]), 18); Write('', 15); Write('', 12); end; Write('', 9); end; procedure TRODLToWSDL.WriteEnum(anEnum: TRODLEnum); var i : integer; begin if fExternalTypesAsReferences and (anEnum.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then exit; Write(Format('', [anEnum.Name]), 9); WriteAnnotation(anEnum.Documentation, 12); {Giovanni} Write('', 12); for i := 0 to anEnum.Count-1 do begin //WriteDocumentation(anEnum.Items[i].Documentation, 12); {Giovanni} Write(Format('', [Unprefix(anEnum.Items[i].Name)]), 15); end; Write('', 12); Write('', 9); end; function TRODLToWSDL.GetAnchestor(aLibrary: TRODLLibrary; aService: TRODLService): TRODLService; begin result := NIL; if (aService.Ancestor<>'') and not aService.isPrivate then result := aLibrary.FindService(aService.Ancestor) end; procedure TRODLToWSDL.WriteMessages(aLibrary: TRODLLibrary; aService: TRODLService); var o, p : integer; dups : TStringList; lRet: TRODLStruct; lType, s, svcname, mtdname : string; op : TRODLOperation; begin // Writes all the methods of this service and its anchestors. // If more than one service descend from the same base one, the WSDL has to be generated // using a format like this: http://localhost:8099/SOAP?Service=ServiceOne svcname := aService.Name; dups := TStringList.Create; dups.Duplicates := dupIgnore; dups.Sorted := TRUE; try while Assigned(aService) and not aService.isPrivate do begin with aService.Default do begin for o := 0 to (Count-1) do begin op := Items[o]; // If a method with this name is present, it skips it mtdname := UpperCase(op.Name); if (dups.IndexOf(mtdname)>=0) then Continue else dups.Add(mtdname); if fUseLiteral and fUseDocument then begin Write(Format('', [Unprefix(svcname), Unprefix(op.Name)]), 3); s := op.Attributes.Values['SOAPInputNameOverride']; if s = '' then s := Format('%s___%s', [svcname, op.Name]); Write(Format('', [s]), 6); Write('', 3); Write(Format('', [Unprefix(svcname), Unprefix(op.Name)]), 3); s := op.Attributes.Values['SOAPOutputNameOverride']; if s = '' then s := Format('%s___%sResponse', [svcname, op.Name]); Write(Format('', [s]), 6); Write('', 3); end else begin // Continues with Items[o] do begin // Request Write(Format('', [Unprefix(svcname), Unprefix(op.Name)]), 3); for p := 0 to (Count-1) do if IsInputFlag(Items[p].Flag) then begin lType := Items[p].DataType; lRet := aLibrary.FindStruct(lType); if (lRet <> nil) and (lRet.Count = 1) and (lRet.Attributes.Values['Anonymous'] = '1') then lType := lRet.Items[0].DataType; Write(Format('', [Unprefix(Items[p].Name), ExtSOAPDataType(aLibrary, lType)]), 6); end; Write('', 3); // Response Write(Format('', [Unprefix(svcname), Unprefix(op.Name)]), 3); if Assigned(aService.Default.Items[o].Result) then begin lType := op.Result.DataType; lRet := aLibrary.FindStruct(lType); if (lRet <> nil) and (lRet.Count = 1) and (lRet.Attributes.Values['Anonymous'] = '1') then lType := lRet.Items[0].DataType; Write(Format('', [Unprefix(op.Result.Name), ExtSOAPDataType(aLibrary, lType)]), 6); end; //Write(Format('', [SOAPDataType(aService.Default.Items[o].Result.DataType)]), 6); for p := 0 to (Count-1) do begin if Items[p].Flag in [fOut, fInOut] then begin lType := Items[p].DataType; lRet := aLibrary.FindStruct(lType); if (lRet <> nil) and (lRet.Count = 1) and (lRet.Attributes.Values['Anonymous'] = '1') then lType := lRet.Items[0].DataType; Write(Format('', [Unprefix(Items[p].Name), ExtSOAPDataType(aLibrary, lType)]), 6); end; end; Write('', 3); end; end; end; end; aService := GetAnchestor(aLibrary, aService); end; finally dups.Free; end; end; procedure TRODLToWSDL.WritePorts(aLibrary: TRODLLibrary; aService: TRODLService); var o : integer; svcname: string; begin // Writes a port for each method of this service and its anchestors. // Refer to the comment in TRODLToWSDL.WriteMessages if aService.isPrivate then Exit; svcname := aService.Name; Write(Format('', [Unprefix(svcname)]), 3); WriteDocumentation(aService.Documentation, 6, 'wsdl:'); while Assigned(aService) and not aService.isPrivate do begin for o := 0 to (aService.Default.Count-1) do begin with aService.Default.Items[o] do begin Write(Format('', [Unprefix(Name)]), 6); WriteDocumentation(Documentation, 6, 'wsdl:'); {Giovanni} Write(Format('', [Unprefix(svcname), Unprefix(Name)]), 9); Write(Format('', [Unprefix(svcname), Unprefix(Name)]), 9); WriteExceptionParts(aService.Default.Items[o]); Write(Format('', [Name]), 6) end; end; aService := GetAnchestor(aLibrary, aService); end; Write('', 3); end; procedure TRODLToWSDL.WriteBindings(aLibrary: TRODLLibrary; aService: TRODLService); var o : integer; lAct, svcname : string; begin // Write all the bindings for this service and its anchestors using the method names. // It's important to notice that we NEVER use the anchestor name when composing the SOAPAction, but // always use the final service name if aService.isPrivate then Exit; svcname := aService.Name; Write(Format('', [Unprefix(svcname), Unprefix(svcname)]), 3); WriteAnnotation(aService.Documentation, 6); {Giovanni} if fUseDocument then Write('', 6) else Write('', 6); while Assigned(aService) and not aService.isPrivate do begin for o := 0 to (aService.Default.Count-1) do begin with aService.Default.Items[o] do begin lAct := Attributes.Values['Action']; Write(Format('', [Unprefix(Name)]), 9); if lAct <> '' then begin if pos(':', lAct) = 0 then lAct := 'urn:'+lAct; if fUseDocument then Write(Format('', [lAct]),12) else Write(Format('', [lAct]),12); end else begin if fUseDocument then Write(Format('', [aLibrary.Name, Unprefix(svcname), Unprefix(Name)]),12) else Write(Format('', [aLibrary.Name, Unprefix(svcname), Unprefix(Name)]),12); end; if fUseLiteral then begin Write('', 12); Write('', 15); if fShowClientId and fUseDocument then write('', 15); Write('', 12); Write('', 12); Write('', 15); if fShowClientId and fUseDocument then write('', 15); Write('', 12); end else begin Write('', 12); Write(Format('', [Unprefix(aLibrary.Name), Unprefix(svcname)]), 15); Write('', 12); Write('', 12); Write(Format('', [Unprefix(aLibrary.Name), Unprefix(svcname)]), 15); Write('', 12); end; Write('', 9); end; end; aService := GetAnchestor(aLibrary, aService); end; Write('', 3); end; procedure TRODLToWSDL.WriteAnnotation(aDocString: string; aIndentation: Integer = 0; aNs: string = 'xs:'); begin if Trim(aDocString) = '' then exit; Write(Format('<%sannotation>',[aNs]), aIndentation); WriteDocumentation(aDocString,aIndentation+3, aNs); Write(Format('',[aNs]), aIndentation); end; procedure TRODLToWSDL.WriteDocumentation(aDocString: string; aIndentation: Integer = 0; aNs: string = 'xs:'); var lDocString: String; begin lDocString := ReplaceSpecialChars(aDocString); if Trim(aDocString) = '' then exit; Write(Format('<%sdocumentation>',[aNs]), aIndentation); Write(Format('%s', [lDocString]),aIndentation); Write(Format('',[aNs]), aIndentation); end; procedure TRODLToWSDL.WriteService(aLibrary: TRODLLibrary; aService: TRODLService); begin // We only write the service itself, ignoring the anchestors if aService.isPrivate then Exit; Write(Format('', [Unprefix(aService.Name)]), 3); WriteAnnotation(aService.Default.Documentation, 6); while Assigned(aService) and not aService.isPrivate do begin Write(Format('', [Unprefix(aService.Name), Unprefix(aService.Name)]), 6); Write(Format('', [fLocation+'?service='+StringReplace(aService.Name,' ', '+', [rfReplaceAll])]), 9); Write('', 6); aService := NIL;//GetAnchestor(aLibrary, aService); end; Write('',3); end; procedure TRODLToWSDL.WriteStruct(const aLibrary: TRODLLibrary; aStruct: TRODLStruct); var i : integer; lLax: Boolean; lRet: TRODLStruct; begin if fExternalTypesAsReferences and (aStruct.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then exit; if aStruct.Attributes.Values['Anonymous'] = '1' then exit; Write(Format('', [Unprefix(aStruct.Name)]), 9); WriteAnnotation(aStruct.Documentation, 9); {Giovanni} if fUseDocument then begin if aStruct.Ancestor <> '' then begin write(Format('', [ExtSOAPDataType(aLibrary, aStruct.Ancestor)]), 9); end; end; Write('', 12); lLax := aStruct.Attributes.Values['lax'] = '1'; while Assigned(aStruct) do begin for i := 0 to aStruct.Count-1 do with aStruct.Items[i] do begin lRet := aLibrary.FindStruct(DataType); if (lRet <> nil) and (lRet.Count = 1) and (lRet.Attributes.Values['Anonymous'] = '1') then begin if lRet.Attributes.Values['Nillable'] = '1' then Write(Format('', [Unprefix(Name), ExtSOAPDataType(aLibrary, lRet.Items[0].DataType)]), 15) else Write(Format('', [Unprefix(Name), ExtSOAPDataType(aLibrary, lRet.Items[0].DataType)]), 15); end else begin Write(Format('', [Unprefix(Name), ExtSOAPDataType(aLibrary, DataType)]), 15); end; WriteAnnotation(Documentation, 15); {Giovanni} Write('',15); end; if fUseDocument then break; if aStruct.Ancestor <> '' then begin aStruct := aLibrary.FindStruct(aStruct.Ancestor) end else begin aStruct := nil; end; end; if lLax then Write('', 15); Write('', 12); if fUseDocument then begin if aStruct.Ancestor <> '' then write('', 9); end; Write('', 9); end; procedure TRODLToWSDL.WriteLiteralParameters(aLibrary: TRODLLibrary; aService: TRODLService); var o, p, i : integer; dups : TStringList; s, svcname, mtdname : string; op : TRODLOperation; lRet: TRODLStruct; begin // Writes all the methods of this service and its anchestors. // If more than one service descend from the same base one, the WSDL has to be generated // using a format like this: http://localhost:8099/SOAP?Service=ServiceOne svcname := aService.Name; dups := TStringList.Create; dups.Duplicates := dupIgnore; dups.Sorted := TRUE; try while Assigned(aService) and not aService.isPrivate do begin for o := 0 to (aService.Default.Count-1) do begin op := aService.Default.Items[o]; // If a method with this name is present, it skips it mtdname := UpperCase(op.Name); if (dups.IndexOf(mtdname)>=0) then Continue else dups.Add(mtdname); s := op.Attributes.Values['SOAPInputNameOverride']; if s = '' then s := Format('%s___%s', [Unprefix(svcname), Unprefix(op.Name)]); if not ((fExternalTypesAsReferences) and (op.Attributes.Values['InputImportedFromUrl'] <> fTargetXSD)) then begin p := 0; for i := 0 to op.Count -1 do begin if op[i].Flag in [fIn, fInOut] then inc(p); end; write(Format('', [Unprefix(s)]), 3); if p = 0 then begin write('', 6); end else begin write('', 6); write('', 9); for i := 0 to op.Count -1 do begin if op[i].Flag in [fIn, fInOut] then begin lRet := aLibrary.FindStruct(op[i].DataType); if (lRet <> nil) and (lRet.Count = 1) and (lRet.Attributes.Values['Anonymous'] = '1') then begin if lRet.Attributes.Values['Nillable'] = '1' then write(Format('', [Unprefix(op[i].Name), ExtSOAPDataType(aLibrary, lRet[0].DataType)]), 12) else write(Format('', [Unprefix(op[i].Name), ExtSOAPDataType(aLibrary, lRet[0].DataType)]), 12); end else write(Format('', [Unprefix(op[i].Name), ExtSOAPDataType(aLibrary, op[i].DataType)]), 12); end; end; if op.Attributes.VAlues['InputLax'] = '1' then Write('', 12); write('', 9); write('', 6); end; write('', 3); end; s := op.Attributes.Values['SOAPOutputNameOverride']; if s = '' then s := Format('%s___%sResponse', [Unprefix(svcname), Unprefix(op.Name)]); if not ((fExternalTypesAsReferences) and (op.Attributes.Values['OutputImportedFromUrl'] <> fTargetXSD)) then begin p := 0; for i := 0 to op.Count -1 do begin if op[i].Flag in [fOut, fInOut, fResult] then inc(p); end; if op.Result <> nil then begin inc(p); end; write(Format('', [Unprefix(s)]), 3); if p = 0 then begin write('', 6); end else begin write('', 6); write('', 9); if op.Result <> nil then begin lRet := aLibrary.FindStruct(op.Result.DataType); if (lRet <> nil) and (lRet.Count = 1) and (lRet.Attributes.Values['Anonymous'] = '1') then begin if lRet.Attributes.Values['Nillable'] = '1' then write(Format('', [Unprefix(op.Result.Name), ExtSOAPDataType(aLibrary, lRet[0].DataType)]), 12) else write(Format('', [Unprefix(op.Result.Name), ExtSOAPDataType(aLibrary, lRet[0].DataType)]), 12); end else write(Format('', [Unprefix(op.Result.Name), ExtSOAPDataType(aLibrary, op.Result.DataType)]), 12); end; for i := 0 to op.Count -1 do begin if op[i].Flag in [fOut, fInOut, fResult] then begin lRet := aLibrary.FindStruct(op[i].DataType); if (lRet <> nil) and (lRet.Count = 1) and (lRet.Attributes.Values['Anonymous'] = '1') then begin if lRet.Attributes.Values['Nillable'] = '1' then write(Format('', [Unprefix(op[i].Name), ExtSOAPDataType(aLibrary, lRet[0].DataType)]), 12) else write(Format('', [Unprefix(op[i].Name), ExtSOAPDataType(aLibrary, lRet[0].DataType)]), 12); end else write(Format('', [Unprefix(op[i].Name), ExtSOAPDataType(aLibrary, op[i].DataType)]), 12); end; end; if op.Attributes.VAlues['OutputLax'] = '1' then Write('', 12); write('', 9); write('', 6); end; write('', 3); end; end; aService := GetAnchestor(aLibrary, aService); end; finally dups.Free; end; end; constructor TRODLToWSDL.Create(const aLibraryFile, aTargetEntity: string); begin fTargetNamespace := 'http://tempuri.org/'; fExternalRefs := TStringList.Create; fExternalUrls := TStringList.Create; inherited; end; constructor TRODLToWSDL.Create(const aLibrary: TRODLLibrary; const aTargetEntity: string); begin fTargetNamespace := 'http://tempuri.org/'; fExternalRefs := TStringList.Create; fExternalUrls := TStringList.Create; inherited; end; destructor TRODLToWSDL.Destroy; begin fExternalRefs.Free; fExternalUrls.Free; inherited; end; procedure TRODLToWSDL.AddExternal(aNode: TRODLEntity); var lEx: TRODLException; begin if Anode = nil then exit; if aNode is TRODLException then begin lEx := TRODLException(aNode); if (fTargetXSD = '') or (fTargetXSD <> lEx.Attributes.Values['ElementUrl']) then AddExternal(lEx.Attributes.Values['ElementNamespace'], lEx.Attributes.Values['ElementUrl']); exit; end; if aNode.Attributes.Values['ImportedFromUrl'] = '' then exit; AddExternal(aNode.Attributes.Values['ImportedFromNamespace'], aNode.Attributes.Values['ImportedFromUrl']); end; procedure TRODLToWSDL.AddExternal(const aNs,aUrl: string); var i: Integer; begin for i := 0 to fExternalRefs.Count -1 do begin if (fExternalRefs[i] = aNs) and (fExternalUrls[i] = aUrl) then exit; end; fExternalRefs.Add(aNs); fExternalUrls.ADd(aUrl); end; function TRODLToWSDL.ExtSOAPDataType(aLibrary: TRODLLibrary; const aDataTypeName: string): string; var el: TRODLEntity; begin if fExternalTypesAsReferences then begin el := aLibrary.FindStruct(aDataTypeName); if el = nil then el := aLibrary.FindException(aDataTypeName); if el = nil then el := aLibrary.FindEnum(aDataTypeName); if el = nil then el := aLibrary.FindArray(aDataTypeName); if el <> nil then begin if (el.Attributes.values['ElementNamespace'] <> '') and (fXsdTns <> el.Attributes.values['ElementNamespace']) then begin result := 'ns'+IntToStr(fExternalRefs.IndexOf(el.Attributes.values['ElementNamespace']))+':'+Unprefix(aDataTypeName); exit; end; if (el.Attributes.values['ImportedFromNamespace'] <> '') and (fXsdTns <> el.Attributes.values['ImportedFromNamespace']) then begin result := 'ns'+IntToStr(fExternalRefs.IndexOf(el.Attributes.values['ImportedFromNamespace']))+':'+Unprefix(aDataTypeName); exit; end; end; end; result := SOAPDataType(Unprefix(aDataTypeName), True); end; procedure TRODLToWSDL.ResolveExternalReferences(aLibrary: TRODLLibrary); var i, j, k: Integer; lIsTarget: Boolean; lServ: TRODLService; lStr: TRODLStruct; lEx: TRODLException; lEl: TRODLEntity; lOp: TRODLOperation; lList: TList; begin lList := TList.Create; try // assume only 1 of fTargetEntity/fTargetXsd is set for i := 0 to aLibrary.ExceptionCount -1 do begin lEx := aLibrary.Exceptions[i]; if (lEx.Attributes.Values['ElementUrl'] = fTargetXSD) and (lEx.Count = 1) then begin fHasXsdData := true; if (fXsdTns = '') and (lEx.Attributes.Values['ElementNamespace'] <> '') then fXsdTns := lEx.Attributes.Values['ElementNamespace']; lEl := aLibrary.ItemByName(lEx.Items[0].DataType); if (lEl <> nil) and (lEl.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then AddExternal(lEl); lEl := aLibrary.ItemByName(lex.Ancestor); if (lEl <> nil) and (lEl.Attributes.Values['ElementUrl'] <> fTargetXSD) then AddExternal(lEl); end; end; for i := 0 to aLibrary.ArrayCount -1 do begin if aLibrary.Arrays[i].Attributes.Values['ImportedFromUrl'] = fTargetXSD then begin fHasXsdData := true; if (fXsdTns = '') and (aLibrary.Arrays[i].Attributes.Values['ImportedFromNamespace'] <> '') then fXsdTns := aLibrary.Arrays[i].Attributes.Values['ImportedFromNamespace']; lEl := aLibrary.ItemByName(aLibrary.Arrays[i].ElementType); if (lEl <> nil) and (lEl.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then AddExternal(lEl); end else if fTargetXSD = '' then AddExternal(aLibrary.Arrays[i]); end; for i := 0 to aLibrary.StructCount -1 do begin lStr := aLibrary.Structs[i]; if lStr.Attributes.Values['ImportedFromUrl'] = fTargetXSD then begin while lStr <> nil do begin fHasXsdData := true; if (fXsdTns = '') and (lStr.Attributes.Values['ImportedFromNamespace'] <> '') then fXsdTns := lStr.Attributes.Values['ImportedFromNamespace']; for j := 0 to lStr.Count -1 do begin lEl := aLibrary.ItemByName(lStr[j].DataType); if (lEl <> nil) and (lEl.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then AddExternal(lEl); end; lEl := aLibrary.ItemByName(lStr.Ancestor); if (lEl <> nil) and (lEl.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then AddExternal(lEl); if lEl is TRODLStruct then lStr := TRodlStruct(lEl) else break; end; end else if fTargetXSD = '' then AddExternal(lStr); end; for i := 0 to aLibrary.EnumCount -1 do begin if aLibrary.Enums[i].Attributes.Values['ImportedFromUrl'] = fTargetXSD then begin fHasXsdData := true; if (fXsdTns = '') and (aLibrary.Enums[i].Attributes.Values['ImportedFromNamespace'] <> '') then fXsdTns := aLibrary.Enums[i].Attributes.Values['ImportedFromNamespace']; end else if fTargetXSD = '' then AddExternal(aLibrary.Enums[i]); end; for i := 0 to aLibrary.ServiceCount -1 do begin lServ := aLibrary.Services[i]; lIsTarget := ((fTargetEntity = '') or (lServ.Name = fTargetEntity)) and (fTargetXsd = ''); if lIsTarget or (fTargetXSD <> '') then begin for j := 0 to lServ[0].Count -1 do begin lOp := lServ[0][j]; if lIsTarget then for k := 0 to lOp.Attributes.Count -1 do begin if copy(lOp.Attributes[k], 1, 6) = 'fault_' then begin AddExternal(aLibrary.FindException(lOp.Attributes.Values[lOp.Attributes.Names[k]])); end; end; if lOp.Attributes.Values['InputImportedFromUrl'] = fTargetXSD then begin for k := 0 to lOp.Count -1 do begin if lOp[k].Flag in [fIn, fInOut] then begin lEl := aLibrary.ItemByName(lOp[k].DataType); if (lEl <> nil) and (lEl.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then AddExternal(lEl); end; end; end else if lIsTarget and (lOp.Attributes.Values['InputImportedFromUrl'] <> '') then begin AddExternal(fTargetNamespace, lOp.Attributes.Values['InputImportedFromUrl']); end; if lOp.Attributes.Values['OutputImportedFromUrl'] = fTargetXSD then begin for k := 0 to lOp.Count -1 do begin if lOp[k].Flag in [fInOut] then begin lEl := aLibrary.ItemByName(lOp[k].DataType); if (lEl <> nil) and (lEl.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then AddExternal(lEl); end; end; if lOp.Result <> nil then begin lEl := aLibrary.ItemByName(lOp.Result.DataType); if (lEl <> nil) and (lEl.Attributes.Values['ImportedFromUrl'] <> fTargetXSD) then AddExternal(lEl); end; end else if lIsTarget and (lOp.Attributes.Values['OutputImportedFromUrl'] <> '') then begin AddExternal(fTargetNamespace, lOp.Attributes.Values['OutputImportedFromUrl']); end; end; end; end; finally lList.Free; end; end; procedure TRODLToWSDL.WriteExceptionMessage(AnException: TRODLException); var i: Integer; lItem: TRODLTypedEntity; begin if not fUseDocument then exit; // only supported for document Write(Format('', [anException.Name]), 3); for i := 0 to anException.Count -1 do begin lItem := anException[i]; if AnException.Attributes.Values['ElementName'] <> '' then Write(Format('', [lItem.Name, GetPrefix(AnException.Attributes.Values['ElementName'], AnException.Attributes.Values['ElementNamespace'])]), 6) else Write(Format('', [lItem.Name, ExtSOAPDataType(anException.OwnerLibrary, lItem.DataType)]), 6); end; Write('', 3); end; procedure TRODLToWSDL.WriteExceptionParts(aMeth: TRODLOperation); var i: Integer; s, lVal: string; begin if not UseDocument then exit; for i := 0 to aMeth.Attributes.Count -1 do begin s := aMeth.Attributes.Names[i]; if copy(s,1,6)= 'fault_' then begin lVal := aMeth.Attributes.Values[s]; if aMeth.OwnerLibrary.FindException(lVal) <> nil then begin Write(Format('', [copy(s,7,MaxInt), lVal]), 9); end; end; end; end; procedure TRODLToWSDL.WriteExceptionElement(anException: TRODLException); var lRet: TRODLStruct; i: Integer; begin if fExternalTypesAsReferences and (anException.Attributes.Values['ElementUrl'] <> fTargetXSD) then exit; if (anException.Attributes.Values['ElementType'] = '') and (anException.Attributes.Values['ElementName'] <> '') then begin Write(Format('', [anException.Attributes.Values['ElementName']]), 9); WriteAnnotation(anException.Documentation, 9); {Giovanni} Write('', 9); end else begin if anException.Attributes.Values['ElementType'] = '' then Write(Format('', [anException.Name]), 9) else Write(Format('', [anException.Attributes.Values['ElementType']]), 9); WriteAnnotation(anException.Documentation, 9); {Giovanni} end; if anException.Ancestor <> '' then begin write('', 9); write(Format('', [ExtSOAPDataType(anException.OwnerLibrary, anException.Ancestor)]), 9); end; Write('', 12); for i := 0 to anException.Count-1 do begin with anException.Items[i] do begin lRet := anException.OwnerLibrary.FindStruct(DataType); if (lRet <> nil) and (lRet.Count = 1) and (lRet.Attributes.Values['Anonymous'] = '1') then begin if lRet.Attributes.Values['Nillable'] = '1' then Write(Format('', [Unprefix(Name), ExtSOAPDataType(anException.OwnerLibrary, lRet.Items[0].DataType)]), 15) else Write(Format('', [Unprefix(Name), ExtSOAPDataType(anException.OwnerLibrary, lRet.Items[0].DataType)]), 15); end else begin Write(Format('', [Unprefix(Name), ExtSOAPDataType(anException.OwnerLibrary, DataType)]), 15); end; WriteAnnotation(Documentation, 15); {Giovanni} Write('',15); end; end; Write('', 12); if anException.Ancestor <> '' then begin write('', 9); write('', 9); end; Write('', 9); if (anException.Attributes.Values['ElementType'] = '') and (anException.Attributes.Values['ElementName'] <> '') then Write('', 9); if anException.Attributes.Values['ElementType'] <> '' then begin Write(Format('', [anException.Attributes.Values['ElementName'], anException.Attributes.Values['ElementType']]), 9); end; end; function TRODLToWSDL.GetPrefix(const aType, aNs: string): String; begin if (fTargetXSD = '') and (aNs = fTargetNamespace) then begin result := 'tns:'+aType; exit; end; if aNs <> '' then begin result := 'ns'+IntToStr(fExternalRefs.IndexOf(aNs))+':'+Unprefix(aType); exit; end; Result := 'tns:'+ aType; end; function TRODLToWSDL.ReplaceSpecialChars(aText: String): String; begin result := StringReplace(aText, '&', '&', [rfReplaceAll, rfIgnoreCase]); result := StringReplace(result, '"', '"', [rfReplaceAll, rfIgnoreCase]); result := StringReplace(result, '''', ''', [rfReplaceAll, rfIgnoreCase]); result := StringReplace(result, '<', '<', [rfReplaceAll, rfIgnoreCase]); result := StringReplace(result, '>', '>', [rfReplaceAll, rfIgnoreCase]); end; end.