[ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ]

MS - DOM parser syntax for document creation.

Return to the parser object reference we used earlier. Because this is an XML-intimate,object, you will immediately see how it protects you from some of the problems you face when you generate documents manually. For example, try this at the command window:

    ox = CREATEOBJECT(“Microsoft.XMLDOM”)
    oy = ox.createElement("xxx")
    oy.text = "<>&'"+["]
    ? oy.text
    * result: <>&'"
    ? oy.xml
    * result: <xxx>&lt;&gt;&amp;'"</xxx>

See the difference? The XML for this newly-created element object is appropriately transformed to include the entity references. I have not yet appended this element into an XML document, using the parser – but when I do, this element will load, and become a valid part of a parseable document without any problems.

The DOM has rich syntax for creating nodes of different types and using them to build documents, of which the above is a small sample. The syntax I’m showing you in this section may include some Microsoft extensions, which means that you will not be able to do exactly the same thing with other parsers. Even within the standard, other parsers beyond Microsoft’s may use different method names for the same functionality. Basically, however, they all work the same way.

Here is an excerpt from the VFP 7 Coverage engine’s GetStackXML(tcLog) method, to give you a more extensive example. I’ve added some comments so you can see what the different parser-related activities are:

    * instantiate the parser:
    loXML = CREATEOBJECT("Microsoft.XMLDom")
    * set up a root node, an empty document,
    * by loading a string:
    loXML.LoadXML("<?xml version='1.0'?>”+ ;
    <"+COV_STACKROOT+"-"+JUSTFNAME(THIS.cSourceFile)+"/>")
    liStackLevel = 0
    SCAN
    * I have omitted a section here in which
    * the current record is checked to figure out
    * whether it is an “ON EVENT” and what its parent node is
    IF llAdd
    loThisNode = NULL
    IF NOT THIS.lStackXMLExtendedTree
    * check to see if this element already exists
    * at this level, using an XPATH expression
    * This expression can be read “where the parent node
    * name matches the one I stipulate, the nodename matches
    * the one I stipulate, and the stack level is the same
    * as the level for the current log entry”
    loThisNode = loXML.SelectSingleNode( ;
    ""+loParent.NodeName+"/"+ ;
    lcTag+"[@StackLevel="+TRANSFORM(FStack)+"]")
    ENDIF
    IF ISNULL(loThisNode)
    * create a node
    loThisNode = loXML.createElement(lcTag)
    IF llEvent
    * set an attribute on the node
    loThisNode.setAttribute("RunsFor","N-A")
    ELSE
    loThisNode.setAttribute("RunsFor",TRANSFORM(FDuration))
    ENDIF
    * set another attribute
    loThisNode.setAttribute("StackLevel",TRANSFORM(FStack))
    * add the child node to the parent --
    * since the document is “living”, appending the
    * child to the parent immediately changes the contents
    * of the document XML as a whole:
    loParent.appendChild(loThisNode)
    ELSE
    IF NOT llEvent
    * add the current duration statistic
    * to the value of the current RunsFor attribute
    * for the existing node. Again we use an XPATH
    * expression, this time to grab the value of an
    * attribute rather than a reference to a node:
    loThisNode.SetAttribute("RunsFor", ;
    TRANSF(VAL(loThisNode.SelectSingleNode("@RunsFor").nodeValue)+;
    FDuration))
    ENDIF
    ENDIF
    loNode = loThisNode
    ENDIF
    * end of XML-adjusting code, some
    * maintenance code here…
    ENDSCAN

The code above is not complicated, given a little time spent with an Object Browser and the MSXML parser. The only part that will be strange to you, and take some practice, is the XPATH syntax, used twice in this code snippet.XPATH is a kind of query syntax, which you can use directly in the MS parser to select a single node or value (as used above, with the SelectSingleNode(cXPATHExpression) method) or to get a reference to a collection of nodes sharing some characteristics (use the SelectNodes(cXPATHExpression) method.

XPATH is odd looking but very powerful, something like “regular expression” syntax. In both direct use with a parser, as here, and within an XSL transformation, XPATH allows you to winnow through very complex document structures, using object references and variables, and setting multiple filter conditions on different levels of your query expression. As you can see when you contrast the two uses of XPATH above, you can apply the query expression either to an entire document or the portion of a document represented by a single node reference (which includes all its children).

The DOM syntax and object model has a few other concepts you may find strange at first. For example, it’s often difficult for people to realize that the text surrounded by two element tags (for example the word whatever in the document fragment <mytag>whatever</mytag><someothertag/>) is actually an object, a node of type text, not just a string. Sometimes the Microsoft parser will let you forget about this distinction (other parsers usually won’t) but often you will have to treat this text as the proper text node object type to get the results you want.

Consider the following javascript snippet, which changes the text for a particular element if it has been previously filled, and otherwise just adds new text. If we were editing the document fragment above, this code would change the whatever text to some new text. If <mytag> had no current text, this code would simply add it. In this code you can see how the text is being treated as an object and also how it exists as a child node of another document element:

    var oNode = httpXML.selectSingleNode(tcQualifiedNodeName) ;
    if (oNode) {
    var oTextNode = httpXML.createTextNode(tcNodeValue) ;
    if (oNode.hasChildNodes()) {
    // we should be at the bottom level
    // at this point, in this particular document
    // so there should only be one child, the text node.
    // If oNode could have other children, such as
    // child elements, I might
    // write this code a little differently:
    var oOldChild = oNode.firstChild ;
    oNode.replaceChild(oTextNode,oOldChild) ;
    }
    else {
    // no text yet, just add it
    oNode.appendChild(oTextNode) ;
    }
    }

Recommendations

Although using the DOM parser in this manner is powerful and flexible, I recommend you use a combination of VFP’s string-handling abilities and the parser to create your documents. In VFP 7, use the native faciities, such as CURSORTOXML(), too. An especially good technique is to have a skeletal or template document ready, either on disk, in a memo field, or built as a string. You don’t worry about making sure that this template is well-formed because it is a known part of your system, not something created out of unpredictable parts at runtime. (You checked it for well-formedness when you created it, didn’t you? You won’t need to check it at runtime).

You load this template into the parser and then use a few parser calls to add the dynamic values for this instance of the document using code similar to the javascript above. For example, you could have a request document ready for somebody else’s server that included a complex request format, complete with a number of elements you set the same way every time you make a request of this server. All these options and the general request document would be included in your template. At runtime, you add your user ID and password into the appropriate nodes, add a few request parameters specific to this occasion, and you’re ready to send the request.

If some parts of the request parameters were repetitive (for example, multiple names and addresses), you might have a cursor holding the various instances of the request within one document. You’d use CURSORTOXML() to generate XML for these the sections. There is no reason to have COM calls, building static sections of the document, just for the joy of creating and appending elements to the DOM model!

When your application functions as a server, you may want to have many response templates as appropriate to different sorts of clients. (the InfoWorld news article example discussed earlier may be “kickstarted” using this strategy). Web servers can evaluate what type of client has made a request both to determine an appropriate template and the an appropriate XSL transformation to apply.

I recommend you check cyScape Products for a look at BrowserHawk (http://www.cyscape.com/products/ ). This product gives you much finer understanding of your client than other web-server-based methods, and also can be used on multiple servers, in multiple environments. The latest version will tell you about the user’s connection speed, available plug-ins, and a lot more – plus it is intelligent about a wide variety of clients (see figure 10 below).

Now that you have some sense of how you construct an XML document, how will you handle the XML documents you receive? The next section will give you some ideas.

Figure 10, BrowserHawk documentation shows you how this product can give you critical aid in determining “who you’re talking to”. This helps you figure out what type of data interchange or presentation is best suited to the current “conversation”.

 

[ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ]