2009-06-17 39 views
3

示例模式:在.NET XML反序列化中,如何允许多态使用数组类型?

<complexType name="Dog">...</complexType> 
<complexType name="Cat">...</complexType> 

<complexType name="ArrayOfDog"> 
    <sequence> 
     <element name="Dog" type="tns:Dog minOccurs="0" maxOccurs="unbounded" /> 
    </sequence> 
</complexType> 

<complexType name="Foo"> 
    <sequence> 
     <element name="Bar" type="string"/>   
     <element name="Baz" type="anyType"/> 
    </sequence> 
</complexType> 

通过.NET的Wsdl.exe用运行这个生成类似下面的代码:

[System.Xml.Serialization.XmlIncludeAttribute(typeof(Dog[]))] 

public partial class Dog { ... } 

public partial class Cat { ... } 

public partial class Foo { 
    private string barField; 
    private object bazField; 
} 

看来,Wsdl.exe用正努力成为“智能”,并认识到我的ArrayOfDog实际上只是一个可以编码为C#数组的包装类型。当ArrayOfDog在另一个数据类型中显式引用时,这工作正常。然而,当ArrayOfDog多态使用时(例如,作为xsd:anyType的替代),这会中断。它似乎中断了,因为.NET运行库对名为“ArrayOfDog”的complexType一无所知 - 它基本上抛弃了这种信息,而仅仅使用本地C#数组。

实施例的XML文档1:

<Foo> 
    <Bar>Hello</Bar> 
    <Baz xsi:type="Cat"> 
     ... 
    </Baz> 
</Foo> 

实施例的XML文档2:

<Foo> 
    <Bar>Hello</Bar> 
    <Baz xsi:type="ArrayOfDog"> 
     <Dog>...</Dog> 
     <Dog>...</Dog> 
    </Baz> 
</Foo> 

文献#1由运行时正确地反序列化。我为Bar和Baz获得了正确反序列化字段的Foo类型对象。

运行时,文档#2被反序列化错误地。我得到了一个类型为Foo的对象,其Bar中有一个正确的反序列化字段,但对于Baz字段,我得到了System.XML.XMLNode []。我的猜测是因为运行时对名为“ArrayOfDog”的实体的任何类型绑定一无所知。你可能会认为XmlInclude指令“XmlIncludeAttribute(typeof(Dog []))”会处理这个,但它似乎不工作。

有没有人遇到过这个?

这里有没有优雅的解决方案?我正在考虑使用的解决方法是将我的“ArrayOf”类型封装在另一个类型中,并将其包含在xsd:anyType的替代中。

+0

这是什么情况?一个ASMX网络服务?它返回什么类型?键入Foo?尝试使用“BunchOfDogs”而不是“ArrayOfDog”,这是.NET从Dog []生成的名称。 – 2009-06-17 15:10:50

+0

错误发生在Web服务的C#客户端中。 Web服务的WSDL是用我们上面提到的定义的数据类型来定义的。服务端点使用Java实现。 – Eric 2009-06-17 18:05:11

回答

1

我不认为这与多态性有什么关系。我认为这是XML序列化程序中的一个错误,假设任何包含“Dog”序列的名为“ArrayOfDog”的类型都代表Dog []。作为这个理论的一个测试,尝试改变WSDL来使用名字“BunchOfDogs”来代替,并且看看这是否改变了客户端中的代理代码。

如果你想多态性XML,那么这两个ArrayOfDog,和猫,将需要相同的基本类型的扩展名(比XSD其他:任何)。如果是这样的话,那么我期望.NET将Baz生成为基本类型。

架构与XSD:只是一般任何原因导致的问题。那里几乎可能有任何东西,有些组合根本就没有意义。

如果这个Java服务是从轴,或它是什么版本,你都没有说。我已经看到Axis的行为就像xsi:type是有效模式的替代品一样。小心需要“正确”使用xsi:type的模式。

1

你想开始什么?如果你开始这样定义的类型:

public partial class Foo 
{ 
    private string _bar; 

    private object[] _baz; 

    public string Bar 
    { 
     get { return _bar; } 
     set { _bar= value; } 
    } 

    [XmlArray("Baz")] 
    [XmlArrayItem("Type1", typeof(Type1))] 
    public object[] Baz 
    { 
     get { return _baz; } 
     set { _baz= value; } 
    } 
} 

然后你可以序列化和喜欢你的文档#2反序列化的文档。

似乎你想从WSDL和XSD开始。在这种情况下,你可以概括你的架构是这个样子:

<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="Foo" nillable="true" type="Foo" /> 
    <xs:complexType name="Foo"> 
    <xs:sequence> 
     <xs:element minOccurs="0" maxOccurs="1" name="Bar" type="xs:string" /> 
     <xs:element minOccurs="0" maxOccurs="1" name="Baz" type="UntypedArray" /> 
    </xs:sequence> 
    </xs:complexType> 


    <xs:complexType name="UntypedArray"> 
    <xs:choice minOccurs="1" maxOccurs="unbounded"> 
     <xs:element name="Type1" type="Type1" minOccurs="1" maxOccurs="1"/> 
     <xs:any namespace="##other" processContents="lax" minOccurs="1" maxOccurs="1"/> 
    </xs:choice> 
    </xs:complexType> 


    <xs:complexType name="Type1" mixed="true"> 
    <xs:sequence> 
     <xs:element minOccurs="0" maxOccurs="1" name="Child" type="xs:string" /> 
    </xs:sequence> 
    </xs:complexType> 
</xs:schema> 

上面的架构生成此代码:

public partial class Foo { 

    private string barField; 

    private object[] bazField; 

    /// <remarks/> 
    public string Bar { 
     get { 
      return this.barField; 
     } 
     set { 
      this.barField = value; 
     } 
    } 

    /// <remarks/> 
    [System.Xml.Serialization.XmlArrayItemAttribute("", typeof(System.Xml.XmlElement), IsNullable=false)] 
    [System.Xml.Serialization.XmlArrayItemAttribute(typeof(Type1), IsNullable=false)] 
    public object[] Baz { 
     get { 
      return this.bazField; 
     } 
     set { 
      this.bazField = value; 
     } 
    } 
} 

如果要包括其他类型,然后添加元素到了xsd:选择适当的。

由于您想允许xsd:其中的任何内容,Foo.Baz是一个对象数组。它上面的编程模型要求你用类似(foo.Baz [i]类型1)来测试或者转换每个元素。

相关问题