You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

Unknown macro: {span}

JAX-RS : Advanced XML

XPath support

XPath is supported on the server and client sides with the help of XMLSource utility and XPathProvider provider classes. The difference between the two is that XPathProvider allows for specifying the XPath expressions in the external configuration.

Introduction

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.

Here are some examples:

InputStream is = new ByteArrayInputStream("<foo><bar attr=\"3\">barValue</bar></foo>".getBytes());
XMLSource xp = new XMLSource(is);
xp.setBuffering(true);
// query 1
String value = xp.getValue("/foo/bar/@attr");
assertEquals("3", value);

// query 2
Integer intValue = xp.getNode("/foo/bar/@attr", Integer.class);
assertEquals(3, intValue);

// query 3
Node node = xp.getNode("/foo/bar/@attr", Node.class);
assertEquals("3", node.getTextValue());

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

public class Bar {
    @XmlAttribute
    private String attr;  
    public String getAttribute() {
        return attr;
    } 
}

InputStream is = new ByteArrayInputStream("<foo><bar attr=\"3\">barValue</bar></foo>".getBytes());
XMLSource xp = new XMLSource(is);
xp.setBuffering(true);

// query 1
Bar bean = xp.getNode("/foo/bar", Bar.class);
assertEquals("3", bean.getAttribute());
 
// query 2
String value = xp.getValue("/foo/bar");
assertEquals("<bar attr=\"3\">barValue</bar>", value);

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.

Using XMLSource and XPathProvider in the application code

Please see this section on how http-centric WebClients can use XPath, and here is an example for the server side:

@Path("/root")
public class Root {
   @POST
   public void post(XMLSource source) {
       String value = source.getProperty("/books/book/@name");
   }    
}

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

XPathProvider provider = new XPathProvider();
provider.setGlobalExpression("/books/book[position() = 1]");
WebClient wc = WebClient.create("http://aggregated/data", Collections.singletonList(provider));
Book b = wc.get(Book.class);

XSLT support

TODO : Expand this section

XSLT is currently supported by XSLTJaxbProvider. 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.

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.

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.

For example, given this resource method definition :

@Path("/root")
public class Root {
   @GET
   @Path("{id}") 
   public Book get(@PathParam("id") String id, @QueryParam("name") String name) {
       return getBook(id, name);
   }    
}

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

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 :

WebClient client = WebClient.create("http://books");
client.path("/store/1").get();

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 :

WebClient client = WebClient.create("http://books");
client.path("/store/{id}", 1).get();
  • No labels