XPath Datatypes & Functions, Using Ant, and XSLT in Web Applications
R. Alexander Milowski
milowski at sims.berkeley.edu
#1
Datatypes
XPath has three basic datatypes: nodes, literals, and numbers.
All numbers are floating point numbers (e.g. 1.0 is the same as 1)
Literals must be quoted: 'value' or "value"
Predicate examples:
item[@id='late'] item[position()=1]
#2
Functions
You can make function calls in expression and predicates.
Functions can take parameters and they always return values.
Parameters can be expressions (e.g. person/@href ).
Datatypes are implicitly converted to the type required by a parameter.
#3
Functions - Nodes
There are some basic node functions:
last() - returns the index of the last node in the current node set.
position() - returns the index of the current node in the current node set.
count(node-set) - returns the size of the node set.
local-name(node-set?) - returns the local name of a node.
namespace-uri(node-set?) - returns the namespace name of a node.
name(node-set?) - returns the QName of a node.
#4
Functions - Strings
There are some basic string functions:
concat(string,string,string*)
starts-with(string,string)
contains(string,string)
substring-before(string,string)
substring-after(string,string)
substring(string,number,number?)
string-length(string?)
#5
Functions in General
There are many functions.
You can look them up in your XSLT book.
Sometimes processors provide their own "extension" functions.
You just need to understand how type conversion works in XSLT/XPath.
#6
String Manipulation
You can manipulate values (strings) just like in programming languages.
substring-before("1999/04/01","/") returns "1999"
substring-after("1999/04/01","/") returns "04/01"
contains("big geek","geek") returns true.
The can all use XPath expressions too:
substring-before(@date,"/")
substring-after(book/pubdate,$delimiter)
#7
Strings and xsl:value-of
These are the same:
<xsl:value-of select="name"/> <xsl:value-of select="string(name)"/>
Implicit conversions of node sets to strings is via string():
The first node in the set is used.
The "text" descendants are the value.
#8
Numbers
All numbers in XSLT are floating point.
Conversion to numbers can be implicit.
You can explicitly convert to a number via: number(expr).
Summing numbers:
<xsl:template match="items"> <p>Total: <xsl:value-of select="sum(item/cost)"/></p> </xsl:template>
#9
Number Formatting
format-number() function can format a number.
A picture string is used: #.00
The full specification is from the Java class java.text.DecimalFormat or in the book.
Example
format-number("5.5","#.00") → 5.50
#10
Identifiers
Sometimes you need unique identifiers in the output.
generate-id(node) will return the same unique identifier for a given node.
generate-id() just returns a value--your schema says if it is valid where you use it.
Example:
<xsl:template match="annotation"> <xsl:copy> <xsl:attribute name="id"><xsl:value-of select="generate-id(.)"/></xsl:attribute> </xsl:copy> </xsl:template>
#11
Language
Matching language attributes can also be accomplished via a lang() function.
Example:
<terms> <term xml:lang="en"></term> <term xml:lang="fr"></term> <term xml:lang="pl"></term> </terms>
to find the Polish language term:
<xsl:template match="term[lang('pl')]"> Polish: <xsl:apply-templates/> </xsl:template>
ISO language codes are somewhat complex. For example, 'en', 'EN', 'en-us' all qualify as the language 'english'.
#12
Multiple Input Documents
You can create aggregates with document()
This includes additional documents as inputs to the transformation.
The document() function can have one or two arguments (see next slide).
Example:
<xsl:template match="include"> <xsl:apply-templates select="document(@href)"/> </xsl:template>
#13
Base URI & document()
If the first argument is a node set:
Each node in the set is processed by an implicit call to document().
The first argument is the node's value via string()
The second argument is the node (so relative URI values work).
If the URI value is relative, the base URI is the node set in context:
If the there is only one argument and it is a node set, then the base URI is that of the node being processed.
If the there is only one argument and it is a not a node set, then the base URI is that of the stylesheet.
If the there are two arguments, the base URI of the second is used.
An example: docfunc.xsl example.xml one.xml two.xml
#14
Aggregation Example
I've got a master document:
<talk-master><title>My Talk</title> <slide-group href="group-1.xml"/> <slide-group href="group-2.xml"/> </talk-master>
And I can then merge these documents with:
<xsl:template match="slide-group"> <xsl:apply-templates select="document(@href)/slide-group/node()"/> </xsl:template>
Here's that stylesheet and example: merge-slides.xsl talk-master.xml group-1.xml group-2.xml
#15
Using Ant to Apply XSLT
Ant is a tool for building/testing software.
It provides the ability to run XSLT on XML documents.
This is very useful for producing web content or alternate forms of documentation.
#16
The Basic Ant File
The Ant file is usually called 'build.xml' and is an XML file.
The root element is 'project' and has an attribute 'name' containing your project name:
<project name="myxslt"> <!-- My project file --> </project>
#17
The Ant Concept
Ant files typically contain a set of 'target' elements.
Each target represents some collection of tasks that can be executed.
Targets have names and you can default the starting target on the 'project' element:
Example:
<project name="myxslt" default='build-xhtml'> <target name="build-xhtml"> </target> </project>
#18
The XSLT Task
The 'xslt' element represents the task of running XSLT on an XML input.
It has three attributes:
@in - the input document as a relative URI.
@out - the output document as a relative URI.
@style - the stylesheet to apply to the input to produce the output.
Example:
<project name="myxslt" default='build-xhtml'> <target name="build-xhtml"> <xslt in='index.xml' out='index.xhtml' style='mydoc2xhtml.xsl'/> </target> </project>
#19
XSLT in Web Applications
You can use XSLT in a web application in at least three basic ways:
Use XSLT offline to style the content (e.g. via Ant).
Create an XSLT stylesheet for all your content and run that "on the server".
Create XSLT stylesheets for specific documents and run that when those documents are requested.
Good implementations of server technology will allow you to cache styled content.
#20
Structuring a Web Application
A J2EE web applicaiton is essentially a directory hierarchy with one special directory called 'WEB-INF'.
In that directory, there is a special XML document called 'web.xml'.
That document describes the web application to the J2EE Servlet Container (e.g. Tomcat).
#21
Setting Up a Web Project in Netbeans
Choose the File->New Project menu item.
Select 'Web' in the project 'Categories' panel and 'Web Application' from the 'Projects' panel and then click on 'Next'.
Choose a project name.
You may change the project location. If you leave the 'Project Folder' input alone, it will concatenate the name and the location together to make the project folder.
Click on 'Finish'.
#22
The Basic web.xml File
The 'web.xml' file describes the web app. The empty file looks like:
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <session-config> <session-timeout> 30 </session-timeout> </session-config> </web-app>
#23
Using Filters to Style with XSLT
We can use a J2EE component called a Servlet Filter to filter requests for XML documents.
On the way out, we'll run XSLT and style the document to XHTML.
This uses some code I wrote and is available on the class website.
The code uses JAXP (a standard Java API) to run XSLT on the document.
#24
Two Necessary Steps
The supporting libraries need to be added to your project:
Create a 'lib' directory in your 'WEB-INF' folder.
Copy the 'jaxp.jar' from the website into that folder.
Add the filter to the web.xml file--see next slide.
#25
Filter Configuration
Add this element to the web.xml file:
<filter> <filter-name>StaticXSLT</filter-name> <filter-class>com.milowski.jaxp.XSLTFilter</filter-class> <init-param> <param-name>content-type</param-name> <param-value>application/xhtml+xml</param-value> </init-param> <init-param> <param-name>reload</param-name> <param-value>yes</param-value> </init-param> <init-param> <param-name>static-extensions</param-name> <param-value>xml</param-value> </init-param> <init-param> <param-name>extensions</param-name> <param-value>xml,jsp</param-value> </init-param> <init-param> <param-name>stylesheet</param-name> <param-value>site.xsl</param-value> </init-param> </filter>
#26
Filter Parameters
content-type - the content type of the result for the browser--defaults to 'text/html'.
stylesheet - specifies the stylesheet to run on all the requests. If this is not specified, a stylesheet specific to the request is loaded. That is, if the request is '/index.xml', then '/index.xsl' is loaded.
reload - A boolean that indicates whether the stylesheet should be checked for changes--defaults to false.
extensions - the extensions for which this filter should be active. If this is not specified, it will run for all requests.
static-extensions - specifies which extensions should be files on the local disk. This is an optimization for local files.
#27
Mapping the Filter
All that remains is to associate the filter with requests.
This is accomplished via the 'filter-mapping' element:
<filter-mapping> <filter-name>StaticXSLT</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
The 'url-pattern' contains a simple prefix/suffix wildcard for the requests.
The 'filter-name' must match the name used in the 'filter' element.
#28
Tweaking the Starting Document
The 'welcome-file-list' element specifies the starting documents when the request ends in a slash ('/').
It contains a 'welcome-file' element for each welcome filename:
<welcome-file-list> <welcome-file> index.xml </welcome-file> </welcome-file-list>
#29
The Complete web.xml File
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <session-config> <session-timeout> 30 </session-timeout> </session-config> <welcome-file-list> <welcome-file> index.xml </welcome-file> </welcome-file-list> <filter> <filter-name>StaticXSLT</filter-name> <filter-class>com.milowski.jaxp.XSLTFilter</filter-class> <init-param> <param-name>content-type</param-name> <param-value>application/xhtml+xml</param-value> </init-param> <init-param> <param-name>reload</param-name> <param-value>yes</param-value> </init-param> <init-param> <param-name>static-extensions</param-name> <param-value>xml</param-value> </init-param> <init-param> <param-name>extensions</param-name> <param-value>xml,jsp</param-value> </init-param> <init-param> <param-name>stylesheet</param-name> <param-value>site.xsl</param-value> </init-param> </filter> <filter> <filter-name>DynamicXSLT</filter-name> <filter-class>com.milowski.jaxp.XSLTFilter</filter-class> <init-param> <param-name>content-type</param-name> <param-value>application/xhtml+xml</param-value> </init-param> <init-param> <param-name>reload</param-name> <param-value>yes</param-value> </init-param> <init-param> <param-name>static-extensions</param-name> <param-value>xml</param-value> </init-param> <init-param> <param-name>extensions</param-name> <param-value>xml,jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>DynamicXSLT</filter-name> <url-pattern>/xslt-test.xml</url-pattern> </filter-mapping> <filter-mapping> <filter-name>StaticXSLT</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>