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, 08 Dec 2011 17:58: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 (9)</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" >&lt;/map&gt; <br>&lt;/bean&gt;
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">/&lt;beans&gt;</span>
<span class="diff-added-words"style="background-color: #dfd;">&lt;/beans&gt;</span>
<br></td></tr>
            <tr><td class="diff-unchanged" >{code} <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >Otherwise the best option is to extend
JAXBElementProvider and set marshaller properties there by using JAX-RS UriInfo to get to
the base request URI. <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >Starting from CXF 2.5.1 and 2.4.5
one can use an <span class="diff-changed-words"><span class="diff-added-chars"style="background-color:
#dfd;">[</span>XMLInstruction<span class="diff-added-chars"style="background-color:
#dfd;">|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/xml/XMLInstruction.java]</span></span>
annotation: <br></td></tr>
            <tr><td class="diff-unchanged" >{code:java} <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">@Path(&quot;books&quot;)</span>
<span class="diff-added-words"style="background-color: #dfd;">@Path(&quot;products&quot;)</span>
<br></td></tr>
            <tr><td class="diff-unchanged" >public class Resource { <br>
  @GET <br>   @Produces(&quot;application/xml&quot;) <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-changed-words">@XM<span
class="diff-deleted-chars"style="color:#999;background-color:#fdd;text-decoration:line-through;">l</span><span
class="diff-added-chars"style="background-color: #dfd;">L</span>Instruction(&quot;&lt;?xml-stylesheet</span>
type=&#39;text/xls&#39; href=&#39;/stylesheets/toHTML.xsl&#39;?&gt;&quot;)
<br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">
  public Book getBook() {} <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
  public Products getProducts() {} <br></td></tr>
            <tr><td class="diff-unchanged" >} <br>{code} <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >Lets assume one runs a &#39;myapp&#39;
web application with CXFServlet listening on &quot;/services/*&quot;, which can accept
requests such as &quot;GET <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">http://localhost/myapp/services/books&quot;.</span>
<span class="diff-added-words"style="background-color: #dfd;">http://localhost/myapp/services/products&quot;.</span>
<br></td></tr>
            <tr><td class="diff-unchanged" > <br>The above relative href
value will be converted to &quot;http://localhost/myapp/stylesheets/toHTML.xsl&quot;
thus making it easy to resources not &#39;covered&#39; by CXFServlet. What if you
prefer not to even list &#39;stylesheets&#39; in href=&#39;/stylesheets/toHTML.xsl&#39;
given that the name of the resource folder may change ? <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >&lt;property name=&quot;xmlResourceOffset&quot;
value=&quot;stylesheets&quot;/&gt; <br>&lt;/bean&gt; <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">/&lt;beans&gt;</span>
<span class="diff-added-words"style="background-color: #dfd;">&lt;/beans&gt;</span>
<br></td></tr>
            <tr><td class="diff-unchanged" >{code} <br> <br>and only
have href=&#39;toHTML.xsl&#39;. You can also use xmlResourceOffset to make sure the
absolute URI will be covered by CXFServlet if preferred. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
<br>h1. XSI SchemaLocation <br> <br>Some tools such as [Microsoft Excel|http://office.microsoft.com/en-us/excel-help/get-and-analyze-data-from-the-web-in-excel-HA001054848.aspx]
can do WEB queries and import the XML payload but this payload is expected to use an xsi:schemaLocation
attribute pointing to the XML schema document describing this XML, for example: <br>{code:xml}
<br>&lt;products xmlns=&quot;http://products&quot; <br>   xmlns:xsi=&quot;&quot;http://www.w3.org/2000/10/XMLSchema-instance&quot;&quot;
<br>   xsi:schemaLocation=&quot;http://localhost/myapp/schemas/product.xsd&quot;&gt;
<br>   &lt;product id=&quot;1&quot;/&gt; <br>&lt;/products&gt;
<br>{code} <br> <br>In order to get this attribute set with JAXB, one needs
to use a &quot;javax.xml.bind.Marshaller.JAXB_SCHEMA_LOCATION&quot; property which
can be set on JAXBElementProvider directly (similarly to the way XML Processing Instructions
set, see the previous section) or, starting with CXF 2.5.1, with the help of a new [XSISchemaLocation|http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/xml/XSISchemaLocation.java]
annotation: <br>{code:java} <br>@Path(&quot;products&quot;) <br>public
class Resource { <br>   @GET <br>   @Produces(&quot;application/xml&quot;)
<br>   @XSISchemaLocation(&quot;schemas/products.xsd&quot;) <br>   public
Products getProducts() {} <br>} <br>{code}  <br> <br>Please see the
previous section on how to affect the absolute URI to a given schema with the help of JAXBElementProvider.
<br>Note that XSISchemaLocation may have a noNamespace attribute set to &#39;true&#39;
if a given schema has no target namespace.    <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>
    <li><a href='#JAX-RSAdvancedXML-XMLProcessingInstructions'>XML Processing
Instructions</a></li>
    <li><a href='#JAX-RSAdvancedXML-XSISchemaLocation'>XSI SchemaLocation</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 which
is a JAX-RS MessageBodyReader, 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>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 relies
on JAXB to initiate the transformation process 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. This provider can be used on the server and client sides.</p>

<p>Please see this <a href="http://sberyozkin.blogspot.com/2009/05/mvc-xml-way-with-cxf-jax-rs.html"
class="external-link" rel="nofollow">blog entry</a> for an overview of how this provider
can help with separating the presentation logic from the main application code.</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. These parameters will be injected
with the names equal to corresponding @PathParam, QueryParam, etc values. Additionally, an
absolute, base and relative path URIs will be injected as "absolute.path", "base.path" and
"relative.path" parameters. Finally, custom inParameters and outParameters map properties
can also be injected and they will be added to all the XSLT template instances.</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>) 
   @Produces({<span class="code-quote">"application/xml"</span>, <span class="code-quote">"application/json"</span>,
<span class="code-quote">"text/html"</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>the XSLT templates will have parameters with name 'id' and 'name' injected. In this
particular case it may make sense to have two templates, one for processing a Book XML stream
(generated by JAXB) only, and the other one for adding HTML specific elements. The HTML-specific
template will most likely import the template dealing with the Book stream.</p>

<p>Here are some examples of how XSLTJaxbTemplate can be configured:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
   <span class="code-tag">&lt;map id=<span class="code-quote">"outTemplates"</span>&gt;</span>
      <span class="code-tag">&lt;entry key=<span class="code-quote">"application/xml"</span>
value=<span class="code-quote">"classpath:/WEB-INF/templates/book-xml.xsl"</span>/&gt;</span>
      <span class="code-tag">&lt;entry key=<span class="code-quote">"text/html"</span>
value=<span class="code-quote">"classpath:/WEB-INF/templates/book-html.xsl"</span>/&gt;</span>
      <span class="code-tag">&lt;entry key=<span class="code-quote">"application/json"</span>
value=<span class="code-quote">"classpath:/WEB-INF/templates/book-json.xsl"</span>/&gt;</span>
  <span class="code-tag">&lt;/map&gt;</span>
  
  <span class="code-tag">&lt;bean id=<span class="code-quote">"uriResolver"</span>
class=<span class="code-quote">"org.apache.cxf.systest.jaxrs.URIResolverImpl"</span>/&gt;</span>
  
  <span class="code-tag">&lt;bean id=<span class="code-quote">"xsltProvider"</span>
class=<span class="code-quote">"org.apache.cxf.jaxrs.provider.XSLTJaxbProvider"</span>&gt;</span>
   
      <span class="code-tag">&lt;property name=<span class="code-quote">"outMediaTemplates"</span>
ref=<span class="code-quote">"outTemplates"</span>/&gt;</span>
      <span class="code-tag">&lt;property name=<span class="code-quote">"resolver"</span>
ref=<span class="code-quote">"uriResolver"</span>/&gt;</span>
  <span class="code-tag">&lt;/bean&gt;</span>
</pre>
</div></div>

<p>In this example, the provider is injected with three out templates, one for modifying
the Book XML stream, the other one - for creating an HTML Book representation and the last
one for writing a JSON sequence which the existing JSON providers may not be able to generate.</p>

<p>A 'uriResolver' property can be used to point to a custom javax.xml.transform.URIResolver
implementation which can be used to resolve relative links in few XSLT instructions such as
'import'/etc. A 'systemId' property can also be set. Additionally, inProperties and outProperties
map properties can be injected and they will be used when XSLT template instances will be
created. </p>

<p>Here is a simpler configuration example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
   <span class="code-tag">&lt;bean id=<span class="code-quote">"xsltProvider"</span>
class=<span class="code-quote">"org.apache.cxf.jaxrs.provider.XSLTJaxbProvider"</span>&gt;</span>
   
      <span class="code-tag">&lt;property name=<span class="code-quote">"outTemplate"</span>
value=<span class="code-quote">"classpath:/WEB-INF/templates/book-xml.xsl"</span>/&gt;</span>
      <span class="code-tag">&lt;property name=<span class="code-quote">"inTemplate"</span>
class=<span class="code-quote">"classpath:/WEB-INF/templates/fromNewBookToOldBook.xsl"</span>/&gt;</span>
  <span class="code-tag">&lt;/bean&gt;</span>
</pre>
</div></div>

<p>The provider is configured with one output template and one input template which
will apply to all request and response data. </p>

<p>When XSLTJaxbProvider is used for processing the incoming requests, its main goal
is to ensure the incoming XML can be adapted as needed for the JAXB unmarshalling to succeed.
The in template can modify the incoming XML in a number of ways or it can extract the XML
fragment out of the bigger XML instance which is similar to what XMLSource and XPathProvider
can do as well. Please also check the new <a href="http://cxf.apache.org/docs/transformationfeature.html"
class="external-link" rel="nofollow">Transformation</a> feature.</p>

<p>Note that XSLTJaxbProvider may be used with other XML-aware providers on the same
endpoint if needed. In such cases one needs to restrict the set of classes it can handle,
for it to not interfere with the other XML provider. This can be done using inClassNames and
outClassNames list properties which enumerate supported class names. Alternatively, a new
"supportJaxbOnly" property can be set, in which case XSLTJaxbProvider will simply delegate
to JAXBElementProvider if no template is available for a given class.   </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>

<h1><a name="JAX-RSAdvancedXML-XMLProcessingInstructions"></a>XML Processing
Instructions</h1>

<p>One way to get outbound XML transformed to HTML or get an XHTML payload further decorated
with CSS tags is to <a href="http://www.w3.org/TR/xml-stylesheet/" class="external-link"
rel="nofollow">associate an xml-stylesheet processing instruction</a> with the XML
payload, for example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;?xml-stylesheet type=<span class="code-quote">"text/xls"</span>
href=<span class="code-quote">"http://localhost/myapp/stylesheets/toHTML.xsl"</span>?&gt;</span>
<span class="code-tag">&lt;products xmlns=<span class="code-quote">"http://products"</span>&gt;</span>
   <span class="code-tag">&lt;product id=<span class="code-quote">"1"</span>/&gt;</span>
<span class="code-tag">&lt;/products&gt;</span>
</pre>
</div></div> 

<p>The browser will fetch a stylesheet from the server and will transform this XML on
the client's machine.<br/>
This option is alternative to using XSLTJaxbProvider to create HTML on the server side. It
may become less easy to use if XSL stylesheets importing other documents or rely on additional
parameters to produce the HTML but it can definitely be used to offload the cost of doing
the transformations from the server in some cases.</p>

<p>You can also combine XSLTJaxbProvider to create complex HTML on the server and use
xml-stylesheet instructions to get the browser to download and cache the CSS stylesheets,
for example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;?xml-stylesheet type=<span class="code-quote">"text/css"</span>
href=<span class="code-quote">"http://localhost/myapp/stylesheets/HTMLDecorator.css"</span>?&gt;</span>
&lt;! 
   XSLTJaxbProvider transformed the XML products payload into well-formed XHTML.
   The browser will get HTMLDecorator.css at the next step and apply it to this HTML 
--&gt;
<span class="code-tag">&lt;html&gt;</span>
   <span class="code-tag">&lt;title&gt;</span>The products<span class="code-tag">&lt;/title&gt;</span>
   <span class="code-tag">&lt;table&gt;</span>
     <span class="code-tag"><span class="code-comment">&lt;!-- description
of products --&gt;</span></span>
   <span class="code-tag">&lt;/table&gt;</span>
<span class="code-tag">&lt;/html&gt;</span>
</pre>
</div></div> 

<p>When working with JAXB, the way to add such xml processing instructions is to set
a   <br/>
"com.sun.xml.bind.xmlHeaders" or "com.sun.xml.internal.bind.xmlHeaders" on the JAXB Marshaller.</p>

<p>Up until CXF 2.5.1 the way to do is to use a JAXBElementProvider 'marshallerProperties'
map property, for example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;beans <span class="code-keyword">xmlns:util</span>=<span
class="code-quote">"http://www.springframework.org/schema/util"</span>&gt;</span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"jaxbProvider"</span>
class=<span class="code-quote">"org.apache.cxf.jaxrs.provider.JAXBElementProvider"</span>&gt;</span>
<span class="code-tag">&lt;map&gt;</span>
&lt;entry key=<span class="code-quote">"com.sun.xml.bind.xmlHeaders"</span>

       value=<span class="code-quote">"<span class="code-tag">&lt;?xml-stylesheet
type='text/xls' href='/stylesheets/toHTML.xsl'?&gt;</span>"</span>/&gt;
<span class="code-tag">&lt;/map&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>
<span class="code-tag">&lt;/beans&gt;</span>
</pre>
</div></div>

<p>The problem here is how to correctly point to an absolute URI identifying the toHTML.xsl
resource.<br/>
Assuming that the browser will correctly resolve a relative URI such as "/stylesheets/toHTML.xsl",
then all is set.<br/>
Otherwise the best option is to extend JAXBElementProvider and set marshaller properties there
by using JAX-RS UriInfo to get to the base request URI.</p>

<p>Starting from CXF 2.5.1 and 2.4.5 one can use an <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/xml/XMLInstruction.java"
class="external-link" rel="nofollow">XMLInstruction</a> annotation:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
@Path(<span class="code-quote">"products"</span>)
<span class="code-keyword">public</span> class Resource {
   @GET
   @Produces(<span class="code-quote">"application/xml"</span>)
   @XMLInstruction(<span class="code-quote">"&lt;?xml-stylesheet type='text/xls'
href='/stylesheets/toHTML.xsl'?&gt;"</span>)
   <span class="code-keyword">public</span> Products getProducts() {}
}
</pre>
</div></div>

<p>Lets assume one runs a 'myapp' web application with CXFServlet listening on "/services/*",
which can accept requests such as "GET <a href="http://localhost/myapp/services/products"
class="external-link" rel="nofollow">http://localhost/myapp/services/products</a>".</p>

<p>The above relative href value will be converted to "http://localhost/myapp/stylesheets/toHTML.xsl"
thus making it easy to resources not 'covered' by CXFServlet. What if you prefer not to even
list 'stylesheets' in href='/stylesheets/toHTML.xsl' given that the name of the resource folder
may change ?<br/>
Use an 'xmlResourceOffset' property of JAXBElementProvider:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;bean id=<span class="code-quote">"jaxbProvider"</span>
class=<span class="code-quote">"org.apache.cxf.jaxrs.provider.JAXBElementProvider"</span>&gt;</span>
<span class="code-tag">&lt;property name=<span class="code-quote">"xmlResourceOffset"</span>
value=<span class="code-quote">"stylesheets"</span>/&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>
<span class="code-tag">&lt;/beans&gt;</span>
</pre>
</div></div>

<p>and only have href='toHTML.xsl'. You can also use xmlResourceOffset to make sure
the absolute URI will be covered by CXFServlet if preferred.</p>

<h1><a name="JAX-RSAdvancedXML-XSISchemaLocation"></a>XSI SchemaLocation</h1>

<p>Some tools such as <a href="http://office.microsoft.com/en-us/excel-help/get-and-analyze-data-from-the-web-in-excel-HA001054848.aspx"
class="external-link" rel="nofollow">Microsoft Excel</a> can do WEB queries and import
the XML payload but this payload is expected to use an xsi:schemaLocation attribute pointing
to the XML schema document describing this XML, for example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
&lt;products xmlns=<span class="code-quote">"http://products"</span>
   <span class="code-keyword">xmlns:xsi</span>=<span class="code-quote">""http://www.w3.org/2000/10/XMLSchema-instance"</span>"
   xsi:schemaLocation=<span class="code-quote">"http://localhost/myapp/schemas/product.xsd"</span>&gt;
   <span class="code-tag">&lt;product id=<span class="code-quote">"1"</span>/&gt;</span>
<span class="code-tag">&lt;/products&gt;</span>
</pre>
</div></div>

<p>In order to get this attribute set with JAXB, one needs to use a "javax.xml.bind.Marshaller.JAXB_SCHEMA_LOCATION"
property which can be set on JAXBElementProvider directly (similarly to the way XML Processing
Instructions set, see the previous section) or, starting with CXF 2.5.1, with the help of
a new <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/xml/XSISchemaLocation.java"
class="external-link" rel="nofollow">XSISchemaLocation</a> annotation:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
@Path(<span class="code-quote">"products"</span>)
<span class="code-keyword">public</span> class Resource {
   @GET
   @Produces(<span class="code-quote">"application/xml"</span>)
   @XSISchemaLocation(<span class="code-quote">"schemas/products.xsd"</span>)
   <span class="code-keyword">public</span> Products getProducts() {}
}
</pre>
</div></div> 

<p>Please see the previous section on how to affect the absolute URI to a given schema
with the help of JAXBElementProvider.<br/>
Note that XSISchemaLocation may have a noNamespace attribute set to 'true' if a given schema
has no target namespace.   </p>
    </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=10&originalVersion=9">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