poi/xmlbeans/docs/guide/conHandlingAny.html
2018-02-16 22:41:27 +00:00

1 line
15 KiB
HTML

<!doctype HTML public "-//W3C//DTD HTML 4.0 Frameset//EN">
<!-- Copyright 2004 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. -->
<html>
<head>
<!-- InstanceBeginEditable name="doctitle" -->
<title>Handling xs:any with the XMLBeans API </title>
<!-- InstanceEndEditable -->
<!--(Meta)==========================================================-->
<meta http-equiv=Content-Type content="text/html; charset=$CHARSET;">
<!-- InstanceBeginEditable name="metatags" -->
<meta content="your name" name="author">
<meta content="A description of the topic contents." name="description">
<meta content="keywords to help in searches" name="keywords">
<meta content="10/25/02" name="date last modified">
<!-- InstanceEndEditable -->
<!--(Links)=========================================================-->
<!-- InstanceBeginEditable name="head" -->
<link href="../xmlbeans.css" rel="stylesheet" type="text/css">
<!-- InstanceEndEditable -->
<link href="../xmlbeans.css" rel="stylesheet" type="text/css">
<a href="../../../core/index.html" id="index"></a>
<script language="JavaScript" src="../../../core/topicInfo.js"></script>
<script language="JavaScript" src="../../../core/CookieClass.js"></script>
<script language="JavaScript" src="../../../core/displayContent.js"></script>
</head>
<!--(Body)==========================================================-->
<body>
<script language="JavaScript">
</script>
<!-- InstanceBeginEditable name="body" -->
<h1> Handling xs:any with the XMLBeans API </h1>
<p>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 <code>xs:any</code> particles, you may have noticed that XMLBeans doesn't generate accessors for these these particles. </p>
<p>For example, imagine the accessors generated by compiling the following schema snippet: </p>
<div id="topictext"><pre>&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://xmlbeans.apache.org/samples/any"
targetNamespace="http://xmlbeans.apache.org/samples/any" elementFormDefault="qualified">
&lt;xs:element name="root">
&lt;xs:complexType>
&lt;xs:sequence>
&lt;xs:element ref="stringelement"/>
&lt;xs:any processContents="lax"/>
&lt;xs:element name="arrayofany">
&lt;xs:complexType>
&lt;xs:sequence>
&lt;xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
&lt;/xs:sequence>
&lt;/xs:complexType>
&lt;/xs:element>
&lt;/xs:sequence>
&lt;/xs:complexType>
&lt;/xs:element>
&lt;xs:element name="stringelement" type="xs:string"/>
&lt;xs:complexType name="ListOfStrings">
&lt;xs:sequence>
&lt;xs:element ref="stringelement" minOccurs="0" maxOccurs="unbounded"/>
&lt;/xs:sequence>
&lt;xs:attribute name="id" type="xs:string"/>
&lt;/xs:complexType>
&lt;/xs:schema></pre>
<p>After compilation, you'd have the follow methods for <code>Root</code>, the type that gives you access to the <code>&lt;root&gt;</code> element:</p>
<p><code>addNewArrayofany()</code></p>
<p><code>getArrayofany()</code></p>
<p><code>getStringelement()</code></p>
<p><code>setArrayofany(Arrayofany)</code></p>
<p><code>setStringelement(String)</code></p>
<p><code>xgetStringelement()</code></p>
<p><code>xsetStringelement(XmlString)</code></p>
<p>What's missing? There's no <code>getAny</code> or <code>setAny</code>. How do you get or set the <code>&lt;root&gt;</code> 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:</p>
<ul>
<li><a href="#using_cursors">Using <code>XmlCursor</code> instances</a> to &quot;walk&quot; the XML, handling elements cursor-style.</li>
<li><a href="#using_xpath">Using the <code>selectPath</code> method</a> to retrieve the XML you want via XPath.</li>
<li><a href="#using_selectchildren">Using the <code>selectChildren</code> method</a> to retrieve child elements by name.</li>
<li> <a href="#using_dom">Using the DOM API</a> to &quot;walk&quot; the node tree, handling elements by name.</li>
</ul>
<h2><a name="using_cursors"></a>Using Cursors to Add XML </h2>
<p>As described in <a href="conNavigatingXMLwithCursors.html">Navigating XML with Cursors</a>, with an <code>XmlCursor</code> 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.</p>
<p>The following example illustrates how you might, in the course of building out the <code>&lt;root&gt;</code> document, create a second child element <code>&lt;anyfoo&gt;</code> where schema specifies <code>xs:any</code>. You add the element by creating it with a cursor, then (in lieu of a setter) using the <code>XmlCursor.copyXml</code> or <code>XmlCursor.moveXml</code> method to put the element where it needs to go.</p>
<pre>// Start by creating a &lt;root> element that will contain
// the children built by this code.
RootDocument rootDoc = RootDocument.Factory.newInstance();
RootDocument.Root root = rootDoc.addNewRoot();
// Add the first element, &lt;stringelement>.
root.setStringelement("some text");
// Create an XmlObject in which to build the second
// element in the sequence, &lt;anyfoo>. Here, the
// XmlObject instance is simply a kind of incubator
// for the XML. Later the XML will be moved into the
// document this code is building.
XmlObject anyFoo = XmlObject.Factory.newInstance();
// Add a cursor to do the work of building the XML.
XmlCursor anyFooCursor = anyFoo.newCursor();
anyFooCursor.toNextToken();
// Add the element in the schema's namespace, then add
// element content.
anyFooCursor.beginElement(new QName(m_namespaceUri, "anyfoo"));
anyFooCursor.insertChars("some text");
// Move the cursor back to the new element's top, where
// it can grab all of the element's XML.
anyFooCursor.toStartDoc();
anyFooCursor.toNextToken();
// Finally, move the XML into the &lt;root> document by moving it
// from a position at one cursor to a position at
// another.
XmlCursor rootCursor = root.newCursor();
rootCursor.toEndToken();
anyFooCursor.moveXml(rootCursor);</pre>
<p>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 <code>xs:any</code> space in an instance. The following code adds a <code>&lt;stringelement&gt; </code>element as a child of the <code>&lt;arrayofany&gt;</code> element, which schema defines as containing a sequence of <code>xs:any</code> particles. The <code>&lt;stringlement&gt;</code> element is simple, but it could just as easily be a complex schema type.</p>
<pre>// Create a simple &lt;stringelement>.
StringelementDocument stringElementDoc =
StringelementDocument.Factory.newInstance();
stringElementDoc.setStringelement("some text");
XmlCursor stringElementCursor = stringElementDoc.newCursor();
stringElementCursor.toFirstContentToken();
// Add a cursor to mark the position to which the new child
// XML will be moved.
XmlCursor arrayCursor = arrayOfAny.newCursor();
arrayCursor.toNextToken();
// Move the new &lt;stringelement> into place.
stringElementCursor.moveXml(arrayCursor);
stringElementCursor.dispose();</pre>
<h2><a name="using_xpath"></a>Using XPath and the selectPath Method to Find XML </h2>
<p>XPath is a convenient, direct way to get at specific chunks of XML. In the XMLBeans API, you execute XPath expressions with the <code>XmlObject.selectPath</code> or <code>XmlCursor.selectPath</code> methods. The example in Java below assumes the following instance conforming to the schema introduced at the beginning of this topic:</p>
<pre>&lt;root xmlns="http://xmlbeans.apache.org/samples/any">
&lt;stringelement>some text&lt;/stringelement>
&lt;anyfoo>some text&lt;/anyfoo>
&lt;arrayofany>
&lt;stringelement>some text&lt;/stringelement>
&lt;someelement>
&lt;stringlist id="001">
&lt;stringelement>string1&lt;/stringelement>
&lt;stringelement>string2&lt;/stringelement>
&lt;/stringlist>
&lt;/someelement>
&lt;/arrayofany>
&lt;/root></pre>
<p>The following code uses XPath to reach the <code>&lt;stringelement&gt;</code> element because there is no accessor available. It then shifts the XML around a little, moving <code>&lt;stringelement&gt;</code> up in the hierarchy to replace its parent, <code>&lt;someelement&gt;</code>. </p>
<pre>public boolean editExistingDocWithSelectPath(RootDocument rootDoc)
{
String namespaceUri = "http://xmlbeans.apache.org/samples/any";
// Put a cursor at the top of the &lt;arrayofany> element.
XmlCursor selectionCursor = rootDoc.getRoot().getArrayofany().newCursor();
// Use XPath and cursor movement to position the cursor at
// the &lt;stringlist> element.
String namespaceDecl = "declare namespace any='" + namespaceUri + "'; ";
selectionCursor.selectPath(namespaceDecl +
"$this//any:someelement/any:stringlist");
selectionCursor.toNextSelection();
// Create a new cursor at the same location and move it to
// &lt;stringelement&gt;'s &lt;someelement> parent.
XmlCursor editCursor = selectionCursor.newCursor();
editCursor.toParent();
// Move the &lt;stringelement> element to this position, displacing
// the &lt;someelement> downward. Remove the &lt;someelement> XML,
// effectively replacing &lt;someelement> with &lt;stringlist>.
selectionCursor.moveXml(editCursor);
editCursor.removeXml();
editCursor.dispose();
return rootDoc.validate();
}</pre>
<h2><a name="using_selectchildren"></a>Using the selectChildren Method to Find XML </h2>
<p>The <code>XmlObject.selectChildren</code> method you can retrieve an array of the child elements of a specified name. The method is overloaded to take <code>java.xml.namespace.QName</code> instances or strings as parameters. The following code (based on the instance used in the preceding example) simply finds the <code>&lt;anyfoo&gt;</code> element, an <code>xs:any</code>, and replaces it with an <code>&lt;anybar&gt;</code> element. </p>
<pre>public boolean editExistingDocWithSelectChildren(RootDocument rootDoc)
{
String namespaceUri = "http://xmlbeans.apache.org/samples/any";
RootDocument.Root root = rootDoc.getRoot();
// Select the &lt;anyfoo> children of &lt;root>.
XmlObject[] stringElements =
root.selectChildren(new QName(m_namespaceUri, "anyfoo"));
// If the element is there, replace it with another element.
if (stringElements.length > 0)
{
XmlCursor editCursor = stringElements[0].newCursor();
editCursor.removeXml();
editCursor.beginElement(new QName(namespaceUri, "anybar"));
editCursor.insertChars("some other text");
editCursor.dispose();
}
return rootDoc.validate();
}</pre>
<h2><a name="using_dom"></a>Using the DOM API to Find XML </h2>
<p>Through the <code>getDomNode</code> method (exposed by <code>XmlObject</code> and types generated from schema), you can get a live DOM node representing your XML. For example, calling <code>myElement.getDomNode()</code> will return a <code>org.w3c.dom.Node</code> instance representing the XML bound to <code>myElement</code>. If you're already familiar with DOM-style access to XML, this can be a familiar alternative for handling <code>xs:any</code> instances.</p>
<p> Using the instance introduced earlier in this topic, the following example adds a new <code>&lt;bar&gt;</code> element between the first and second children of the <code>&lt;arrayofany&gt;</code> element. The code also ensures that the first and second children are <code>&lt;stringelement&gt;</code> and <code>&lt;someelement&gt;</code>, respectively.</p>
<pre>public boolean editExistingDocWithDOM(RootDocument rootDoc)
{
RootDocument.Root root = rootDoc.getRoot();
// Get the DOM nodes for the &lt;arrayofany> element's children.
Node arrayOfAnyNode = root.getArrayofany().getDomNode();
// You don't have get* accessors for any of the &lt;arrayofany>
// element's children, so use DOM to identify the first
// and second elements while looping through the child list.
NodeList childList = arrayOfAnyNode.getChildNodes();
Element firstElementChild = null;
Element secondElementChild = null;
// Find the first child element and make sure it's
// &lt;stringelement>.
for (int i = 0; i < childList.getLength(); i++)
{
Node node = childList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
if (node.getLocalName().equals("stringelement"))
{
firstElementChild = (Element)node;
break;
}
}
}
if (firstElementChild == null) {return false;}
// Find the second child element and make sure it's
// &lt;someelement>.
Node node = firstElementChild.getNextSibling();
do
{
if (node.getNodeType() == Node.ELEMENT_NODE)
{
if (node.getLocalName().equals("someelement"))
{
secondElementChild = (Element)node;
break;
}
}
node = node.getNextSibling();
} while (node != null);
if (secondElementChild == null) {return false;}
// Create and insert a new &lt;bar> element.
Element fooElement =
secondElementChild.getOwnerDocument().createElementNS("http://openuri.org","bar");
Node valueNode =
fooElement.getOwnerDocument().createTextNode("some text");
fooElement.appendChild(valueNode);
arrayOfAnyNode.insertBefore(fooElement, secondElementChild);
return rootDoc.validate();
}</pre>
</div>
<div>
<h2>Related Topics</h2>
</div>
<p><a href="conGettingStartedwithXMLBeans.html">Getting Started with XMLBeans</a></p>
<!-- InstanceEndEditable -->
<script language="JavaScript">
</script>
</body>
</html>