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.html
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.)網絡
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.app
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.less
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 Related topics 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:ide
1flex 2ui 3this 4spa 5code |
|
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:
1 |
|
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
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 insteadof whatever resource is located at the supplied system ID. (在這個方法中,若是這個實體的system ID匹配了URL地址的值。將會加載本地的XML文檔做爲輸入流byteStream返回,就不須要根據URL地址進行網絡加載了,若是那個byteStream返回null,後面的程序仍是會根據system ID指定的地址去加載實體引用文件。EntityResolver主要就是起這個做用的!!!)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.
1 2 3 4 |
|
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!