Handling xs:any with the XMLBeans API
Compiling the schema
Compiling schema for use with XMLBeans generates a kind of custom API specific to your schema. This API includes types with accessors designed to get and set parts of the XML defined by the schema. But if you've compiled schema that includes xs:any particles, you may have noticed that XMLBeans doesn't generate accessors for these these particles.
For example, imagine the accessors generated by compiling the following schema snippet:
After compilation, you'd have the follow methods for Root, the type that gives you access to the <root> element:
addNewArrayofany()
getArrayofany()
getStringelement()
setArrayofany(Arrayofany)
setStringelement(String)
xgetStringelement()
xsetStringelement(XmlString)
What's missing? There's no getAny or setAny. How do you get or set the <root> element's second child? As it turns out, you do this by leaving behind (at least for a moment) JavaBeans-style accessors, and picking up any of a number of tools the API provides. These tools include:
- Using XmlCursor instances to "walk" the XML, handling elements cursor-style.
- Using the selectPath method to retrieve the XML you want via XPath.
- Using the selectChildren method to retrieve child elements by name.
- Using the DOM API to "walk" the node tree, handling elements by name.
Using Cursors to Add XML
As described in Navigating XML with Cursors, with an XmlCursor instance you can traverse your XML instance's full infoset. A cursor views XML as tokens, and you move a cursor from one token to another as if they were cars in a train.
The following example illustrates how you might, in the course of building out the <root> document, create a second child element <anyfoo> where schema specifies xs:any. You add the element by creating it with a cursor, then (in lieu of a setter) using the XmlCursor.copyXml or XmlCursor.moveXml method to put the element where it needs to go.
You might find that this build-and-move-cursor-to-cursor pattern is common when you're creating or moving XML when accessors aren't available. For example, you could do the same sort of thing when your schema defines a type that you want to place into an xs:any space in an instance. The following code adds a <stringelement>element as a child of the <arrayofany> element, which schema defines as containing a sequence of xs:any particles. The <stringlement> element is simple, but it could just as easily be a complex schema type.
Using XPath and the selectPath Method to Find XML
XPath is a convenient, direct way to get at specific chunks of XML. In the XMLBeans API, you execute XPath expressions with the XmlObject.selectPath or XmlCursor.selectPath methods. The example in Java below assumes the following instance conforming to the schema introduced at the beginning of this topic:
The following code uses XPath to reach the <stringelement> element because there is no accessor available. It then shifts the XML around a little, moving <stringelement> up in the hierarchy to replace its parent, <someelement>.
Using the selectChildren Method to Find XML
The XmlObject.selectChildren method you can retrieve an array of the child elements of a specified name. The method is overloaded to take java.xml.namespace.QName instances or strings as parameters. The following code (based on the instance used in the preceding example) simply finds the <anyfoo> element, an xs:any, and replaces it with an <anybar> element.
Using the DOM API to Find XML
Through the getDomNode method (exposed by XmlObject and types generated from schema), you can get a live DOM node representing your XML. For example, calling myElement.getDomNode() will return a org.w3c.dom.Node instance representing the XML bound to myElement. If you're already familiar with DOM-style access to XML, this can be a familiar alternative for handling xs:any instances.
Using the instance introduced earlier in this topic, the following example adds a new <bar> element between the first and second children of the <arrayofany> element. The code also ensures that the first and second children are <stringelement> and <someelement>, respectively.