Building WSDXML sections

Last year I described the general structure of WSDAPI's WSDXML sections and provided some hints for creating and consuming these structures.  I've received a few requests since then to provide more concrete examples of how to build these structures in code.

Before we get started, I do recommend you re-read my original post on WSDXML.  The relationship between WSDXML_ELEMENT, WSDXML_TYPE, and WSDXML_NODE is an important part of understanding how everything fits together.

Simple example: element with text
The first example will demonstrate how to build a single element with text, but without any attributes or children.  If we imagine the "ex" prefix is bound to the https://www.example.org namespace, here's the element we will want to build:

        <ex:TestElement>text</ex:TestElement>

Creating this structure is straightforward.  It involves two steps:

  1. Extract an XML name ("ex:TestElement") from the XML context
  2. Build a WSDXML_ELEMENT structure from that XML name

Here's what it looks like in code.

        // All error handling is omitted from this example
        HRESULT hr = S_OK;
        IWSDXMLContext *pContext = NULL;
        WSDXML_NAME *pName = NULL;
        WSDXML_ELEMENT *pElement = NULL;

        hr = WSDXMLCreateContext( &pContext );

        hr = pContext->AddNamespace(
                L"https://www.example.org",
                L"ex",
                NULL );

        hr = pContext->AddNameToNamespace(
                L"https://www.example.org",
                L"TestElement",
                &pName );

        hr = WSDXMLBuildAnyForSingleElement(
                pName,  // pName is copied here, and must be freed separately
                L"text",
                &pElement );

        // pElement is now complete, and contains: <ex:TestElement>text</ex:TestElement>

        // cleanup:
        // WSDFreeLinkedMemory( pElement );
        // WSDFreeLinkedMemory( pName );
        // pContext->Release();

Note that you can omit the "text" parameter to WSDXMLBuildAnyForSingleElement to generate empty elements.  Supplying NULL here would result in <ex:TestElement />

Advanced example: chaining elements
We'll build on the last example to show how you can create chains of structures.  Here's the element we want to build this time:

        <ex:ParentElement>
            <ex:ChildElement>text</ex:ChildElement>
            <ex:AnotherChildElement />
        </ex:ParentElement>

In this case, the steps go like this:

  1. Build ParentElement, ChildElement, and AnotherChildElement separately using the instructions above.
  2. Use WSDXMLAddChild to link ParentElement to ChildElement
  3. Use WSDXMLAddChild or WSDXMLAddSibling to add in AnotherChildElement.  Either is acceptable.

Important: see section below on cleaning up WSDXML structures.Also note that you only need to call IWSDXMLContext::AddNamespace once for a given namespace--it is not necessary to call it for every name you add.

Here's some example code:

        // Use steps above to create pParentElement, pChildElement,
        //     and pAnotherChildElement

        hr = WSDXMLAddChild( pParentElement, pChildElement );

        hr = WSDXMLAddSibling( pChildElement, pAnotherChildElement );
        // It is also acceptable to call
        // WSDXMLAddChild( pParentElement, pAnotherChildElement);

        // cleanup:
        // WSDFreeLinkedMemory( pParentElement );
        // Use WSDFreeLinkedMemory to destroy WSDXML_NAME objects
        //     extracted from IWSDXMLContext
        // DO NOT FREE pChildElement or pAnotherChildElement;
        //     they are attached to pParentElement

Destroying WSDXML structures
At first glance, it may seem complex to destroy these structures, but they're designed to be simple.  You only need to follow a few simple rules to write robust and leak-free WSDXML code:

  • All WSDXML functions use linked memory.  Always use WSDFreeLinkedMemory to destroy individual structures or whole trees.
  • WSDXMLBuildAnyForSingleElement copies the "name" parameter and links a copy into the new tree.
  • WSDXMLAddChild and WSDXMLAddSibling link together all structures in the tree.
  • Only free the topmost WSDXML_ELEMENT structure in an entire tree.
  • When passing WSDXML structures as outparams from services, be sure to link the entire WSDXML tree into the outparameter.