Welcome To The Home Of The Visual FoxPro Experts  
home. signup. forum. archives. search. google. articles. downloads. faq. members. weblogs. file info. rss. print.
GETTING TO GRIPS WITH THE MICROSOFT DOM OBJECT

What is the DOM, the DOM is the Document Object Model and relates to XML documents. Examples included with this article are:

VFP 5/6/7/8 Compatible Programs

File NameDescriptionDOMObject.prgManually create an XML documentTableToXML.prgCreates an XML Document from the Customer tableXMLToCursor.prgCreates a Cursor from the XML File created by TableToXML.prgTableToXML2.prgCreates XML Document with Field Type PrefixXMLToCursor2.prgCreates Cursor with Correct field types – read file created by above programXMLClass.vcxClass that works similar to the XMLTextWriter in VS.NETSample1.prgCreates the Sample XML file in this documentTest.prgExample using the XMLClass

VFP8 Only Programs

File NameDescriptionXMLAdapter1.prgCreate an XML Document using the Adapter

Structure of an XML Document


The structure of a simple xml file is as follows:


<?xml version=”1.0” ?> Processing Instruction (1 of this type *).
<Rootnode> Main Root Node – only one of these allowed.
<ChildNode> Start of Child nodes (Records).
<Field1>MyData</Field1> Start of Data (Fields and Values).
</ChildNode>
<ChildNode> Start of Next Record.
<Field1>MyData</Field1> Start of Data (Fields and Values).
</ChildNode>
</Rootnode>


Note: there are other Processing instructions that you can add to the document, like Stylesheet information, also XML files can contain DTD’s and Schema information, all these can start before the Rootnode, the scope of this article does not cover these.

Using the DOM object to create above sample xml file
1st Create the Object:
oXML = CreateObject("MSXML.DOMDocument")

oXML now contains a completely empty Dom Document. To Add the Processing Instruction, this can be done by using either of the following commands.

oXML.appendChild( oXML.createNode("PROCESSINGINSTRUCTION","xml",""))

or
oPI = oXML.createProcessingInstruction("xml","version=’1.0’")
oXML.appendChild( oPI )

Let’s add the Rootnode.

oRoot = oXML.appendChild( oXML.createNode("ELEMENT","RootNode",""))

Now the child nodes

oChild = oRoot.appendChild( oXML.createNode("ELEMENT","ChildNode",""))
oChild.appendChild(oXML.createElement("Field1"))
oChild.lastChild.text = "MyData"

Add the Other ChildNode

oChild = oRoot.appendChild( oXML.createNode("ELEMENT","ChildNode",""))
oChild.appendChild(oXML.createElement("Field1"))
oChild.lastChild.text = "MyData"

Now Save the File.

oXML.Save("c:\Temp\MyXML.xml") 

Problems when using the DOM and VFP tables
One of the main problems with using the DOM this way is that you don’t know what the field type is, you can achieve this with the aid of a schema, but I have found a very nice way of determining the type based on the field name, I create the field names prefixed with the field type, e.g. iField1 = Integer, cField2 = Character, etc...

The XMLToCursor.prg treats every field as Character. By using the field names above (prefixed with the type) you can create a cursor with the correct field types, the only the character field as to be created with a large size to ensure that all the data is in the field. TableToXML2.prg is a modified version of the first that adds the field type as a prefix to the field name. XMLToCursor2.prg is a modified version of the first that reads the new xml file created by TableToXML2.

VFP 7 and 8 Related Information
If you are creating single XML files from your cursors you can of course use the CURSORTOXML() and XMLTOCURSOR() functions that are part of the VFP 7 language.

CURSORTOXML("Customer","c:\customer.xml",1,512,0,"1")

To Read this back in issue the following:

XMLTOCURSOR("c:\customer.xml","mycursor",512+2048)

Because you include an inline schema the resulting cursor matches the original table. If you have created an XML file without the Inline Schema using the CURSORTOXML() function, you can first create your cursor with the correct data type then read the file with the XMLTOCURSOR() function, adding the flag of 8192, this is not shown in the VFP 7 help file but was introduced in Service Pack 1. It is however included in the VFP 8 help file.

VFP 8 – XML Classes


With the release of VFP 8 we have been given some new base classes that can work with more types of XML and provide more control over XML input and output. These new features do require the new MSXML 4.0 Service pack 1; these should be installed when you installed VFP 8. If you have written any programs that use the new classes you must make sure that you install this version of Microsoft XML. XMLAdapter is the main class of the three new ones, this is an adapter between XML and VFP data; it can import XML in a variety of formats into VFP cursors and output XML from VFP cursors.

Lets look at the XMLAdapter class.

PropertyDescriptionDisableEncodeThe default value for the DisableEncode property for new XMLField objects. (see the XMLField class for description).ForceCloseTagIndicates whether the ToXML method outputs single empty element tags (False, the default) or sets of empty element open and close tags (True) for blank data.FormattedOutputDetermines whether the ToXML method outputs formatted XML (True, the default) or a single continuous string (False).IsDiffgramIndicates whether imported XML is in diffgram format or not, and determines whether ToXML outputs to diffgram format.IsLoadedIndicates whether XML has been loaded or not.IXMLDOMElementContains an object reference to an IXMLDOMElement object after XML has been loaded.MapN19_4ToCurrencyIndicates whether the xsd:decimal data type is mapped to the VFP Currency. (False is the default).NoCpTransThe default value for the NoCpTrans property for new XMLField objects.PreserveWhiteSpaceIndicates whether white space is preserved (True) or removed (False the default).RespectCursorCPSpecifies whether the ToXML method creates XML with the default windows 1252 encoding (False, the default).SOMContains an object reference to an ISchema object after loading XML.TablesA Collection of XMLTable objects.UnicodeThe default value for the Unicode Property for new XMLField objects.UFT8EncodedIndicates whether the ToXML method creates XML with UTF-8 encoding (True) or uses the RespectCursorCP property.WrapCharInCDATAThe default value for the WrapInCDATA property for new XMLField objects representing Character fields.WrapMemoInCDATAThe default value for the WrapInCDATA property for new XMLField objects representing Memo fields.XMLConstraintsContains an object reference to an ISchemaItemCollection object after XML has been loaded.XMLNameThe name of the element used to locate tables in the XML.XMLNamespaceThe XML Namespace to which the XML name belongs.XMLPrefixThe prefix used to reference the XML namespace.XMLSchemaLocationThe location of the schema when loading or outputting XML. Accepts the same values as the schema location parameter of CURSORTOXML().

XMLAdapter has five methods: LoadXML, AddTableSchema, Attach, ToXML and ReleaseXML. LoadXML loads XML into the Adapter object, the XML can come from a file or a string. The syntax for this method is:

Object.LoadXML( cXML [, lFile [, lValidateOnParse ] ] )

cXML is either an XML string or the name of an XML file; if it is a file then the lFile parameter needs to be True.

Once LoadXML has finished, the XMLAdapter is fully populated with XMLTable and XMLField objects, and then you can generate VFP Cursors. The LoadXML method raises an error rather than returning False, you should really wrap the call in a TRY structure.

AddTableSchema adds a new XMLTable and set of XMLField objects based on an existing VFP Cursor. The syntax for this method is:

Object.AddTableSchema( cAlias [, lElementBased [, cXMLName [, cXMLNameSpace [, cXMLPrefix [, lWrapMemoInCDATA [, lWrapCharInCDATA ] ] ] ] ] ] )

cAlias is the alias of the cursor and lElementBased indicates whether the XML should be element-based (the default if this parameter isn’t passed) or attribute-based. cXMLName specifies the name of the table in the XML; defaults to the alias name if not passed.

The Attach method uses an existing XML DOM document or element to load XML into an Adapater. This is typically used when you receive XML from something as a DOM object rather than an XML string. For example, if you call a Web Service that returns an ADO.NET DataSet, you can’t use LoadXML on the result because the DataSet is returned as a DOM object. Instead, use Attach. The syntax is:

Object.Attach( oDOM [, oSchema ] )

ToXML generates XML, either to a file or a string. The syntax is:

Object.ToXML( cXML [, cSchemaLocation [, lFile [, lIncludeBefore [, lChangesOnly ] ] ] ] )

XMLTable class object

PropertyDescriptionAliasThe alias of the table.ChildTableContains an object reference to an XMLTable object that’s the child of this one when hierarchical XML is used.FieldsA collection of XMLField objects.ParentTableContains an object reference to an XMLTable object that’s the parent of this one when hierarchical XML is used.XMLAdapterContains an object reference to the XMLAdapter this object belongs to.XMLConstraintsContains an object reference to an ISchemaItemCollection object after XML has been loaded.XMLNameThe name of the element use to locate tables in the XML.XMLNamespaceThe XML Namespace to which the XML name belongs.XMLPrefixThe prefix used to reference the XML namespace.

The ToCursor method creates a VFP cursor or appends data to an existing one. It has the following syntax:

Object.ToCursor( [lAppend [, cAlais [, Reserved ] ] ] )

If lAppend is True, ToCursor appends the data to an existing cursor; otherwise, it creates a new cursor.

XMLField Class Object

PropertyDescriptionAliasThe name of the field.DataTypeThe VFP Data type for the field (eg. “C” = Character)DisableEncodeIdicates whether Memo (binary) or Character (binary) data is encoded.FractionDigitsFor Numeric fields, the number of digits to the right of the decimal, -1 for all other data types of if there are no decimals.IsAttributeIndcates whether the field is an attribute (True) or element (False, the default) in the XML Document.IsBase64Indicates whether the field is encoded as Base64 (True) or hexBinary (False, the default).IsBinaryIndicates whether the field is defined as Binary in the Schema.IsNullIndicates whether the field accepts null values or not (default is false).KeyFieldTrue if the field is a key field, false if not.MaxLengthThe total length of a character or Numeric field. See the “Unicode” topic in the VFP Help for more information on how this affects the MaxLength.NoCpTransIndicates whether VFP performs code page translation on this field.UnicodeSpecifies whether character fields are handled as Unicode data.WrapInCDATASpecifies whether Character and Memo data are wrapped in CDATA sections.XMLNameThe element or attribute name for this field in the XML Document.XMLTableAn object reference to the XMLTable object this field belongs to.XMLTypeAn object reference to an ISchemaType object that contains information for the fieldXSDfractionDigitsContains the XML Schema Definition (XSD) fractionDigits value, which is the number of places to the right of the decimal.XSDmaxLengthContains the XSD maxLength value.XSDtotalDigitsContains the XSD totalDigits value, which is the total number of digits.XSDtypeContains the XSD data type of the field, without the “xsd:” prefix.

The XML DOM is made up of the following:

DOCUMENTThe XMLDOMDocument object represents the top level of the XML source. It includes methods and properties to obtain or create all other XML objects. (Example: objDoc=CreateObject("Microsoft.XMLDOM"))MemberDefinitionTypeabort()*Aborts an asynchronous download in progress.Masync*Indicates whether asynchronous download is permitted.R/WcreateAttribute(name)Creates a new attribute with the specified name.McreateCDATASection(data)Creates a CDATA section node that contains the supplied data.McreateComment(data)Creates a comment node that contains the supplied data.McreateDocumentFragment()Creates an empty DocumentFragment object.McreateElement(tagName)Creates an element node using the specified name.McreateEntityReference(name)Creates a new EntityReference object.McreateNode (type,name,namespaceURI)Creates a node using the supplied type, name and namespace.McreateProcessingInstruction (target,data)Creates a processing instruction node that contains the supplied target and data.McreateTextNode(data)Creates a text node that contains the supplied data.MdoctypeContains the document type node that specifies the DTD for this document.ROdocumentElementSpecifies the root element of the document.R/WgetElementsByTagName (tagName)Returns a collection of elements that have the specified name.MimplementationContains the implementation object for this document.ROload(url)*Loads an XML document from the specified location.MloadXML(xmlString)*Loads an XML document using the supplied string.MnodeFromID(idString)*Returns the node whose ID attribute matches the supplied value.Mondataavailable()*Indicates that the XML document data is available.Eondataavailable*Specifies the event handler for the ondataavailable event.R/Wonreadystatechange()*Indicates when the readyState property changes.Eonreadystatechange*Specifies the event handler to be called when the readyState property changes.R/Wontransformnode (nodeCode,nodeData)Fires before each node in the style sheet is applied to each node in the XML source.Eontransformnode*Specifies the event handler for the ontransformnode event. parseError*Contains a ParseError object that contains information about the last parsing error (See ParseError Table).ROpreserveWhiteSpace*Contains true if the default processing preserves white space, or false otherwise.R/WreadyState*Indicates the current state of the XML document.ROresolveExternals*Indicates whether external definitions (resolvable namespaces, DTD external subsets, and external entity references) are to be resolved at parse time, independent of validation.R/Wsave(objTarget)*Saves an XML document to the specified location.Murl*Contains the canonicalised URL for the last loaded XML document.ROvalidateOnParse*Indicates whether the parser should validate this document.R/W

NODEThe XMLDOMNode object extends the core XMLDOMNode interface with support for data types, namespaces, DTDs, and schemas.MemberDefinitionTypeappendChild(newChild)Appends a newChild as the last child of this node.MattributesContains the list of attributes for this node.RObaseName*Contains the base name for the name qualified with the namespace.ROchildNodesContains a node list containing the children (for nodes that can have children). See NodeList table.ROcloneNode(deep)Creates a new node that is an exact clone of this node.MdataType*Specifies the data type for this node.R/Wdefinition*Contains the definition of the node in the DTD or Schema.ROfirstChildContains the first child of this node.ROhasChildNodes()Returns true if this node has children.MinsertBefore (newChild,refChild)Inserts a child node to the left of the specified node or at the end of the list.MlastChildContains the last child node.ROnamespaceURI*Contains the URI for the namespace.ROnextSiblingContains the next sibling of this node in the parent’s child list.ROnodeNameContains the qualified name of the element, attribute, or entity reference, or a fixed string for other node types.ROnodeTypeContains the XML DOM node type, which determines valid values and whether the node can have child nodes. See nodeType Property table.ROnodeTypedValue*Specifies this node’s value expressed in its defined data type.R/WnodeTypeString*Contains the node type in string form.ROnodeValueSpecifies the text associated with the node.R/WownerDocumentContains the root of the document that contains this node.ROparentNodeContains the parent node (for nodes that can have parents).ROparsed*Contains true if this node and all descendents have been parsed and instantiated, or false if any nodes remain to be parsed.ROprefix*Contains the namespace prefix.ROpreviousSiblingContains the left sibling of this node.ROremoveChild(oldChild)Removes the specified child node from the list of children and returns it.MreplaceChild (newChild,oldChild)Replaces the specified old child node with the supplied new child node in the set of children of this node, and returns the old child node.MselectNodes(patternString)*Applies the specified pattern-matching operation to this node’s context and returns the list of matching nodes.MselectSingleNode (patternString) *Applies the specified pattern-matching operation to this node’s context and returns the first matching node.Mspecified*Indicates whether the node (usually and attribute) is explicitly specified or derived from a default value in the DTD or schema.ROtext*Contains the text content of the node and its subtrees.R/WtransformNode(stylesheet)*Processes this node and its children using the supplied XSL style sheet, and returns the resulting transformation.MtransformNodeToObject (stylesheet, outputObject)Processes this node and its children using the supplied XSL style sheet, and returns the resulting transformation in the supplied object.Mxml*Contains the XML representation of the node and all its descendants.RO

NAMEDNODEMAPThe XMLDOMNamedNodeMap object adds support for namespaces and iteration through the collection of attribute nodes.MemberDefinitionTypegetNamedItem(name)Retrieves the attribute with the specified name.MgetQualifiedItem (baseName,nameSpaceURI)*Returns the attribute with the specified namespace and attribute name.Mitem(index)Allows random access to individual nodes within the collection.MlengthIndicates the number of items in the collection.ROnextNode()*Returns the nect node in the collection.MremoveNamedItem(name)Removes an attribute from the collection.MremovedQualifiedItem (baseName,nameSpaceURI)*Removes the attribute with the specified namespace and attribute name.Mreset()*Resets the iterator.MsetNamedItem(newItem)Adds the supplied node to the collection.MIEnumVARIANT()*Supported by NamedNodeMap so that Microsoft Visual Basic programmers can use a “for each” statement and Microsoft Jscript programmers can use the Enumerator object to iterate over the items in the NamedNodeMap.M

NODELISTThe XMLDOMNodeList object supports iteration through the live collection, in addition to indexed access.MemberDefinitionTypeitem(index)Allows random access to individual nodes within the collection.MlengthIndicates the number of items in the collection.ROnextNode()*Returns the nect node in the collection.Mreset()*Resets the iterator.MIEnumVARIANT()*Supported by NamedNodeMap so that Microsoft Visual Basic programmers can use a “for each” statement and Microsoft Jscript programmers can use the Enumerator object to iterate over the items in the NamedNodeMap.M

PARSEERRORThe XMLDOMParseError object returns detailed information about the last parse error, including the error number, line number, character position, and a text description.MemberDefinitionTypeerrorCodeContains the error code of the last parse error.ROfileposContains the absolute file position where the error occurred.ROlineSpecifies the line number that contains the error.ROreasonExplains the reason for the error.ROsrcTextContains the full text of the line containing the error.ROurlContains the URL of the XML document containing the last error.RO

LEGEND AbbreviationDescriptionRORead-Only property.R/WRead-Write property.MMethod.EEvent.*Member is a Microsoft extension

Download code
You can download Simons sample here. The download is a zipfile. Its size is 10.041 bytes.

ABOUT THE AUTHOR: SIMON ARNOLD

Simon Arnold Simon has worked with FoxPro for over 16 years. He currently works for a company based in Harrogate, North Yorkshire (UK), which specialises in FoxPro, Web and Unix development.
He has a weblog at http://weblogs.foxite.com/simonarnold.

FEEDBACK


Your Name: 
Your Feedback: 

Spam Protection:
Enter the code shown: