XML (eXtensible Markup Language) is a very simple and elegant language for representing structured data. However, XML programming has a big learning curve. There are several APIs such as SAX (Simple API for XML), DOM (Document Object Model), and TrAX (Transformation API for XML) to understand. There is a family of languages such as XSLT (XML Stylesheet Language Transformations) and XPath to learn. DTDs and XML Schemas must be mastered to describe the structure, content, and semantics of XML documents.
Are you getting started doing XML development? Have you been doing XML development for a while and want to see how you can get better in your craft? This article will share a few short lessons learned in XML programming by both experience and through observation. Most people learn the hard way by making mistakes and learning from them. This article will try to help you learn the easy way, by building upon the successes and avoiding the failures of your peers.
Here are the ten lessons we’ll be discussing:
- Lesson 1: Know What Type of Parser to Use
- Lesson 2: Use XPath to Query a DOM
- Lesson 3: Use “//” XPath Statements with Care
- Lesson 4: Model XML Documents
- Lesson 5: Use DOM Wrapper Objects
- Lesson 6: Know What Type of Transformation to Use
- Lesson 7: Use Rules-Based Stylesheets
- Lesson 8: Optimize XSLT Stylesheet Execution
- Lesson 9: Use DTDs or Schemas
- Lesson 10: Use Document-Oriented Meta Data
Lesson 1: Know What Type of Parser to Use
There are two standard types of parsers that can be used to process XML documents: SAX (Simple API for XML) and DOM (Document Object Model). It’s important to know the benefits and tradeoffs of each type of parser.
When dealing with large XML streams and when a sequential parsing algorithm will do, SAX (Simple API for XML) can’t be beat. The SAX API parses XML as a stream of events. Typically, a handler class is written to be the recipient of those events and it can handle them as it wishes. SAX can handle very large structures because it doesn’t keep an entire XML document in memory at one time. However, the sequential nature of the algorithm creates limitations. It cannot be used to query the XML document. It cannot be used to directly perform insert, update, and delete operations against the document, either.
The DOM API provides an object representation of an XML document. Unlike SAX, it’s great for querying the XML document programmatically or by using XPath. It also provides the ability to insert, update, and delete nodes of the document. It’s a great way to cache a reasonably sized document in memory.
When I first learned XML programming, I learned SAX and used it for everything. Often, I would use it to create custom, in-memory representations of the XML document. When I later learned DOM, I realized that I could have more easily created a DOM for this purpose.
Once I saw the virtues of DOM, I began to use it almost exclusively. However, SAX still has its strengths, too. A previous article, “Transforming Flat Files To XML With SAX and XSLT,” discussed how to leverage SAX to efficiently transform arbitrary, non-XML data structures into XML. This is a unique capability of SAX. And, SAX can handle large structures much better than DOM, although DOM has been getting better in this regard.
Hopefully, I’m a bit more balanced now that the pendulum has swung from SAX to DOM and now ended up back in the middle. It’s great having both SAX and DOM in your toolbox and knowing when to use each tool.
Lesson 2: Use XPath to Query a DOM
When the need arises to search for nodes in a DOM, it can be awfully tempting to fall into the procedural trap and programmatically navigate through the DOM to search for particular elements. However, there is a much more powerful tool for this task. XPath is the query language of XML. Its relationship to XML is akin to the relationship of SQL to relational data. Why programmatically recurse through a document when a simple XPath query can do all the work? I’ve seen an awful lot of code that could be summed up with a very simple XPath expression.
XPath Visualizer is a free tool that provides the capability for running XPath queries against documents and visually seeing the results. It’s worth taking a look at and adding to your XML toolbox.
Lesson 3: Use “//” XPath Statements With Care
When developers begin using XPath and are having trouble getting the expected results from an expression, they often find that beginning the expression with the “//” operator helps. Then, the developer gets in the habit of always starting expressions with “//”. The “//” operator in XPath is a shorthand for /descendant-or-self::node()/ which searches for all descendants of a node in the document, not just immediate children. When it is used at the start of an XPath expression, it causes a recursive search beginning at the document root. In the relational database world, this is somewhat analogous to a full table scan. And, anyone who has done relational database performance tuning knows that full table scans are something that should generally be avoided with large structures.
XPath has the notion of a context node that becomes the “axis” for doing searches. Rather than beginning a search from the start of the document, it is usually more advantageous to begin from the current context. If immediate children of the context node are being queried, an XPath expression shouldn’t begin with “//”, “/”, or “..” at all. If sibling nodes are being queried, the “..” operator navigates to the parent node of the context node, and then a path can be constructed from there.
Another approach to consider is providing the absolute path of a node from the document root by beginning the expression with “/”. This can be a very efficient way to address the data in an XML document. However, it can make code brittle. If intermediate nodes are added to the document schema, XPath expressions will need to be updated. Relative path expressions are less prone to impact from adding intermediate structures.
The bottom line: Use “//” XPath statements with care. Know how they work and use them discriminately.
Lesson 4: Model XML Documents
It’s a best practice to model an XML document’s structure with UML class diagrams or E-R (Entity-Relationship) diagrams. A visual representation of the structure helps understanding the relationships between elements in a way that a pure textual format cannot. A model will also help in normalizing or eliminating the redundancies in the XML structure.
Pay particular attention to how one-to-many relationships are modeled. It is very common in XML to see one-to-many relationships modeled as containment relationships. However, this is a restrictive way to model data and often doesn’t reflect the true relationship between elements. For example, an employee may work for a department, but is not contained by a department. If the department goes away, the employee still exists! A previous article, “Modeling One-To-Many Relationships in XML,” discussed how to model intra-document and inter-document relationships for flexibility using standard ID, IDREF, and HREF attributes.
Lesson 5: Use DOM Wrapper Objects
DOM API code can get quite verbose and procedural. In fact, it’s often difficult to see the business logic between the programmatic DOM statements and XPath expressions. If you are not careful, changes to the XML structure can break code in multiple places.
One of the ways to address this problem is by using the Wrapper or Decorator design pattern. A DOM wrapper object is constructed with a DOM. It encapsulates all DOM and XPath code and provides standard public getter, setter, and interrogator methods to clients. When changes are made to the XML structure, they are isolated to the wrapper object and do not affect client code. If the XML document was modeled with UML (see Lesson 4), it will be easy to identify candidate wrapper objects and their method signatures.
Lesson 6: Know What Type of Transformation to Use
Another form of procedural abuse can be using DOM programming for transforming XML structures rather than XSLT. For relatively simple transformations, DOM programming could be a good fit. This technique programmatically reads from one DOM while creating another DOM node by node. However, it can become quite tedious. An XSLT stylesheet is a much easier way to transform complex XML structures. It also results in more maintainable code because the transformation code can be organized into discrete, rules-based templates (see Lesson 7). Using the TrAX API, it is very easy to run XSLT transformations from Java programs. Generally, the way this works is by providing a source document to a transformer object for a stylesheet, which returns the result of the transformation.
Lesson 7: Use Rules-Based Stylesheets
An XSLT stylesheet with many <xsl:for-each> statements (and especially nested <xsl:for-each> statements), is a procedural stylesheet. While it is probably functional, a procedural stylesheet is much more difficult to maintain than a rules-based stylesheet and doesn’t take advantage of the full features of XSLT.
A rules-based stylesheet consists of several discrete templates that are invoked when their rule is matched. The XSLT engine does the tree walking by recursing over the document nodes selected via an <xsl:apply-templates select=”…”> statement and applies the templates of all the matched rules.
A previous article, “Following The Rules-Based Approach To Stylesheet Development,” solves the same business problem with both procedural and rules-based stylesheets and compares and contrasts the approaches. Another article, “Building Modular Stylesheet Components,” dives a little deeper and shows how to design reusable stylesheet components.
It’s a good idea for a beginning stylesheet developer to completely forgo <xsl:for-each> statements that can lead to very procedural code and concentrate on learning the rules-based approach
Lesson 8: Optimize XSLT Stylesheet Execution
Compiling an XSLT stylesheet can be an expensive operation, taking a few hundred milliseconds. Improper use of the TrAX API can cause a compilation with each transformation. Fortunately, TrAX allows a client to create a compiled representation of a stylesheet, called a Templates object, that can be cached and used over many transformations. A previous article, “Optimizing Stylesheet Execution with TrAX,” discusses how to cache compiled representations of the stylesheets and make them hot deployable. Learn this technique and don’t take an unnecessary performance hit when running XSLT transformations from Java programs.
Lesson 9: Use DTDs or Schemas
DTDs and Schemas document the structure, content, and semantics of XML documents. However, they are not required by XML—a document essentially describes itself. Often, when programming XML, “strong-typing” and compile-time error checking is sacrificed for “strong-tagging” and run-time errors. Using DTDs and Schemas helps mitigate the risk of run time errors. They can be used to communicate the “contract” of a document to various clients and to validate documents at run time.
XML IDEs and editors take advantage of DTDs and Schemas by providing drop-down lists of values and other productivity features. Many can generate DTDs and Schemas for you, thereby eliminating a lot of tedious work.
When DTDs and Schemas are not used, a document’s structure has not been fully defined. It can be misinterpreted and inadvertently changed. A document without a DTD or Schema cannot be validated except programmatically. In short, not using DTDs or Schemas are a shortcut a developer cannot afford to take.
Lesson 10: Use Document-Oriented Meta Data
Meta data is essentially data that describes the characteristics of other data or objects. Document-oriented meta data is quite simply meta data stored in an XML document.
Why use XML over relational databases or other data storage mechanisms for representing meta data? A single document can store complex data structures of related meta data elements in a cohesive manner. This document can be versioned in a configuration management tool. It can be edited using standard, off-the-shelf tools. If built with a DTD or Schema (see Lesson 9) and edited with an XML editor, the meta data author will be guided to create a valid document. Document-oriented meta data can be made available to an application via an XML database, file system, or URI. It can be loaded in memory as a DOM and easily queried. Contrast this with relational databases that have a tendency to scatter the meta data over many tables. It will not be cohesive by nature, easily versionable, edited, nor able to be represented in memory directly.
A previous article, “Dynamic Screen Generation with XSL,” showed how to build an XSLT stylesheet that can dynamically generate a multitude of screens from document-oriented meta data that describes the screen. Another article, “Code Generation with XSL,” shows how to generate Java programs from document-oriented meta data. These articles are examples of how to think more abstractly about how to solve a business problem and how to build meta data-driven frameworks and systems.
In this article, we’ve reviewed ten short lessons learned from an XML developer. Hopefully, they will help you to adopt some of the best practices and avoid some of the pitfalls in XML development. If you’ve read my articles, you’ll notice that I always end them the same way. “The rest is up to you.” This is because I firmly believe that it is in the doing that the learning occurs. It’s one thing for me to explain a technique. By itself, this has some value. But it’s much better when an article inspires you to want to try it for yourself. The light bulb really goes off in your head when you’ve got the code working and you are applying it to your problem domain. So, review this list of lessons learned before you start your next XML project. Adopt the best practices and avoid the pitfalls. The rest is up to you!
I would like to thank Tom Sorensen, Mike Stevens, and Jim Linn for taking time out of their busy schedules for reviewing this and other articles prior to publication. Their feedback has been of immeasurable help to me. I would also like to thank all the readers who take the time to e-mail me as well with feedback and ideas for future articles. Please keep them coming! I appreciate it.
About the Author
|Jeff Ryan is an architect for Hartford Financial Services. He has eighteen years of experience designing and developing automated solutions to business problems. His current focus is on Java, XML, and Web Services technology. He may be reached at firstname.lastname@example.org.|