Java Articles

Advertisement

JAXP SAX Namespace Aware Parser Example

by Ram Satish

Share

In this article we will look into an example of a SAX parser that supports namespaces.

A brief about SAX – SAX (Simple API for XML) is an event-driven, serial-access mechanism that does element-by-element processing.

If you want to see an example of SAX Paser with namespace processing turned off, click here.

Let’s start with our example.

XML Sample with Namespaces

Advertisement

A namespace is the logical container in which an element is defined. Namespaces are defined so that elements with the same name in different namespaces can exist in the same document without becoming ambiguously-defined. A prefix is the short-hand key used to refer to a namespace.

In the below Employee XML we have a namespace to define employee attributes "http://www.javarticles.com/Emp and a second namespace to define the attributes that identify an employee "http://www.javarticles.com/Emp. Employee namespace is referred to by prefix e and the identity namespace is referred to by prefix i.

employee.xml:

<?xml version="1.0"?>
<e:employees xmlns:e="http://www.javarticles.com/Emp"
xmlns:i="http://www.javarticles.com/Identity">
<e:employee i:id="1">
<i:name>Joe</i:name>
<e:age>34</e:age>
</e:employee>
<e:employee i:id="2">
<i:name>Sam</i:name>
<e:age>24</e:age>
</e:employee>
<e:employee i:id="3">
<i:name>John</i:name>
<e:age>44</e:age>
</e:employee>
</e:employees>

Here is the employee bean.

Employee:

Advertisement
package com.javarticles.sax;

public class Employee {
private String name;
private Integer age;
private Integer id;

Employee(){}

Employee(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String toString() {
return "Employee(id:"+ id + ", name:" + name + ", age:" + age + ")";
}
}

Difference between qName and localName

A local name (localName) is the element’s name in the document without any namespace prefix. In the above example, employee, name and age are the local names. Local names can be ambiguous if you have multiple namespaces referenced in your document and one or more of those namespaces define elements with the same name.

A qualified Name (qName) consists of the prefix for the namespace, followed by a colon (:), followed by the element’s local name. In our example, e:employee, i:name and e:age are qualified names. These names are unambiguous, and can be processed by the parser and validated.

With namespace processing turned off, only the qName is being returned (with no prefix) and localName will be null.

A namespace aware parser will return qName containing the qualified name (with prefix) whereas the localName will be the element’s name without prefix.

Advertisement

Namespace aware SAX Parser Example

This example is of SAX parser with namespace support. Click here for an example with namespace processing turned off.
In order for the parser to support namespace, we just need to make sure that we can identify the element with its fully qualified name rather than depend on its local name.

  1. We override startPrefixMapping() to storing the prefix mapping. We need this to identity namespace prefix.
  2. In startElement() and endElement() callbacks, we need to know the employee element’s namespace prefix to compare with the qName passed in. We can find out the prefix from the mapped uri-prefix values.

EmpXmlHandler:

package com.javarticles.sax;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class EmpXmlHandler extends DefaultHandler {
private List<Employee> empList;
private StringBuilder currentValue;
private Stack<StringBuilder> values = new Stack<>();
private Stack<Employee> empStack = new Stack<>();
private Map<String, String> namespaces = new HashMap<>();

public void startDocument() throws SAXException {
empList = new ArrayList<Employee>();
System.out.println("Document parsing started");
}

public void endDocument() throws SAXException {
System.out.println("end document");
System.out.println("no. of employees: " + empList.size());
empList.forEach(System.out::print);
}

public void startPrefixMapping(String prefix, String uri)
throws SAXException {
System.out.println("startPrefixMapping, prefix: " + prefix + ", uri: " + uri);
namespaces.put(uri, prefix);
}

public void endPrefixMapping(String prefix) throws SAXException {
System.out.println("endPrefixMapping, prefix: " + prefix);
}

public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
values.push(currentValue);
currentValue = new StringBuilder();
String prefix = namespaces.get(uri);
System.out.println("uri: " + uri + ", local name: " + localName + ", qname: " + qName);
for (int i = 0; i < attributes.getLength(); i++) {
System.out.println("qname: " + attributes.getQName(i));
System.out.println("local: " + attributes.getLocalName(i));
System.out.println("value: " + attributes.getValue(i));
}
if (qName.equals(prefix + ":" + "employee")) {
Employee emp = new Employee();
for (int i = 0; i < attributes.getLength(); i++) {
String attrLocalName = attributes.getLocalName(i);
String attrQName = attributes.getQName(i);
if ("id".equals(attrLocalName)) {
emp.setId(Integer.parseInt(attributes.getValue(attrQName)));
empStack.push(emp);
}
}
}
}

public void endElement(String uri, String localName, String qName)
throws SAXException {
String prefix = namespaces.get(uri);
if (qName.equals(prefix + ":" + "employee")) {
empList.add(empStack.pop());
} else if (qName.equals(prefix + ":" + "name")) {
empStack.peek().setName(currentValue.toString());
} else if (qName.equals(prefix + ":" + "age")) {
empStack.peek().setAge(Integer.parseInt(currentValue.toString()));
}
}

public void characters(char ch[], int start, int length)
throws SAXException {
currentValue.append(ch, start, length);
}

}

We first create a SAXParserFactory instance.

Advertisement
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

Since the example is about supporting XML namespace, we set the namespaceAware property to true by calling

saxParserFactory.setNamespaceAware(true);

A SAXParser instance is obtained from the factory by invoking its newSAXParser() method.

SAXParser saxParser = saxParserFactory.newSAXParser();

Finally, we parse the XML.

Advertisement
saxParser.parse(SAXNamespaceAwareParserExample.class.getResourceAsStream("emp.xml"), new EmpXmlHandler());

SAXNamespaceAwareParserExample:

package com.javarticles.sax;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;


public class SAXNamespaceAwareParserExample {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setNamespaceAware(true);
SAXParser saxParser = saxParserFactory.newSAXParser();
saxParser.parse(SAXNamespaceAwareParserExample.class.getResourceAsStream("emp.xml"), new EmpXmlHandler());
}
}

Output:

Document parsing started
startPrefixMapping, prefix: e, uri: http://www.javarticles.com/Emp
startPrefixMapping, prefix: i, uri: http://www.javarticles.com/Identity
uri: http://www.javarticles.com/Emp, local name: employees, qname: e:employees
uri: http://www.javarticles.com/Emp, local name: employee, qname: e:employee
qname: i:id
local: id
value: 1
uri: http://www.javarticles.com/Identity, local name: name, qname: i:name
uri: http://www.javarticles.com/Emp, local name: age, qname: e:age
uri: http://www.javarticles.com/Emp, local name: employee, qname: e:employee
qname: i:id
local: id
value: 2
uri: http://www.javarticles.com/Identity, local name: name, qname: i:name
uri: http://www.javarticles.com/Emp, local name: age, qname: e:age
uri: http://www.javarticles.com/Emp, local name: employee, qname: e:employee
qname: i:id
local: id
value: 3
uri: http://www.javarticles.com/Identity, local name: name, qname: i:name
uri: http://www.javarticles.com/Emp, local name: age, qname: e:age
endPrefixMapping, prefix: e
endPrefixMapping, prefix: i
end document
no. of employees: 3
Employee(id:1, name:Joe, age:34)Employee(id:2, name:Sam, age:24)Employee(id:3, name:John, age:44)

Download the source code

This was an example of a SAX parser that supports namespaces.

You can download the source code here: saxNamespaceParserExample.zip

Advertisement

Share

Related

Advertisement

Latest

Advertisement