Table of Contents
A resources script provides a catalog of named pages that encapsulate a service of some kind. A page is associated with actions - transforming XML to HTML through the application of a stylesheet, serializing XML to PDF, transforming a flat file to XML, updating records in a database, and so forth.
Basically, three kinds:
The example below shows two named resources (the px:content elements), and two properties (the px:cachingOptions elements.)
<px:resources xmlns:px="http://www.presentingxml.com/PresentingXML"> <px:cachingOptions caching="no"/> <px:systemContent name="books" href="documents/books.xml"/> <px:systemContent name="authors" href="documents/books.xml"> <px:cachingOptions caching="yes"/> </px:systemContent> </px:resources>
In this example, the default rule is set so that there is no caching of content. In particular, the books document is not cached. The authors document, on the other hand, is cached.
Let's use the following resources script as an example.
<px:resources xmlns:px="http://www.presentingxml.com/PresentingXML"> <px:page name="pipeline"> <px:show> <px:transform> <px:systemContent href="documents/mixed-up.xml"/> <px:saxFilter className="PreFilter"/> <px:style href="styles/filter.xsl"/> <px:saxFilter className="PostFilter"/> </px:transform> </px:show> </px:page> </px:resources>
This script contains one top level named resource - a page - and four annonymous resources in the content of the page - an XML file, pre and post SAX filters, and an XSLT stylesheet. Note that the top level page resource has the "name" attribute. This is the local name of the page resource. The full name of the resource consists of a namespace and a local name. In the example above, the namespace is empty.
Annonymous resources cannot be reused in the definition of other pages. Therefore it is useful to make them top level named resources and refer to them by reference. We can do this as follows.
<px:resources xmlns:px="http://www.presentingxml.com/PresentingXML"> <px:systemContent name="mixed-up" href="documents/mixed-up.xml"/> <px:page name="pipeline"> <px:show> <px:transform> <px:content ref="mixed-up"/> <px:filter ref="pre-filter"/> <px:style ref="xsl-filter"/> <px:filter ref="post-filter"/> </px:transform> </px:show> </px:page> <px:saxFilter name="pre-filter" className="PreFilter"/> <px:style name="xsl-filter" href="styles/filter.xsl"/> <px:saxFilter name="post-filter" className="PostFilter"/> </px:resources>
Named resources, in addition to being referenced with an actual name, can be referenced through parameter values. This is illustrated in the example below.
<px:resources xmlns:px="http://www.presentingxml.com/PresentingXML"> <px:systemContent name="mixed-up" href="documents/mixed-up.xml"/> <px:parameter name="my-param">mixed-up</parameter> <px:page name="still-mixed-up"> <px:show> <px:transform> <px:content ref="$my-param"/> </px:transform> </px:show> </px:page> </px:resources>
If two resources are of different types, e.g. content and filter, they can have the same name and there is no conflict. If two resources have the same type, however, such as an XSLT stylesheet and a SAX filter, there is a conflict. We can, however, have two resources of the same type with the same local names if they belong to different namespaces.
The example below shows how to set the namespace for a resource and how to refer to one by its fully qualified name. The namespace is specified by a "ns" attribute. Note that if a resource element does not have the "ns" attribute, its namespace defaults to the namespace of its nearest ancestor that does have a "ns" attribute. Also note that the order in which the top level instructions appear in the document does not matter. The px:systemContent element, for example, may appear below or above the px:page element that refers to it.
<px:resources xmlns:px="http://www.presentingxml.com/PresentingXML" xmlns:myapp="http://www.presentingxml.com/myapp" xmlns:mystyle="http://www.presentingxml.com/myapp/style" ns="http://www.presentingxml.com/myapp"> <px:systemContent name="mixed-up" href="documents/mixed-up.xml"/> <px:page name="pipeline"> <px:show> <px:transform> <px:content ref="myapp:mixed-up"/> <px:filter ref="myapp:pre-filter"/> <px:style ref="mystyle:xsl-filter"/> <px:filter ref="myapp:post-filter"/> </px:transform> </px:show> </px:page> <px:saxFilter name="pre-filter" className="PreFilter"/> <px:style ns="http://www.presentingxml.com/myapp/style" name="xsl-filter" href="styles/filter.xsl"/> <px:saxFilter name="post-filter" className="PostFilter"/> </px:resources>
As a resources script becomes bigger, it becomes desirable to reorganize it, perhaps splitting off the content and style elements into separate files, in separate directories. For example, we may wish to have the directory tree:
<px:resources xmlns:px="http://www.presentingxml.com/PresentingXML" xmlns:myapp="http://www.presentingxml.com/myapp" xmlns:mystyle="http://www.presentingxml.com/myapp/style" ns="http://www.presentingxml.com/myapp"> <px:include href="../documents/documents.xml"/> <px:include href="../styles/styles.xml"/> <px:page name="pipeline"> <px:show> <px:transform> <px:content ref="myapp:mixed-up"/> <px:filter ref="myapp:pre-filter"/> <px:style ref="mystyle:xsl-filter"/> <px:filter ref="myapp:post-filter"/> </px:transform> </px:show> </px:page> <px:saxFilter name="pre-filter" className="PreFilter"/> <px:saxFilter name="post-filter" className="PostFilter"/> </px:resources>
Yes. Property and named resource elements must be registered in the components.xml file that currently resides in the resource directory of the presentingxml project (a more decentralized approach is planned for the future.)
Any component that satisfies the contract of a pipeline, action, filter, content, or other component can be used interchangeably in the script with like components. You can also define new kinds of components that you can use within your own components.
User defined components should be assigned to their own namespace (not the Presenting XML namespace.)
Do the following:
To implement the dynamic content handler that actually performs the validation, you need to implement the tagging interface com.presentingxml.components.content.dynamic.RequestHandler. You will need to provide a method called doRequest that takes three arguments:
An example of a RequestHandler implementation is shown below.
public class BookstoreGatekeeper implements RequestHandler { public void doRequest(PageContext context, Login login, ContentWriter writer) throws PresentingXMLException { // Put code to validate servlet request here } } interface Login { String getUserId(); String getPassword(); }
The resources script that puts all this together will look as follows.
<px:resources xmlns:px="http://www.presentingxml.com/PresentingXML" xmlns:myapp="http://www.presentingxml.com/myapp" ns="http://www.presentingxml.com/myapp"> <px:app name="bookstore"> <px:validateRequest><px:page ref="myapp:bookstore-gatekeeper"/></px:validateRequest> <px:mapRequest> <!-- device and request URI matchers --> </px:mapRequest> </px:app> <px:page name="bookstore-gatekeeper"> <px:show> <!-- px:requestURI is a built-in variable that holds the value of the original request URI --> <px:localRedirect select="$px:requestURI"> <px:dynamicContent className="samples.common.BookstoreGatekeeper"/> </px:localRedirect> </px:show> </px:page> <!-- other resource definitions --> </px:resources>
First, the px:page element that defines the books page must contain a px:parameter element,
<px:page name="books"> <px:parameter ns="" name="category"/>
Now suppose we implement a SelectHandler to service a request for article titles, something like
public class BookCatalog implements SelectHandler { public void doRequest(PageContext context, Book parameters, ContentWriter contentWriter) throws PresentingXMLException { // Implementation here } }Note the second argument in the doRequest method, parameters, which we have declared to be of type Book. This interface is defined as follows:
public interface Book { public String getCategory(); }Now, if within the doRequest method we call the getCategory method on the Book interface, and if the HTTP request to the servlet has a parameter category, then the getCategory method will return the value of that parameter. It will return null if there is no parameter.
The mapping from request parameters to method invocations on an interface is done automatically according to bean naming conventions using the Java proxy classes.
The px:parameter element will be the same,
<px:page name="books"> <px:parameter ns="" name="category"/>
The Book interface will need to be written as follows:
public interface Book { public String[] getCategory(); }
The parameter values will still be mapped correctly to the string array if the request conatins only one category value or no category value.
Use the select attribute of the px:parameter element,
<px:page name="books"> <px:parameter ns="" name="category" select="category-code"/>
Note that the same request parameter may be mapped into more than one parameters.