Dynamic Indexing with XSL

In OU Campus content is generally displayed in a static format. This means that the content entered never changes unless it is updated manually. When a page is transformed, the data entered on the page is visible.

An easier way to update data frequently is to display data from many pages on a single indexed page. This involves querying multiple static pages, and displaying the information in a pre-configured format. This example makes use of a faculty directory to illustrate the use of dynamic indexing with XSL.

Using dynamic indexing involves taking pages with matching node structures (PCF files) and compiling the data into a faculty index page. The PCFs are similar to any other page template within an OU Campus site. They contain <title> and other common data nodes from which data are pulled. This technique utilizes XSL to query each PCF file and obtain the information to display.

There are many different ways to arrange the PCF files in order to access them. The most common, in which the files are all contained within the same physical folder, is the example used. This method can grab information from PCF files in folders throughout the site by making small changes to the XSL. Typically, the scope of the index should be kept small as this helps reduce the amount of time required to preview and publish the page.

The compiled data can be displayed in many different ways. For instance, a standard faculty directory can pull data from one directory and display it in a table format. The front-end HTML or JavaScript can be further developed to enable on-demand sorting or filtering. This utilizes any of the information that has been pulled from the PCF to interact with design elements. While this is possible, this example uses Gallena University and does not include front-end design elements.

To demonstrate the process of using dynamic indexing in OU Campus, it is valuable to review some theories along with XSL elements and functions. This information is used to create a functional faculty index.

XSL Functions and Elements

xsl:function

An <xsl:function> allows the developer to create stylesheet functions that can be referenced from any XPath expression used in the stylesheet. Functions provide the developer with a wide range of freedom in determining the actions performed.

Example Syntax

<xsl:function
   name= qname
   as=sequence-type
   override = "yes" | "no">
       <!-- Content: (xsl:param, sequence-constructor) -->
</xsl:function>

Example

<?xml version="1.0" encoding="utf-8”?>
<!DOCTYPE xsl:stylesheet SYSTEM "http://commons.omniupdate.com/dtd/standard.dtd">
<xsl:stylesheet version="2.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:ou="http://omniupdate.com/XSL/Variables">

<!-- function Definition -->
<xsl:function name="ou:sample_function" as="xs:string">
   <!-- Sequence processing for the function. -->
   <xsl:param name="string-value" />
   <xsl:variable name="string-chars"
       select="tokenize($string-value, ' ') " />
   <!-- continue processing logic -->
   <xsl:copy-of select="$string-chars[1]" />
</xsl:function>

<xsl:template match="/">
     <xsl:copy-of select="ou:sample_function('my string') " />
</xsl:template>

</xsl:stylesheet>

Attributes

Attribute Name Syntax Message Description
name name="ou:faculty" Required. Defines the name of the function. The name must have a namespace prefix to avoid clashing with other defined functions
as as="xs:string: Optional. The attribute defines the type of value returned when the function is evaluated.
override override="no" Optional. Specifies whether the function overrides any vendor-supplied function of the same name.

xsl:copy-of

<xsl:copy-of> copies the sequence of nodes to the resultant sequence. Also known as “deep copy,” when applied to a sequence, the node and all its descendants are copied. The select attribute is required. By default, <xsl:copy-of> copies all namespaces.

Example Syntax

<xsl:copy-of
select = expression
copy-namespaces = "yes" | "no"
type = qname
validation = "strict" | "lax" | "preserve" | "strip" />

Example

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "http://commons.omniupdate.com/dtd/standard.dtd">
<xsl:stylesheet version="2.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:ou="http://omniupdate.com/XSL/Variables">

<xsl:template match="/">
<!-- example calling the sample function above -->
<xsl:copy-of select="ou:sample_function('my string')" />

<!-- example using a variable -->
<xsl:copy-of select="$myvariable" />

<!-- example using XPath -->
<xsl:copy-of select="document/maincontent/node()" />
</xsl:template>

Attributes

Attribute Name Syntax Message Description
select select=expression Required. The sequence of values or nodes to be copied in the stylesheet.
copy-namespace copy-namespaces="no" Optional. Indicates whether the namespace of an element should be copied. The default value is "yes".
type type=qname Optional. Identifies the type of declaration against copied nodes.
validation validation="strict" Optional. Specifies whether the copied nodes should be subjected to schema validation, or whether existing type annotations should be retained or removed.

xsl:variable

The <xsl:variable> element enables the developer to declare a variable. Once defined, the expression can be applied within the XSL using the variable as opposed to entering the full expression multiple times.

Variables are defined as global or local depending on their location in the document. Global variables are those defined as children of the <xsl:stylesheet>, and are available throughout the stylesheet. Local variables are those defined within an <xsl:template>, and can only be used within the context of that template.

Variables can be referenced within an XSL expression or inline by utilizing curly braces { }.

Example Syntax

<xsl:variable
   name="name"
   select="expression"
   as="sequence-type">
      <!-- Content: sequence-constructor -->
</xsl:variable>

Note: When the sequence-constructor is blank, the xsl:variable element should be self-closed. <xsl:variable name="example" select="'blue'" />

Example

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "http://commons.omniupdate.com/dtd/standard.dtd">
<xsl:stylesheet version="2.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:ou="http://omniupdate.com/XSL/Variables">

<xsl:template match="/">
   <xsl:variable name="favoriteColor">blue</xsl:variable>
   <!-- inline variable reference -->
   <p style="color:{$favoriteColor}">This is my favorite color!</p>

   <!-- XSL expression variable reference -->
   <p>
   <xsl:attribute name="style" select="concat('color:', $favoriteColor)" />
   This is my favorite color!
   </p>
</xsl:template>

Local Variable Assignment

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "http://commons.omniupdate.com/dtd/standard.dtd">
<xsl:stylesheet version="2.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:ou="http://omniupdate.com/XSL/Variables">

<xsl:variable name="favoriteColor">blue</xsl:variable>

<xsl:template name="paragraph-blue">
<p style="color:{$favoriteColor}">This is my favorite color!</p>
</xsl:template>

<xsl:template name="paragraph-gray">
<xsl:variable name="favoriteColor">gray</xsl:variable>
<p style="color:{$favoriteColor}">This is my favorite color!</p>
</xsl:template>

</xsl:stylesheet>

Attributes

Attribute Name Syntax Message Description
name name="fac_name" Required. Defines the name of the variable.
select select="/document/content/name/text()" Optional. The expression that is evaluated as the value of this variable. If omitted, the value is determined by the value of the sequence constructor of the xsl:variable element.
as as="xs:date" Optional. The return type of the variable.

xsl:param

The <xsl:param> enables the developer to declare a parameter. Similar to variables, parameters are defined as global or local depending on the where they are defined within the document. There are three different usage categories for parameters; this example primarily uses Function Parameters.

Stylesheet Parameters

Stylesheet parameters are useful in creating global parameters that are accessible throughout the entire stylesheet declaration. A stylesheet parameter may be declared as mandatory or may have a default value specified for use when no value is supplied.

Template Parameters

As a child of the template, <xsl:param> is used to define the parameter of the template, which may be supplied when the template is invoked.

Function Parameters

As a child of the function, <xsl:param> is used to define the parameter of the function, which is supplied when the function is invoked. Functional parameters are mandatory when called within an XPath.

Example Syntax

<xsl:param
   name="name"
   select="expression"
   as="sequence-type"
    required= "yes" | "no">
      <!-- Content: sequence-constructor -->
</xsl:param>

Note: When the sequence-constructor is blank, the xsl:param element should be self-closed. <xsl:param name="example" />

Example

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "http://commons.omniupdate.com/dtd/standard.dtd">
<xsl:stylesheet version="2.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:ou="http://omniupdate.com/XSL/Variables">

<xsl:template match="/">
   The best colors are: <xsl:copy-of select="ou:colors('blue','gray')" />.
</xsl:template>

<xsl:function name="ou:colors">
   <xsl:param name="favorite-color" />
   <xsl:param name="runner-up" />
   <xsl:copy-of select=”concat($favorite-color, ' and ', $runner-up)" />
</xsl:function>

Attributes

Attribute Name Syntax Message Description
name name="fac_name" Required. Defines the name of the parameter.
select select="/document/content/name/text()" Optional. The expression that is evaluated as the value of the parameter. If omitted, the value is determined by the value of the sequence constructor of the xsl:param element.
as as="xs:date" Optional. The return type of the parameter.
required required="yes"

Optional. Specifies whether the parameter is optional or mandatory. 

xsl:for-each

xsl:for-each selects a sequence of items using an XPath expression and performs the same processing for each item in the sequence.

Example Syntax

<xsl:for-each
   select="expression">
      <!-- Content: sequence-constructor -->
</xsl:for-each>

Example

<xsl:for-each select="//tbody/tr">
      <xsl:copy-of select="current()"/>
<xsl:for-each>

Attributes

Attribute Name Syntax Message Description
select select="maincontent/node()" Required. Expression returning a sequence of nodes and values that need to be processed.

System-Defined Xpath Functions

concat()

The concat() function takes two or more arguments and returns a string. Note that each argument is converted into a string.

concat(arg1, arg2, ... )

Example

<xsl:value-of select="concat('blue', 'and', 'gray')" />

Output

blue and gray

Argument: arg(n)(mandatory): More than one argument of strings to be combined.

substring-after()

The substring-after() function returns the part of the string after a delimiter. Note that the function returns the first occurrence of the specified substring.

substring-after(string, delimiter)
substring-before(string, delimiter)

Example

<xsl:value-of select="substring-after('index.html', '.')"/>

Output

html

Argument: string (mandatory): The containing string.

Argument: delimiter (mandatory): The delimiter substring.

substring-before()

The substring-before() function returns the part of the string, before a delimiter. Note that the function returns the first occurrence of the specified substring.

substring-before(string, delimiter)

Example

<xsl:value-of select="substring-before('index.html', '.')"/>

Output

index

Argument: string(mandatory): The containing string.

Argument: delimiter(mandatory): The delimiter substring.

XSL DOC Call and the OU Campus List Trigger

In order to display data from many pages on a single page, it is necessary to query documents outside of the page being transformed (the index). The XSL doc function is used to query the external documents for specified XPath locations. The OU Campus system adds on to this functionality with the list trigger. Adding the list trigger provides the list of files or folders and their related <title> nodes.

This functionality provides a list of the files needed to parse in order to get the appropriate data for the index. This listing enables the developer to programmatically loop through each file in the list and obtain the designated information.

The doc function is typically invoked within a select statement:

<xsl:copy-of select="doc($directory)/list" />

In the above example, after the doc is the list trigger:

/list

The list trigger instructs the OU Campus transformation engine to provide a list of files within the specified path.

In order to parse the document for data, the doc call is reformatted:

<xsl:copy-of select=
"doc(concat($directory,'filename.xml'))/root/title/node()" />

Note: It is not advisable to have a root node called list, as this can produce unexpected results.

Example Syntax

<!-- the doc call should always be invoked within an XSL select -->

doc(full path)/list <!-- list files and titles -->
doc(full path)/list/directory <!-- list directories -->
doc(full file path)/xpath <!-- parse document and return data at specified xpath --> 

Creating a Faculty Index

Now that the theories behind some of the elements that will be used in the following code have been defined and explained, a faculty index can be created.

For the faculty index, the index page is going to create a list of the faculty members who have profiles on individual pages. In this example, the faculty member’s image, name, and biography are displayed with a link to the full profile page.

Faulty Index Page

To accomplish this, the PCFs for the individual faculty profile pages are created first. For this example, MultiEdit is used. MultiEdit is valuable as it ensures that the same node structure is used for every document.

It is important that the structure remains the same because to obtain the information each file is programmatically looped through.

Individual Profile Example

Individual Profile for Faculty

Code Example

Coding for Individual Faculty Profile

Configuring the Individual Profile XML Data for Retrieval

Purpose: To learn how to modify XSL to add additional information to the XML data file.

Objective: To create a single additional XML node in the profile page output XML.

Editing the PCF

1. Create a new faculty profile using the faculty profile template. Fill in the applicable fields, and choose Create.

2. The name, designation, and image should be populated. Open the page in Edit mode to add additional information for Biography, Publications, and Education. Be sure to populate the Education field.

3. View the profile with the Source Editor and notice the multi-edit nodes containing information displayed on each profile. The profile contains the node <education>. This information in this node is displayed on the individual profile, but not in the index.

The education information will be added to the XML data output. This makes the information available for display on the index page.

Editing the XSL

  1. Navigate to the fac_profile.xsl file typically found in the _resources/xsl folder.
  2. Edit the file.
  3. Within the <root> node, add an additional node <education></education>.

  4. Within the <education> node, enter the XSL statement:

    <xsl:value-of select="document/education/node()[not(self::comment())]" />
  5. Save the XSL file, preview the newly created PCF file, and click the XML tab.
  6. Review the new education data within the XML node, and publish the faculty profile page to make the XML changes live on the production server.

Faculty Index Page

The next step involves editing the XSL to configure the index page for the faculty section. This is the page on which the faculty data from each individual profile will be displayed.

Adding Education Data to the Index Page

Purpose: To learn how to modify XSL to add additional information to the index page display.

Objective: To write XSL that pulls in the educational data from the revised XML document published by each individual profile.

Within the <xsl:for-each select=... /> statement, additional XSL can be added to display the educational data on each profile listing.

1. Navigate to the content.xsl file typically found in the _resources/xsl/import folder.

2. Educational information will be added under the image. Locate the following code: <xsl:for-each select="$faculty_list/faculty"> and within it locate <div class="portfolio-img">.

3.  After the ending </a> tag, enter the following:

<em><xsl:value-of select="./education/node()"/></em>

In-context it should look like this:

<div class="portfolio-img">
   <a href="{./link/node()}">
          <img width="320" height="180" src="{./image/node()}"/>
          <span class="portfolio-overlay">&nbsp;</span>
     </a>
     <em><xsl:value-of select="./education/node()"/></em>
</div>
4. Save the file.   The value will not appear within the index until the faculty function is modified.  

About the Faculty Listing Function

The function includes the name (i.e., <xsl:function name="ou:faculty-listing">) of the function that is called into the template, parameters, and variables. Functions are typically located in the following file: /_resources/xsl/functions.xsl.

The three parameters (xsl:param) include:

  • The path to the faculty profiles on staging: fac_loc
  • The path to the faculty profiles on production: fac_loc_pro
  • The file extension used: file_type

The four variables (xsl:variable) are:

  • A list of all of the directories and files within the faculty profiles directory on staging: all
  • The current file’s file name: file_name
  • A Boolean value which returns if the XML file is available on the production server: xml_available
  • A Boolean value which returns if the HTML file is available on the production server: html_available

Listing the Required Files

The doc function obtains a list of the directories and files in the faculty location. The $fac_loc is defined as a parameter and the value when the <xsl:function> is called.

<xsl:copy-of select="doc($fac_loc)/list"/>

The /list portion of the code instructs OU Campus to list the files in the faculty directory specified by $fac_loc.

Parsing each Document for Data

This doc function determines the path to the data file on production by using the $fac_loc_pro variable, adding a forward slash, and using the $file_name variable to determine the name of the file. It is replacing .pcf with .xml in order to point to the appropriate data file on the production server.

This document is parsed in accordance to the XPath written outside the doc call. This defines the node path to follow in order to fetch the appropriate information.

<xsl:value-of select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/title/node()"/>

The doc function is used each time a new XPath location is referenced.

Complete Function

<xsl:function name="ou:faculty-listing">
      <xsl:param name="fac_loc"/>
      <xsl:param name="fac_loc_pro"/>
      <xsl:param name="file_type"/>

      <xsl:variable name="all"><xsl:copy-of select="doc($fac_loc)/list"/></xsl:variable>
            <xsl:for-each select="$all/list/file">
                  <xsl:variable name="file_name"><xsl:value-of select="."/></xsl:variable>
                  <xsl:if test="not(($file_name='_leftnav.inc') or ($file_name='_properties.inc') or ($file_name='index.pcf'))">
                        <xsl:variable name="xml_available" as="xs:boolean"><xsl:copy-of select="unparsed-text-available(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))"/></xsl:variable>
                        <xsl:variable name="html_available" as="xs:boolean"><xsl:copy-of select="unparsed-text-available(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.',$file_type)))"/></xsl:variable>
                        <xsl:if test="$xml_available = true() and $html_available = true()">
                              <faculty>
                                   <title><xsl:value-of select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/title/node()"/></title>
                                    <sub-heading><xsl:value-of select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/sub-heading/node()"/></sub-heading>
                                    <image><xsl:value-of select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/image/node()"/></image>
                                   <bio><xsl:value-of disable-output-escaping="yes" select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/bio/node()"/></bio>
                                   <link><xsl:value-of select="concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.html'))"/></link>
                              </faculty>
                        </xsl:if>
                  </xsl:if>
            </xsl:for-each>
</xsl:function>

Editing the Function

The function has to be edited to add the education data to the index page. To complete the function, the nodes for the transformation need to be declared. In order to pull a node value from another document, the doc function is used.
  1. Navigate to /_resources/xsl/functions.xsl.
  2. Edit the file.
  3. Find <xsl:function name="ou:faculty-listing>".
  4. Locate the <xsl:if> (after the variables declarations) that is testing if the HTML and XML are available.
    <xsl:if test="$xml_available = true() and $html_available = true()">
  5. Locate the <faculty> node between the opening and closing <xsl:if>.
  6. Between the open and closing <faculty> tags there are existing nodes (corresponding to the MultiEdit fields for the faculty profile; for example, <title>, <image>, and <bio>. The code snippet to add will do the following:
    —Generate an <education></education> node and get the value of the education node added to the profile xml.
    —Parse the documentation on the production server using the doc function and specify the appropriate Xpath to the <education> node.
    Add the code snippet:
    <education>
    <xsl:value-of select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/education/node()"/>
    </education>
  7. Save the changes.
<faculty>  
      <title><xsl:value-of select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/title/node()"/></title>
      <image><xsl:value-of select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/image/node()"/></image>
      <bio><xsl:value-of disable-output-escaping="yes" select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/bio/node()"/></bio>
      <link><xsl:value-of select="concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.html'))"/></link>
<education><xsl:value-of select="doc(concat($fac_loc_pro,'/',concat(substring-before($file_name,'.pcf'),'.xml')))/root/education/node()"/></education>
</faculty>

Testing Configuration and Updates

The files have all been configured to transform the faculty pages. Publish the faculty directory to update the indexing for the individual pages. To test that all of the code is working as expected, navigate to index.pcf. When previewed, the page should now display a list of faculty members, including the newly created faculty profile. Publish the page to verify that the page looks as expected on production as well.