65.9K
CodeProject 正在变化。 阅读更多。
Home

深入了解 XML 数据绑定,包括产品评估

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (16投票s)

2004年8月19日

CPOL

16分钟阅读

viewsIcon

153781

downloadIcon

1

XML 数据绑定简介,以及对一些领先产品的评论。

目录

什么是 XML 数据绑定?

XML 数据绑定允许您通过一组简单的对象来操作 XML 文档。定义 XML 文档“形状”的规则在 XML 模式中描述。通常,可以将 XML 文档读入 XML 绑定库,并通过简单的 get 和 set 方法以编程方式操作它。反之,可以从 XML 数据绑定库创建文档,并将其序列化为 XML 文档。

还不清楚?那么,我们来看看它的好处。

一个简单示例

让我们尝试创建一个符合图 1a 中模式的 XML 文档。

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                                          elementFormDefault="qualified">
    <xsd:element name="bookstore" type="bookstoreType" />
    <xsd:complexType name="bookstoreType">
        <xsd:sequence maxOccurs="unbounded">
            <xsd:element name="book" type="bookType" />
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="bookType">
        <xsd:sequence>
            <xsd:element name="title" type="xsd:string" />
            <xsd:element name="author" type="authorName" />
            <xsd:element name="price" type="xsd:decimal" />
        </xsd:sequence>
        <xsd:attribute name="genre" type="xsd:string" />
        <xsd:attribute name="publicationdate" type="xsd:string" />
        <xsd:attribute name="ISBN" type="xsd:string" />
    </xsd:complexType>
    <xsd:complexType name="authorName">
        <xsd:sequence>
            <xsd:element name="first-name" type="xsd:string" />
            <xsd:element name="last-name" type="xsd:string" />
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

(图 1a)

(或图形化表示,图 1b

显而易见的方法是使用 DOM。我将以 MSXML 和 VB6 为例,见图 2。

Dim oXmlDoc As MSXML2.DOMDocument40
Dim oElmBookStore As MSXML2.IXMLDOMElement
Dim oElmBook As MSXML2.IXMLDOMElement
Dim oAttrGenre As MSXML2.IXMLDOMAttribute
Dim oAttrPublicationDate As MSXML2.IXMLDOMAttribute
Dim oAttrISBN As MSXML2.IXMLDOMAttribute
Dim oElmBookTitle As MSXML2.IXMLDOMElement
Dim oElmBookAuthor As MSXML2.IXMLDOMElement
Dim oElmBookAuthorFirstName As MSXML2.IXMLDOMElement
Dim oElmBookAuthorLastName As MSXML2.IXMLDOMElement
Dim oElmBookPrice As MSXML2.IXMLDOMElement

' create the document

Set oXmlDoc = New MSXML2.DOMDocument40

' Create the document element

Set oElmBookStore = oXmlDoc.createElement("bookstore")
oXmlDoc.appendChild oElmBookStore

' Add the first book

Set oElmBook = oXmlDoc.createElement("book")
oElmBookStore.appendChild oElmBook

' add genre attribute

Set oAttrGenre = oXmlDoc.createAttribute("genre")
oElmBook.Attributes.setNamedItem oAttrGenre
oAttrGenre.Value = "autobiography"

' add publicationdate attribute

Set oAttrPublicationDate = oXmlDoc.createAttribute("publicationdate")
oElmBook.Attributes.setNamedItem oAttrPublicationDate
oAttrPublicationDate.Value = "1981"

' add publicationdate attribute

Set oAttrISBN = oXmlDoc.createAttribute("ISBN")
oElmBook.Attributes.setNamedItem oAttrISBN
oAttrISBN.Value = "1-861003-11-0"

' Add Title to book

Set oElmBookTitle = oXmlDoc.createElement("title")
oElmBook.appendChild oElmBookTitle
oElmBookTitle.nodeTypedValue = "The Autobiography of Benjamin Franklin"

' Add Author to book

Set oElmBookAuthor = oXmlDoc.createElement("author")
oElmBook.appendChild oElmBookAuthor

' Add the first name attributes to the author

Set oElmBookAuthorFirstName = oXmlDoc.createElement("first-name")
oElmBookAuthor.appendChild oElmBookAuthorFirstName
oElmBookAuthorFirstName.nodeTypedValue = "Benjamin"

' Add the last name attributes to the author

Set oElmBookAuthorLastName = oXmlDoc.createElement("last-name")
oElmBookAuthor.appendChild oElmBookAuthorLastName
oElmBookAuthorLastName.nodeTypedValue = "Franklin"

' Add Price to book

Set oElmBookPrice = oXmlDoc.createElement("price")
oElmBook.appendChild oElmBookPrice
oElmBookPrice.nodeTypedValue = "8.99"

' output the XML we created

Debug.Print oXmlDoc.xml
(Figure 2)

图 2 中的代码创建了图 3 中的 XML 文档。代码很多,做的事情却很少!

<bookstore>
    <book genre="autobiography" publicationdate="1981" ISBN="1-861003-11-0">
        <title>The Autobiography of Benjamin Franklin</title>
        <author>
            <first-name>Benjamin</first-name>
            <last-name>Franklin</last-name>
        </author>
        <price>8.99</price>
    </book>
</bookstore>

(图 3)

现在,让我们看看使用 XML 数据绑定库编写的相同代码,见图 4。(我们稍后将介绍 XML 绑定库的来源细节)。

Dim oElmBookStore As New BookStoreSampleLib.Bookstore
Dim oElmBook As BookStoreSampleLib.Book

' create a new book

Set oElmBook = oElmBookStore.Books.Add

' populate the book

oElmBook.Genre = "autobiography"
oElmBook.PublicationDate = "1981"
oElmBook.ISBN = "1-861003-11-0"
oElmBook.Title = "The Autobiography of Benjamin Franklin"
oElmBook.Author.Firstname = "Benjamin"
oElmBook.Author.Lastname = "Franklin"
oElmBook.Price = 8.99

' output the XML we created

Debug.Print oElmBook.xml

(图 4)

代码少了一点,而且维护起来更简单。在读取和解释 XML 文档时,这些优势可能更加明显。

那么,XML 数据绑定库 BookStoreSampleLib 是从哪里来的呢?它是由工具为您生成的。目前市场上有许多不同的工具,每种工具将 XML 模式转换为面向对象库的方式略有不同。

产品

市场上有许多产品,如果您的模式非常简单并且您使用的是 Java,那么 Castor 可能是您最好的选择。已经有一些关于 Castor 的好文章,我不打算重复。但是,如果您不是 Java 开发人员,或者您的模式包含更高级的功能(扩展、限制、替换组等),那么您需要进一步探索。我们已经审查了市场上主要产品,并对其功能进行了简单总结。本文的其余部分,我们将参考 Liquid Technologies 提供的生成器,因为它支持主要的模式(DTD、XDR 和 XSD)和主要的语言(C#、VB6、Java 和跨平台 C++)。

在选择合适的产品时,还有一些重要事项需要考虑(免费不总是廉价的)。

用户创建的模式

如果您正在设计自己的模式,那么您可以根据所选数据绑定产品的任何限制来调整您的模式。因此,即使是功能相当有限的绑定产品,如果模式包含它能够处理的构造,也可以期望生成可工作的代码。但是,这种方法可能会导致您在模式设计上妥协,迫使您使用非常简单的构造和类型。这些妥协最终可能会影响您项目的开发。

第三方模式

在处理标准模式时,产品的选择更为重要。标准模式的问题在于您无法更改它们;您有时可以调整它们的编写方式,但不能改变它们的含义。所以,想象一下您开始使用标准模式,并使用像 JAXB 这样的产品,它最初工作正常。后来,模式的下一个版本发布了,它使用了更多的 XSD 标准(例如扩展),现在 JAXB 将不再工作。您该怎么办?您或多或少回到了原点。您唯一真正的选择是寻找一个支持新模式的产品,但这将意味着重构所有现有代码。因此,权衡之下,最好选择一个能提供大量前期支持的产品。

本节包含对多个主要 XML 数据绑定产品支持功能的评论。

产品 安装大小 易于安装 入门 易用性 输出质量 成本 综合评分 评论(一目了然,详情见下文的完整评论)
Castor   6 3 3 62% 开源 5 使用 Castor 启动和运行非常痛苦。它可以为简单模式生成 Java 代码。生成的代码直接且运行良好(参见完整评论)。
JAXB 46MB 8 7 7 55% ? 6 JAXB 作为 Sun Web 开发工具包的一部分安装。安装简单,如果您安装了 JDK 1.4,则无故障。提供了批处理文件,使其易于使用。不幸的是,JAXB 无法处理除了非常基本的 XSD 模式之外的任何内容(参见完整评论)。
Liquid Technologies XML 数据绑定 11MB 9 8 9 87% £495 8.5 XML 数据绑定向导安装简单。使用基本向导生成代码也很简单。该产品可以为 Java、C#、VB6 和 C++(Win32、Solaris 和 Linux)输出代码,并且能够处理 XSD 标准的大部分内容(参见完整评论)。
微软的 xsd.exe N/A N/A 5 7 61% N/A 6 随 Visual Studio .NET 安装。命令行界面使其操作有点烦人。它能处理大部分 XSD 标准,但没有提供验证,并且仍然要求用户对目标 XSD 有很好的理解(参见完整评论)。

功能摘要

  • Gen - 为具有这些功能的模式生成代码。
  • Sup - 在创建的代码中正确支持这些功能。
产品 Castor JAXB Liquid Tech Xsd.exe
支持的语言
    C# (.NET)
    Java
    C++ (Win32, Linux, Solaris)
    Visual Basic 6
    VB.NET (.NET)

 

产品 Castor JAXB Liquid Tech Xsd.exe
  Gen Sup Gen Sup Gen Sup Gen Sup
复杂类型组
  序列 *1*5
  选择 *4
  所有 *5
  多个模型,相同复杂类型 *1*5
Types
  十六进制/Base64
  日期/时间/gMonthDay 等 *2 *2
  基本类型集合 *13
所有基本数据类型 *18*19 *18 *18 *18
  联合 *2 *2 *2
  任意
  任意属性
  默认值
  填充字符(&<>" 等) N/A N/A N/A N/A
  强类型输出 N/A N/A  *23 N/A 不适用  *10
方面
  小数位数    
  长度    
  最大排他 *20 *18    
  最小排他 *20 *18    
  最大包含 *20    
  最小包含 *20    
  最大长度    
  最小长度    
  模式     *9  
  总位数    
  空白  
基数
  可选 *17 *5
  强制 *5
  多重 *5*11
枚举
  枚举属性 *14 *22 *3
  枚举元素 *14 *22 *3
  0-n 枚举元素 *14*15 *22 *3
文档
  文档生成 *21 *21 *21 *21    
  包含模式中的注释    
复杂内容
  扩展
  限制 *7 ?
  不同的基本模型类型 ?
架构
   命名空间
   导入 ?
   包含 ?
   组    
   递归定义的元素
   替换组
   语言的无效名称
   同名元素和属性 ?
   混合元素 *8 *8 *8 *8
                 
总计 87% 62% 75% 55% 97% 87% 86% 61%
  1. 不对元素的顺序进行验证。
  2. 被视为字符串。
  3. 仅适用于字符串。
  4. 错误地接受包含 0 个或多个元素的选择。
  5. 未进行验证以确保必填字段已填写。
  6. 忽略有效的替换元素。
  7. 允许被限制的子元素。
  8. 无法处理混合内容(例如 HTML <H1>text<B>more text</B>Some More Text</H1> 中的“text”和“Some More Text”被错误表示;通常是连接在一起)。
  9. 支持某些数据类型。
  10. 选择和一些扩展用法导致返回非类型化对象。
  11. 可能产生无效的 XML 输出。
  12. 输出中缺少元素。
  13. 一个奇怪的 bug,它发明了 2 个具有任意值的无符号字节元素,而 XML 中只声明了 1 个。
  14. 不是基于字符串的枚举命名不佳(value0、value1、value2 等)。
  15. 设置值时未进行验证。
  16. 读取 XML 时未进行验证。
  17. 不支持可选组(即,可选序列或选择)。
  18. 支持所有数据类型,但验证规则并非应用于所有类型。
  19. 许多基本类型不受支持,导致代码无法编译(ENTITY、ENTITIES、name、token、UnsignedLong、UnsignedInt、UnsignedShort、UnsignedByte)。
  20. 在某些数据类型(即 gDay)上使用 facet 会导致输出代码无效(即无法编译)。
  21. 创建 JavaDoc 注释。
  22. 支持枚举类型,但被视为基本类型(未执行验证)。
  23. 集合不是强类型。

Castor (0.9.5)

Castor 是同类工具中最早的工具之一。它为 Java 框架提供 XML 和 DB 数据绑定。在我们开始之前,我应该指出我只研究了 XML 数据绑定功能。

Castor 能够接受 XSD 文件,并生成 Java 库的源代码,该库允许与 XML 进行序列化和反序列化。生成的代码依赖 Xerces 作为其 XML 解析器。生成的代码是分离的;一个类用于保存 XML 元素中包含的信息,第二个类用于处理与 XML 的编组和解组。这种分离的优点是保持内存占用小,但确实导致生成大量类!

Castor 对开发人员很有吸引力,因为它是一个开源项目,并且看起来设计得相当周密。然而,它远未完成,缺少许多类和功能区域。因此,它能够很好地处理简单模式,但无法处理许多实际标准中的复杂性。

限制包括

  • 不支持扩展元素(扩展和限制)
  • 不支持替换组
  • 不支持命名空间
  • 对基本数据类型的支持不完善(不支持 name、token、ENTITY 等)
  • 对 facet 的支持不完善。

总结Castor 是处理简单模式的不错选择,它拥有强大的追随者并且仍在改进中。然而,它仍然是一个正在进行中的工作,带有一个笨拙的命令行界面。最终,它可能是一个明智的选择,但目前它仍在成熟中。适用于您直接控制的小型模式。尝试将其与外部控制的模式一起使用,从长远来看,当它们添加 Castor 无法处理的功能时,您将自找麻烦。

JAXB

JAXB 由 Sun 提供,作为其 Web 开发工具包的一部分(我相信这使得它是免费的,但我不确定其许可证的确切条款——请查阅 Sun 的最终用户许可证)。JAXB 有点半心半意的尝试,但能够为非常基本的模式生成 Java 代码,但如果给它任何实际的工作,它就会窒息。

限制包括

  • 不支持扩展元素(扩展和限制)
  • 不支持外部元素(any、anyType)
  • 不支持枚举元素
  • 集合不是强类型
  • 不适用于 Web Logic

总结;如果您选择的产品必须免费,请使用 Castor,否则几乎没有理由使用 JAXB。

Liquid Technologies - XML 数据绑定向导 (3.1)

Liquid Technologies 解决方案是目前最完整的产品之一,几乎完全支持 XSD、XDR 和 DTD 模式。它还具有为多种平台和语言(C#、Java、VB6、C++(适用于 Win32、Linux、HP 和 Solaris))生成代码的优势。它还为生成的类库提供了一整套文档(CHM 和 HTML),使开发更简单。

该产品是处理行业标准和手工制作模式的理想选择。它是目前唯一足够可靠,可用于不断发展的行业标准的系统,因为它是市场上唯一支持如此多 XSD 标准的生成器。

限制包括

  • 不对限制进行验证
  • 不对联合进行验证

总结;这是市场上最完整的系统(截至撰写本文时),使其成为用户定义和行业标准模式的理想选择。生成的代码清晰易用,生成的文档是一个额外的优势。然而,这是一个商业产品,因此需要付费(495 英镑);尽管如此,它应该在一周内收回成本!

Xsd.exe (1.0.3705.0.)

微软对其生成器采取了一种非常极简的方法,生成的类(C# 或 VB.NET)只包含映射到 XSD 属性和元素的公共成员变量,没有访问器,没有方法,什么都没有。XML 序列化由 .NET 框架附带的外部库执行。这些类使用在每个生成类中声明的属性数据(方括号中的内容)。

生成的类允许支持 XSD 标准的许多功能,但是,它们几乎不提供任何验证。它们很乐意读取几乎任何 XML,并会尝试将其适配到生成的对象中。这是一个重要的限制,但可以通过以下方法来缓解:首先将数据读取到验证 XML DOM(根据模式进行验证),然后再将其加载到生成的对象模型中;当然,这会消耗 CPU 周期。此外,填充本身不符合模式的对象太容易了;同样,这可以通过使用验证 DOM 解析器根据模式验证输出 XML 来解决。

该生成器其他显著的缺点包括

  • 缺乏对命名空间的支持
  • 替换组
  • 缺乏对嵌套组(包含选择的序列等)的支持。
  • 带有默认值的可选项目不能从输出 XML 中排除。
  • 所有类都生成到同一个文件中,较大的 XSD 可能会变得难以管理。
  • 选择被表示为非类型化项,可以将其转换为适当的类型。当类型不明确时,会创建一个属性 ItemsElementName,此枚举的名称为 ItemsChoiceTypeX,这使得选择元素的正确类型变得困难。

总结,微软提供的方案是解决该问题的优雅方案,避免验证的决定应该使其代码生成健壮。然而,它仍然无法处理许多实际模式中出现的许多 XSD 功能。这使得它不适用于大型复杂模式,特别是当您无法自行更改模式时。但是,它是免费且易于使用的,因此非常适合您自己描述模式的小型项目。


详细信息

正如您已经看到的,使用数据绑定工具生成的代码可以大大减少处理 XML 时必须编写的代码量和复杂性。如果您有一个复杂的模式并且不是 XSD 专家,那么好处是显而易见的。在下一节中,我们将查看为一些 XSD 构造生成的代码。我们选择 C# 作为语言,因为它更容易阅读;然而,Java、C++ 和 VB6 的输出形式相同,使用生成代码所需的代码几乎相同(一旦考虑了语言语法)。

检查的元素


序列

序列描述一个元素,并定义所有子元素必须出现(如果是强制的)并且它们必须以正确的顺序出现。

示例 XSD

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <xs:element name="ParentSeq">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="FirstChild" type="Xs:string" />
                <Xs:element name="SecondChild" type="Xs:string" />
                <Xs:element name="ThirdChild" type="Xs:string" />
            </Xs:sequence>
        </Xs:complexType>
    </Xs:element>
</Xs:schema>

代码

// create an instance of the class to load the XML file into

SequenceLib.ParentSeq elm = new SequenceLib.ParentSeq();
// Set data into element

elm.ThirdChild = "Some Data 3";
elm.FirstChild = "Some Data 1";
elm.SecondChild = "Some Data 2";
// Lets see what we've got

Trace.WriteLine(elm.ToXml());

创建的 XML

<?xml version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries 
         (www.liquid-technologies.com) for simon-->
<ParentSeq xmlns:Xs="http://www.w3.org/2001/XMLSchema-instance">
    <FirstChild>Some Data 1</FirstChild>
    <SecondChild>Some Data 2</SecondChild>
    <ThirdChild>Some Data 3</ThirdChild>
</ParentSeq>

注释

子元素的设置顺序无关紧要,它们将以正确的顺序出现在输出 XML 中。如果在读取 XML 文件时子元素的顺序不正确,则会引发异常。all 元素的工作方式与 sequence 相同,元素按照定义的顺序写入,但读取时可以以任何顺序。


选择

“选择”描述一个元素,并定义只能出现一个子元素。

示例 XSD

<?xml version="1.0" encoding="UTF-8" ?>
<Xs:schema xmlns:Xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <Xs:element name="ParentSeq">
        <Xs:complexType>
            <Xs:choice>
                <Xs:element name="FirstChild" type="Xs:string" />
                <Xs:element name="SecondChild" type="Xs:string" />
                <Xs:element name="ThirdChild" type="Xs:string" />
            </Xs:choice>
        </Xs:complexType>
    </Xs:element>
</Xs:schema>

代码——从文件读取

// create an instance of the class to load the XML file into

choiceLib.ParentChoice elm = new choiceLib.ParentChoice();
elm.FromXmlFile("c:\\Choice.xml");
// we can find out child child element

// is selected using ChoiceSelectedElement

if (elm.ChoiceSelectedElement == "SecondChild")
{
    Trace.Write("The second child element" + 
     " was present and has the value " + elm.SecondChild);
}
// or by looking at the IsValid flags

Debug.Assert(elm.IsValidFirstChild == false);
Debug.Assert(elm.IsValidSecondChild == true);
Debug.Assert(elm.IsValidThirdChild == false);

注释

如果在 XML 中选择了多个子元素,则 `FromXmlFile` 将引发异常。


基本类型和复杂类型

我们现在已经介绍了基本构造(all/sequence/choice)的表示方式。然而,所有使用的子项都是字符串类型。本节将探讨其他类型,并展示如何操作其他更复杂的子元素。

示例 XSD

<?xml version="1.0" encoding="UTF-8" ?>
<Xs:schema xmlns:Xs="http://www.w3.org/2001/XMLSchema" 
     elementFormDefault="qualified" attributeFormDefault="unqualified">
    <Xs:element name="RootElm">
        <Xs:complexType>
            <Xs:sequence>
                <Xs:element name="StringType" type="Xs:string" />
                <Xs:element name="intType" type="Xs:int" />
                <Xs:element name="ComplexType">
                  <Xs:complexType>
                    <Xs:sequence>
                      <Xs:element name="DateType" type="Xs:dateTime" />
                      <Xs:element name="Base64Type" type="Xs:base64Binary" />
                    </Xs:sequence>
                  </Xs:complexType>
                </Xs:element>
            </Xs:sequence>
        </Xs:complexType>
    </Xs:element>
</Xs:schema>

创建的类

public class RootElm : LiquidTechnologies.LtXmlLib3.XmlObjectBase
{
    public String StringType { get... set...}
    public Int32 IntType { get... set...}
    public TypesLib.ComplexType ComplexType { get... set...}
}
public class ComplexType : LiquidTechnologies.LtXmlLib3.XmlObjectBase
{
    public LiquidTechnologies.LtXmlLib3.XmlDateTime DateType
  { get... set...}
    public LiquidTechnologies.LtXmlLib3.BinaryData Base64Type
  { get... set...}
}
Code creating an XML document
// create an instance of the class to load the XML file into

TypesLib.RootElm elm = new TypesLib.RootElm();
// set data into the element

elm.StringType = "Test String value";
elm.IntType = 5;
// and the child element

elm.ComplexType.DateType.SetDateTime(2004, 4, 26, 10, 41, 35);
elm.ComplexType.Base64Type.SetData("075BCD15", BinaryData.Encoding.Hex);
// Lets look at the XML we produced.

Trace.WriteLine(elm.ToXml());

生成的 XML

<?xml version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries 
         (www.liquid-technologies.com) for simon-->
<RootElm xmlns:Xs="http://www.w3.org/2001/XMLSchema-instance">
    <StringType>Test String value</StringType>
    <intType>5</intType>
    <ComplexType>
        <DateType>2004-04-26T10:41:35</DateType>
        <Base64Type>cLXcUQ==</Base64Type>
    </ComplexType>
</RootElm>

注释

如果 `RootElm` 中包含的 `ComplexType` 是可选的,那么在使用它之前,您必须创建并分配一个对象给 `elm.ComplexType`(参见下一项)。


基数

在此示例中,序列包含多个子元素。子元素都具有不同的基数(通过设置 `minOccurs` 和 `maxOccurs` 属性来改变,两者默认为 1)。生成器以 3 种不同方式处理这些标志

  • 强制性 - minOccurs=1 和 maxOccurs=1

    如果子元素是原始类型(字符串、短时间等),则提供 getset 访问器。所持有的值必须始终包含有效(非空)值。如果子元素是另一个复杂元素(即在生成的代码中表示为新类),则提供一个 get 访问器。这始终会返回一个有效对象。

  • 可选 - minOccurs=0 和 maxOccurs=1

    如果子元素是原始类型(字符串、短时间等),则提供 get、set 和 `IsValid` 访问器。当 `IsValid` 为 true 时,所持有的值必须始终包含有效(非空)值。如果 `IsValid` 设置为 false,则调用 get 访问器会失败,并且不会在 XML 中创建子元素。如果子元素是另一个复杂元素(即在生成的代码中表示为新类),则提供 getset 访问器。它最初将为 null。如果 XML 中需要子元素,则必须创建一个新的子对象(new XXX()),并将其分配给该属性;可以通过将值设置为 null 来移除它。

  • 集合 - minOccurs=n 且 maxOccurs= >1

    如果子元素是原始类型(字符串、短时间等),则提供一个 get 访问器。从 get 运算符返回的对象是原始类型集合;如果集合为空,则 XML 中不会出现任何项。

    如果子元素是另一个复杂元素(即在生成的代码中表示为新类),则提供一个 get 访问器。它返回一个表示复杂元素集合的对象。

示例 XSD

<?xml version="1.0" encoding="UTF-8" ?>
<Xs:schema xmlns:Xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <Xs:element name="Cardinality">
        <Xs:complexType>
            <Xs:sequence>
                <Xs:element name="MandatoryChild" type="Xs:string" />
                <Xs:element name="OptionalChild" 
                type="Xs:string" minOccurs="0" />
                <Xs:element name="CollectionChild" type="Xs:string" 
                            minOccurs="0" maxOccurs="unbounded" />
            </Xs: sequence >
        </Xs:complexType>
    </Xs:element>
</Xs:schema>

代码

// create an instance of the class to load the XML file into

CardinalityLib.Cardinality elm = new CardinalityLib.Cardinality();
// Write data into the element

elm.MandatoryChild = "Some value";
// set some data into the optional element

elm.OptionalChild = "Some other data";
// if we change our mind we can remove this element from the output

elm.IsValidOptionalChild = false;
// The collection element contains a child collection (the

// collection is always populated)

elm.CollectionChild.Add("First item in collection");
elm.CollectionChild.Add("Second item in collection");
// Lets look at the XML we've just created

Trace.WriteLine(elm.ToXml());
// Reading from the element

Trace.Write("Mandatory element contains value - " + 
elm.MandatoryChild);
if (elm.IsValidOptionalChild == true)
Trace.Write("Optional element present. Value - " + 
elm.OptionalChild);
else
Trace.Write("The optional element is not present");
Trace.Write("Child elements in the Collection element");
foreach(string val in elm.CollectionChild)
Trace.Write(" value - " + val);

创建的 XML

<?xml version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries 
         (www.liquid-technologies.com) for simon-->
<Cardinality xmlns:Xs="http://www.w3.org/2001/XMLSchema-instance">
    <MandatoryChild>Some value</MandatoryChild>
    <CollectionChild>First item in collection</CollectionChild>
    <CollectionChild>Second item in collection</CollectionChild>
</Cardinality>

注释

我们使用 `IsValidOptionalChild` 属性来确定 `OptionalChild` 元素是否出现在 XML 中。


扩展

基本复杂类型可以扩展,这个概念类似于 C#、C++、Java 等中的继承。在这个示例中,我们定义了一个基本复杂类型 `.BaseComplexType.`,并从中派生出另外两个复杂类型 `.DerivedComplexType1.` 和 `.DerivedComplexType2.`。最后,我们定义了一个元素 `.UsingElement.`,它包含一个类型为 `.BaseComplexType.` 的元素。在这个元素中,无论我们看到 `.BaseComplexType.`,我们都可以使用 `.DerivedComplexType1.` 或 `.DerivedComplexType2.`。

示例 XSD

<Xs:schema xmlns:Xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <Xs:complexType name="BaseComplexType">
        <Xs:sequence>
            <Xs:element name="ChildOfBaseType" type="Xs:string" />
        </Xs:sequence>
    </Xs:complexType>
    <Xs:complexType name="DerivedComplexType1">
        <Xs:complexContent>
          <Xs:extension base="BaseComplexType">
            <Xs:sequence>
              <Xs:element name="ChildOfDerivedType1" type="Xs:string" />
            </Xs:sequence>
          </Xs:extension>
        </Xs:complexContent>
    </Xs:complexType>
    <Xs:complexType name="DerivedComplexType2">
        <Xs:complexContent>
          <Xs:extension base="BaseComplexType">
            <Xs:sequence>
              <Xs:element name="ChildOfDerivedType2" type="Xs:string" />
            </Xs:sequence>
          </Xs:extension>
        </Xs:complexContent>
    </Xs:complexType>
    <Xs:element name="UsingElement">
        <Xs complexType >
            <Xs:sequence>
                <Xs:element name="BaseType" type="BaseComplexType"/>
            </Xs:sequence>
        </Xs complexType >
    </Xs:element>
</Xs:schema>

代码

// create an instance of the class to load the XML file into

ExtensionLib.UsingElement elm = new ExtensionLib.UsingElement();

//////////////////////////////////////

// Write Data into the new element

// Use the element DerivedComplexType2 in the base element

// UsingElement.BaseType where a BaseComplexType is exected 

ExtensionLib.DerivedComplexType2 elmDerv2 = 
           new ExtensionLib.DerivedComplexType2();
elmDerv2.ChildOfBaseType = "Data field From Base";
elmDerv2.ChildOfDerivedType2 = "Data field From Derived Class";
elm.BaseType = elmDerv2;

// Look at the XMl we just created

Trace.WriteLine(elm.ToXml());

//////////////////////////////////////

// Read data from the element

// The object we get from elm.BaseType is exposed via 

// an interface common to all the objects that can

// be used in its place (IBaseComplexType).

Trace.WriteLine("Data from the Base class - " 
             + elm.BaseType.ChildOfBaseType);

// The actual object held in elm.BaseType can be either

// DerivedComplexType1, DerivedComplexType2 or BaseComplexType

// we need to use runtime type info to find out.

if (elm.BaseType.GetType().Name == "DerivedComplexType2")
{
  // now we know the type, we can cast it up accordingly

  ExtensionLib.DerivedComplexType2 elmDerv = 
           (ExtensionLib.DerivedComplexType2)elm.BaseType;
  // and then make use of the properties defined in the derived class

  Trace.WriteLine("Data in DerivedComplexType2." + 
    "ChildOfDerivedType2 class - " + 
    elmDerv.ChildOfDerivedType2);
}

创建的 XML

<?xml version="1.0"?>
<!--Created by Liquid XML Data Binding Libraries 
         (www.liquid-technologies.com) for simon-->
<UsingElement xmlns:Xs="http://www.w3.org/2001/XMLSchema-instance">
  <BaseType Xs:type="DerivedComplexType2">
    <ChildOfBaseType>Data field From Base</ChildOfBaseType>
    <ChildOfDerivedType2>Data field From Derived Class</ChildOfDerivedType2>
  </BaseType>
</UsingElement>
© . All rights reserved.