Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Visual CSharp .NET Programming (2002) [eng]

.pdf
Скачиваний:
58
Добавлен:
16.08.2013
Размер:
7.98 Mб
Скачать

As I’ll show you in this chapter, the tools built into the development environment, and the XML classes in the .NET Framework, make it easy to create XML schemas and to validate XML documents—which means, to make sure that the elements in the documents comply with the schema.

XML Namespaces

Some of the most important namespaces that contain classes related to XML development are shown in Table 12.1.

 

 

Table 12.1: Namespaces Related to XML

Namespace

 

Description

 

 

 

System.Xml

 

Provides primary support for a variety of XML functions.

 

 

 

System.Xml.Schema

 

Contains the XML classes that provide support for XML Schemas

 

 

Definition (XSD) schemas.

System.Xml.Serialization

System.Xml.XPath

Contains the classes used to serialize and deserialize XML and XML schemas to and from SOAP (Simple Object Access Protocol). SOAP is an open-standard mechanism for wrapping XML and other content so that it can be transmitted over HTTP. SOAP is used as a mechanism for invoking methods on a remote server using XML documents.

Provides an XPath parser and evaluation engine. XPath (XML Path Language) enables you to easily write queries that retrieve partic ular subsets of XML data.

System.Xml.Xsl

 

Provides the tools needed to work with XSLT (Extensible

 

 

Stylesheet Language Transformations). Essentially, XSLT lets you

 

 

create tem plates that can be used to manipulate XML documents

 

 

into other formats and/or to tweak theXML. One use of XSLT is to

 

 

trans form XML into HTML so that it can be rendered in a web

 

 

browser, as explained later in this chapter.

Creating an XML Schema

To create an XML schema using the Visual Studio .NET Schema Designer, choose Project Add New Item from the Project menu. When the Add New Item dialog opens, select XML Schema, as shown in Figure 12.1, and click Open.

Figure 12.1: You can create an XML schema by adding an XML Schema module to your project.

Note In Figure 12.1, you can also see the templates you would select to open an XML Designer (XML File) and an XSLT Designer (XSLT File).

The XML Schema Designer will open, as shown in Figure 12.2. The designer is empty when it first opens.

Figure 12.2: The XML Designer is empty when it opens. To add elements and attributes to your schema, right-click the designer and choose Add.

At this point, with the XML Schema Designer open, there are many ways you can go about adding elements, attributes, and other items to the schema. The techniques, some of which will be covered later in this chapter, include:

Right-clicking the surface of the designer, choosing Add from the context menu, and selecting a new item from the submenu.

Dragging-and-dropping any of the items from the XML Schema tab of the Toolbox to the designer. The XML Schema tab of the Toolbox, which is shown in Figure 12.3, will be available when the XML Designer is open.

Figure 12.3: You can add an item to a schema using the components on the XML Schema tab of the Toolbox.

Using the Server Explorer to drill down into a database and its tables. You can then simply drag and drop a table onto the Schema Designer. The schema will be generated automatically based on the database table elements.

Using the XML Designer to generate a schema based on specific XML in the designer.

Clicking the XML tab of the designer, and editing the XML that constitutes the schema by hand.

Note In addition, you can create a schema programmatically using the Items collection of the XmlSchema class, as I’ll show you shortly.

The items in the XML Schema tab—and the XML Designer Add context menu—correspond to the standard elements of a XSD schema as approved by the World Wide Web Consortium (W3C). They also correspond to classes and members within the System.XML.Schema namespace, which are collectively called the Schema Object Model (SOM). For example, objects of the XmlSchema class are each elements in a schema.

Put differently, the SOM implements W3C-approved XSD schemas within the .NET Framework. The SOM can be used to programmatically create and edit schemas in much the same way that the Document Object Model (DOM), discussed later in this chapter, can be used to edit XML documents themselves. The XmlSchema class can also be used to validate the syntactic and semantic structure of a programmatically built schema.

Table 12.2 shows the meanings of the items that appear on the XML Designer context menu and on the XML Schema tab of the Toolbox.

Note You can also learn more about XSD schemas by looking up the topics “XML Schema Reference” and “XML Schema Elements” in online help. You can also have a look at the information published by the W3C regarding XML schemas at www.w3.org/2001/ XMLSchema.

Table 12.2: XSD Schema Items

Toolbox Item What It Does

element

Creates an element, which associates a name with a type. The element can be global, added to other elements, added to groups, or used to construct complexTypes.

attribute

Creates an attribute, which associates a name with a type and is associated with an element or complexType. Attributes can be global, added to elements, or added to groups.

attributeGroup Creates an attributeGroup (a group of attributes) that can be global, added to elements, or used in the construct of complexTypes.

complexType

 

Creates a complexType to which you can add elements, attributes, attribute

 

 

Groups, anys, and anyAttributes.

 

 

 

simpleType

 

Creates a simpleType to which you can add facets.

 

 

 

group

 

Creates groups that can be global, added to other groups, elements, or

 

 

complexTypes.

any

Creates an any element (meaning any element, or sequence of elements, from a specified namespace) that can be added to elements, complexTypes, or groups.

anyAttribute

 

Creates an anyAttribute element (meaning any attribute element, or sequence

 

 

of attribute elements, from a specified namespace) that can be added to

 

 

elements, attribute groups, or complex types.

 

 

 

facet

 

Sets limits on the type of content a simpleType can contain (for an example

 

 

using facets, see “Create It in Code” later in this chapter).

key

Relation

Launches the Edit Key dialog box, which is used to create keys when added to an element. Keys are the primary fields that tie relations together (see “Database Basics” later in this chapter).

Launches the Edit Relation dialog box, which is used to define relationships between elements.

Whichever method you use with the Schema Designer to create a schema, the schema appears in the designer in tabular form (can we all say together, “just like a database schema”?) as you can see in Figure 12.4.

Figure 12.4: When you add items from the Toolbox, context menu, or Server Explorer, the schema appears in tabular form in the designer.

Programmatically Creating and Validating a Schema

Before I show you how to use the XmlSchema class to create and validate a schema, let’s define the schema manually. To put the cart even further before the horse, let’s first create some XML that we’d like to be the basis for the schema, and describe how we’d like the XML to work (in fact, this is likely to be the way schemas are created in the real world).

One If by Hand

My XML excerpt describes a product, which is an element that is a complex type. Each product must have an integer product identification number and a product type chosen from the enumeration “Candy”, “Toy”, or “Gadget”. In addition, each product should have a name, a description, and as many or few subparts as one would like. Here’s an XML rendering of this element for a candy named a “Purple Wheeler”:

<?xml version="1.0" encoding="utf-8" ?> <Product ProdId="123" ProdType="Candy">

<Name>Purple Wheeler</Name> <Desc>Tastes like grape</Desc> <SubPart>Wheel</SubPart> <SubPart>Purple</SubPart>

</Product>

To enforce the conditions I’d like for the XML, I must create a sequence of simple elements falling within my product element, with zero to many occurrences of the SubPart element. In addition, two required attributes must be specified, with one of them taking values from an enumeration. Here’s how this looks as an XML schema with the xs schema item prefix omitted for clarity:

<?xml version="1.0" ?>

<schema xmlns="http://www.w3.org/2001/XMLSchema"> <element name="Product">

<complexType>

<sequence>

<element name="Name" type="string" /> <element name="Desc" type="string" />

<element name="SubPart" minOccurs="0" maxOccurs="unbounded" />

</sequence>

<attribute name="ProdId" use="required" type="integer" /> <attribute name="ProdType" use="required" >

<simpleType>

<restriction base = "string"> <enumeration value="Candy" /> <enumeration value="Toy" /> <enumeration value="Gadget" />

</restriction>

</simpleType>

</attribute>

</complexType>

</element>

</schema>

Listing 12.1 shows the same XML schema rendered a little more formally.

Note The xs:schema declaration says that the text represents a schema, and that the xs prefix will be used before elements. The xmlns:xs="http://www.w3.org/2001/XMLSchema" declaration says that all tags should be interpreted according to the W3C defaults. The targetNamespace declaration names the schema and provides a URI as its default namespace (the same purpose is also achieved using xmlns and xmlns:mstns declarations). If you create a schema within Visual Studio using one of the tools available (such as the Create Schema menu item available from the XML Designer), you’ll probably find that some additional attribute declarations, many of them Microsoft-specific, have been added to the schema tag.

Listing 12.1: An XSD XML Schema

<?xml version="1.0" ?>

<xs:schema targetNamespace="http://www.tempuri.org/XMLFile1.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="Product"> <xs:complexType>

<xs:sequence>

<xs:element name="Name" type="xs:string" /> <xs:element name="Desc" type="xs:string" /> <xs:element name="SubPart" minOccurs="0"

maxOccurs="unbounded" type="xs:string" /> </xs:sequence>

<xs:attribute name="ProdId" use="required" type="xs:integer" />

<xs:attribute name="ProdType" use="required"> <xs:simpleType>

<xs:restriction base="xs:string"> <xs:enumeration value="Candy" /> <xs:enumeration value="Toy" /> <xs:enumeration value="Gagdet" />

</xs:restriction>

</xs:simpleType>

</xs:attribute>

</xs:complexType>

</xs:element>

</xs:schema>

Next, if the XML schema shown in Listing 12.1 is copied into an XML Schema Designer

in Visual Studio, it can be validated by giving the designer the focus and selecting Schema Validate. If you’ve left something off—for instance, a closing bracket—validation will tell you. If there are no validation errors, then the schema is “well-formed” and usable.

Going back to our original XML fragment, we can now enter it in an XML Designer and connect it to its intended schema:

<?xml version="1.0" encoding="utf-8" ?> <Product xsi:ProdId="123" xsi:ProdType="Candy"

xmlns="http://www.tempuri.org/XMLFile1.xsd"

xmlns:xsi="http://www.tempuri.org/XMLFile1.xsd"> <Name>Purple Wheeler</Name>

<Desc>Tastes like grape</Desc> <SubPart>Wheel</SubPart> <SubPart>Purple</SubPart>

</Product>

Note To open a new, empty XML Designer in Visual Studio, select Project ?Add New Item, and then select XML File in the Add New Item dialog.

Note that connecting XML and target schemas within Visual Studio that have not been created using auto-generation tools can be a little tricky. In addition to the internal namespace declaration (xmlns="http://www.tempuri.org/XMLFile1.xsd"), you may need to use the Properties window to point an XML Designer at its target schema.

Note If the XSD schema isn’t qualified by a namespace, you can link an XML document to it using a noNameSpaceSchema declaration.

The whole point of creating a well-formed XSD schema and linking XML to it is that the schema can enforce conditions on the XML. Let’s try this out in the example. In the XML Designer, change the value of the ProdType enumeration to a value not included in the enumeration—for example, "Game". If you now try to validate the XML against the schema (by selecting XML Validate XML Data), you’ll get an error message, as shown in Figure 12.5.

Figure 12.5: An XSD schema is used to enforce typing and conditions within an XML document.

Create It in Code

The XmlSchema and related classes are used to construct and validate an XSD schema programmatically. XmlSchema is a member of the System.Xml.Schema namespace.

To see how this works, let’s construct the same schema (for the Product defined earlier in this chapter) one more time using code mechanisms.

Note The code for creating the schema may seem like a great deal of trouble, considering the excellent tools available in Visual Studio for creating schemas without programming. But if you need to work with XML, you’ll want to know the classes, objects, and relationships involved in a programmatic construction of a schema. Often, no human being is available to build the schema.

First, create a new schema and the Product schema element:

XmlSchema schema = new XmlSchema(); XmlSchemaElement eProduct = new XmlSchemaElement(); eProduct.Name = "Product";

schema.Items.Add (eProduct);

Next, establish the Product element as a complex type that includes a sequence:

XmlSchemaComplexType ct = new XmlSchemaComplexType(); eProduct.SchemaType = ct;

XmlSchemaSequence ss = new XmlSchemaSequence(); ct.Particle = ss;

For each simple element in the schema sequence, add it to the sequence by adding it to the schema sequence Items collection:

XmlSchemaElement eName = new XmlSchemaElement(); eName.Name = "Name";

eName.SchemaTypeName = new XmlQualifiedName("string", "http://www.w3.org/2001/XMLSchema");

ss.Items.Add (eName);

...

As you’ll recall, the SubPart element can occur no times, or many times, in the sequence. This is coded using the element’s MinOccurs and MaxOccursString properties:

XmlSchemaElement eSubPart = new XmlSchemaElement(); eSubPart.Name = "SubPart";

eSubPart.SchemaTypeName = new XmlQualifiedName("string", "http://www.w3.org/2001/XMLSchema");

eSubPart.MinOccurs = 0; eSubPart.MaxOccursString = "unbounded"; ss.Items.Add (eSubPart);

Next, the attributes are added to the complex type’s Attributes collection:

XmlSchemaAttribute aProdId = new XmlSchemaAttribute(); aProdId.Name = "ProdId";

aProdId.SchemaTypeName = new XmlQualifiedName("integer", "http://www.w3.org/2001/XMLSchema");

aProdId.Use = XmlSchemaUse.Required; ct.Attributes.Add(aProdId);

The ProdType attribute is a little more complicated, since it uses a type restriction and facets on a simple type to achieve its goal of restricting user choice to an enumeration:

XmlSchemaSimpleType st = new XmlSchemaSimpleType(); aProdType.SchemaType = st;

XmlSchemaSimpleTypeRestriction res = new XmlSchemaSimpleTypeRestriction(); res.BaseTypeName = new XmlQualifiedName ("string",

"http://www.w3.org/2001/XMLSchema"); st.Content = res;

XmlSchemaEnumerationFacet f1 = new XmlSchemaEnumerationFacet(); XmlSchemaEnumerationFacet f2 = new XmlSchemaEnumerationFacet(); XmlSchemaEnumerationFacet f3 = new XmlSchemaEnumerationFacet(); f1.Value = "Candy";

f2.Value = "Toy"; f3.Value = "Gadget"; res.Facets.Add(f1); res.Facets.Add(f2); res.Facets.Add(f3);

ct.Attributes.Add(aProdType);

With the schema elements complete, the remaining step is to use the XmlSchema’s Compile method, assigning it a callback method for reporting any validation errors:

...

schema.Compile(new ValidationEventHandler(SOMHandler)); if (txtValidate.Text == "")

txtValidate.Text = "Schema validates without problems.";

...

}

private void SOMHandler(object sender, ValidationEventArgs e){ txtValidate.Text += e.Message;

}

Note If no validation errors are reported, the code after the Compile method is invoked displays a "validates without problems" message.

I used a FileStream along with an XMLTextWriter to write the schema to a file:

file = new FileStream("Product.xsd", FileMode.Create, FileAccess.ReadWrite);

XmlTextWriter xwriter = new XmlTextWriter(file, new UTF8Encoding()); xwriter.Formatting = Formatting.Indented;

schema.Write (xwriter);

I chose to read the file as plain text back into a multiline TextBox:

nfile = new FileStream("Product.xsd", FileMode.Open, FileAccess.ReadWrite); reader = new StreamReader(nfile);

txtSchema.Text = reader.ReadToEnd();

The complete code for creating and validating the schema is shown in Listing 12.2. If you run the program, the schema will be displayed (Figure 12.6).

Figure 12.6: The XmlSchema class is used to create a Schema Object Model (SOM) schema in code.

It’s worth experimenting to see what will happen if you add some errors into the schema. Doing this involves walking a fine line, because your “error” has to pass syntax compilation, which not just any old error will do.

For example, the following “bogus” element type is not “really” part of the W3C schema specification, but it does not cause a C# syntax error because the syntaxes of the statements creating the element are legal:

XmlSchemaElement eBogus = new XmlSchemaElement(); eBogus.Name = "Bogus";

eBogus.SchemaTypeName = new XmlQualifiedName("bogus", "http://www.w3.org/2001/XMLSchema");

ss.Items.Add (eBogus);

If you add the “bogus” element type to the code, you’ll get an appropriate error message (Figure 12.7).

Figure 12.7: A schema validation error is thrown because “bogus” is not a recognized element type.

Note If you find yourself struggling with schema validation issues, it’s a good idea to copy