Using the Microsoft XML library with Functional Developer

Home
Introduction
Tips and Techniques
Projects
Libraries
Links

The Microsoft XML library (MSXML) is a set of COM objects for using XML and XSL. MSXML is available for download from Microsoft's XML site.

It is easiest to use these COM libraries if you create a seperate library to store the Dylan wrappers that call the COM routines. Functional Developer includes a wizard that makes this easy but it has a problem with importing the MSXML library which is easily fixed.

The steps to get a working Dylan wrapper to MSXML are:

  1. Install the March 2000 preview release of MSXML from the Microsoft XML site. Install the XML SDK if you want the XML documentation (Definitely recommended).
  2. Start a new Dylan project using "Interface to COM Type Library" as the wizard.
  3. From the list of type libraries choose "Microsoft XML, v3.0".
  4. The stub option from the next wizard page should be the first one, "Dispatch client interfaces".
  5. The next page allows you to select individual interfaces to include in the translation. Functional Developer 2.0 has a problem generating code for one of the items in the list. To prevent this problem, select the "Translate Selected" option and select everything in the list except for the very last item called "XML Document" (An easy way to do this is to select the one above "XML Document" called "__xml_error" and press Shift+Home).
  6. On the next page, choose any name for the project that you want. In this example I use "example-msxml".
  7. The following page allows you to select additional libraries. Choose "Minimal".
  8. Choose Finish from the last page and you'll have a project. One change needs to be made to the project to prevent a compilation warning.
  9. Edit the file module.dylan and remove the following lines:
  10.    use simple-format;
       use threads;
    
  11. Compile the project. It should compile successfully.

The next stage is to create a project that uses the library we built above. In the example below we'll create a project and use the interactor to play with the MSXML library interactively.

  1. Start a new project. Use the "Console Application" wizard. You can use the GUI Application Wizard as well but the console one keeps things simple for this example.
  2. In the "User Libraries" page of the wizard, choose "Minimal" and press Finish on the following page. The project should be created.
  3. Edit library.dylan and add the library we created for the MSXML wrappers and the ole-automation library. Something like:
       define library xml-play-1
         use functional-dylan;
         use ole-automation;
         use example-msxml;      
    
         export xml-play-1;
       end library xml-play-1;
    
  4. Note that I called the project xml-play-1.

  5. Edit module.dylan and add the module for the MSXML wrapper library and the ole-automation module. Something like:
       define module xml-play-1
         use functional-dylan;
         use simple-format;  
         use ole-automation;
         use example-msxml;
       end module xml-play-1;     
    
  6. Compile the project using "Interactive Development Mode" (This can be set from the Projects/Settings menu option in the project).

You now have a compiled project that you can use to interactively experiment with the MSXML library. Here is an example of using it:

  1. Choose "Application/Interact" from the menu of the project you just created.

    You are now at the interactor prompt and can enter Dylan expressions. This is useful for exploring libraries and trying out ideas while writing programs. It is similar in functionality to a Lisp listener. In the following, anything appearing after '=>' is the result displayed by the interactor. Don't enter this, the interactor will display it.

  2. The first method to call is to initialize the OLE libraries. Enter:
       ole-initialize();
          => no values
    
  3. Create an XML DOM document object:
       make(<IXMLDOMDocument>, class-id: "Microsoft.XMLDOM");
          => $0 = {<ixmldomdocument>}
    
  4. Load some XML:
      IXMLDOMDocument/loadXML($0, 
         "<test><line>Line 1</line><line>Line 2</line></test>");
          => $1 = #t
    

    The '#t' indicates that the load succeeded.

  5. We can get the root of the DOM tree:
      IXMLDOMDocument/documentElement($0);
          => $2 = {<ixmldomelement>} 
    
  6. If you want to know what methods you can call on an object (say, the $2 that was returned above) you can right click on the <ixmldomelement> on the $2 line and choose "Browse Type" from the menu. A browser will appear showing all the methods (and other things) for that type. This is a great way to interact, experiment and otherwise explore with the XML libraries. Continuing the iteration through the DOM tree:
      IXMLDOMElement/childNodes($2);
          => $3 = {<ixmldomnodelist>} 
    
      IXMLDOMNodeList/Length($3);
          => $4 = 2
    
      as(<byte-string>, IXMLDomNode/text($3[0]));
          => $6 = "Line 1"
    
      as(<byte-string>, IXMLDomNode/text($3[1]));
          => $7 = "Line 2"
    
  7. Here is an example of all the above used to print the XML nodes to the console:
       with-interface(dom = make(<IXMLDOMDocument>, 
                      class-id: "Microsoft.XMLDOM"))
         IXMLDOMDocument/loadXML(dom, 
                                 "<test><line>Line 1</line><line>Line 2</line></test>");
         with-interface(root = IXMLDOMDocument/documentElement(dom))
           with-interface(child-nodes = IXMLDOMElement/childNodes(root))
             for(index from 0 below IXMLDOMNodeList/Length(child-nodes))
               format-out("%s\n", 
                          as(<byte-string>, IXMLDOMNode/text(child-nodes[index])))
             end for
           end
         end
       end;
    

    The above uses the with-interface macro which I created to automatically call release on the COM interfaces:

       define macro with-interface 
       { with-interface ( ?:name = ?init:expression ) ?:body end }
       => { begin
              let ?name = ?init;
              block()
                ?body
              cleanup
                release(?name)
              end
            end
         }
       end macro with-interface;
    

The default wrappers that are created are quite verbose to use. It is possible to make the MSXML library easier to use and read by using some of the more advanced options that can be passed to the OLE wrapper macros. But the above examples should give a good starting to exploring OLE and XML with Dylan. An interesting exercise would be to come up with a more Dylan style XML framework. Perhaps implemented using the automatically generated MSXML wrappers.


Copyright © 2000, Chris Double. All Rights Reserved.
All products and brand names are the registered trademarks or trademarks of their respective owners.