cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache CXF Documentation > JAX-RS Advanced XML
Date Thu, 31 Mar 2011 12:15:03 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/1/_/styles/combined.css?spaceKey=CXF20DOC&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Advanced+XML">JAX-RS
Advanced XML</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~sergey_beryozkin">Sergey
Beryozkin</a>
    </h4>
        <br/>
                         <h4>Changes (1)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >Note that JAXB is used internally
to convert the matched XML element into a class like Bar which does not have to have an @XmlRootElement
annotation. The 2nd query in the above example how a String representation of the matched
complex node can be captured. <br> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">XMLSource
also provides methods for capturing multiple nodes, example: <br> <br>{code:java}
<br>InputStream is = new ByteArrayInputStream(&quot;&lt;foo&gt;&lt;bar
attr=\&quot;3\&quot;&gt;value1&lt;/bar&gt;&lt;bar attr=\&quot;4\&quot;&gt;value2&lt;/bar&gt;&lt;/foo&gt;&quot;.getBytes());
<br>XMLSource xp = new XMLSource(is); <br>xp.setBuffering(true); <br>//
query 1 <br>String[] values = xp.getValue(&quot;/foo/bar/text()&quot;); <br>assertEquals(&quot;value1&quot;,
values[0]); <br>assertEquals(&quot;value2&quot;, values[1]); <br> <br>//
query 2 <br>Integer[] intValues = xp.getNodes(&quot;/foo/bar/@attr&quot;, Integer.class);
<br>assertEquals(3, intValues[0]); <br>assertEquals(4, intValues[1]); <br>
<br>// query 3 <br>Bar[] nodes = xp.getNodes(&quot;/foo/bar&quot;, Bar.class);
<br>{code} <br> <br>All the above examples have been simplified in that
no namespaces have been used. Most real XML instances will have plenty of them and XMLSource
has methods accepting optional maps containing prefixes as keys and namespaces as values:
<br> <br>{code:java} <br>InputStream is = new ByteArrayInputStream(&quot;&lt;foo
xmlns=\&quot;http://foo\&quot;&gt;&lt;ns1:bar xmlns:ns1=\&quot;http://bar\&quot;
attr=\&quot;3\&quot;&gt;barValue&lt;/bar&gt;&lt;/foo&gt;&quot;.getBytes());
<br>XMLSource xp = new XMLSource(is); <br>xp.setBuffering(true); <br> <br>Foo
foo = xp.getNode(&quot;/ps1:foo&quot;, Collections.singletonMap(&quot;ps1&quot;,
&quot;http://foo&quot;), Foo.class); <br>assertNotNull(foo); <br> <br>Bar
foo = xp.getNode(&quot;/ps2:bar&quot;, Collections.singletonMap(&quot;ps2&quot;,
&quot;http://bar&quot;), Bar.class); <br>assertNotNull(foo); <br>{code}
<br> <br>In the above example, a default &quot;http://foo&quot; namespace
qualifies the root &quot;foo&quot; element while its &#39;bar&#39; children
are qualified with the   <br>&quot;http://bar&quot; namespace. Note that XMLSource
is configured to make sure these namespaces are checked but the prefixes used do not have
to match the ones in the actual XML instance which may not even have them at all, for example,
when default namespaces are used. <br> <br></td></tr>
            <tr><td class="diff-unchanged" >h2. Using XMLSource and XPathProvider
in the application code <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <p><span style="font-size:2em;font-weight:bold"> JAX-RS : Advanced XML
</span></p>

<div>
<ul>
    <li><a href='#JAX-RSAdvancedXML-XPathsupport'>XPath support</a></li>
<ul>
    <li><a href='#JAX-RSAdvancedXML-Introduction'>Introduction</a></li>
    <li><a href='#JAX-RSAdvancedXML-UsingXMLSourceandXPathProviderintheapplicationcode'>Using
XMLSource and XPathProvider in the application code</a></li>
</ul>
    <li><a href='#JAX-RSAdvancedXML-XSLTsupport'>XSLT support</a></li>
</ul></div>

<h1><a name="JAX-RSAdvancedXML-XPathsupport"></a>XPath support</h1>

<p>XPath is supported on the server and client sides with the help of <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/xml/XMLSource.java"
class="external-link" rel="nofollow">XMLSource</a> utility and <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/XPathProvider.java"
class="external-link" rel="nofollow">XPathProvider</a> provider classes. The difference
between the two is that XPathProvider allows for specifying the XPath expressions in the external
configuration.</p>

<h2><a name="JAX-RSAdvancedXML-Introduction"></a>Introduction</h2>

<p>XMLSource allows for converting matched XML DOM element, attribute and text nodes
into typed complex and primitive classes. DOM Node and Element classes as well as JAXP Source
and DOMSource can also be used. A single XMLSource instance can be used to query the same
input source multiple times if the buffering mode is enabled.</p>

<p>Here are some examples:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
InputStream is = <span class="code-keyword">new</span> ByteArrayInputStream(<span
class="code-quote">"&lt;foo&gt;&lt;bar attr=\"</span>3\<span class="code-quote">"&gt;barValue&lt;/bar&gt;&lt;/foo&gt;"</span>.getBytes());
XMLSource xp = <span class="code-keyword">new</span> XMLSource(is);
xp.setBuffering(<span class="code-keyword">true</span>);
<span class="code-comment">// query 1
</span><span class="code-object">String</span> value = xp.getValue(<span
class="code-quote">"/foo/bar/@attr"</span>);
assertEquals(<span class="code-quote">"3"</span>, value);

<span class="code-comment">// query 2
</span><span class="code-object">Integer</span> intValue = xp.getNode(<span
class="code-quote">"/foo/bar/@attr"</span>, <span class="code-object">Integer</span>.class);
assertEquals(3, intValue);

<span class="code-comment">// query 3
</span>Node node = xp.getNode(<span class="code-quote">"/foo/bar/@attr"</span>,
Node.class);
assertEquals(<span class="code-quote">"3"</span>, node.getTextValue());
</pre>
</div></div>

<p>In the above example a primitive attribute node is accessed in a number of ways,
using the same XMLSource instance. <br/>
Matched XML complex (element) nodes can be converted in a similar way:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class Bar {
    @XmlAttribute
    <span class="code-keyword">private</span> <span class="code-object">String</span>
attr;  
    <span class="code-keyword">public</span> <span class="code-object">String</span>
getAttribute() {
        <span class="code-keyword">return</span> attr;
    } 
}

InputStream is = <span class="code-keyword">new</span> ByteArrayInputStream(<span
class="code-quote">"&lt;foo&gt;&lt;bar attr=\"</span>3\<span class="code-quote">"&gt;barValue&lt;/bar&gt;&lt;/foo&gt;"</span>.getBytes());
XMLSource xp = <span class="code-keyword">new</span> XMLSource(is);
xp.setBuffering(<span class="code-keyword">true</span>);

<span class="code-comment">// query 1
</span>Bar bean = xp.getNode(<span class="code-quote">"/foo/bar"</span>,
Bar.class);
assertEquals(<span class="code-quote">"3"</span>, bean.getAttribute());
 
<span class="code-comment">// query 2
</span><span class="code-object">String</span> value = xp.getValue(<span
class="code-quote">"/foo/bar"</span>);
assertEquals(<span class="code-quote">"&lt;bar attr=\"</span>3\<span class="code-quote">"&gt;barValue&lt;/bar&gt;"</span>,
value);
</pre>
</div></div>

<p>Note that JAXB is used internally to convert the matched XML element into a class
like Bar which does not have to have an @XmlRootElement annotation. The 2nd query in the above
example how a String representation of the matched complex node can be captured.</p>

<p>XMLSource also provides methods for capturing multiple nodes, example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
InputStream is = <span class="code-keyword">new</span> ByteArrayInputStream(<span
class="code-quote">"&lt;foo&gt;&lt;bar attr=\"</span>3\<span class="code-quote">"&gt;value1&lt;/bar&gt;&lt;bar
attr=\"</span>4\<span class="code-quote">"&gt;value2&lt;/bar&gt;&lt;/foo&gt;"</span>.getBytes());
XMLSource xp = <span class="code-keyword">new</span> XMLSource(is);
xp.setBuffering(<span class="code-keyword">true</span>);
<span class="code-comment">// query 1
</span><span class="code-object">String</span>[] values = xp.getValue(<span
class="code-quote">"/foo/bar/text()"</span>);
assertEquals(<span class="code-quote">"value1"</span>, values[0]);
assertEquals(<span class="code-quote">"value2"</span>, values[1]);

<span class="code-comment">// query 2
</span><span class="code-object">Integer</span>[] intValues = xp.getNodes(<span
class="code-quote">"/foo/bar/@attr"</span>, <span class="code-object">Integer</span>.class);
assertEquals(3, intValues[0]);
assertEquals(4, intValues[1]);

<span class="code-comment">// query 3
</span>Bar[] nodes = xp.getNodes(<span class="code-quote">"/foo/bar"</span>,
Bar.class);
</pre>
</div></div>

<p>All the above examples have been simplified in that no namespaces have been used.
Most real XML instances will have plenty of them and XMLSource has methods accepting optional
maps containing prefixes as keys and namespaces as values:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
InputStream is = <span class="code-keyword">new</span> ByteArrayInputStream(<span
class="code-quote">"&lt;foo xmlns=\"</span>http:<span class="code-comment">//foo\<span
class="code-quote">"&gt;&lt;ns1:bar xmlns:ns1=\"</span>http://bar\<span
class="code-quote">" attr=\"</span>3\<span class="code-quote">"&gt;barValue&lt;/bar&gt;&lt;/foo&gt;"</span>.getBytes());
</span>XMLSource xp = <span class="code-keyword">new</span> XMLSource(is);
xp.setBuffering(<span class="code-keyword">true</span>);

Foo foo = xp.getNode(<span class="code-quote">"/ps1:foo"</span>, Collections.singletonMap(<span
class="code-quote">"ps1"</span>, <span class="code-quote">"http:<span class="code-comment">//foo"</span>),
Foo.class);
</span>assertNotNull(foo);

Bar foo = xp.getNode(<span class="code-quote">"/ps2:bar"</span>, Collections.singletonMap(<span
class="code-quote">"ps2"</span>, <span class="code-quote">"http:<span class="code-comment">//bar"</span>),
Bar.class);
</span>assertNotNull(foo);
</pre>
</div></div>

<p>In the above example, a default "http://foo" namespace qualifies the root "foo" element
while its 'bar' children are qualified with the  <br/>
"http://bar" namespace. Note that XMLSource is configured to make sure these namespaces are
checked but the prefixes used do not have to match the ones in the actual XML instance which
may not even have them at all, for example, when default namespaces are used.</p>

<h2><a name="JAX-RSAdvancedXML-UsingXMLSourceandXPathProviderintheapplicationcode"></a>Using
XMLSource and XPathProvider in the application code</h2>

<p>Please see <a href="http://cxf.apache.org/docs/jax-rs-client-api.html#JAX-RSClientAPI-XMLcentricclients"
class="external-link" rel="nofollow">this section</a> on how http-centric WebClients
can use XPath, and here is an example for the server side:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
@Path(<span class="code-quote">"/root"</span>)
<span class="code-keyword">public</span> class Root {
   @POST
   <span class="code-keyword">public</span> void post(XMLSource source) {
       <span class="code-object">String</span> value = source.getProperty(<span
class="code-quote">"/books/book/@name"</span>);
   }    
}
</pre>
</div></div> 

<p>Users have an option to hide XPath expressions, by registering an XPathProvider,
either on the client or server sides. For example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
XPathProvider provider = <span class="code-keyword">new</span> XPathProvider();
provider.setGlobalExpression(<span class="code-quote">"/books/book[position() = 1]"</span>);
WebClient wc = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//aggregated/data"</span>,
Collections.singletonList(provider));
</span>Book b = wc.get(Book.class);
</pre>
</div></div>

<h1><a name="JAX-RSAdvancedXML-XSLTsupport"></a>XSLT support</h1>

<p>TODO : Expand this section</p>

<p>XSLT is currently supported by <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/XSLTJaxbProvider.java"
class="external-link" rel="nofollow">XSLTJaxbProvider</a>. This provider works in
tandem with JAXB and can be used to produce pretty much any format, including non-XML ones.
Likewise, it can be used to extract XML data out of incoming XML fragments, either on the
client or server sides.</p>

<p>XSLTJaxbProvider can be configured to handle input or output data, scoped by media
types if needed. For example, one may configure it such that one template handles "application/xml"
formats only while the other one handles "application/json" writes only.</p>

<p>XSLTJaxbProvider uses an injected JAX-RS UriInfo to inject all the usual JAX-RS information
like template or query parameters into a given XSLT template.</p>

<p>For example, given this resource method definition :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
@Path(<span class="code-quote">"/root"</span>)
<span class="code-keyword">public</span> class Root {
   @GET
   @Path(<span class="code-quote">"{id}"</span>) 
   <span class="code-keyword">public</span> Book get(@PathParam(<span class="code-quote">"id"</span>)
<span class="code-object">String</span> id, @QueryParam(<span class="code-quote">"name"</span>)
<span class="code-object">String</span> name) {
       <span class="code-keyword">return</span> getBook(id, name);
   }    
}
</pre>
</div></div>

<p>an XSLT template processing the JAXB-driven serialization of a Book instance will
have parameters with name 'id' and 'name' injected.</p>

<p>Note that when XSLTJaxbProvider is used on the client side, it may not always be
possible for template parameters be injected in cases when http-centric clients are used (as
opposed to proxies). For example :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
WebClient client = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//books"</span>);
</span>client.path(<span class="code-quote">"/store/1"</span>).get();
</pre>
</div></div>

<p>it is not possible to deduce that '1' represents a template parameter in the "/store/1"
expression. However, one can use the following code instead if '1' needs to be available to
XSLT templates :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
WebClient client = WebClient.create(<span class="code-quote">"http:<span class="code-comment">//books"</span>);
</span>client.path(<span class="code-quote">"/store/{id}"</span>, 1).get();
</pre>
</div></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Advanced+XML">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=24190965&revisedVersion=4&originalVersion=3">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Advanced+XML?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message