Home > Articles

  • Print
  • + Share This
From the author of

Producing XML



After the initial housekeeping setup, XML can be produced using the repeated invocation of only a few methods. The basic approach involves calling the DOM Document interface's create method for whatever flavor of DOM Node we're creating, and then attaching the newly created node to its parent node. The sample program ProduceXML.cpp follows this approach, with only a few deviations when it produces attributes. (Click here for the source file.)



 1 /* ProduceXML.cpp 2
 3 This program illustrates basic DOM operations involved
 4 with creating an XML document using MSXML's DOM
 5 implementation.
 6
 7 Michael C. Rawlins, 2003, for InformIT
 8
 9 */
 10
 11 #include <iostream.h>
 12
 13 #import <msxml4.dll>
 14 using namespace MSXML2;
 15
 16 int main(int argc, char* argv[])
 17 {
 18
 19  // Local variables and initializations
 20  HRESULT hResult = S_OK;
 21
 22  cout << endl << "Sample ProduceXML Program" << endl << endl;
 23
 24  // Initialize the COM library
 25  hResult = CoInitialize(NULL);
 26  if (FAILED(hResult))
 27  {
 28   cerr << "Failed to initialize COM environment" << endl;
 29   return 1;
 30  }
 31
 32  // Main try block for MSXML DOM operations
 33  try
 34  {
 35   // MSXML COM smart pointers
 36   // Use the Dccument2 class to enable schema validation
 37   IXMLDOMDocument2Ptr spDocOutput;
 38   IXMLDOMElementPtr spElemRoot;
 39   IXMLDOMElementPtr spElemL1;
 40   IXMLDOMElementPtr spElemL2;
 41   IXMLDOMProcessingInstructionPtr spXMLDecl;
 42   IXMLDOMAttributePtr spSchemaLocationAttribute;
 43   IXMLDOMTextPtr spText;
 44
 45   // Create the COM DOM Document object
 46   hResult = spDocOutput.CreateInstance(__uuidof(DOMDocument40));
 47
 48   if FAILED(hResult)
 49   {
 50    cerr << "Failed to create Document instance" << endl;
 51    return 1;
 52   }
 53
 54   // Create the XML Declaration as a Processing Instruction
 55   //  and append it to the document node
 56   spXMLDecl = spDocOutput->createProcessingInstruction("xml",
 57     "version=\"1.0\" encoding=\"UTF-8\"");
 58   spDocOutput->appendChild(spXMLDecl);
 59
 60   // Create the root element and append it to the Document
 61   spElemRoot = spDocOutput->createElement("SampleDocumentElement");
 62   spDocOutput->appendChild(spElemRoot);
 63
 64   // Add the schema attributes to the Root Element
 65   // First declare the xsi namespace
 66   spElemRoot->setAttribute("xmlns:xsi",
 67     "http://www.w3.org/2001/XMLSchema-instance");
 68
 69   // Next set the schema location
 70   // MSXML requires that namespace qualified Attributes
 71   // be created as Nodes, then set
 72   _variant_t varType((short)NODE_ATTRIBUTE);
 73   spSchemaLocationAttribute = spDocOutput->createNode(
 74     varType,"xsi:noNamespaceSchemaLocation",
 75     "http://www.w3.org/2001/XMLSchema-instance");
 76   spElemRoot->setAttributeNode(spSchemaLocationAttribute);
 77
 78   // We can finally set it now
 79   spElemRoot->setAttribute("xsi:noNamespaceSchemaLocation",
 80     "SampleSchema.xsd");
 81
 82   // Create the first FirstLevelChild element and append
 83   // to the document element
 84   spElemL1 = spDocOutput->createElement("FirstLevelChild");
 85   spElemRoot->appendChild(spElemL1);
 86
 87   // Add the Attribute1 attribute
 88   spElemL1->setAttribute("Attribute1","Attribute Value");
 89
 90   // Create the SecondLevelChild element and append
 91   // to the FirstLevelChild
 92   spElemL2 = spDocOutput->createElement("SecondLevelChild");
 93   spElemL1->appendChild(spElemL2);
 94
 95   // Add text for the SecondLevelChild by creating a Text
 96   // node and appending it
 97   spText = spDocOutput->createTextNode("Element Text");
 98   spElemL2->appendChild(spText);
 99
100   // Create the empty second FirstLevelChild element and
101   // append to the document element. Note that we can reuse
102   // this pointer.
103   spElemL1 = spDocOutput->createElement("FirstLevelChild");
104   spElemRoot->appendChild(spElemL1);
105
106   // Save the output XML Document
107   hResult = spDocOutput->save("SampleDccument.xml");
108
109   if FAILED(hResult)
110   {
111    cerr << "Failed to save document" << endl;
112    return 1;
113   }
114
115  } // End of try block
116
117  // Catch COM exceptions
118  catch (_com_error &e)
119  {
120   cerr << "COM Error" << endl;
121   cerr << "Message = " << e.ErrorMessage() << endl;
122   return 1;
123  }
124
125  // Release COM resources
126  CoUninitialize();
127
128  cout << endl << endl << "Successful Completion" << endl;
129
130  return 0;
131 }

The initial program logic up to line 54 is nearly identical to the beginning of the ConsumeXML program. The COM library is readied and the DOM Document is created. The first DOM Node that must be created is the XML declaration in the first line of the sample document. Even though it isn't technically a processing instruction according to the XML Recommendation, we create in the DOM a ProcessingInstruction node and append it to the Document element as its first child. The DOM allows programmers to insert nodes as well as append them, but for simplicity and consistency I always append them when building a document tree from scratch.

After creating the XML declaration, the program then creates the Document element SampleDocumentElement and appends it to the document at lines 60–62. After that, we see the two basic ways to create attributes using the MSXML DOM implementation. We must create two attributes. The first is the xmlns namespace attribute in line 3 of the sample document. This attribute is easily created by a single call to the document element's setAttribute method at lines 64–67. The second attribute in line 4 of the sample document specifies the location of the schema. This attribute is a bit more difficult to deal with in MSXML because, being associated with the XMLSchema-instance namespace, it's namespace qualified. The DOM specifies a setAttributeNS method that's implemented by several other DOM APIs, but not by MSXML. In MSXML, a namespace-qualified attribute must first be created using the Document interface's createNode method, specifying a node type of Attribute. Then, once the attribute node is created as a namespace-qualified node, it can be assigned to the root element using the setAttributeNode method. This approach is demonstrated in lines 69–80. Notice that at line 72 the node type is created as a VARIANT, and passed in the createNode invocation of line 73.

Lines 90 through 104 create the remaining elements and attributes using the same basic methods. The main thing to keep track of here is being sure that newly created nodes are attached to the proper parent. At line 107, the DOM document is saved to disk using the Document interface's save method.

  • + Share This
  • 🔖 Save To Your Account