Figure 9, XML at work at InfoWorld’s news site.
Here’s where we start our whirlwind tour of coding XML in VFP. You usually design your document as a DTD or schema (in XML SPY, Visual Notepad, or your own favorite tool), and you put some sample data in it (just as you’d append records interactively in a newly-created Visual FoxPro table, to make sure you had the fields right).
Now we have to figure out how VFP will handle the three main tasks with real documents:
· Creating the documents we send to partners, clients, and servers
· Parsing the documents they send to us
· Transforming between XML formats, as necessary, in between.
Creating the XML documents we’ve designed
In VFP we are used to creating strings on the fly, and they can be very large strings. There is no reason why you can’t create a couple of classes designed especially for this purpose. In VFP 7, SET TEXTMERGE and TEXT… ENDTEXT have been improved in ways that you’ll find useful for this work. You can also build the document as a string and use StrtoFile(), introduced in VFP 6. If the document is eventually saved to disk, I often use low level file functions rather than SET TEXTMERGE or StrToFile() for the best possible performance.
Manual document creation (some tips)
Most of us started off creating our XML documents in Fox manually, in this manner. I’ll give you some advice, in case you want to do this, and then we’ll go on to some alternatives.
The method you’ll use to build up a document manually varies depending on the content of the document. You’ll often SCAN through tables evaluating the contents of various fields, or include the property values of relevant objects. You will find that the TRANSFORM() method becomes your best friend, because it allows you to convert everything to character type, as you concatenate your string or write out your file, without worrying about the original type of each value.
I’ve created a subclass of my FRXCLASS document generation system, which
uses a template FRX to drive report creation. The advantage of this system,
which I’ve used previously for WinWord and HTML document creation, is that a
single FRX, without any visible objects, can handle grouping and record pointer
movement for you, while the events it triggers in the associated FRXClass
object creates the real output. The FRX2XML subclass is particularly good in
that it generates a default representation of any open file, by default (the
other FRXClass subclasses have to know something about your data before they
can generate .DOC or .HTM files). FRX2XML creates its default representation of
a row using this VFP-native, or “manual”, method:
This method is neither a recommendation nor necessarily the best way to create XML that looks like a row available to you in VFP – I’ve done the same task numerous times and keep coming up with different variations. (It never ceases to amaze me how many good ways Fox has of massaging data and text.) I’ve included all the source for FRX2XML, its superclass FRXClass and the other format-specific subclasses of FRXClass, with several examples, as part of the source for this session. You will find a text document named FRXClass.API with full instructions. I find it very convenient to use FRX2XML for various manual parsing situations, including another example application I’ll present later in this paper, and you may too, even though it is just one method of many.
You knew it had to happen.I brought up VFP REPORT FORMs, so we had to discuss at least one bug in the product, FRXs are such a fertile field for them!
Be aware that VFP 7 has added a new application-level property, .LanguageOptions, which allows you to specify strict memvar declaration.Unfortunately, there is no way to get the option to give you compile-time errors – you’ll just have to turn .LanguageOptions on and test all your code to see what variables remain undeclared.(Use the Coverage Profiler to help you find code that you haven’t tested!)
Even more unfortunately, , at this writing report variables can not be declared so they don’t cause an error when strict memvar declaration is turned on. No word yet on whether this will be fixed before release. The Coverage application saves and restores _VFP.LanguageOptions setting in code surrounding the REPORT FORM command in the DisplayProjectStatistics()method. There is a #DEFINE that will remove this kludge if they fix the bug. If you use use REPORT FORM… NOWAIT, not even this kludge will save you (at least in the current build). You might have to turn _VFP.LanguageOptions off in an early DataEnvironment method, and turn it back on in a late one. I haven’t tried this.
No matter how many times I create a manual XML document creation procedure, however, there are a couple of XML principles I have to keep in mind. You’ll need to follow them, too, for any manual parsing you do.
Here is the most critical rule: be careful, if you build the documents manually in this manner, to make sure your documents are well formed before passing them to another application or a user. An XML document is well formed if it follows the syntax rules of XML, including the necessity of closing all tags and having a single root node.
NB: The output from an XSL transformation is not required to be well-formed, in that the single document or root node is not required. It is required only to be well-balanced (all the tags that exist have to be closed). This output is considered to be an object of type Document Fragment, not Document, within the standard. These document fragment objects can be concatenated together, or further built up with additional elements using other methods, before being released as a final document object.
Don’t confuse well-formedness with validity. An XML document is not required to have a DTD (document type definition) or a schema. If the document does reference a DTD or schema, it is required to be valid according to that DTD or schema. But every XML document is required to be well-formed, regardless of validity. Although your manual string-building may not be able to tell whether or not a document is well-formed, many of your clients for the document will not be able to use your document at all unless it is well-formed. They are using standard XML parsers to handle the document you send – and the document will not load in the parser if it is not well formed. It is the responsibility of the application formulating the XML to make sure the XML will be parse-able, without any further adjustment, by the receiver of the document.
How can you check for well-formedness? The easiest way to test the XML you’re generating manually is to load your results into a parser conforming to the XML standard, at least for debugging purposes.
To check from the command window, simply CREATEOBJECT(“Microsoft.XMLDOM”), which gives you a reference to the Microsoft XML parser. Now load your document into the parser as a string using the LoadXML(tcString) method, or use the Load(tcFile) method for a file on disk. If the method returns .F. (or errors, depending on your version of the Microsoft parser and/or your version of FoxPro!), you should be able to check the <ParserReference>.parseError.reason property to see what went wrong.
If you don’t mind leaving the VFP environment for your tests, load your XML output into _CLIPTEXT and move over to an XML-oriented IDE like XML Spy. In this type of editor, you will get more exact information about your error, and usually more help in resolving it.
An important error that people often make when creating documents manually
is to omit translating characters used in expressing XML syntax when they
include data elements. There are only five such characters, but if your data
includes them the document will not parse, because the parser won’t be able to
tell where tags and entity references begin and end. Here’s how FRX2XML handles
Another way of resolving errors arising from XML control characters in data is to surround the data in a CDATA block, which tells parsers not to parse the contents of the block at all. In this way the offending characters are masked from the parser. I think this is less flexible, however.
Ensuring well-formedness (and validity if your scenario includes a DTD or a schema) is quite a bit of work if you create documents manually. Your alternative in VFP 7 might be to use CURSORTOXML(), which I described earlier, and which removes the problem from your hands. The problem you’ll face, as we saw in the StackXML example, is that the resulting document will be more closely tied to your database structure than might be appropriate for the contents of your data.
A better alternative is to use an XML-standard parser object model to construct, or finish constructing, your document. For document construction, you will usually use the DOM (document object model) parser we’ve already mentioned briefly. In the next section, instead of using the DOM parser just to test well-formedness, we’ll use it for document creation.
The FRX2XML class can just as easily generate its XML using a reference to the DOM parser, as FRX2DOC uses a reference to Word, rather than the manual parsing currently used in this class. It’s too useful a system for me to stop using, even though the mechanics driving each form of output changes over time.
FRX2XML is probably the last FRXClass subclass I’ll ever write. That’s because , with XML available, I’m not really interested in getting VFP to generate other formats such as RTF or PDF. I’ll use VFP to generate my XML document structure, and then transform the results using objects and applications expressly written to provide the various output formats, using the principles of XSL:FO (formatting objects). You can check out a commercial XSL rendering engine application at RenderX (http://www.renderx.com/) or FOP, an open source XSL renderer, at http://xml.apache.org/fop/.
The XSL:FO standard is, unfortunately, not as far along as the other XML-related standards, possibly because established cross platform alternatives, such as PDF, do exist. This is an area I don’t know much about but will be pursuing in the future.