The next obvious thing to do is to manipulate the XML. Let's add a site to the document.

Site newsite=sites.addNewSite();

Again, XMLbeans' scomp has generated methods to allow you to create an empty Site instance and add it to the Sites instance. All we need to do now is set the "src" attribute...

newsite.setSrc("http://www.example.net/specialpurpose.html");

You can also address sequences by index number, for example, if we wanted to insert a Comment at the start of the Site element's contents, then you can use

Comment newcomment=newsite.insertNewComment(0);

...which creates and inserts an empty Comment at the 0th position. All you need to do now is set its attribute and value.

newcomment.setEmail("fred@example.com");
newcomment.setStringValue("This was a reasonable addition");

After all this manipulation, we would reasonably want to save the document.

sd.save(new File("./newsites.xml"));

With the example source that comes with this article, you'll find all the above code in Example1.java. Before you can run it, you'll need to copy xbean.jar and jsr173_api.jar from the XmlBeans distribution, and the sites.jar file we generated earlier, into the lib directory. All you need to do then run "ant example1" and you should have a newsites.xml file in the directory.

If you look at the newsites.xml file, you'll see a demonstration of how XmlBeans preserves the XML Infoset. The file has been modified, but you'll note that comments in the sites.xml file have not been removed from the file but have been kept in place. This is incredibly useful attribute when you need to process XML files without losing any content of the files, for example when you are manipulating files which go through a version control system, and it is something that is not usually achievable with other XML mechanisms which decant XML content away from the DOM.

As mentioned earlier, all the generated classes are based on XmlObject. It's XmlObject which provides more navigation and validation options. XmlBeans operates by default without validation, but by calling the validate() method on an XmlBean, you can test the validity of the contents of any bean, including its children. The validation includes the XML Schema restrictions if they are defined. In our example sites.xsd file, we have a restriction on the Email type to ensure that only valid email addresses are entered. We can create an instance of the Email class using its factory, set it to a value and then validate it.

Email email=Email.Factory.newInstance();
email.setStringValue("email@example.com");
if(!email.validate()) { .... }

In the examples you'll find Validate.java which uses this to test an array of email addresses. This isn't the only validation mechanism in XmlBeans; you can have a validation error listener which can gather up all the validation errors in one location, or you can turn on validation on setting though this is really only used for debugging.

To navigate around a document, you can use XML Cursor to traverse from any XmlObject. Just request a cursor from an object, so if we navigate to the first site element in our example file:

String stnamespace="http://www.example.com/sites/SITE";
SitesDocument sd=SitesDocument.Factory.parse(new File("./sites.xml"));
Site site=sd.getSites().getSiteArray()[0];
XmlCursor cursor=site.newCursor();

This cursor now points to the site element and with this cursor we can navigate relative to this; for example, if we want the first element child then we can move the cursor like so

cursor.toChild(stnamespace,"rating");

XmlCursors are most useful when you want the ability to traverse the document at a token level, though you can get down to character by character level. If you want to get a feel for how a document looks to an XmlCursor, the next example (CursorWalk.java) parses a document and walks through the document, printing what it finds;

XmlObject sd=XmlObject.Factory.parse(new File("./sites.xml"));
XmlCursor sdcursor=sd.newCursor();
while(sdcursor.hasNextToken()) {
    sdcursor.toNextToken();
    if(sdcursor.isText()) {
      System.out.println(sdcursor.currentTokenType()
        + " " + sdcursor.getChars());
    } else {
      System.out.println(sdcursor.currentTokenType()
      + " " + sdcursor.getName());
    }
}

Notice here for the first time, we've not used the SiteDocument class we generated with scomp, and instead have used the XmlObject directly allowing us to parse any well formed XML file without a schema file.

The other way to navigate in XmlBeans goes to the opposite end of the abstraction spectrum; the ability to select and query using XPath/XQuery expressions, giving you the ability to query the document and select from the nodes within it. XmlObjects support selectPath() and execQuery() methods. The selectPath() is purely for selecting nodes in the document, whereas the execQuery() method lets you run XQuery and can create completely new XML as its return data.

To use this capability you will need to add two more libraries to your classpath, the Saxon library, but more specifically the 8.1.1 version, and the xbean_xpath.jar from the XmlBeans distribution. You'll find a link to the right version of Saxon at the XmlBeans site; take the saxon8.jar from the Saxon distribution and the xbean_xpath.jar file and copy them to the lib directory of the example source.

For a simple demonstration of using XPath queries, there's SimpleXPath.java; let's look at the relevant part of the source;

String namespace="declare namespace st='http://www.example.com/sites/SITE';";
XmlObject[] sitelist=sd.selectPath(namespace+"//st:site[st:rating/@rated=5]");
for(Site site:(Site[])sitelist) System.out.println(site.getSrc());

The first part is some XQuery to declare the namespace. This will be prepended to the query. Then we have the selectPath() call; selectPath() and execQuery() both return an array of XmlObjects. The actual XPath is

//st:site[st:rating/@rated=5]

which says select any site element which contains a rating element with a rated attribute of 5. We get back an array of XmlObjects, which we can cast to an array of Sites and print the results.

XPath and XQuery are a whole separate topic, but suffice to say they open the way for XmlBeans to perform some pretty nifty queries and document generation without descending the hierarchy of schema classes, but without losing the facilities offered by the XmlBeans generated classes.

XmlBeans is an excellent option if you are looking for a one stop shop for your XML mangling needs. If you are wondering "but won't I always need an XML Schema", although it can't fine tune a schema like hand coding can, XmlBean's inst2xsd tool can take a number of XML files and attempt to generate a .xsd file for you.

In the next article, we'll look at E4X, which is built on the foundation that is XmlBeans and use both together to access a Web based information service.

DJ Walker-Morgan is a consulting developer, specialising in Java and user-to-user messaging and conferencing.

Do you need help with XML? Gain advice from Builder AU forums

Related links

Comments

1

Rick Simms - 03/11/05

I always get an IO exception - even if I include my sdk bin and xml bin in a -cp parameter - in your example I used
scomp -out sites.jat sites.xsd
and
scomp -cp C:\j2sdk1.4.2_09\bin;D:\xmlbeans-2.0.0\bin -out sites.jat sites.xsd

I always get -

Time to build schema type system: 1.057 seconds
Time to generate code: 0.17 seconds
java.io.IOException: CreateProcess: D:\XMLExamples\xmlbnat\javac @D:\DOCUME~1\dz
8fnk\LOCALS~1\Temp\javac62757 error=2
null
java.io.IOException: CreateProcess: D:\XMLExamples\xmlbnat\javac @D:\DOCUME~1\dz
8fnk\LOCALS~1\Temp\javac62757 error=2
at java.lang.Win32Process.create(Native Method)
at java.lang.Win32Process.(Unknown Source)
at java.lang.Runtime.execInternal(Native Method)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at org.apache.xmlbeans.impl.tool.CodeGenUtil.externalCompile(CodeGenUtil
.java:229)
at org.apache.xmlbeans.impl.tool.SchemaCompiler.compile(SchemaCompiler.j
ava:1121)
at org.apache.xmlbeans.impl.tool.SchemaCompiler.main(SchemaCompiler.java
:367)
BUILD FAILED

-------------------------------------------------

I have been able to open the temp file - add spaces for example it has -dD:\DOCUME~1\dz8fnk\LOCALS~1\Temp\xbean5761.d\cl****es

I add spaces before or after switches file names etc and get it to at least compile with javac.

Any help would be appreciated - with this method I do not get the jar and when I try to create/run code it can not find the import for apache.

» Report offensive content

2

Gaurav Saxena - 24/07/06

I get the same exception while working with xmlbeans2.2.0
here is the exception trace

        at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at org.apache.xmlbeans.impl.tool.CodeGenUtil.externalCompile(CodeGenUtil
.java:231)
at org.apache.xmlbeans.impl.tool.SchemaCompiler.compile(SchemaCompiler.j
ava:1126)
at org.apache.xmlbeans.impl.tool.SchemaCompiler.main(SchemaCompiler.java
:368)
BUILD FAILED

» Report offensive content

3

Data Recovery Software - 13/11/08

IPod digital video recovery software supports all type of IPod include IPod first generation to next generation series etc.

» Report offensive content

4

Invoice program - 02/12/08

http://www.quick-billing.com
Providing billing software download to handle your revenues, income tax detail, inventory report.

» Report offensive content

Leave a comment

You must read and type the 6 chars within 0..9 and A..F

* indicates mandatory fields.

4

Invoice program - 12/02/08

http://www.quick-billing.com Providing billing software download to handle your revenues, income tax detail, inventory report. ... more

3

Data Recovery Software - 13/11/08

IPod digital video recovery software supports all type of IPod include IPod first generation to next generation series etc. ... more

2

Gaurav Saxena - 24/07/06

I get the same exception while working with xmlbeans2.2.0 here is the exception trace ... more

Log in


Sign up | Forgot your password?

What's on?