Most XML and HTML developers are familiar with entity references, the odd little XML constructs
you often see that begin with an ampersand (&) and end with a semicolon (;). Probably the most common use of entity references is to literalize characters that aren't legal in XML, such as < to represent the opening angle bracket (<, also known as the less than symbol) that begins an XML or HTML element.
Some developers use another kind of entity reference as a way to include in an XML document some material from a different source -- often a piece of content that's intended to be shared across multiple XML documents, or perhaps an item such as a Flash animation sequence that cannot be converted
to XML. That kind of entity reference, called an external entity reference, saves the time you might otherwise spend copying and pasting the content over and over again. For instance, you might use an entity reference (such as ©right;) in an XML document to reference boilerplate
sections in a different document that someone else is responsible for keeping up to date. (If you don't have a DTD or XML schema, though, external entity references won't work, so don't even try it.)
Parsing entity references, and the associated problems
When XML parsing occurs, the parser resolves the external entity reference in an XML document using the location specified in the DTD or XML schema (In this tip, I'm focusing on DTDs because today they are more commonly used in production applications). During resolution, the parser locates the referenced content and inserts it into the XML. This means that when you manipulate the parsed document (in Java, C, Perl, PHP, Python, or whatever other language you are using), the referenced content appears just as any other content would. As long as everything works properly, you don't have to worry about handling each piece of referenced content individually. Complications, however, may cause the simple process to break down.
You may, for example, need a live network connection in order for the resolution to work properly because so many referenced entities refer to a remote URL somewhere (for instance, http://www.ibm.com/developerWorks/copyright.xml in the example code in Listing 3). The resolution (opening up a connection, pulling down content, closing the connection, and so on) also may slow down the parsing process. You may begin to wonder if there's a way to provide cached, local copies of the referenced pieces of content or another way to circumvent the entity-resolution process. I'm happy to report that there is.
A simple way to resolve external entity references
As long as you're using the Simple API for XML (SAX), you're in luck! And since both DOM and JDOM use SAX under the hood, this simple solution works for all of three APIs (see Resources for background on all three APIs). SAX defines an interface, org.xml.sax.EntityResolver, that provides just the functionality you want. This interface defines only one method, as shown in Listing 1:
package org.xml.sax;
public interface EntityResolver {
public InputSource resolveEntity(String publicID, String systemID)
throws SAXException;
}
|
The sole method in this interface, resolveEntity(), provides a means to step into the entity-resolution process. Because each external entity reference has either or both a public ID and a system ID in the DTD specifying how to resolve the content, you can match these up in this method and implement your own behavior. For example, consider the DTD fragment in Listing 2 that defines the copyright external entity reference:
<!ENTITY copyright SYSTEM "http://www.ibm.com/developerWorks/copyright.xml"> |
Here, there is no public ID, and the system ID is http://www.ibm.com/developerWorks/copyright.xml.
So, you could create a class called CopyrightEntityResolver as shown in Listing 3.
package com.ibm.developerWorks;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class CopyrightResolver implements EntityResolver {
public InputSource resolveEntity(String publicID, String systemID)
throws SAXException {
if (systemID.equals("http://www.ibm.com/developerWorks/copyright.xml")) {
// Return local copy of the copyright.xml file
return new InputSource("/usr/local/content/localCopyright.xml");
}
// If no match, returning null makes process continue normally
return null;
}
|
In this simple implementation, the resolveEntity() method will be invoked every time an entity is resolved. If the system ID for the entity matches the URL in that method, a local XML document (localCopyright.xml) is returned; this is instead of whatever resource is located at
the supplied system ID. In this way, you can "short circuit" the process and supply your own data for a given public or system ID. You'll want to be sure to always return null if no match occurs, so that entity resolution will occur normally in non-special cases.
That's about all there is to it. You can register your entity resolver on your parser as shown in Listing 4.
// Get an XML Reader - this code not detailed here
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setEntityResolver(new CopyrightResolver());
reader.parse(new InputSource("article.xml"));
|
So there you have it. If you can obtain local copies of entity reference content, or if you need to substitute your own content for an entity reference, use the SAX EntityResolver interface. This should help speed your applications and increase the flexibility of your XML documents. Enjoy!
- Visit the birthplace of SAX at Dave Megginson's site.
- Find out more about JDOM at the JDOM home page.
- Look into the background of DOM at the W3C's DOM page.
- For an flyover of the XML specifications and standards, including SAX, download the PDF of the slides from the presentation Overview of XML and Related Technologies from the speaker page of IBM XML Evangelist Marc Colan.
- For a more in-depth intro to SAX and DOM, open the PDF of the slides from the presentation A Detailed Introduction to Parsing and Processing XML Documents Using Java(TM) Technology from the speaker page of Kelvin Lawrence (IBM CTO for XML technology).
- If you want to know how IBM's WebSphere Application Server (WAS) supports XML development, see this technical background info on XML in the WAS Advanced Edition 3.5 online help.
- Find more XML resources on the developerWorks XML zone. For a complete list of XML tips to date, check out the tips summary page.

Brett McLaughlin works as Enhydra strategist at Lutris Technologies and specializes in distributed systems architecture. He is author of Java and XML (O'Reilly). He is involved in technologies such as Java servlets, Enterprise JavaBeans technology, XML, and business-to-business applications. Along with Jason Hunter, he founded the JDOM project, which provides a simple API for manipulating XML from Java applications. He is also an active developer on the Apache Cocoon project and the EJBoss EJB server as well as a co-founder of the Apache Turbine project. Brett can be reached at brett@newinstance.com.