This topic walks you through a sample that covers the basic XML API functions.
The sample is loading an existing XML document from a file. It modifies this XML document and iterates through the document with the possible techniques. The file the sample is using has the following structure:
<Order> <Name>Scott Bradley</Name> <OrderItems> <Item id="1">Lord of the Rings</Item> </OrderItems> <Price>25.90</Price> </Order>
First, we create a new project (the project type does not matter). Then, we take the XML snapshot from the Sample Overview section, store it in a text file and add it to the data file section of our project. Store the file as ORDER.XML.
use "XMLAPI.BDH"
The first step is to load the document and get the document handle. We need a variable that is storing the handle (number) and one string variable to get the absolute path of our XML document. We have to get the absolute path because XmlCreateDocumentFromFile requires the absolute path to the file that should be loaded - GetDataFilePath is the function that returns the absolute path to a file in the data file section.
As you can see in the sample code below we have to check if the returned handle value is not null. In case of an error - every XML function that returns a handle will return a 0. As you can further see - we have to free the handles when they are no longer needed - so we free the document handle at the end of our script.
dcltrans transaction TmyTrans1 var hDoc : number; sXmlFile : string; begin GetDataFilePath("order.xml", sXmlFile); hDoc := XmlCreateDocumentFromFile (sXmlFile); if (hDoc <> 0) then ... XmlFreeHandle(hDoc); end; end TmyTrans1;
We now have a document handle in hDoc which is in fact the "virtual" document root node - a node that is the parent node of all top level nodes in the document - in our case it would be the parent of the node "Order".
If we want to iterate through all nodes in the XML document we have to get all child nodes of the document and iterate through them. And we also go through the child nodes of the returned child nodes - so to iterate through the whole document we have to write a function that will be called recursively - to make things easier in this sample we only iterate 2 node levels.
XmlGetChildNodes returns a nodelist handle. XmlGetCount returns the number of items in the nodelist and with XmlGetItem we can access one node in the list identified by the index (0 for the first item; XmlGetCount - 1 for the last).
We are going to write the node names and values to the output file:
dcltrans transaction TmyTrans1 var hDoc, hChildren, hChildNode, nChildIx, nChildCount : number; hChildren2, hChildNode2, nChildIx2, nChildCount2 : number; sXmlFile, sName, sValue : string; begin GetDataFilePath("order.xml", sXmlFile); hDoc := XmlCreateDocumentFromFile(sXmlFile); if (hDoc <> 0) then hChildren := XmlGetChildNodes(hDoc); // get the nodelist to the children nChildCount := XmlGetCount(hChildren); // get the number of items in the nodelist for nChildIx := 0 to nChildCount -1 do// iterate through the children hChildNode := XmlGetItem(hChildren, nChildIx); // get a child out of the list XmlGetNodeName(hChildNode, sName); XmlGetNodeValue(hChildNode, sValue); writeln(sName + ":" + sValue); // now we do the same for the children of this child node hChildren2 := XmlGetChildNodes(hChildNode); nChildCount2 := XmlGetCount(hChildren2); for nChildIx2 := 0 to nChildCount2 -1 do hChildNode2 := XmlGetItem(hChildren2, nChildIx2); XmlGetNodeName(hChildNode2 , sName); XmlGetNodeValue(hChildNode2 , sValue); writeln(" " + sName + ":" + sValue); XmlFreeHandle(hChildNode2); end; XmlFreeHandle(hChildren2); XmlFreeHandle(hChildNode); end; XmlFreeHandle(hChildren); XmlFreeHandle(hDoc); end; end TmyTrans1;
Output File:
Order: Name:Scott Bradley OrderItems: Price:
If you know exactly which node in the document you want to get - you can execute an X-Path query. There are two functions that allow you to execute queries - XmlSelectNodes and XmlSelectSingleNode. XmlSelectNodes returns a nodelist of all resulting nodes whereas XmlSelectSingleNode returns the first resulting node or 0 if there were no nodes matching the query. In our sample we want to query all nodes with name "Item" and write the values to the output file.
dcltrans transaction TmyTrans1 var hDoc, hResultNodes, hNode, nResultIx, nResultCount : number; sXmlFile, sName, sValue : string; begin GetDataFilePath("order.xml", sXmlFile); hDoc := XmlCreateDocumentFromFile(sXmlFile); if (hDoc <> 0) then hResultNodes := XmlSelectNodes(hDoc, "//Item"); // get all nodes of name Item nResultCount := XmlGetCount(hResultNodes); // get the number of items in the nodelist for nResultIx := 0 to nResultCount -1 do // iterate through the children hNode := XmlGetItem(hResultNodes, nResultIx); // get a child out of the list XmlGetNodeName(hNode, sName); XmlGetNodeValue(hNode, sValue); writeln(sName + ":" + sValue); XmlFreeHandle(hNode); end; XmlFreeHandle(hResultNodes); XmlFreeHandle(hDoc); end; end TmyTrans1;
Output File:
Item: Lord of the Rings
Now lets create a new Item node in our XML document. We can either create the whole XML node (including value and attributes) with XmlCreateNodeFromXml or we can create the node with XmlCreateNode and set the value and attributes with other API functions. After creating the node and setting the values - we are appending the node to the OrderItems node. So we have to do the following steps: Create the node, Set the value and attributes, Get the OrderItems node and append the created node to the order items node.
dcltrans transaction TmyTrans1 var hDoc, hOrderItems, hNewItem : number; sXmlFile, sXml : string; begin GetDataFilePath("order.xml", sXmlFile); hDoc := XmlCreateDocumentFromFile(sXmlFile); if (hDoc <> 0) then hOrderItems := XmlSelectSingleNode(hDoc, "/Order/OrderItems"); // get the OrderItems node hNewItem := XmlCreateNode("Item"); // Create a new Item Node XmlSetNodeAttribute(hNewItem, "id", "2"); // set the node attribute XmlSetNodeValue(hNewItem, "Star Wars - Episode II"); // set the node value XmlAppendChild(hOrderItems, hNewItem); // append the node // now lets get the XML representation XmlGetXml(hDoc, sXml); writeln(sXml); XmlFreeHandle(hNewItem); XmlFreeHandle(hOrderItems); XmlFreeHandle(hDoc); end; end TmyTrans1;
Output File:
<Order> <Name>Scott Bradley</Name> <OrderItems> <Item id="1">Lord of the Rings</Item> <Item id="2">Star Wars - Episode II</Item> </OrderItems> <Price>25.90</Price> </Order>
As you have already seen in the previous examples - there are several functions to get the name and value of a node XmlGetNodeValue, XmlGetNodeName) and there are functions to set the value and attributes of a node (XmlSetNodeValue, XmlSetNodeAttribute).
Iterating through nodes is also already described above - but there is also another way to get a child node of a node. XmlGetChildNodeByIndex directly returns the node handle to a child of a node. This function is useful if you know exactly which child node you want to access. Otherwise, you need to iterate through the nodelist returned by XmlGetChildNodes.
Attributes can also be accessed either by name or by index. XmlGetAttributeByIndex returns the value of an attribute identified by its index whereas XmlGetAttributeByName returns the value of an attribute identified by its name.
XmlRemoveChild allows you to remove a node from the document.
The following sample code will make use of some of the above mentioned functions to remove the Item node with the attribute value "2" for attribute "id":
dcltrans transaction TmyTrans1 var hDoc, hOrderItems, hItems, hItem, nItemCount, nItemIx : number; sXmlFile, sXml : string; begin GetDataFilePath("order.xml", sXmlFile); hDoc := XmlCreateDocumentFromFile(sXmlFile); if (hDoc <> 0) then hOrderItems := XmlSelectSingleNode(hDoc, "/Order/OrderItems/*"); // get all Item nodes nItemCount := XmlGetCount(hOrderItems); for nItemIx := 0 to nItemCount -1 do hItem := XmlGetItem(hOrderItems, nItemIx); XmlGetAttributeByName(hItem, "id", sAttrValue); if(StrICmp(sAttrValue, "2") = 0) then XmlRemoveChild(hItem); end; XmlFreeHandle(hItem); end; // now lets get the XML representation XmlGetXml(hDoc, sXml); writeln(sXml); XmlFreeHandle(hOrderItems); XmlFreeHandle(hDoc); end; end TmyTrans1;
Output File:
<Order> <Name>Scott Bradley</Name> <OrderItems> <Item id="1">Lord of the Rings</Item> </OrderItems> <Price>25.90</Price> </Order>