The most basic component used to define which transformations will be applied to a given resource within AxKit is perhaps best termed a style processor definition. These definitions indicate a single transformational step (applying an XSLT stylesheet or passing the content through a SAX Filter, for example) in what may be a chain of transformations. In their most basic and typical form, these style definitions declare two bits of crucial information: a MIME type that will be used by AxKit to determine which Language module will be used to transform the content, and a file path to a stylesheet (or other Language-specific argument) that will be used by that Language module to determine how to transform the content. Individual processor definitions may optionally be combined into named style and media groups that can then be selected conditionally, based on a number of factors.
By default, style processors are defined within AxKit in one of two ways: by using AxKit’s processor configuration directives or by special stylesheet processing instructions contained in the source documents themselves. (In Chapter 8, you’ll learn to create your own way to configure AxKit’s styling rules by rolling a custom ConfigReader module, but that’s another story.) The following illustrates how to create a simple named style containing a single style definition using AxKit’s server configuration directives. The lone processor definition contains the required MIME type and path to the stylesheet that will be applied.
<AxStyleName "#default"> AxAddProcessor text/xsl /path/to/style1.xsl </AxStyleName>
The MIME type used in the processor definition corresponds to the one you associated earlier with the Language::LibXSLT module. The effect of this is that, starting with the source, XML will be transformed by the LibXSLT processor by applying the stylesheet at the location defined by the second argument.
AxKit offers a small host of runtime configuration directives that can
be used to define the styles for a given site. These directives are
actually extensions of Apache’s configuration syntax
and, as such, are added to the usual server configuration files, such
as httpd.conf
or
.htaccess
files. They can be mixed and matched with other Apache directives. A
basic familiarity with Apache’s runtime
configuration syntax is presumed in this section.
Using AxKit’s configuration directives, style definitions can be added and applied in all cases or applied conditionally, based on an aspect of the XML document being served (the document’s root element name, URI on the server, etc.). A style definition’s first argument is the MIME type associated with the language module that will apply the transformation, and the second is the path to the stylesheet that will be applied. Conditional processor definitions add a third, directive-specific argument that defines the rules that govern when and if that processor will be adding to the current processing chain.
Relative stylesheet
paths are
resolved in the context of the directory that contains the resource
being requested, while qualified paths are resolved relative to the
host’s DocumentRoot
. However, not
all language modules employ external stylesheets. For example, the
SAXMachines module expects a quoted, whitespace-separated list of
Perl package names that implement SAX Filters instead of a stylesheet
path. Others, such as XSP, are self-contained (the source document
itself defines the transformations), and the literal string
NULL
is used in place of the stylesheet path.
We will now take a look at each of AxKit’s processor definition configuration directives. Keep in mind as you read the details of each directive that these are just the lowest-level building blocks from which you can create sophisticated application- and media-specific processing chains.
AxAddProcessor
, the most basic of the styling
configuration directives, unconditionally adds that processor
definition to AxKit’s processing chain. The
processor definition requires two arguments: the MIME type associated
with the language processor that will be used to do the
transformation, and the path to the stylesheet that will be used by
that processor to transform the XML source.
AxAddProcessor text/xsl /styles/global.xsl
This unconditionally adds the stylesheet
/styles/global.xsl
to the processing chain and
tells AxKit to use the language module associated with the MIME type
text/xsl
to perform the transformation.
The AxAddProcessor
directive is commonly used in
conjunction with Apache’s standard
<Files>
,
<Directory>
,
<Location>
, and similar directives. For
example, adding the following to a
.htaccess
at
the root level of a site would configure AxKit to apply the
stylesheet /styles/docbook_simple.xsl
to all
documents in that site that have the file extension
.dkb,
while
transforming all documents with .xml
extension
with the global stylesheet from the above example:
<Files *.dkb> AxAddProcessor text/xsl /styles/docbook_simple.xsl </Files> <Files *.xml> AxAddProcessor text/xsl /styles/global.xsl </Files>
Transformation chains can be created by adding more than one style
processor definition to a given context. The following would
configure AxKit to apply the stylesheet
pre_process.xsl
to all documents in the
/docs
directory and then to apply the stylesheet
main.xsl
to the result of the first
transformation:
<Directory /docs> AxAddProcessor text/xsl /styles/pre_process.xsl AxAddProcessor text/xsl /styles/main.xsl </Directory>
AxKit processing definitions, like many Apache directives, are inherited recursively down directory branches. So, a style definition configured for the root of a site will be applied to all documents in that site, unless explicitly overridden.
The
AxAddRootProcessor
directive sets up
document-to-stylesheet mappings based on the name of the root element
in the source XML document. It requires
three arguments: the MIME type
associated with the language processor that will perform the
transformation, the path to the stylesheet that will be applied, and
the name of the root element to match against.
The following configures AxKit to apply the stylesheet
/styles/docbook_simple.xsl
to all documents in
the current scope that have a root element named
article
:
AxAddRootProcessor text/xsl /styles/docbook_simple.xsl article
Matching top-level element names in documents employing XML
namespaces is supported using the
Clarkian Notation,
in which the element’s namespace URI is wrapped in
curly braces
{ }
and prepended
to the element’s local name.
AxAddRootProcessor text/xsl /styles/mydoc.xsl {http://localhost/NS/mydoc}document
This would apply the stylesheet
/styles/mydoc.xsl
to both of the following
documents:
<?xml version="1.0"?> <document xmlns="http://localhost/NS/mydoc"> <element/> </document> <?xml version="1.0"?> <doc:document xmlns:doc="http://localhost/NS/mydoc"> <doc:element/> </doc:document>
The element’s namespace prefix is not considered, since it is really only a syntactic shortcut used to bind the given element to the namespace URI to which the prefix is bound. Hence, the following would match neither of the above documents:
AxAddRootProcessor text/xsl /styles/mydoc.xsl {http://localhost/NS/mydoc}
doc:
document
These directives allow for stylesheet selection based on aspects of the source content’s Document Type Definition (DTD).
The AxAddDocTypeProcessor
directive conditionally adds processors
based on the value assigned to the PUBLIC identifier contained in the
source document’s DTD. So, to add a style processor
to match the following Simplified DocBook document, do the following:
<?xml version="1.0"?> <!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN" "http://www.oasis-open.org/docbook/xml/simple/4.1.2.5/sdocbook.dtd" [ ]> <article> . . . </article>
You can use the following AxAddDocTypeProcessor
directive:
AxAddDocTypeProcessor text/xsl /styles/sdocbook.xsl "-//OASIS//DTD Simplified DocBook XML V4.1.2.5//EN"
Similarly, the AxAddDTDProcessor
directive conditionally adds processors based on
the path contained in the SYSTEM identifier in the source
document’s DTD:
<?xml version="1.0"?> <!DOCTYPE mydoc SYSTEM "/path/to/my.dtd" [ ]> <article> . . . </article>
and the matching AxAddDTDProcessor
directive:
AxAddDTDProcessor text/xsl /styles/sdocbook.xsl /path/to/my.dtd
It is important to remember that only the
original source document is examined for matches against the
conditional AxAddRootProcessor
,
AxAddDTDProcessor
, and
AxAddDocTypeProcessor
directives. So, for example,
if you alter the document’s root element name during
a transformation by one stylesheet, that new root element will
not be evaluated against any
AxAddRootProcessor
directives that may exist in
the current context.
The
AxAddURIProcessor
provides a way to apply styles by matching a Perl regular expression
against the current request URI. Mostly, this directive is a useful
way to emulate
LocationMatch blocks in contexts in
which those blocks are not allowed.
# In httpd.conf, fine here <LocationMatch "/my/virtual/uri"> AxAddProcessor text/xsl /styles/application.xsl </LocationMatch> # But I like .htaccess files and can't use LocationMatch!! AxAddURIProcessor text/xsl /styles/application.xsl "/my/virtual/uri"
AxAddDynamicProcessor
,
the syntactic oddball among the processor directives, accepts the
name of a Perl package as its sole argument. When this directive is
found in a given context, AxKit calls the handler(
)
subroutine in the package specified. That function is
expected to return a list of processor definitions that will be added
to the current processing chain.
The handler( )
subroutine is passed, in order:
an instance of the current ContentProvider class, the preferred media
name, the preferred style name, the source content’s
DTD PUBLIC identifier, its SYSTEM identifier, and root element name.
If the source content does not contain a DTD, or a preferred media
and style that have not been set by an upstream plug-in for the
current request, those corresponding arguments will not be defined.
The styles returned take the form of a list of HASH references, each
containing two required key/value pairs: href
,
whose value should contain the path to the stylesheet being applied;
and type
, whose value should contain the MIME
associated with the Language module that will do the transformation.
package My::Processors; sub handler { my ($provider, $preferred_media_name, $preferred_style_name, $doctype, $dtd, $root) = @_; # normally, @styles will be generated dynamically rather than hardcoded, as # it is here. my @styles = ( { type => 'application/x-xsp', href => 'NULL' }, { type => 'text/xsl', href => '/styles/mystyle.xsl' }, ); return @styles; }
The
AxResetProcessors
directive
clears the list of processor mapping within the scope of its
surrounding block. This is especially useful for handling special
cases in otherwise homogeneous configurations.
# Set the default style for the entire site <Directory "/www/sites/mysite"> AxAddProcessor text/xsl /styles/global.xsl </Directory> # But you need to transform the content in the 'products' # directory with a different style and you don't want to # inherit the global style. <Directory "/www/sites/mysite/products"> AxResetProcessors AxAddProcessor text/xsl /styles/products.xsl </Directory>
Like most Apache configuration directives, AxKit style processor
definitions are inherited recursively down directories. A
style defined at the root level
of the site, for example, will be applied to all documents in or
below that directory in the hierarchy, and, hence, the entire site.
Styles added to locations deeper in the hierarchy do not override the
styles defined by their parents but rather are
added to the processing chain. So, for instance,
if you have a global style defined for the root level of the site,
and one defined for a child directory named
contact
, all documents in the
contact
directory will have both styles applied
during processing. What surprises many new AxKit users, however, is
the order in which the styles are applied in these cases—styles
defined in
child directories are prepended to the list of
processors defined by their parents, not appended, as you may
initially expect. Consider the following style configuration:
<Directory "/www/sites/mysite"> AxAddProcessor text/xsl /styles/global.xsl </Directory> <Directory "/www/sites/mysite/contact"> AxAddProcessor application/x-xsp NULL </Directory>
The mysite
directory has a style definition that
applies the global.xsl
XSLT stylesheet to all of
its contents, and that the .contact
directory (a
child of the mysite
directory) adds a style
definition that configures AxKit to process contents of that
directory with the XSP processor. With this configuration, a document
requested from the contact
directory will have
both styles applied, but the local XSP process will be applied
first and the result of that will be processed
using the global.xsl
stylesheet. While this
behavior seems a bit strange at first glance, in practice it helps
simplify setting up the Style processing for many sites where a
common look and feel is applied to all content and various
source-specific transformations are configured for lower levels in
the document hierarchy. (The results are often copied through
verbatim by the higher level transformations.)
Taken together, these configuration directives represent a rich set of options that, when combined with Apache’s standard configuration blocks, can meet the styling requirements of a great many sites. However, in Section 4.3, you will see how these components can be combined with AxKit’s StyleChooser and media chooser modules to make your sites even more dynamic and responsive.
In addition to defining style processor mappings through the
configuration directives,
stylesheets can also be applied
based on one or more
xml-stylesheet
processing instructions in the source document itself. Stylesheet
processing instructions must appear in the prolog of the
document—that is, between the XML declaration and the top-level
document element:
<?xml version="1.0"?>]]><emphasis role="bold"><![CDATA[ <?xml-stylesheet type="text/xsl" href="/styles/docbook_simple.xsl" ?>]]></emphasis><![CDATA[ <article> . . . </article>
Similar in behavior to the AddAddProcessor
configuration directive, the xml-stylesheet
processing instruction’s type
attribute should contain the MIME type associated with the language
module that will perform the transformation. The
href
attribute should contain the path to the
stylesheet that will be applied.
Styles added via xml-stylesheet
processing
instructions come in three flavors: persistent
styles that are applied in all cases, preferred styles that define a
default style if none is specifically selected, and alternate styles
that are only applied under specific conditions.
Persistent styles are defined as
those whose processing instruction has neither a
title
nor an alternate
attribute. The following adds two persistent styles to the document
that contains them:
<?xml-stylesheet type="text/xsl" href="/styles/nav_includes.xsl"?> <?xml-stylesheet type="text/xsl" href="/styles/html.xsl"?>
All relevant styles in a given document are applied in the order in
which their xml-stylesheet
processing instructions
appear. So, the above would tell AxKit to apply the
/styles/nav_includes.xsl
stylesheet to the
source XML and then apply the /styles/html.xsl
stylesheet to the result of the first transformation.
A preferred
style is one whose
processing instruction contains a title
but not an
alternate
attribute. It is used to define the
nonpersistent default style among a set of alternate styles:
<?xml-stylesheet type="text/xsl" href="/styles/html.xsl"
title="html"
?>
An alternate
style is one whose
processing instruction contains both a
title
and an alternate
attribute:
<![CDATA[
<?xml-stylesheet type="text/xsl" href="/styles/html.xsl" title="html"
alternate="yes"
]]>
In AxKit, alternate styles are used together with a StyleChooser module to select the appropriate styles to apply for a given circumstance. (See Section 4.3.1 later in this chapter.)
Finally, styles set via xml-stylesheet
processing instruction can associate
themselves with a specific media type by adding the
media
attribute. This allows alternate styles to
be selected based on the type of device requesting the resource. (See
Section 4.3.1.)
<?xml-stylesheet type="text/xsl" href="/styles/wap.xsl"
alternate="yes" media="handheld"
?>
Stylesheet processing instructions are extracted
only by the ContentProvider module that fetches
the original source XML document. This means that you cannot add
stylesheets to the processing chain by
including xml-stylesheet
instructions in the
output of a stylesheet transformation. Once the document is sent to
AxKit’s language modules to process, the stylesheet
PIs (if any) have already been extracted, and the results of the
transformations are not reexamined.
Any styles defined by xml-stylesheet
processing
instructions in the source document override all
those defined via configuration directive. This is often desirable.
For example, it provides applications that return dynamic documents
through a custom ContentProvider, an easy way to set the styles for
that application state while still having defaults set via
configuration directive to cover common cases. In many situations,
however, this is not the behavior that you want. To disregard all
styles defined by
xml-stylesheet
processing instructions in a particular context, use the
AxIgnoreStylesheetPI
directive:
AxIgnoreStylesheetPI On
So, which is better,
styles defined by configuration
directive or by xml-stylesheet
processing
instruction? The answer depends largely on the
site’s requirements, but, in general, sites that
define style processors via configuration directive tend to be more
flexible and easier to maintain in the long run. For example,
altering the stylesheet path for a given style is a one-line change
for a site that uses configuration directive to define its styles,
while the path would have to be altered in each
document that references that style in the same site that
relies on xml-stylesheet
processing instructions.
Get XML Publishing with AxKit now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.