HOME | SIGN UP | ACCOUNT | SUBSCRIBE | TROUBLESHOOTING | LOGIN
News · Meetings · Jobs · Downloads · Universal Thread articles · Web articles · Conference coverages · Consultants · Blogs · FAQ · User groups · Photos · Videos

Introducing XML for VFP Programmers - Part II

Fabio Vazquez, Microsoft
Fabio Vazquez (Sao Paulo, Brazil) is a Software Development Engineer for the Microsoft Dynamics Ax Globalization Team at Microsoft. He is a former Microsoft Most Valuable Professional (MVP) in C# and VFP and a frequent speaker at software development conferences in Brazil, including the Microsoft PDC (Professional Developers Conference) and Tech-Ed. Fabio has two books published and has a great passion for agile development practices.

On the first part of this article, I introduced the concepts of eXtensible Markup Language (XML) and developed a sample program in VFP which reads a well-formed XML document. That program used the Microsoft XML parser (MSXML) to do the reading and interpretation of the document and recursively rebuilt the document's hierarchical structure. In this article, I will be approaching new concepts, such as Namespaces and XML Schemas, and putting them into the context of Visual FoxPro 7.0 application development.

XML Namespaces

As we already noticed, XML offers a high level of flexibility. With XML, we can build our own structure to represent virtually any type of data we want. This flexibility allows a diversity of solutions for developers to develop distinct representations to common concepts, creating in this way, documents which represent similar subjects. This can lead to the creation of different structures to represent the same concept, all based on the understanding of each company or person. The integration of XML documents developed by different persons may result in identical names and elements. In these cases, who "owns" the names? To resolve this kind of conflict, the XML recommendation defines XML Namespaces. Namespaces allow for a set of tags don't conflict with other set of tags. So they create a logical organization of the elements and attributes of an XML document so these elements and attributes may have a way to distinct one of the other.

Understanding namespaces

The concept of namespaces, which confuses most of the XML beginners, is quite simple and familiar to all of us. Imagine, for example, the names you could give to your children. You have an infinite possible choices, as far as you don't repeat the same name to more than one child. This is possible because our surname will differentiate our children from the individuals with the same name around the world. By that, we can imagine our family's surname as a namespace - a logical group of names. This way, different persons with the same name can exist around the world, but what differentiates them is the combination of name and surname or, translating this to the XML world, a combination of names and namespaces.

A namespace is specified by prefixing the element or attribute name with the namespace name plus a colon character. Let's again take the XML document that represents compact discs we had already analyzed on the first part of this article. The following listing gives an example of an XML document representing a set of CDs:

<?xml version="1.0" encoding="Windows-1252"?>
<CDS> 
    <CD genre="rock">
        <TITLE>Abbey Road</TITLE>
        <AUTHOR>The Beatles</AUTHOR>
        <YEAR>1969</YEAR>
        <LABEL>Emd-Capitol</LABEL>
    </CD>
</CDS>

There is nothing new in this document, right? Well, let's suppose we want to make the elements of our document unique. Let's create a namespace named "rapozine", so that all the elements of our document, from the root element on, will be prefixed with "rapozine:". To define a namespace, we put a special attribute called "xmlns" at the opening tag of any element. The syntax to create a new namespace has the following format:

xmlns:prefix="namespace_name"

The prefix portion will be used before any element or attribute for which we want to specify the namespace. The portion "namespace_name" is an URI (Uniform Resource Identifier) we use to uniquely identify our namespace. The following line defines a namespace "rapozine":

xmlns:rapozine="http://www.rapozine.com.br"
In this example, the namespace prefix is "rapozine". The namespace identifier is "http://www.rapozione.com.br". The URI does not have to be be a valid URL. Normally, the XML authors specify an URL with the sole purpose of attaching a universally unique identifier to their namespace. At the moment the document is used, the parser will not try to connect to the URL to do any kind of verification. It is the responsibility of the author to specify a globally unique URI for his/her document.

As I said earlier, the "xmlns" attribute can be put into any opening tag in the document. All the child elements of the element where the namespace attribute is put in will be on the namespace scope. This means that we can use the namespace in these nested elements/attributes. Listing 2 presents the document shown in Listing 1 modified to include the namespace "rapozine" in all elements and attributes from the root element (CDS) on.

<?xml version="1.0" encoding="Windows-1252"?>
<rapozine:CDS 
 xmlns:rapozine="http://www.rapozine.com.br">
    <rapozine:CD rapozine:genre="rock">
        <rapozine:TITLE>Abbey Road</rapozine:TITLE>
        <rapozine:AUTHOR>The Beatles</rapozine:AUTHOR>
        <rapozine:YEAR>1969</rapozine:YEAR>
        <rapozine:LABEL>Emd-Capitol</rapozine:LABEL>
    </rapozine:CD>
</rapozine:CDS>

The namespace is defined on the root element <CDS>. All inner elements are considered in the namespace scope and we can prefix them or its attributes with the namespace prefix, as the example above shows.

Validating XML Documents

On the first part of this series of articles, I defined the concept of well-formed documents and valid documents. An XML document, to be considered well-formed, must follow some basic formatting rules. Although mandatory, these rules don't make the document valid. A XML document is said to be valid when it has associated an DTD (Document Type Definition) or XML Schema with it and when it follows the rules estabilished in this DTD or XML Schema. But, what is the goal of having a valid XML document? Why go through the burden of defining a rigid structure for a document that must be followed? Doesn't it come against the concept of flexibility intrinsic of the XML standard?

Imagine that your company receives sales orders from diverse customers where these orders are represented in XML. How can we guarantee that all the companies sending these orders are creating XML documents which conform to the desired structure? Compare the following two documents:

XML document representing a simple sales order

<?xml version="1.0" encoding="UTF-8"?>
<ORDER>
    <CUSTOMER>0001</CUSTOMER>
    <ITEMS>
        <ITEM>
            <ID>0100</ID>
            <QUANT>10</QUANT>
        </ITEM>
        <ITEM>
            <ID>0200</ID>
            <QUANT>20</QUANT>
        </ITEM>
    </ITEMS>
</ORDER>

XML document representing a simple sales order with a structure different from the previous listing

<?xml version="1.0" encoding="UTF-8"?>
<ORDER>
    <CUSTOMER>0002</CUSTOMER>
    <ITEMS>
        <ITEM ID="0100">
            <QUANT>10</QUANT>
        </ITEM>
        <ITEM ID="0200">
            <QUANT>20</QUANT>
        </ITEM>
    </ITEMS>
</ORDER>

Both documents represent the same information - an order with two items posted by a specific customer. See, however, that there is a subtile difference between the two models where the document of the first listing specifies the "ID" of an item by an <ID> element and the last listing represents the same ID by an attribute of the <ITEM> element. For us, humans who are reading the examples, it doesn't make so much difference, but for a computer program or parser which does the interpretation of these documents, there must be a consensun about the correct structure. Here, enter DTDs and XML Schemas. Through these constructions, we can formalize the correct structure of an XML document: how elements must be hierarchically organized, what is the cardinality of each element, which must be the root element, where can attributes be used and what will be the name and data types of them, among other definitions. Translating these possibilities to our example, the received XML documents can be validated against the DTDs or XML Schemas and we can, as developers of the solution who interpret the documents, to know if the XML received matches the expected structure. In the case, it does not match. This document can be said as being not valid and can be rejected immediately by the application.

DTDs and XML Schemas are distinct technologies for XML documents validation. DTDs were broadly used for a long time, given the fact that XML Schemas turned a W3C recommendation in May 2001. Nevertheless, XML Schemas have been observed as a growing tendency over DTDs. This is because XML Schema is XML based, contrary to DTD and allows a more refined level of control of its elements and attributes.

Because of this tendency observed on the future of these two validation technologies, I will, on the remaining of this article, cover only the XML Schema subject. If you are interested in knowing more about DTDs, access the web page about them at W3C (http://www.w3.org/TR/REC-xml). We will see also how these concepts are already implemented today in Visual FoxPro 7.0.

XML Schema

XML Schema Definition Language, also known as XSD, turned out a W3C recommendation on May 2001. Until then, a lot of proposes had already been made with the intend of officially recognizing this type of schema. In this interim, companies like Microsoft ended defining its own provisory schema definition language. In the case of Microsoft, versions of MSXML parser had support for this intermediary language, known as XML-Data Reduced (XDR). The XML functionalities of SQL Server 2000 also make use of XDR schemas. After the W3C recommendation, XSD has been each time more adopted by most of the big software suppliers. MSXML 4.0 already has functions for XSD schema validation. Visual Studio .NET also comes with a XML Schema editor that allows these schemas to be graphically generated, which eases the job for beginners and allows a better management of more complex schemas.

What are schemas?

Schemas are intended to define the structure of something. In our case, "something" is an XML document. If we translate this concept to database systems, we can think of schemas as DDL (Data Definition Language) instructions, where we can define the structure of our tables and columns. Similarly, in XML we can define what structure our document must have through the use of schemas. The term "XML Schema" was given to W3C to its technology to validate XML documents. The correct name of the technology is "XML Schema". It is wrong one to write "XML schema", for example. We are talking about a specific technology here. What are schemas?

Schemas are intended to define the structure of something. In our case, "something" is an XML document. If we translate this concept to database systems, we can think of schemas as DDL (Data Definition Language) instructions, where we can define the structure of our tables and columns. Similarly, in XML we can define what structure our document must have through the use of schemas. The term "XML Schema" was given to W3C to its technology to validate XML documents. The correct name of the technology is "XML Schema". It is wrong one to write "XML schema", for example. We are talking about a specific technology here.

XML Schema data types

One of the greatest advantages of XML Schemas over DTDs is the possibility of defining the data types of our elements and attributes. With this feature, we can specify whether a given element or attribute will be a string, an integer, a floating-point number, a date, an URL and so on. We can also create our own customized data types, based on already existing ones in order to make an implementation more flexible. XML Schema defines two categories of data types: simple and complex. Elements that can contain other elements (subelements) or attributes are said to have complex type (complexType), whereas elements that contain only text (without subelements) are said to have simple type (simpleType). Attributes are naturally of simple type since they cannot contain subelements. You can find a list of the primitive XML Schema data types at http://www.w3.org/TR/xmlschema-0/#CreatDt

Getting started with XML Schemas

The best way to learn to use XML Schemas is to see practical examples. A great advantage of the recommendation is that XML Schemas are written using XML syntax. This is interesting, since it doesn't require the learning of a new syntax for schema definition as is the case with DTDs. As we are already familiar with the CD example shown in part I, let's consider it here as our example. We can call a document which conforms with the specification of its XML Schema an instance document. Let's analyze the instance document bellow and see how we can create a simple XML Schema:

<?xml version="1.0" encoding="Windows-1252"?>
<CDS> 
    <CD genre="rock">
        <TITLE>Abbey Road</TITLE>
        <AUTHOR>The Beatles</AUTHOR>
        <YEAR>1969</YEAR>
        <LABEL>Emd-Capitol</LABEL>
    </CD>
    <CD genre="blues">
        <TITLE>B.B.King</TITLE>
        <AUTHOR>Blues Summit</AUTHOR>
        <YEAR>1993</YEAR>
        <LABEL>MCA</LABEL>
    </CD>
    <CD genre="flamenco">
        <TITLE>Concerto de Aranjuez</TITLE>
        <AUTHOR>Paco De Lucia</AUTHOR>
        <YEAR>1993</YEAR>
        <LABEL>Verve</LABEL>
    </CD>
</CDS>
Now observe in the following listing an XML Schema which performs the validation of the document of the previous listing.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="CDS">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="CD" minOccurs="1" maxOccurs="unbounded" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="CD">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="TITLE" type="xsd:string" />
        <xsd:element name="AUTHOR" type="xsd:string" />
        <xsd:element name="YEAR" type="xsd:gYear" />
        <xsd:element name="LABEL" type="xsd:string" />
      </xsd:sequence>
      <xsd:attribute name="genre" type="xsd:string" />
    </xsd:complexType>
  </xsd:element>
</xsd:schema>
As you can notice, the document is indeed an XML document and as such must be well-formed. The root element of this document is named "schema". All XML Schema documents will have a root element with this name. See also that in the opening tag of the "schema" element a namespace named "http://www.w3.org/2001/XMLSchema" was defined whose prefix is "xsd".
<schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
This namespace is very important when it comes to the tools used to read these schemas. Internally XML parsers which conform to the XSD schema recommendation will search for this namespace name in order to know they are dealing with a valid schema. Notice also that the namespace prefix can be other than "xsd". This is only a common practice.

Defining elements

To define the elements our document will have, we use the XML Schema element "element". Into this element we can have defined simple or complex types. In our example we can see, for example, the definition of the element "TITLE" as being of type string and as a child element of the element "CD".

Defining attributes

The definition of attributes is as simple as the definition of elements. In order to define attributes we use the XML Schema "attribute" element. In our example, I have defined an attribute called "genre" as being part of the element "CD". The definition of the attributes of an element must be done after the definition of all its child elements.

Cardinality of elements

With XML Schemas, we can define cardinality for the elements. In other words, we can define how many times an element can occur into an instance document. Through the "minOccurs" and "maxOccurs" attributes in the opening tag of an element definition, we can specify the minimum and maximum number of times a given element can appear respectively. The default value for these attributes is 1. This means that if the "minOccurs" and "maxOccurs" attributes are omitted, the element must appear once and only once. When these attributes are specified, special attention must be paid to the fact that both must have a positive integer value and that the value specified for "minOccurs" must be less or iqual to the "maxOccurs" value. The "maxOccurs" attribute may have a special value of "unbounded", which allows an unlimited number of occurrences to the element. In the XML Schema, the "CD" element was defined to support one or more occurrences.

<xsd:element ref="CD" minOccurs="1" maxOccurs="unbounded" />

Occurrences of Attributes

Differently of elements, the concept of cardinality does not apply to attributes. So attributes cannot appear more than once into a tag. However, an attribute does not need to be present at all. In order to define the occurrence constraints of an attribute we use the XML Schema "attribute" element with an attribute named "used". The three possible values for this attribute are:

ValueDetails
RequiredIndicates that the attribute must appear
OptionalIndicates that the attribute can appear once or not appear at all
ProhibitedIndicates that the attribute cannot appear

In the XML Schema, the attribute "genre" was defined without the "used" attribute. This means the default value will be assumed, which in this case is "optional".

<xsd:attribute name="genre" type="xsd:string" />

The equivalent to the above line is:

<xsd:attribute name="genre" type="xsd:string" used="optional" />

Value constraints on elements

With DTDs, it is possible to specify default values for attributes but not for the content of the elements. On the other hand, with XML Schemas we can, through the use of the "default" attribute of the "element" tag, to define default values for the content of these elements. The default value will be given to the element content in the cases where the parser reads the instance document and the element is empty. If we would like to have a default value to the "YEAR" element, we could have been written it the following way:

<xsd:element name="YEAR" type="xsd:gYear" default="2001" />

Another possibility on the specification of value constraints is the one of defining fixed values for the content of the elements. Fixed values, like default values, are attached to the element content when it is empty. On the other hand, contrary to default values, fixed values do not accept other values in the case they are specified in the instance document. This way, the "default" and "fixed" attributes are mutually exclusive and cannot appear at the same time in the element definition.

Value constraints on attributes

With XML Schemas, we can specify default values for attributes the same way we do for elements, as we saw earlier. Like in the elements, the "default" attribute of the opening tag for the "attribute" element, defines a default value for the attribute. Note that we must use the "used" attribute with the value "optional" (used=optional) in order to use default values. The same mutuality rules of the "fixed" and "default" attributes that existed for elements apply also for attributes.

Creating Sequences of Elements

XML Schemas allow us to define a sequence in which children elements must appear inside their parent in the instance document. To specify a sequence of elements, we use the XML Schema "sequence" attribute. In our example, I defined a specific sequence for the elements that appear inside the "CD" element. According to the listing, the elements inside the "CD" element must be in the following order: "TITLE", "AUTHOR", "YEAR" and "LABEL". If the elements appear in a different order, the document cannot be considered a valid one.

Creating Choices

In some situations, we could want an element to have various possible subelements, but only one of them could be chosen. We have seen that we can define sequences of elements. Now, we will see how to define a set of possible elements where one and only one of them can appear in the document. Through the XML Schema "choice" element, we can define such elements. Let's suppose we have a situation where in one of the elements we could specify one CD or a set of CDS. Using the definitions for "CD" and "CDS", we can suppose the following configuration:

<xsd:choice>
	<xsd:element ref="CDS" />
	<xsd:element ref="CD" />
</xsd:choice>

Creating simple types

Even if there is a really broad quantity of simple types predefined by the XML Schema recommendation, sometimes, we want to define our own custom types in order to better match our business area. We can do that through the use of facets. Facets allow that constraints can be established over the predefined types. For example, let's suppose we want to define a type to maintain school grades of a student in a given discipline (0 to 10). Predefined types as "integer", "int" or "positiveInteger" could be well used to represent this type of value. However, we can be more specific and define constraints over one of these predefined types in a way we can create a new simple type. This simple type will be based on one of the existing types and can restrict the possible values to the numbers 0 to 10. See in the example bellow how we could create a new simple type named "grade" based on the predefined type "integer".

<xsd:simpleType name="grade">
	<xsd:restriction base="xsd:integer">
		<xsd:minInclusive value="0" />
		<xsd:maxInclusive value="10" />
	</xsd:restriction>
</xsd:simpleType>
I used the XML Schema element "simpleType" to define and name a new simple type. Then I used the subelement "restriction" to indicate the base type (already existent). Finally, I used the elements for the desired facets as subelements of the element "restriction". The facets used in the example are "minInclusive" and "maxInclusive", whose goal does not require further explanations. There are other facets I will not cover in this article, but the important thing is to know their objective. More information about facets, as well as the detailed description of each one of them, can be found in http://www.w3.org/TR/xmlschema-2. An attribute of type "grade" could be defined in an XML Schema in the following way:
<xsd:attibute name="maxGrade" type="grade" />

Where does XML enter in VFP?

We have talked about XML and every subject we have touched is related to the standards established by W3C and will be valid on any platform and programming language which implement XML and XML Schemas in particular. In VFP 7.0, we were presented with functions for XML document manipulation, from which the most famous are certainly CURSORTOXML() and XMLTOCURSOR(). Through these functions, we can respectively transform XML cursors into XML documents and vice-versa. These functions certainly add lots of resources to the utilization of VFP as a tool for building middle-tier components. We can now communicate components between the tiers of our n-tier applications using XML as the transport medium. The possibility of creating a consuming Web Services in VFP 7.0 also elevates XML to a much more important technology in the set of technologies used by Visual FoxPro developers.

The following example creates a VFP cursor representing a customer with two fields (customer name and quantity of orders put by this customer). After, an XML document is created with the CURSORTOXML() function and the content of the document is shown in a window.

LOCAL lcXML 
CREATE CURSOR Customer (Name Char(20), QtyOrders Integer)
INSERT INTO Customer VALUES ("Fabio Vazquez", 1)
INSERT INTO Customer VALUES ("Another Customer", 0)
CURSORTOXML("Customer", "lcXML")
STRTOFILE(lcXML, "output.xml")
MODIFY FILE ("output.xml")
DELETE FILE "output.xml"
In this example, I have used the most basic form of utilization to the CURSORTOXML() function. In other words, only the first two parameters were passed in. The first one is the name of the cursor on which the XML document will be based. The second one indicates the output type for the document, which in our case is a memory variable called "lcXML". There are other important parameters we will discuss further in this article. For now, let's keep this example only with both parameters to see what consequences this can generate. In the window showed by the MODIFY WINDOW command we can see the XML document generated by CURSORTOXML(), which should look like the one showed in the listing bellow.
<?xml version = "1.0" encoding="Windows-1252" standalone="yes"?>
<VFPData>
	<customer>
		<name>Fabio Vazquez</name>
		<qtyorders>1</qtyorders>
	</customer>
	<customer>
		<name>Another Customer</name>
		<qtyorders>0</qtyorders>
	</customer>
</VFPData>
Where is the schema of this document? Actually, no schema was generated for this document and this can bring undesired consequences. If we try to do the reverse path of the preceding operation, in other words, if we try to convert the generated XML string back to a new cursor, we will get a strange behavior. Try adding the following two lines to the code:
XMLTOCURSOR(lcXML, "NewCustomer")
MODIFY STRUCTURE
The first line generates a new cursor named "NewCustomer" based on the XML string contained in the "lcXML" variable. The second line will just show us the structure for the new generated cursor. The picture bellow shows the screen output for the MODIFY STRUCTURE command:

What do you see that seems strange in this figure? Actually there are two problems here. The first is the creation of the field "Name" with type Char(6). The other problem, even more serious, is the creation of the field "QtyOrders" as Logical type! But, how had this happened?

All these problems are because the absence of schemas to the generated XML document. Without schemas, XMLTOCURSOR() has to "guess" the data type structure of the elements and this guessing, as we can verify, is not always the right one. By generating schemas we can really solve these kind of problems. Let's modify our code so that it will use schemas and let's verify what changes this bring us.

LOCAL lcXML 
CREATE CURSOR Customer (Name Char(20), QtyOrders Integer)
INSERT INTO Customer VALUES ("Fabio Vazquez", 1)
INSERT INTO Customer VALUES ("Another Customer", 0)
CURSORTOXML("Customer", "lcXML", 1, 0, 0, "1")
STRTOFILE(lcXML, "output.xml")
MODIFY FILE ("output.xml")
DELETE FILE "output.xml"
You can see that in the call to CURSORTOXML(), we add some additional parameters. The third, fourth and fifth parameters are passed in with their default values, so they really do not make the difference. The sixth parameter, on the other hand, will make all the difference in relation to our primer example. This parameter indicates the name of the schema to be used for the generation of the document. There are three possible values for this parameter:

ValueDetails
Specifies that no schema will be produced
1Specifies that an inline schema will be produced, in other words, the XML Schema will be generated along with the XML document
<schemaname>Specifies the name and path of the external file to contain the schema
<?xml version = "1.0" encoding="Windows-1252" standalone="yes"?>
<VFPData>
  <xsd:schema id="VFPData" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:element name="VFPData" msdata:lsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="customer">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="name">
                  <xsd:simpleType>
                    <xsd:restriction base="xsd:string">
                      <xsd:maxLength value="20"/>
                    </xsd:restriction>
                  </xsd:simpleType>
                </xsd:element>
                <xsd:element name="qtyorders" type="xsd:int"/>
              </xsd:sequence>
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <customer>
    <name>Fabio Vazquez</name>
    <qtyorders>1</qtyorders>
  </customer>
  <customer>
    <name>Another Customer</name>
    <qtyorders>0</qtyorders>
  </customer>
</VFPData>

Repeat the earlier procedure, adding the lines bellow and the output of the MODIFY STRUCTURE command will be the one showed in the picture below.

XMLTOCURSOR(lcXML, "NewCustomer")
MODIFY STRUCTURE

Screen output for the MODIFY STRUCTURE command showing the right structure for the cursor

Now the original types of the "Customer" cursor are kept and we will not have major surprises manipulating the newly created cursor "NewCustomer". All this because the inline XML Schema generated, which, by the structure specification of the document and the right data types, allows that the XMLTOCURSOR() function to generate a cursor compatible with the original one.

Validating XML documents using VFP and MSXML 4.0

The latest version of Microsoft XML parser (MSXML 4.0) (available for download at http://msdn.microsoft.com/downloads/default.asp?url=/downloads/topic.asp?URL=/msdn-files/028/000/072/topic.xml), differently from its previous versions, already supports XSD schemas validation and we can, through COM automation, use its objects to validate XML documents against XML Schemas. MSXML 4.0 is installed in side-by-side mode, that allows it can be used in computers that already have other versions of MSXML parser installed. To use pecifically the objects of version 4.0, we can use the ProgIDs and CLSIDs specific to this version. When MSXML 4.0 is installed, also are all the documentation of the SDK (Software Development Kit) that brings a rich set of information about the functionalities of this version and its object model. The listing below is a complete example of how to validate the XML document of Listing 5, saved on a disk file named CDS1.XML, against the XML Schema in Listing 6, saved on a disk file named CDS1.XSD.

* Define and create a schema cache object
LOCAL loXMLSchema as "MSXML2.XMLSchemaCache.4.0"
loXMLSchema = CREATEOBJECT("MSXML2.XMLSchemaCache.4.0")
loXMLSchema.add("", "CDS1.XSD")

* en-us: Define e cria um objeto DOMDocument
LOCAL loXML as "MSXML2.DOMDocument.4.0"
loXML = CREATEOBJECT("MSXML2.DOMDocument.4.0")

* en-us: Assign the schema cache to the DOM Document
loXML.schemas = loXMLSchema

* en-us: Load the XML document
loXML.async = .F.
loXML.load("CDS1.XML")

* en-us: Verify whether the document was sucefully loaded.
IF loXML.parseError.errorCode = 0
  MESSAGEBOX("XML Documento loaded sucefully!")
ELSE
  lcErrorMsg = "The document could not be loaded because it does not conform to its schema" + CHR(13)
  lcErrorMsg = lcErrorMsg + "Line: " + TRANSFORM(loXML.parseError.line)
  lcErrorMsg = lcErrorMsg + "Char in line: " + TRANSFORM(loXML.parseError.linepos)
  lcErrorMsg = lcErrorMsg + "Cause of error: " + TRANSFORM(loXML.parseError.reason)
  MESSAGEBOX(lcErrorMsg)
ENDIF
Basically, what I do here is to load the XML document of CDS1.XML file that, during the load through the method "Load()" of the "DOMDocument", is validated against the schema of the file CDS1.XSD. The validation occurs because I create a schema cache using the object "XMLSchemaCache.4.0". In the schema cache, each schema is associated to a specific namespace. This way, when the XML document is loaded, the parser will seek into the schema cache for a schema associated to the namespace it is loading. Case a schema does exist, the document is validated against the referred schema.

Here is a step-by-step guide to the validation process used in the example:

1) Load the schema into the schema cache object

LOCAL loXMLSchema as "MSXML2.XMLSchemaCache.4.0"
loXMLSchema = CREATEOBJECT("MSXML2.XMLSchemaCache.4.0")
loXMLSchema.add("", "CDS1.XSD")

2) Create a DOMDocument objet that will hold the XML document

LOCAL loXML as "MSXML2.DOMDocument.4.0"
loXML = CREATEOBJECT("MSXML2.DOMDocument.4.0")

3) Assign the schema cache object to the "schemas" property of DOMDocument

loXML.schemas = loXMLSchema

4) Load the XML document through the "Load()" method

loXML.load("CDS1.XML")
5) At this point the loading process will try to validate the document. Case the document is valid, it will be loaded without problems. Case there exist some validation problem, the document will not be loaded and the property "parseError" on the DOMDocument object will have detailed information about the error.

Conclusion

In this article, we discussed important concepts of XML related technologies such as namespaces and XML Schemas. As we can verify in a daily basis, XML is becoming more and more important to every developer and Visual FoxPro developers cannot stay away from it. In the following articles we will be approaching other XML related subjects and seeing how we can put them to work in VFP.

More articles from this author

NoTitleDate
1.An Introduction to Linq to Xml (XLinq)August 2006
2.Coverage of PDC 2002 in BrasilJune 2002
3.LINQ to SQL - When the Query Language Meets an OR MapperSeptember 2007
4.MSBuild: Automating the Build Process of .NET ApplicationsJune 2006
5.Presenting XML Content in .NETApril 2003
6.Real World Transformations Using Linq to Xml (XLinq)November 2006
7.The New features of C# 3 and VB 9 compilersJune 2007
8.What's New in Visual FoxPro 9 BetaJuly 2004

Copyright © 1993 - 2014 Level Extreme Inc., All Rights Reserved · Telephone: 506-783-9007 Email: info@universalthread.com · Privacy & Security · Copyright · Terms & Conditions