Ten Lessons Learned From An XML Developer
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.