|
| Translation of array |
 |
Fri, 15 Feb 2008 12:35:40 -060 |
D2007, importing wsdl, wsdl looks like this:
- <s:complexType name="ArrayOfChoice1">
- <s:choice minOccurs="0" maxOccurs="unbounded">
<s:element minOccurs="1" maxOccurs="1"
name="ProductModifier"
nillable="true" type="s1:ProductModifier" />
<s:element minOccurs="1" maxOccurs="1"
name="ProductChoice"
nillable="true" type="s1:ProductChoice" />
<s:element minOccurs="1" maxOccurs="1"
name="ProductInput" nillable="true"
type="s8:ProductInput" />
</s:choice>
</s:complexType>
translated to below. It looks to me like ArrayOfChoice1 should have been
tranlated to an array of Choice1 where Choice1 is the class but
ArrayOfChoice1 is an array. Not sure if the wsdl is a proper definition or
not.
//
************************************************************************ //
// XML : ArrayOfChoice1, global, <complexType>
// Namespace :
http://www.bvsoftware.com/bvc5/schemas/2005/09/01/Catalog/Product
//
************************************************************************ //
ArrayOfChoice1 = class(TRemotable)
private
FProductModifier: ProductModifier2;
FProductModifier_Specified: boolean;
FProductChoice: ProductChoice2;
FProductChoice_Specified: boolean;
FProductInput: ProductInput;
FProductInput_Specified: boolean;
procedure SetProductModifier(Index: Integer; const AProductModifier2:
ProductModifier2);
function ProductModifier_Specified(Index: Integer): boolean;
procedure SetProductChoice(Index: Integer; const AProductChoice2:
ProductChoice2);
function ProductChoice_Specified(Index: Integer): boolean;
procedure SetProductInput(Index: Integer; const AProductInput:
ProductInput);
function ProductInput_Specified(Index: Integer): boolean;
public
destructor Destroy; override;
published
property ProductModifier: ProductModifier2 Index (IS_OPTN or IS_NLBL)
read FProductModifier write SetProductModifier stored
ProductModifier_Specified;
property ProductChoice: ProductChoice2 Index (IS_OPTN or IS_NLBL)
read FProductChoice write SetProductChoice stored ProductChoice_Specified;
property ProductInput: ProductInput Index (IS_OPTN or IS_NLBL)
read FProductInput write SetProductInput stored ProductInput_Specified;
end;
Wayne
|
| Post Reply
|
| Re: Translation of array |
 |
Fri, 15 Feb 2008 16:10:27 -080 |
Hello,
Yes, your assessment is correct. I mentioned this in other posts recently:
http://groups.google.com/group/borland.public.delphi.webservices.wsdl/msg/86d0fb
ac46d93741
http://groups.google.com/group/borland.public.delphi.webservices.soap/msg/5a560f
4c3ce86f62
Basically we do not support cardinality specified on compositor nodes
(choice, sequence or all). Initially there was a problem retrieving
compositor information from the elements - specially when the compositor
nodes are nested. This issue remains (it's something that the folks working
on the xml area are looking at). However, in the case you mentioned, there's
no nesting of compositor nodes. That one is just a plain failure on the
importer's side.
Sometimes it's easy to rewrite the schema to avoid cardinality on the
compositor node but in your case (with an unbounded choice) that approach
won't work.
In this particular case I'm afraid you might need to take over the
importer's output and edit. Something along the lines of the following
should work (NOTE: I have not tried this out but am happy to investigate
further if this does not work):
Choice1 = class(TRemotable)
private
FProductModifier: ProductModifier2;
FProductModifier_Specified: boolean;
FProductChoice: ProductChoice2;
FProductChoice_Specified: boolean;
FProductInput: ProductInput;
FProductInput_Specified: boolean;
procedure SetProductModifier(Index: Integer; const AProductModifier2:
ProductModifier2);
function ProductModifier_Specified(Index: Integer): boolean;
procedure SetProductChoice(Index: Integer; const AProductChoice2:
ProductChoice2);
function ProductChoice_Specified(Index: Integer): boolean;
procedure SetProductInput(Index: Integer; const AProductInput:
ProductInput);
function ProductInput_Specified(Index: Integer): boolean;
public
destructor Destroy; override;
published
property ProductModifier: ProductModifier2 Index (IS_OPTN or IS_NLBL)
read FProductModifier write SetProductModifier stored
ProductModifier_Specified;
property ProductChoice: ProductChoice2 Index (IS_OPTN or IS_NLBL)
read FProductChoice write SetProductChoice stored ProductChoice_Specified;
property ProductInput: ProductInput Index (IS_OPTN or IS_NLBL)
read FProductInput write SetProductInput stored ProductInput_Specified;
end;
ArrayOfChoice1 = array of Choice1;
ArrayOfChoice = class(TRemotable)
private
FArrayOfChoice: ArrayOfChoice1;
public
destructor Destroy; override;
published
property ArrayOfChoice: ArrayOfChoice1 Index (IS_NLBL or IS_UNBD) read
FArrayOfChoice write FArrayOfChoice;
end;
Oh, and make sure to tag Choice1 as a holder class:
initialization
RemClassRegistry.RegisterSerializeOptions(TypeInfo(Choice1),
[xoHolderClass]);
Let me know if the above does not work. I hope to have some time to work on
compositor nodes with cardinality specified soon.
Cheers,
Bruneau.
|
| Post Reply
|
| Re: Translation of array |
 |
Fri, 15 Feb 2008 16:21:49 -080 |
OK, since I already had the code I posted, I went ahead and wrote a little
test. Here's what I did:
#1. I mapped the leaf-node types to built-in types for simplicity (this
should not affect the rest of the code);
type
ProductModifier2 = string;
ProductChoice2 = integer;
ProductInput = string;
#2. I registered the types I posted in the previous post:
initialization
RemClassRegistry.RegisterXSInfo(TypeInfo(ArrayOfChoice), 'urn:test-ns',
'ArrayOfChoice');
RemClassRegistry.RegisterXSInfo(TypeInfo(Choice1), 'urn:test-ns',
'Choice1');
RemClassRegistry.RegisterSerializeOptions(TypeInfo(Choice1),
[xoHolderClass]);
#3. I wrote a little piece of code that creates an instance of
'ArrayOfChoice' as in:
procedure TForm6.Button2Click(Sender: TObject);
var
AC: ArrayOfChoice;
I: Integer;
begin
AC := ArrayOfChoice.Create;
try
SetLength(AC.FArrayOfChoice, 10);
for I := 0 to Length(AC.FArrayOfChoice) - 1 do
begin
AC.FArrayOfChoice[I] := Choice1.Create;
if ((I mod 3) = 0) then
AC.FArrayOfChoice[I].ProductModifier := 'Modifier' + IntToStr(I)
else if ((I mod 3) = 1) then
AC.FArrayOfChoice[I].ProductInput := 'Input' + IntToStr(I)
else
AC.FArrayOfChoice[I].ProductChoice := I;
end;
Memo1.Text := ObjToXML(AC, CloneConverter(HTTPRIO1));
finally
AC.Free;
end;
end;
#4 The ObjToXML call above is just a little helper routine that uses the
SOAP runtime to generate XML from a TRemotable type. In essence I'm
exercising the serialization logic but omitting the HTTP posting/transport
section.
#5. Here's the resulting XML:
<?xml version="1.0"?>
<Root xmlns="urn:TestNamespace"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ArrayOfChoice xmlns="urn:test-ns">
<ProductModifier>Modifier0</ProductModifier>
<ProductInput>Input1</ProductInput>
<ProductChoice>2</ProductChoice>
<ProductModifier>Modifier3</ProductModifier>
<ProductInput>Input4</ProductInput>
<ProductChoice>5</ProductChoice>
<ProductModifier>Modifier6</ProductModifier>
<ProductInput>Input7</ProductInput>
<ProductChoice>8</ProductChoice>
<ProductModifier>Modifier9</ProductModifier>
</ArrayOfChoice>
</Root>
The contents of each element will be different in your case as you won't be
using the mapping to simple types but the overall <ArrayOfChoice> as an
unbounded choice of one of 3 elements should be working.
Please let me know if this does not work for you.
Cheers,
Bruneau.
|
| Post Reply
|
| Re: Translation of array |
 |
Fri, 15 Feb 2008 18:36:13 -060 |
Hi Bruneau,
Thanks for the quick repsonse. I played around a bit trying to do in a way
what you did, but not being a wizard at this stuff did not quite get it
right. I will try to implement what you have and post back how it goes.
Thanks.
Wayne
"Jean-Marie Babet" <bbabet@borland.com> wrote in message
news:47b62934$1@newsgroups.borland.com...
> Hello,
>
> Yes, your assessment is correct. I mentioned this in other posts recently:
>
>
>
http://groups.google.com/group/borland.public.delphi.webservices.wsdl/msg/86d0fb
ac46d93741
>
>
http://groups.google.com/group/borland.public.delphi.webservices.soap/msg/5a560f
4c3ce86f62
>
> Basically we do not support cardinality specified on compositor nodes
> (choice, sequence or all). Initially there was a problem retrieving
> compositor information from the elements - specially when the compositor
> nodes are nested. This issue remains (it's something that the folks
> working
> on the xml area are looking at). However, in the case you mentioned,
> there's
> no nesting of compositor nodes. That one is just a plain failure on the
> importer's side.
>
> Sometimes it's easy to rewrite the schema to avoid cardinality on the
> compositor node but in your case (with an unbounded choice) that approach
> won't work.
>
> In this particular case I'm afraid you might need to take over the
> importer's output and edit. Something along the lines of the following
> should work (NOTE: I have not tried this out but am happy to investigate
> further if this does not work):
>
>
> Choice1 = class(TRemotable)
> private
> FProductModifier: ProductModifier2;
> FProductModifier_Specified: boolean;
> FProductChoice: ProductChoice2;
> FProductChoice_Specified: boolean;
> FProductInput: ProductInput;
> FProductInput_Specified: boolean;
> procedure SetProductModifier(Index: Integer; const AProductModifier2:
> ProductModifier2);
> function ProductModifier_Specified(Index: Integer): boolean;
> procedure SetProductChoice(Index: Integer; const AProductChoice2:
> ProductChoice2);
> function ProductChoice_Specified(Index: Integer): boolean;
> procedure SetProductInput(Index: Integer; const AProductInput:
> ProductInput);
> function ProductInput_Specified(Index: Integer): boolean;
> public
> destructor Destroy; override;
> published
> property ProductModifier: ProductModifier2 Index (IS_OPTN or IS_NLBL)
> read FProductModifier write SetProductModifier stored
> ProductModifier_Specified;
> property ProductChoice: ProductChoice2 Index (IS_OPTN or IS_NLBL)
> read FProductChoice write SetProductChoice stored ProductChoice_Specified;
> property ProductInput: ProductInput Index (IS_OPTN or IS_NLBL)
> read FProductInput write SetProductInput stored ProductInput_Specified;
> end;
>
>
> ArrayOfChoice1 = array of Choice1;
>
> ArrayOfChoice = class(TRemotable)
> private
> FArrayOfChoice: ArrayOfChoice1;
> public
> destructor Destroy; override;
> published
> property ArrayOfChoice: ArrayOfChoice1 Index (IS_NLBL or IS_UNBD) read
> FArrayOfChoice write FArrayOfChoice;
> end;
>
> Oh, and make sure to tag Choice1 as a holder class:
>
> initialization
> RemClassRegistry.RegisterSerializeOptions(TypeInfo(Choice1),
> [xoHolderClass]);
>
>
> Let me know if the above does not work. I hope to have some time to work
> on
> compositor nodes with cardinality specified soon.
>
> Cheers,
>
> Bruneau.
>
>
|
| Post Reply
|
| Re: Translation of array |
 |
Sat, 16 Feb 2008 01:03:53 +010 |
Hi.
IMO the wsdl-complex type looks ok.
I suppose that the problem is that as of the wsdl the ArrayOfChoice1
can consist of three different types (ProductModifier, ProductChoice and
ProductInput) which can appear in any order - but as of the generated
Pascal source it could perhabs be that only one type is accepted (or
parsed)? You could try to see what happens if you stick to one type
(like having in your array only ProductInput-type). If you receive then
more than the first element it is probably a problem with complex type
and array of choice in Webservices with Delphi. Somehow there is any
representation of wsdl-choice missing in the pascal code - at least
that's what I think. But I do not know what happens internaly.
I would expect something like this being generated but it would need to
be reflected with the proper parsing of the soap-response Delphi internally:
ArrayOfChoice2 = class(TObject);
ProductModifier = class(ArrayOfChoice2);
ProductChoice = class(ArrayOfChoice2);
ProductInput = class(ArrayOfChoice2);
ArrayOfChoice1 = class(TRemotable)
private
!!!this inserted!!!
FArrayOfChoice1: ArrayOfChoice2;
!!!end of insertion!!!
FProductModifier: ProductModifier2;
FProductModifier_Specified: boolean;
FProductChoice: ProductChoice2;
FProductChoice_Specified: boolean;
FProductInput: ProductInput;
FProductInput_Specified: boolean;
!!!this inserted!!!
procedure SetArrayOfChoice1(Index: Integer; const AArrayOfChoice2:
ArrayOfChoice2);
function ArrayOfChoice1_Specified(Index: Integer): boolean;
!!!end of insertion!!!
procedure SetProductModifier(Index: Integer; const
AProductModifier2: ProductModifier2);
function ProductModifier_Specified(Index: Integer): boolean;
procedure SetProductChoice(Index: Integer; const AProductChoice2:
ProductChoice2);
function ProductChoice_Specified(Index: Integer): boolean;
procedure SetProductInput(Index: Integer; const AProductInput:
ProductInput);
function ProductInput_Specified(Index: Integer): boolean;
public
destructor Destroy; override;
published
!!!this inserted!!!
property ArrayOfChoice1: ArrayOfChoice2 Index ((IS_OPTN or IS_NLBL)
read FArrayofChoice1 write SetArrayOfChoice1 stored
ArrayOfChoice1_Specified;
!!!end of insertion!!!
property ProductModifier: ProductModifier2 Index (IS_OPTN or
IS_NLBL) read FProductModifier write SetProductModifier stored
ProductModifier_Specified;
property ProductChoice: ProductChoice2 Index (IS_OPTN or
IS_NLBL) read FProductChoice write SetProductChoice stored
ProductChoice_Specified;
property ProductInput: ProductInput Index (IS_OPTN or
IS_NLBL) read FProductInput write SetProductInput stored
ProductInput_Specified;
end;
That way we would have the generalized array item which consists of
specialized choice-items.
Are WSDLs with complex types and choice a general problem?
I heard that most people construct and parse the soap requests and
responses in web service settings on their own - which is suposed to be
not very well supported with Delphi. In my opinion there is a lack of
easy ways for late binding of webservices to runtime artefacts. But I am
not an expert to judge that.
Further - I am not sure if I understood you right.
Regards
Roland
|
| Post Reply
|
|
|
|
|
|
|
|
|
|