|
Contents
|
 |
 |
 |
1. Basic Usage
1.1 Parsing XML
1.2 Querying with XPath 2.0
1.2.1 The copyOf and valueOf Functions
1.2.2 Variations on valueOf
1.2.3 Selecting the First Value
1.2.4 Selecting Required Values
1.2.5 Selecting the First Required Value
1.3 Working With Namespaces
1.4 Mapping XML to Java Objects
2. Optimizing Performance
2.1 XML Recycling
2.2 Querying with Precompiled XPaths
|
 |
 |
 |
1. Basic Usage
The XML Toolkit's API is designed to be as simple as possible. The
Xml class is the sole class required
to parse and query XML documents.
1.1 Parsing XML
There are three ways to parse XML with the XML Toolkit:
1) as a String
2) as an InputStream
3) as a Reader
All formats parse XML when constructing a new Xml instance.
The following code
samples below illustrate how create a new
Xml instance.
1. Create an instance from a String:
try {
Xml xml = new Xml("<Hello>world</Hello>");
}
catch(ParserException e) {

}
2. Create an instance from an InputStream:
try {
Xml xml = new Xml(new FileInputStream("test.xml"));
}
catch(FileNotFoundException e) {

}
catch(ParserException e) {

}
3. Create an instance from a Reader:
try {
Xml xml = new Xml(new FileReader("test.xml"));
}
catch(FileNotFoundException e) {

}
catch(ParserException e) {

}
1.2 Querying with XPath 2.0
1.2.1 The copyOf and valueOf Functions
The Xml class provides numerous
methods for querying parsed XML documents - all of which use
XPath 2.0 as the query language.
The methods fall into two general groups,
copyOf and
valueOf. These methods behave
exactly like their XSL counter parts,
copy-of and
value-of.
Xml's
copyOf returns an array of
Strings representing a copy of the sequence selected by the given
XPath expression. For
example:
try {

Xml xml = new Xml(
"<Colors>" +
"<Primary type='additive'>red</Primary>" +
"<Primary type='additive'>green</Primary>" +
"<Primary type='additive'>blue</Primary>" +
"<Primary type='subtractive'>yellow</Primary>" +
"<Primary type='subtractive'>cyan</Primary>" +
"<Primary type='subtractive'>magenta</Primary>" +
"</Colors>");
String s[] = xml.copyOf("/Colors/Primary[@type='additive']");
if(s != null) {
for(int i = 0; i < s.length; i++) {
System.out.println("s[" + i + "] = " + s[i]);
}
}
}
catch(XmlException e) {

}
Prints
s[0] = <Primary type='additive>red</Primary>
s[1] = <Primary type='additive>green</Primary>
s[2] = <Primary type='additive>blue</Primary>
Xml's
valueOf returns an array of
Strings representing the values of the sequence selected by the given
XPath expression
cast as xs:string.
For example:
try {

Xml xml = new Xml(
"<Colors>" +
"<Primary type='additive'>red</Primary>" +
"<Primary type='additive'>green</Primary>" +
"<Primary type='additive'>blue</Primary>" +
"<Primary type='subtractive'>yellow</Primary>" +
"<Primary type='subtractive'>cyan</Primary>" +
"<Primary type='subtractive'>magenta</Primary>" +
"</Colors>");
String s[] = xml.valueOf("/Colors/Primary[@type='additive']");
if(s != null) {
for(int i = 0; i < s.length; i++) {
System.out.println("s[" + i + "] = " + s[i]);
}
}
}
catch(XmlException e) {

}
Prints
s[0] = red
s[1] = green
s[2] = blue
1.2.2 Variations on valueOf
For programming convenience, Xml
provides numerous variations of the
valueOf method. These methods
are known as the "select" methods because they take the form selectXXX(...) where
XXX is either "Boolean", "Double", "Integer", or "String".
selectBoolean returns an array of
Booleans representing the
values of the sequence selected by the given
XPath expression
cast as xs:boolean.
For example:
try {

Xml xml = new Xml(
"<Truths>" +
"<True>true</True>" +
"<False>false</False>" +
"<True>1</True>" +
"<False>0</False>" +
"<True>What was the question?</True>" +
"<False> </False>" +
"</Truths>");
Boolean truths[] = xml.selectBoolean("/Truths/(True|False)/text()");
if(truths != null) {
for(int i = 0; i < truths.length; i++) {
System.out.println("truths[" + i + "] = " + truths[i]);
}
}
}
catch(XmlException e) {

}
Prints
truths[0] = true
truths[1] = false
truths[2] = true
truths[3] = false
truths[4] = true
truths[5] = false
selectDouble returns an array of
doubles representing the
values of the sequence selected by the given
XPath expression
cast as xs:double.
For example:
try {

Xml xml = new Xml(
"<Planets>" +
"<Planet name='Mercury' maxSurfaceTemp='800.33'/>" +
"<Planet name='Venus' maxSurfaceTemp='931.73'/>" +
"<Planet name='Earth' maxSurfaceTemp='136.13'/>" +
"<Planet name='Mars' maxSurfaceTemp='67.73'/>" +
"<Planet name='Jupiter' maxSurfaceTemp='-186.07'/>" +
"<Planet name='Saturn' maxSurfaceTemp='-202.27'/>" +
"<Planet name='Uranus' maxSurfaceTemp='-337.27'/>" +
"<Planet name='Neptune' maxSurfaceTemp='-364.27'/>" +
"<Planet name='Pluto' maxSurfaceTemp='-380.47'/>" +
"</Planets>");
double temps[] =
xml.selectDouble("max(//@maxSurfaceTemp)");
if(temps != null) {
System.out.println("The highest temperature is " + temps[0] + "F");
}
}
catch(XmlException e) {

}
Prints
The highest temperature is 931.73F
selectInteger returns an array of
ints representing the
values of the sequence selected by the given
XPath expression
cast as xs:integer.
For example:
try {

Xml xml = new Xml(
"<GreatLiteraryWorks>" +
"<Novel name='Moby-Dick' pageCount='654'/>" +
"<Novel name='The Republic' pageCount='320'/>" +
"<Novel name='Garfield At Large' pageCount='128'/>" +
"</GreatLiteraryWorks>");
int pageCount[] = xml.selectInteger("/GreatLiteraryWorks/Novel/@pageCount");
int totalPages = 0;
if(pageCount != null) {
for(int i = 0; i < pageCount.length; i++) {
totalPages += pageCount[i];
}
}
System.out.println("total pages = " + totalPages);
}
catch(XmlException e) {

}
Prints
total pages = 1102
selectString returns an array of
Strings representing the
values of the sequence selected by the given
XPath expression
cast as xs:string.
Note that this method behaves exactly as the method
valueOf described above.
1.2.3 Selecting the First Value
The copyOf,
valueOf, and select methods
all offer variations that return the first item in the result set in document order.
These methods are copyOfFirst,
valueOfFirst, and selectFirstXXX
where XXX is either "Boolean", "Double", "Integer", or "String" as described in section
1.2.2
above.
These methods are offered as another programming convenience as shown below:
try {

Xml xml = new Xml(
"<GreatLiteraryWorks>" +
"<Novel name='Moby-Dick' pageCount='654'/>" +
"<Novel name='The Republic' pageCount='320'/>" +
"<Novel name='Garfield At Large' pageCount='128'/>" +
"</GreatLiteraryWorks>");
String name = xml.valueOfFirst("/GreatLiteraryWorks/Novel/@name");
if(name != null) {
System.out.println("The first book is " + name);
}
}
catch(XmlException e) {

}
Prints
The first book is Moby-Dick
1.2.4 Selecting Required Values
When querying an XML document for values that may not be null, consider using
copyOfRequired,
valueOfRequired, or
selectRequiredXXX where XXX is either "Boolean", "Double", "Integer", or "String"
as described in section
1.2.2
above. These methods throw an
EmptyResultException if the given
query does not match any nodes. These methods are designed to reduce code complexity.
The more complex code here:
try {

Xml xml = new Xml(
"<Neptune>" +
"<Mass unit='kg'>1.0243E26</Mass>"+
"<MeanTemperature unit='k'>53</MeanTemperature>"+
"<WindSpeed unit='km/h'>2000</WindSpeed>"+
"</Neptune>");
String mass[] = xml.valueOf("/Neptune/Mass");
if(mass == null) {

}
String meanTemp[] = xml.valueOf("/Neptune/MeanTemperature");
if(meanTemp == null) {

}
String windSpeed[] = xml.valueOf("/Neptune/WindSpeed");
if(windSpeed == null) {

}
System.out.println(
"Neptune's mass is " + mass[0] +
"kg, mean temperature is " + meanTemp[0] +
"k, and its wind speeds can reach " + windSpeed[0] + "km/h");
}
catch(XmlException e) {

}
Can be simplified to:
try {

Xml xml = new Xml(
"<Neptune>" +
"<Mass unit='kg'>1.0243E26</Mass>"+
"<MeanTemperature unit='k'>53</MeanTemperature>"+
"<WindSpeed unit='km/h'>2000</WindSpeed>"+
"</Neptune>");
String mass[] = xml.valueOfRequired("/Neptune/Mass");
String meanTemp[] = xml.valueOfRequired("/Neptune/MeanTemperature");
String windSpeed[] = xml.valueOfRequired("/Neptune/WindSpeed");
System.out.println(
"Neptune's mass is " + mass[0] +
"kg, mean temperature is " + meanTemp[0] +
"k, and its wind speeds can reach " + windSpeed[0] + "km/h");
}
catch(EmptyResultException e) {

}
catch(XmlException e) {

}
1.2.5 Selecting the First Required Value
The additional functionality described in sections
1.2.3 and
1.2.4
are combined in
the set of methods
copyOfFirstRequired,
valueOfFirstRequired, and
selectFirstRequiredXXX where XXX is either "Boolean", "Double", "Integer", or "String"
as described in section
1.2.2
above. As the naming indicates, these methods return the first item in
the result set in document order, or throw an
EmptyResultException if the given
query does not match any nodes:
try {

Xml xml = new Xml(
"<Planets>" +
"<Planet name='Mercury' maxSurfaceTemp='800.33'/>" +
"<Planet name='Venus' maxSurfaceTemp='931.73'/>" +
"<Planet name='Earth' maxSurfaceTemp='136.13'/>" +
"<Planet name='Mars' maxSurfaceTemp='67.73'/>" +
"<Planet name='Jupiter' maxSurfaceTemp='-186.07'/>" +
"<Planet name='Saturn' maxSurfaceTemp='-202.27'/>" +
"<Planet name='Uranus' maxSurfaceTemp='-337.27'/>" +
"<Planet name='Neptune' maxSurfaceTemp='-364.27'/>" +
"<Planet name='Pluto' maxSurfaceTemp='-380.47'/>" +
"</Planets>");
System.out.println(
"The highest temperature is " +
xml.valueOfFirstRequired("max(//@maxSurfaceTemp)") +
"F");
}
catch(EmptyResultException e) {

}
catch(XmlException e) {

}
Prints
The highest temperature is 931.73F
1.3 Working with Namespaces
The XML Toolkit library is fully namespace aware. When the query to an XML document contains
a namespace, call setNamespace
before executing the query. For example:
try {

Xml xml = new Xml(
"<soap:Envelope xmlns:soap='http://www.w3.org/2003/05/soap-envelope'>" +
"<soap:Body>" +
"<soatoolkits:Message xmlns:soatoolkits='http://www.soatoolkits.com/contrived/example'>Hello World</soatoolkits:Message>" +
"</soap:Body>" +
"</soap:Envelope>");
xml.setNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
xml.setNamespace("x", "http://www.soatoolkits.com/contrived/example");
String message = xml.valueOfFirstRequired("/s:Envelope/s:Body/x:Message");
System.out.println("The secret message is " + message);
}
catch(EmptyResultException e) {

}
catch(XmlException e) {

}
Prints
The secret message is Hello World
It is important to note that the XML Toolkit defines three namespaces by default. The prefix
"fn" is bound to "http://www.w3.org/2005/xpath-functions", "xs" is bound to
"http://w3.org/2001/XMLSchema", and "xdt" is bound to
"http://www.w3.org/2005/xpath-datatypes"
(XQuery 1.0 and XPath 2.0 Functions and Operators).
It is not necessary to change these bindings,
however, it can by done by calling
xml.setNamespace("xs", "new URI here").
Please note that if the bindings are changed, any system functions and constructors must be
referenced by a user defined namespace mapping:
try {

Xml xml = new Xml("<x/>");
Boolean b = xml.selectFirstBoolean("xs:boolean('true')"); // ok
System.out.println(b);
xml.setNamespace("newNs", "http://www.w3.org/2001/XMLSchema");
b = xml.selectFirstBoolean("newNs:boolean('true')"); // still ok, user defined
System.out.println(b);
xml.setNamespace("xs", "not a good idea");
b = xml.selectFirstBoolean("xs:boolean('true')"); // oops, xs is no longer set to the correct uri
System.out.println(b);
}
catch(XmlException e) {

System.out.println(e.getMessage());
}
Prints
true
true
Error [err.XPATH0017]: line 1, column 11-> The function "[not a good idea]boolean" is undefined.
1.4 Mapping XML to Java Objects
The XML Toolkit maps XML to Java objects using the Xml::mapTo function. This function parses the Java object and invokes methods annotated as XmlMethods with values taken from the Xml instance itself. To see how this is done, let’s assume you want to map the following XML to the Java object shown below:
<User id="user123">
<Username>superuser</Username>
<Password>abc123</Password>
<NotificationEmail>superuser@soatoolkits.com</NotificationEmail>
</User>
public class User {
private String notificationEmail;
private String password;
private String userId;
private String username;
public void setNotificationEmail(String notificationEmail) {
this.notificationEmail = notificationEmail;
}
public void setPassword(String password) {
this.password = password;
}
public void setUserId(String userId) {
this.userId = userId;
}
public void setUserName(String username) {
this.username = username;
}
public String toString() {
return("User id=" + userId + " username=" + username
+ " password=" + password + " notification email="
+ notificationEmail);
}
}
To map the XML to the Java object:
1. Annotate the object as an XmlObject. This marks the class as one that has methods with parameter values taken from XML. The XmlObject takes an optional array of namespaces that will be used when specifying the XPaths to the XML (more on this in step 3). Since the user XML has a namespace defined above, the namespace must be set here.
import com.soatoolkits.xml.XmlObject;
@XmlObject(namespaces={"soatoolkits='http://soatoolkits.com/schemas/1.0/'"})
public class User {
private String notificationEmail;
private String password;
private String userId;
private String username;
public void setNotificationEmail(String notificationEmail) {
this.notificationEmail = notificationEmail;
}
public void setPassword(String password) {
this.password = password;
}
public void setUserId(String userId) {
this.userId = userId;
}
public void setUserName(String username) {
this.username = username;
}
public String toString() {
return("User id=" + userId + " username=" + username
+ " password=" + password + " notification email="
+ notificationEmail);
}
}
2. Annotate the methods as XmlMethods. This marks the methods as having parameter values taken from XML.
import com.soatoolkits.xml.XmlMethod;
import com.soatoolkits.xml.XmlObject;
@XmlObject(namespaces={"soatoolkits='http://soatoolkits.com/schemas/1.0/'"})
public class User {
private String notificationEmail;
private String password;
private String userId;
private String username;
@XmlMethod
public void setNotificationEmail(String notificationEmail) {
this.notificationEmail = notificationEmail;
}
@XmlMethod
public void setPassword(String password) {
this.password = password;
}
@XmlMethod
public void setUserId(String userId) {
this.userId = userId;
}
@XmlMethod
public void setUserName(String username) {
this.username = username;
}
public String toString() {
return("User id=" + userId + " username=" + username
+ " password=" + password + " notification email="
+ notificationEmail);
}
}
3. Annoate the parameters as XmlParams. This marks the parameters as having values taken from XML. This annotation specifies the XPath expression to evaluate against the XML.
import com.soatoolkits.xml.XmlMethod;
import com.soatoolkits.xml.XmlObject;
import com.soatoolkits.xml.XmlParam;
@XmlObject(namespaces={"soatoolkits='http://soatoolkits.com/schemas/1.0/'"})
public class User {
private String notificationEmail;
private String password;
private String userId;
private String username;
@XmlMethod
public void setNotificationEmail(@XmlParam(xpath="/User/NotificationEmail") String notificationEmail) {
this.notificationEmail = notificationEmail;
}
@XmlMethod
public void setPassword(@XmlParam(xpath="/User/Password") String password) {
this.password = password;
}
@XmlMethod
public void setUserId(@XmlParam(xpath="/User/@id") String userId) {
this.userId = userId;
}
@XmlMethod
public void setUserName(@XmlParam(xpath="/User/Username") String username) {
this.username = username;
}
public String toString() {
return("User id=" + userId + " username=" + username
+ " password=" + password + " notification email="
+ notificationEmail);
}
}
4. Invoke the Xml::mapTo function to map the XML to the annotated object.
private static final String USER_XML =
"<soatoolkits:User id=\"user123\" xmlns:soatoolkits=\"http://soatoolkits.com/schemas/1.0/\">\n" +
" <Username>testuser</Username>\n" +
" <Password>abc123</Password>\n" +
" <NotificationEmail>testuser@soatoolkits.com</NotificationEmail>\n" +
"</soatoolkits:User>";
public static void main(final String args[]) {
try {
Xml userXml = new Xml(USER_XML);
User user = userXml.mapTo(User.class);
System.out.println(user);
}
catch(XmlException e) {

e.printStackTrace();
}
}
The sourcecode for this sample can be found here.
2. Optimizing Performance
The XML Toolkit library is designed to be the fastest in existence. While the toolkit is
faster
than any other XML Library, developers can further
triple
its performance by using the recycling capabilities described in section
2.1. A further performance gain
can be realized if queries are be precompiled as described in section
2.2.
2.1 XML Recycling
With existing XML libraries, applications that frequently process XML documents
(including SOAP messages) can spend up to two-thirds of their time collecting garbage.
Xml's
recycle
method allows the XML engine to reuse objects created when parsing and querying XML documents.
It has been
shown
that high-throughput applications, such as those used for web services, can triple their
performance by calling this method. In addition, any application that processes XML will
realize a performance gain by calling
recycle:
Xml xml;
try {

xml = new Xml("<x/>");

...
}
catch(XmlException e) {

System.out.println(e.getMessage());
}
finally {

Xml.recycle(xml);
}
2.2 Querying with Precompiled XPaths
When an application uses XPath queries more than once, it is better to compile them
as constants and reuse them. Compilation is easy and can have a significant impact on
performance because the system does not need to parse the XPath every time.
Statically defined code:
private static XPath selectWorks;
static {
try {
selectWorks = new XPathParser().parse("/GreatLiteraryWorks/Novel/@name");
}
catch(XmlException e) {
}
}
Locally defined code:
Xml xml = null;
try {

xml = new Xml(
"<GreatLiteraryWorks>" +
"<Novel name='Moby-Dick' pageCount='654'/>" +
"<Novel name='The Republic' pageCount='320'/>" +
"<Novel name='Garfield At Large' pageCount='128'/>" +
"</GreatLiteraryWorks>");

String works[] = xml.valueOfRequired(selectWorks);
for(int i = 0; i < works.length; i++) {
System.out.println("works[" + i + "] = " + works[i]);
}
}
catch(EmptyResultException e) {

}
catch(XmlException e) {

System.out.println(e.getMessage());
}
finally {

Xml.recycle(xml);
}
Prints
works[0] = Moby-Dick
works[1] = The Republic
works[2] = Garfield At Large
|
|
|
|