Namespaces

JDOM’s Namespace class, shown in Example 15.17, represents a namespace attached to an element or an attribute. Each namespace has a URI. If the namespace is not a default namespace, then it also has a prefix. Otherwise the prefix is the empty string.

Example 15.17. The JDOM Namespace class

package org.jdom;

public final class Namespace {

  // Common namespaces
  public static final Namespace NO_NAMESPACE;
  public static final Namespace XML_NAMESPACE;

  // Factory methods
  public static Namespace getNamespace(String prefix, String uri);
  public static Namespace getNamespace(String uri);
  
  // Getter methods
  public String getPrefix();
  public String getURI();
  
  // Utility methods
  public boolean equals(Object o);
  public String toString();
  public int hashCode();
  
}

Because repeating long strings like “http://www.w3.org/2002/01/P3Pv1” on each element can eat up memory very quickly, and because a typical document contains many elements in the same namespace, this class uses the flyweight design pattern. This means the constructors are private, and you’ll need to use the factory methods to create Namespace objects. Alternately, the Element and Attribute classes allocate or reuse the necessary Namespace objects automatically when you pass string forms of the namespace URIs to their constructors or setNamespace() methods.

For an example, I try to use well-formed HTML on most of my sites. However, I generally don’t attach the XHTML namespace (http://www.w3.org/1999/xhtml) where I should. The following method forces all unqualified elements into the XHTML namespace:

  public static void xhtmlQualify(Element element) {
   
    Namespace xhtml 
     = Namespace.getNamespace("http://www.w3.org/1999/xhtml");
    
    if (element.getNamespace() == Namespace.NO_NAMESPACE) {
      element.setNamespace(xhtml);
    }
    
    List childElements = element.getChildren();
    Iterator iterator = childElements.iterator();
    while (iterator.hasNext()) {
      Element child = (Element) iterator.next();
      xhtmlQualify(child);
    }
    
  }

This changes the Document object in place (though not the original file on disk or the network). It does not create any new node objects. You could use this as a filter before passing the Document object to a different method that expected pure XHTML. (In practice, you’d probably also need to change all the element names to lower case and add a DocType.)

You normally don’t need to worry about exactly where the xmlns and xmlns:prefix attributes that declare namespaces are placed. (Indeed JDOM won’t let you add attributes with these names since it stores them separately from the other attributes.) When an outputter converts a JDOM Document to a DOM Document, a SAX event sequence, or a stream of bytes, it will figure out where it needs to put namespace declarations to make everything come out right. However, some XML applications, including SOAP, XSLT, and the W3C XML Schema Language, also use namespace prefixes in attribute values and even element content. These prefixes are not necessarily used on any element or attribute names in the document. However, the prefixes still need to be declared. For example, the simple XSLT stylesheet in Example 15.18 needs to declare the prefix svg even though it’s only used in the value of the match attribute.

Example 15.18. An XML document that uses namespace prefixes in attribute values

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:svg="http://www.w3.org/2000/svg">
  
  <xsl:template match="svg:rect">
    <rectangle><xsl:apply-templates/></rectangle>
  </xsl:template>
  
</xsl:stylesheet>

You can add these extra namespace bindings through the addNamespaceDeclaration() method in the Element class. If necessary, you can remove one with the removeNamespaceDeclaration() method:

public Element addNamespaceDeclaration(Namespace namespace);
public Element removeNamespaceDeclaration(Namespace namespace);

For example, this code fragment creates the above xsl:stylesheet element and adds the SVG namespace declaration to it:

Element stylesheet = new Element(
    "stylesheet", "xsl", "http://www.w3.org/1999/XSL/Transform");
Namespace svg = Namespace.getNamespace("svg", 
                                   "http://www.w3.org/2000/svg");
stylesheet.addNamespaceDeclaration(svg);

If you encounter a namespace prefix in character data, and you need to know what prefix it maps to, you have to check the parent element’s namespace, all its attributes’ namespaces, and all its additional namespaces. If that doesn’t give you an answer, repeat the process for the next nearest ancestor, and continue until you either find the answer or run out of ancestors. This can be a little involved, but fortunately the Element class provides a simple method that tells you what URI any given prefix maps to within its scope:

public Namespace getNamespace(String prefix);

Since prefixes can be remapped to different URIs in descendant elements, always make sure to check the namespace in scope from the Attribute or Text object’s immediate parent.


Copyright 2001, 2002 Elliotte Rusty Haroldelharo@metalab.unc.eduLast Modified July 30, 2002
Up To Cafe con Leche