The heart of LXP’s content management is its content inclusion
workhorse: the <include>
tag. The <include>
tag can operate in one of many ways, depending either on the explicit value of the method
attribute with which it is initiated, or the implicit context determined by
its attributes.
The <include>
tag can be used, in its simplest form, to simply
include a flat HTML file, such as a standard header, sidebar, and footer. In its more advanced
incarnations, the <include>
tag can be used to parse token-delimited
files by using arbitrary tokens, parse basic XML documents, embed PHP output inline within the
LXP document, make direct SQL queries, and, of course, include other LXP documents.
Table 13-1 lists each of the LXP inclusion methods available
to the <include>
tag. The method in the first column is value that you
supply to the <include>
tag’s method attribute. The alias in the
second column describes any alternative names that you can use to invoke the same method. The
“Implied by” column shows any attribute values which would imply a method (bypassing the need
for an explicit method
attribute), and the “Description” column gives a
brief description of the method itself.
Table 13-1. LXP inclusion methods
Method |
Aliases |
Implied by |
Description |
---|---|---|---|
|
.lxp extension ending |
Processes the source file through mod_lxp | |
|
Unrecognized extension in |
Displays a file’s literal contents | |
|
Parses a token-delimited file, and breaks it up into accessible | ||
|
|
.xml, .rdf or .rss
extension at the end of the |
Parses a well-formed XML file, and breaks it up into accessible |
|
|
|
Displays output of an Apache subrequest with a |
|
Displays output of an Apache subrequest with a | ||
|
Existence of |
Executes a SQL statement, making query results accessible both as variables, and with
the |
The source of content inclusion is invariably defined in the src
attribute of the <include>
tag. In most cases this is a system
filename, though it may describe a database source or Apache URI request, depending on the
method. When you include a file described by a relative path (one that is not explicitly
defined from the root of the filesystem), LXP will use the working directory of the LXP
document which is performing the inclusion.
To prevent accidental infinite recursion (e.g., including a file that includes itself),
LXP documents may only include to the depth specified in the lxp.conf
file’s MaxIncludeDepth
directive (see the section titled Nuts and Bolts: Configuring lxp.conf). The default maximum include depth is
15.
Any LXP file can be included within another LXP file, if the Apache server has read
access to the document specified in the src
attribute. Any variables set in
the including LXP document will be both accessible, and modifiable, by the included LXP
document.
To include an LXP file, open an LXP region, and use the following syntax where lxpfile is the name of the LXP file you wish to include:
<include src="lxpfile" />
When an LXP file is included, it is parsed as if it had been directly called. Therefore,
you must still use the <lxp>
tag to open an LXP region in the
included LXP document before you are able to use LXP tags within it.
Since the output of the included LXP document is embedded in place of the <include>
tag itself, no closing tag is necessary with this inclusion
method. In this case, the <include>
tag should be an empty-element
tag (i.e., with a trailing slash). If the LXP file you are including does not have an
extension ending in .lxp, you may force it to be parsed by the LXP module
by using the method="lxp"
attribute.
Suppose that you have an LXP application that provides different content depending on the
virtual host accessing the site. Each virtual host’s DocumentRoot
could
store just a single index.lxp file, configured to include the root LXP
application from another directory. Example 13-21 demonstrates
such a simple top-level file, which sets two protected LXP variables, and includes the root
LXP file.
Flat file is a term used to refer to a plain-text document. A flat file is a non-parsed document (such as a simple HTML document, or text file), as far as the server is concerned.
As with the inclusion of LXP documents, the flat file inclusion
method does not require a closing tag, and should therefore be used as an empty-element tag
with a trailing slash. To include a flat file, open an LXP region, and use the following
syntax where flatfile
is the name of the file you wish
to include:
<include src="flatfile" />
If the flat file you are including has a recognized file extension, you may force it to
be displayed literally by using the method="flat"
attribute. Example 13-22 demonstrates an LXP document which includes three
HTML files, from a relative directory called parts, to be used as a
header, sidebar, and footer. Since their extensions do not imply any more complex method, the
files are included as-is in the main document.
Example 13-22. Including flat files
<lxp> <include src="parts/header.html" /> <include src="parts/leftbar.html" /> Welcome to my home page.<br /> <include src="parts/footer.html /> </lxp>
As you can see, this sort of inclusion can make web sites with consistent themes far
easier to maintain by modularizing components in a manner similar to what is done when using
server-side-includes or PHP’s readfile()
function. In addition, flat file
inclusion allows you to achieve this modularity without having to leave the simplicity and
elegance of mark-up design. This is certainly not the full extent of the
<include> tag’s power, as you will find out in subsequent
sections.
A common function of many dynamic web sites is to post the contents of token-delimited files (such as Linux Today’s headlines file) on their web site in some kind of programmatically filtered format. These filters generally are implemented differently from page to page, and site to site, and rely on somewhat involved algorithms to pull apart the data and put it back together again into a useful format.
The LXP approach to displaying such files is with the use of the <include>
tag, by specifying the method="parsed"
attribute. This use of the <include>
tag breaks up the parsed
fields into sequential values, accessible via the general-purpose LXP
<field>
tag.
Blocks are delimited from one another by the value supplied to the delimiter
attribute. Within a block, fields are separated
from one another by each newline (symbolically,
, a literal line-wrap)
found within the block. You may optionally specify a different field delimiter value using the
separator
attribute.
The parsed method for the <include>
tag requires a closing
</include>
tag, because for each block that LXP reads from the file,
it loops back to the beginning of the <include>
tag and re-iterates
the mark-up until the last block is processed.
If you wish to limit the number of blocks to be displayed, the last block number can be
specified with the lastblock
attribute. Additionally, the firstblock
attribute can be used to skip any leading blocks (e.g., an introductory
statement that might be embedded at the top of the text file preceding the first
delimiter).
Here is an example of such a token-delimited file, from www.linuxtoday.com:
Welcome to lthead.txt. Fields are delimited by two ampersands. The first field is the headline. The second field is the URL to the story. The third field is the date the story was posted. Have Fun! ([email protected]) && LinuxProgramming: python-dev summary 2001-06-21 - 2001-07-05 http://linuxtoday.com/news_story.php3?ltsn=2001-07-05-019-21-OS-SW Jul 5, 2001, 21:30:38 && Chicago Sun-Times: Test drive Linux using friendly tryout software http://linuxtoday.com/news_story.php3?ltsn=2001-07-05-018-21-PS-CY Jul 5, 2001, 21:00:48 && [...]
Example 13-23 opens the file
/home/web/headlines/lthead.txt, and parses it into blocks using the
&&
character sequence as the block delimiter.
Example 13-23. Including a token-delimited file
<lxp> <include src="/home/web/headlines/lthead.txt" delimiter="&&" firstblock="2" lastblock="4" method="parsed"> <table border="0" cellspacing="1"><tr> <td bgcolor="#ffffff" width="100%"> <div class="content"> - <field /> </div> </td> </tr><tr> <td bgcolor="#e0e0e8" width="100%"> <strong> <field type="url" link="Read More..." target="_blank" /> </strong><br /> </td> </tr></table> </include> </lxp>
When an inclusion such as the one in Example 13-23
is processed, the <field>
tags are replaced with the field values
found within the parsed blocks. Fields are assigned to <field>
tags
in the order in which they are found.
As you can see in Example 13-23, you may also
specify an alternate type
attribute for an LXP <field>
. Valid types in a parsed inclusion are hidden
(this hides the field if there is a value that you wish to skip over, and not display) and
url
.
The hidden
type is used for a field which you wish to merely skip
over. Since token-delimited files have no identifying name for each block, each field must be
processed in the order that is encountered by LXP in the source file. Therefore, a field can
be assigned a type="hidden"
attribute in order to skip it rather than
display it, allowing you to display fields that are past it in the file.
The url
type is useful in this context when you know that a particular
field will be a URL, as it creates a hyperlink to that URL (with an HTML <a>
tag), rather than just displaying the URL itself. You can set the text
of the generated hyperlink to appear as an arbitrary value, other than just the URL itself
(such as the Read More . . .
value used in Example 13-23), by specifying the value of the link
attribute within the <field>
tag.
Here is example output of what you would see from LXP, after parsing the mark-up from Example 13-23:
<table border="0" cellspacing="1"><tr> <td bgcolor="#ffffff" width="100%"> <div class="content"> - LinuxProgramming: python-dev summary 2001-06-21 - 2001-07-05 </div> </td> </tr><tr> <td bgcolor="#e0e0e8" width="100%"> <strong> <a href="http://linuxtoday.com/news_story.php3?ltsn=2001-07-05-019-21-OS-SW" target="_blank">Read More...</a> </strong><br /> </td> </tr></table> <table border="0" cellspacing="1"><tr> <td bgcolor="#ffffff" width="100%"> <div class="content"> - Chicago Sun-Times: Test drive Linux using friendly tryout software </div> </td> </tr><tr> <td bgcolor="#e0e0e8" width="100%"> <strong> <a href="http://linuxtoday.com/news_story.php3?ltsn=2001-07-05-018-21-PS-CY" target="_blank">Read More...</a> </strong><br /> </td> </tr></table> [...]
To include an external well-formed XML document, the approach is very similar to the
parsed
method. The method
attribute may be set to
either XML
, RSS
, or RDF
to explicitly
set the method to XML parsing. Including a src
attribute that ends in any
of the .xml, .rss, or .rdf
extensions will implicitly invoke this method as well.
The delimiter
attribute in this context sets the name of the element
(tag) within which to look for element fields to parse. For example, most of the relevant
fields in an RDF file are contained directly within the <item>
element; for this reason, item
is the default delimiter element. For each
delimiting element found, the entire <include>
region will be looped
through once.
Like the parsed
method, the XML
method uses the
generalized <field>
tag to display the contents of a field value. In
this context, a field value refers to the character data within a named element (tag) inside
the delimiting element. Field values will be displayed in the order in which they appear in
the XML file unless a name
attribute is set within the <field>
tag, assigning the name of the element field to output. For example,
a name="title"
attribute refers to the character data within <title>
and </title>
in the source XML
document.
As an example, suppose that you have an XML source document called languages.xml that describes languages related to PostgreSQL, with the following structure:
<?xml version="1.0" encoding="utf-8"?> <languages> <language> <name>C</name> <notes>Built-in language.</notes> </language> <language> <name>LXP</name> <notes>Web-based content language.</notes> </language> <language> <name>PL/pgSQL</name> <notes>PostgreSQL procedural language.</notes> </language> </languages>
In this scheme, notice that each language is described within the <language>
element. To parse such an XML file in the same manner as the RDF
example described earlier, set the delimiter
attribute of the <include>
tag to language
and the src
attribute to languages.xml
. This is demonstrated in Example 13-24.
Example 13-24. Including an XML file
<lxp> <include src="languages.xml" delimiter="language" method="xml"> Language Name: <field name="name" /><br /> Language Notes: <field name="notes" /><br /> <hr /> </include> </lxp>
When processed, the output of Example 13-24 would look like this:
Language Name: C<br /> Language Notes: Built-in language.<br /> <hr /> Language Name: LXP<br /> Language Notes: Web-based content language.<br /> <hr /> Language Name: PL/pgSQL<br /> Language Notes: PostgreSQL procedural language.<br /> <hr />
Example 13-25 demonstrates the
display of a simple RDF XML document. This example differs from Example 13-24 in that it addresses, specifically, an RDF document. As a
result, the delimiter
attribute can be omitted, since the default value of
item is appropriate for the RDF schema.
Example 13-25. Including an RDF file
<lxp> <include src="/home/web/ports/headlines/slashdot.rdf" lastblock="5"> <table border="0" cellspacing="1"><tr> <td bgcolor="#ffffff" width="100%"> <div class="content">- <field name="title"></div> </td> </tr><tr> <td bgcolor="#e0e0e8" width="100%"> <strong> <field name="link" type="url" link="Read More..." target="_blank"> </strong><br /> </td> </tr></table> </include> </lxp>
Notice also the use of the lastblock
attribute in Example 13-25, which was also described in the section titled Including Token-Delimited Files earlier in this chapter. Both the firstblock
and lastblock
attributes can also be used with XML,
RDF, and RSS files to limit and offset which blocks of data are displayed.
To include an external content-type configured within Apache, the <include>
tag can be invoked with either the URI
or
local
method. Each performs a subrequest to Apache, meaning that the
inclusion is processed as if it is a direct request to Apache, with the output embedded at the
location of the <include>
tag in the LXP document.
The difference between these two methods is that the URI
method
accepts a src
attribute of the form that Apache would literally accept from
a web browser, prefixed with a forward-slash, and beginning at the document root directory of
the configured host (e.g., /example.php). Alternatively, the local
method tells Apache where the file is located in the local filesystem (e.g.,
/home/web/example.php).
Example 13-26 shows an LXP
file which includes a PHP script in two ways. Note that each of these methods goes through
Apache, and will thus be reliant on Apache to be properly configured for the requested content
type, and especially in the case of the local
method, have the necessary
rights on the directory containing the included script.
Example 13-26. Including other content types
<lxp> An example PHP script:<br /> <include src="/example.php" method="URI" /> <hr /> The same PHP script, using the local method:<br /> <include src="/home/web/default/example.php" method="local" /> </lxp>
Omitting the method
attribute when including a document (specified by
the a src
attribute) with a name ending with any of the common PHP
extensions (.php, .php3, and
.phtml) results in the method being implied as local
.
As of LXP 0.8, however, there is no way to imply the URI
method. You must
therefore specify method="URI"
to use the URI method.
The SQL method in LXP offers a great amount of power through direct connectivity to PostgreSQL. It allows for the embedding of 100% dynamic, database results directly within a web page without the need to call out to a programming language, create explicit connection or statement programming objects, or even to parse and format the results.
To use the SQL method, you may either explicitly use the <include>
tag with a method
attribute of SQL
, or implicitly define the <include>
tag as using the
SQL method by setting the value of the sql
attribute
to the SQL statement you wish to execute. In the following example, the SQL method is implied
as a result of specifying a value for the sql
attribute:
<include sql="SELECT * FROM pg_database">
Like each of the parsing methods, the <include>
tag loops
between its opening <include>
and closing </include>
tags for each row returned from a successfully executed SQL
query.
When using the SQL inclusion method, the src
attribute is used within the <include>
tag to define the database
source to connect to. If this attribute is omitted, LXP will attempt to connect to its
persistent database connection, if one exists.
While there exists a single persistent database connection for each Apache httpd process, the LXP module actually maintains the connection—not Apache.
The format of this connection string will be familiar to anyone who has connected to PostgreSQL through C or PHP. It is a single, character string, within which there are several sub-attributes describing the data source. Available sub-attributes are shown in Table 13-1.
Table 13-2. Database connection attributes
Attribute |
Description |
---|---|
|
The database to connect with (defaults to the same name as the connecting user) |
|
The hostname to connect to |
|
The username to connect with (defaults to the user running Apache) |
|
The password to use, if authentication is required |
|
The port to connect to (Defaults to 5432) |
Within the src
attribute’s value, attribute pairs are separated by
whitespace, and an equal sign separates each attribute from its value. The order in which the
database attributes appear is not important.
Example 13-27 shows the execution of a SQL
query, which uses a connection to a database called example
, on a host
named db_server
, with the username john
.
Column values can be accessed in one of two ways while iterating
through a SQL inclusion region; either through the general <field>
tag, or through the this
object, which is populated with a value for each
column upon each row iteration.
Like the XML inclusion, a name
attribute can be applied to a <field>
tag in order to specify which column is to be displayed. Otherwise,
the column values are displayed in the order they were targeted by the query, from left to
right, with each successive use of the <field>
tag.
Alternatively, the values of each column can be accessed by a variable named this.
column, where column is the name
of the column to be identified. For example, the following two tags would output the same
value within an included SQL region:
<field name="id" /> <putvar name="this.id" />
The main reason for the existence of the this
object is so that
branching logic, and variable substitution, can be performed using the values of the returned
SQL result set. Example 13-28 executes a SQL query, and
formats its output conditionally through the use of branching logic.
When executing a SQL query, some special variable values containing data about the
current result set are assigned to an LXP object called sql
. These
are:
The sql.numrows
variable value contains the number of rows retrieved
by the query. The sql.numcols
(and its sql.numfields
alias) variable value contains the number of columns in each row. When looping between
<include>
and </include>
, the sql.row
variable value contains the numeric index of the current row, counting
from 1, while the sql.offset
variable value contains the numeric index of
the current row counting from 0.
Example 13-29 uses the the sql.row
variable to display the current row index within the looped <include>
region. In addition, the sql.numrows
variable
is used after the query results are displayed to show how many rows were retrieved.
Example 13-29. Using SQL object variable values
<lxp> <include sql="SELECT * FROM pg_user ORDER BY usename LIMIT 5"> User #<putvar name="sql.row" />: <putvar name="this.usename" /><br /> </include> <br /> Selected <putvar name="sql.numrows" /> rows. </lxp>
The output of Example 13-29 would look like this:
User #1: allen<br /> User #2: barbara<br /> User #3: ben<br /> User #4: corwin<br /> User #5: david<br /> <br /> Selected 5 rows.
If you prefer to execute a SQL query only as a means to have access to the result set
returned (bypassing the automatic looping iteration of the <include>
tag), you may supply the setvars
attribute with the name of an LXP object
to be populated with the query results, and immediately close the region with a closing
</include>
tag.
For result sets with a single row returned, this approach sets a variable named
object.column for each column in the row, where
object is the name specified by the setvars
attribute, and column is the name of a column returned by the
query.
For result sets with
more than a single row, square-brackets containing an offset describing the row number are
appended to the column name (e.g., object.column[0]
, object.column[1]
, etc.).
Example 13-30 executes a query on the
pg_user
table, to retrieve three columns about a particular user.
Example 13-30. Selecting SQL results into an LXP object
<lxp> <include sql="SELECT usename, usesuper, usecreatedb FROM pg_user WHERE usesysid = $userid" setvars="userinfo"></include> <if sql.numrows="1"> User name: <putvar name="userinfo.usename"><br /> <if userinfo.usecreatedb='t'> <strong>This user can create databases.</strong><br /> </if> <if userinfo.usesuper='t'> <strong>This user is a superuser.</strong><br /> </if> </if> <else> Error: No user was found. </else> </lxp>
18.226.104.153