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:49:00 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" >&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-added-lines" style="background-color: #dfd;">XMLSource
also provides few methods for capturing attribute or text values representing the HTTP links:
<br> <br>{code:java} <br>String xmlString = &quot;&lt;customers
xmlns=\&quot;http://customers\&quot;&gt; <br>                    + &quot;&lt;customer
id=&quot;1&quot; homepage=\&quot;http://customers/1\&quot;/&gt;&quot;
<br>                    + &quot;&lt;/customers&gt;&quot;; <br>InputStream
is = new ByteArrayInputStream(xmlString.getBytes()); <br>XMLSource xp = new XMLSource(is);
<br> <br>URI homePage = xp.getLink(&quot;/ps1:customer[@id=&#39;1&#39;]/@homePage&quot;,
 <br>                           Collections.singletonMap(&quot;ps1&quot;, &quot;http://customers&quot;));
<br>WebClient client = WebClient.create(homePage); <br>// access the home page
<br>{code} <br> <br>In the above example the link to the home page of the
customer with id equal to &#39;1&#39; is retrieved and is used to create a WebClient
instance. <br> <br>In some cases, the links are relative. In such cases the base
URI is already either known to the application code or it may be specified as the value of
the [xml:base|http://www.w3.org/TR/xmlbase/] attribute. In the latter case XMLSource makes
it easy to get this base URI: <br> <br>{code:java} <br>String xmlString
= &quot;&lt;customers xmlns=\&quot;http://customers\&quot; xml:base=&quot;http://customers&quot;&gt;
<br>                    + &quot;&lt;customer id=&quot;1&quot;/&gt;&lt;customer
id=&quot;2&quot;/&gt;&quot; <br>                    + &quot;&lt;/customers&gt;&quot;;
<br>InputStream is = new ByteArrayInputStream(xmlString.getBytes()); <br>XMLSource
xp = new XMLSource(is); <br>xp.setBuffering(true); <br> <br>URI baseURI
= xp.getBaseURI(); <br>URI[] relativeURIs = xp.getLinks(&quot;/ps1:customer/@id&quot;,
Collections.singletonMap(&quot;ps1&quot;, &quot;http://customers&quot;));
<br> <br>WebClient client = WebClient.create(baseURI); <br>for (URI uri:
relativeURIs) { <br>  client.path(uri); <br>  // access the home page <br>
<br>  // and get back to the base URI <br>  client.back(true);  <br>} <br>{code}
<br> <br>In the last example, a customer id also represents a relative URI, with
xml:base attribute pointing to a base URI. <br>XMLSource is used to get all the relative
URIs, creates a WebClient with the base URI and then iterates using individual relative URIs.
 <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>

<p>XMLSource also provides few methods for capturing attribute or text values representing
the HTTP links:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-object">String</span> xmlString = <span class="code-quote">"&lt;customers
xmlns=\"</span>http:<span class="code-comment">//customers\"&gt;
</span>                    + <span class="code-quote">"&lt;customer id="</span>1<span
class="code-quote">" homepage=\"</span>http:<span class="code-comment">//customers/1\<span
class="code-quote">"/&gt;"</span>
</span>                    + <span class="code-quote">"&lt;/customers&gt;"</span>;
InputStream is = <span class="code-keyword">new</span> ByteArrayInputStream(xmlString.getBytes());
XMLSource xp = <span class="code-keyword">new</span> XMLSource(is);

URI homePage = xp.getLink(<span class="code-quote">"/ps1:customer[@id='1']/@homePage"</span>,

                           Collections.singletonMap(<span class="code-quote">"ps1"</span>,
<span class="code-quote">"http:<span class="code-comment">//customers"</span>));
</span>WebClient client = WebClient.create(homePage);
<span class="code-comment">// access the home page</span>
</pre>
</div></div>

<p>In the above example the link to the home page of the customer with id equal to '1'
is retrieved and is used to create a WebClient instance.</p>

<p>In some cases, the links are relative. In such cases the base URI is already either
known to the application code or it may be specified as the value of the <a href="http://www.w3.org/TR/xmlbase/"
class="external-link" rel="nofollow">xml:base</a> attribute. In the latter case XMLSource
makes it easy to get this base URI:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-object">String</span> xmlString = <span class="code-quote">"&lt;customers
xmlns=\"</span>http:<span class="code-comment">//customers\<span class="code-quote">"
xml:base="</span>http://customers"&gt;
</span>                    + <span class="code-quote">"&lt;customer id="</span>1<span
class="code-quote">"/&gt;&lt;customer id="</span>2<span class="code-quote">"/&gt;"</span>
                    + <span class="code-quote">"&lt;/customers&gt;"</span>;
InputStream is = <span class="code-keyword">new</span> ByteArrayInputStream(xmlString.getBytes());
XMLSource xp = <span class="code-keyword">new</span> XMLSource(is);
xp.setBuffering(<span class="code-keyword">true</span>);

URI baseURI = xp.getBaseURI();
URI[] relativeURIs = xp.getLinks(<span class="code-quote">"/ps1:customer/@id"</span>,
Collections.singletonMap(<span class="code-quote">"ps1"</span>, <span class="code-quote">"http:<span
class="code-comment">//customers"</span>));
</span>
WebClient client = WebClient.create(baseURI);
<span class="code-keyword">for</span> (URI uri: relativeURIs) {
  client.path(uri);
  <span class="code-comment">// access the home page
</span>  
  <span class="code-comment">// and get back to the base URI
</span>  client.back(<span class="code-keyword">true</span>); 
}
</pre>
</div></div>

<p>In the last example, a customer id also represents a relative URI, with xml:base
attribute pointing to a base URI.<br/>
XMLSource is used to get all the relative URIs, creates a WebClient with the base URI and
then iterates using individual relative URIs. </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=5&originalVersion=4">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