Tech Articles


PBDOM with PowerBuilder


​You might think, why should I bother using PBDOM? You can use PDOM to manipulate elements in an XML document. That means you can move elements within a document or from one document to another. You can add elements to a document or delete elements from a document. Moreover, with some coding it is even possible to import nested XML data into a DataWindow.

With the XML capabilities of the DataWindow introduced with PowerBuilder 9 it is possible to import and export data very fast and easily. You might have given a short look at the PBDOM definition in the PowerBuilder help but at the first sight, it looks quite difficult to handle. In the following article, I introduce PBDOM accompanied by some code samples.

PDOM Usage

PBDOM means PowerBuilder Document Object Model. It is similar to the DOM API of the World Wide Web Consortium and JDOM, which is a Java-based document object model for XML files. You can find comparison of these three models in the PowerBuilder Help (PowerBuilder Extension Reference / PowerBuilder Document Object Model / PBDOM objects). Technically, PBDOM is implemented as PBNI (PowerBuilder Native Interface) extension that makes use of the Apache/Xerces DLL.

PBDOM Classes

All PBDOM classes (except PBDOM_Builder and PBDOM_Exception) are inherited from PBDOM_Object.

  • PBDOM_Builder is used to create a PBDOM_Document from data sources like files, strings or DataStores.
  • PBDOM_Exception extends the PowerBuilder exception class and is used for exception handling.
  • PBDOM_Object represents any node in an XML node tree and serves as base class for the different node types
  • PBDOM_Document is the representation of the XML DOM document. It gives access to document level elements.
  • PBDOM_Element represents an XML element and allows access to its attributes, children and text
  • PBDOM_Attribute is the representation of an XML attribute and allows access to its values and namespace information
  • PBDOM_Text represents a DOM text node in a XML document.
  • PBDOM_Processinginstruction are the processing instructions of the XML document

When looking at Listing 1, the saved XML data from the DataWindow, you can see some of the described types. The class PBDOM_Document references all the data including the XML header. The PBDOM_Processinginstruction object references the data in the XML header (e.g. version). [Processing instructions are used to send instructions to the application that is reading the XML.  They begin with "".  Technically, the XML Declaration is not a Processing Instruction, although it is often referred to as such and does have a similar format. – Editor.] The items CUSTOMERS, CUSTOMER, FIRSTNAME, etc are PBDOM_Elements. The ID in the CUSTOMER tag is a PBDOM_Attribute and PBDOM_Text references the values within the tags like Michaels or Devlin.

A namespace in a document is used to distinguish between elements and attributes with the same name but belonging to different items. The element CUSTOMER and the element COMPANY could both have a child element named NAME. References to the element NAME would be ambiguous unless using a namespace. The solution with the prefix the document could look like this:

Doe
Sample LLC

You will find more details about namespaces on the W3C web site and many examples and answers on the XML Namespace FAQ at http://www.rpbourret.com/xml/NamespacesFAQ.htm.

Before you can start working with PBDOM, you have to add PBDOM170.PBD to the library list. In the application search path of PowerBuilder the following files should be accessible: PBDOM170.DLL, PBXerces170.DLL and xerces-c_2_8_0.dll. You have to deploy these four files with your application.

Creating an XML Document

An XML document can be created either from scratch or from an existing file, string or DataStore. In Listing 2 the Sample XML Listing 1 is used to generate an XML DOM document. Only minimal error handling is implemented in this listing. The method BuildFromFile from the PBDOM_Builder class reads and parses the XML Document. The method returns a reference to the PBDOM_Document.

The next few lines of code show some details about the first level of the document. The method GetContent from the PBDOM_Document returns an array of objects in the document. In our sample, the method will return an array of two elements. The first element is of type PBDOM_Processinginstructions, the second of type PBDOM_Element and references the element CUSTOMERS. The call to the method GetRootElement returns the root element of the document, which is also CUSTOMERS.

To visualize a XML document in PowerBuilder you can use a TreeView. Listing 3 shows a recursive function that takes an array of PBDOM_Objects and displays it in a TreeView. The function loops through all elements of the array. Depending on the type of element different information besides the object name are displayed. In the case of a PBDOM_Element, the function loops over all the attributes of this element and creates name/value pairs of each. The name of the PBDOM_Object plus the display information is added to the TreeView. Should the PBDOM_Object have children, the same function is called with an array of these children and the handle of the inserted TreeView item.

Manipulating the XML Document

The big advantage of PBDOM is the possibility to manipulate a single node in a document. For the following example, I'll add some information for customer ID 102. I'll add an order to the customer. Listing 4 shows how we search for the customer with an ID of 102. The function is recursive and loops through all the elements and attributes until the element with the required attribute value is found. Note that the search is case sensitive. Call the function with the root element. The content of the root element is loaded into an array. The method loops over the items of this array. If the item is of type PBDOM_Element the name of it -- returned with the method GetName -- is compared with the name to search for (CUSTOMER in our example). When an element with the name to search for is found, the method GetAttributes loads all the attributes of this element into an array. The function then loops over the attributes and -- as soon as the attribute with the name to search for is found -- the value is checked. When the value matches, the element is returned. If there is no match and the element has children, the method calls itself passing that element. There are W3C standard methods for searching XML documents known as XPath and XQuery.  However, at least as of the date this article was written,  PBDOM does not support XPath or XQuery type operations.

After the appropriate element is found, I add a sales order header (see Listing 5). At first I create a sales order with CREATE PBDOM_Element. Then I set the name of this instance to SALESORDER with the method SetName. The SetName method validates the name (e.g. for spaces in the element name). I then add an attribute with the name ID and the value 111. For the sales order, I need an order date and region. I create them, set their name and put the value into it with SetText. After all these elements are prepared, I put them together with the method AddContent. The AddContent method checks the data for structure (e.g., no loops in a tree), consistence of namespace and ensures that there is only one root element. To catch the runtime errors, I put a TRY … CATCH statement around the call.

To demonstrate some additional more data manipulation, I also remove the customer with ID equals 101. The search for that customer is done using the same method shown in Listing 4. To remove that element the method Detach is used:

lpbdom_Found.Detach()

After the manipulation is done, the XML document is saved with the method SaveDocument of the PBDOM_Document. Unfortunately, as of this writing, there is no method to save it to string or blob. Instead, you must save the XML to a temporary file and then read it back into a string or blob, as applicable.

Conclusion

The PDBOM interface is a powerful way to manipulate complex XML documents. There are various usages possible. We can use it e.g. to customize style sheets for an application.  This article has provided you with a base to start from. For additional information check out the PowerBuilder help.

Download the listings, sample and working sample from our website at: https://www.dropbox.com/s/u8mnh2y611qdk0j/PBDOMSample.zip?dl=1

Comments (2)
Friday, Oct 27 2017

Do I need something more if I import the pbdom.pbx into one of my libraries? I import the extension and see the objects. However, adding these objects to source control still yields a "illegal datatype for pbdom_document" from any other machine until I manually import the extension on each machine. I don't want to add the pbd- I'd rather just import the objects directly.

#1
0

Thursday, Nov 21 2019

Are you 100% sure the other machines did a Get Latest and can see those objects in the PBL? Try doing a Full rebuild as well. If that doesn't work, report it as a bug.

0

Find Articles by Tag

Filter File PowerServer Web OrcaScript COM DataWindow IDE Jenkins Event Variable Linux OS Database Object OAuth 2.0 Bug C# RichTextEdit Control 64-bit Open Source OAuth Debug Validation Database Table Schema Service Performance iOS JSON SnapDevelop Import TortoiseGit SnapObjects Array CI/CD Event Handling Testing Platform Android Authentication Excel Installation Script Configuration Text JSONParser UI Modernization SDK Deployment REST Database Table SqlModelMapper Git Branch & Merge Database Profile .NET Std Framework Windows OS Stored Procedure UI Themes UI RESTClient Messagging XML DragDrop Sort SQL PostgreSQL ODBC driver SqlExecutor Event Handler Debugger WinAPI PBDOM Azure RibbonBar Builder NativePDF Database Table Data DevOps Oracle GhostScript JSONGenerator HTTPClient Automated Testing WebBrowser Elevate Conference PowerServer Mobile API MessageBox DataWindow JSON Menu TLS/SSL BLOB PowerBuilder (Appeon) Syntax Error Resize License ODBC Windows 10 Icons TFS SQL Server Web API PowerScript (PS) Window Encoding External Functions PowerBuilder Compiler InfoMaker .NET Assembly Encryption Export JSON 32-bit Authorization Debugging Database Expression Migration Model Database Painter .NET DataStore PostgreSQL TreeView SVN Design DataType RibbonBar Repository Graph PDFlib CoderObject Import JSON Icon Mobile Database Connection DLL Data ActiveX Interface Application PowerBuilder Charts Export Web Service Proxy Trial PDF Transaction Outlook CrypterObject Source Code Class Source Control SOAP PFC OLE