7.1. Working with External Stylesheets

Several elements in XSLT are used specifically to access stylesheets and template rules that are external to the current (or calling) stylesheet. These elements are <xsl:include> and <xsl:import>, which are the top-level elements used to bring in the external stylesheets, and <xsl:apply-imports>, which is an instruction element used specifically to choose an imported template rule over those in the current stylesheet.

7.1.1. The <xsl:include> Top-Level Element

The <xsl:include> element is used to access and incorporate the contents of another stylesheet into the current, or calling, stylesheet. It can be used anywhere in an XSLT stylesheet as long as it is a direct child of the <xsl:stylesheet> or <xsl:transform> document element. The <xsl:include> top-level element is an empty element, as shown in the following element model definition. It has one required attribute, href, whose value is a URI reference to an external stylesheet that will be included at the point of that the <xsl:include> element is used.

<!-- Category: top-level-element -->
<xsl:include
  href = uri-reference />

When the XSLT processor finds the XSLT stylesheet referenced by the href attribute's value, the top-level elements of that referenced XSLT stylesheet are inserted into the current stylesheet, literally in place of the <xsl:include> element. It inserts the entire included stylesheet—minus its PI and <xsl:stylesheet> or <xsl:transform> document element—as though it was originally part of the stylesheet in which the <xsl:include> element was invoked.

As an XML or SGML reference, the <xsl:include> element acts very much like an entity reference. When the parser sees the entity reference, it goes and resolves the entity and replaces the reference with the content of the entity.

7.1.1.1. Conditions Affecting Included Top-Level Elements

There are a variety of contingencies that can affect the behavior of included top-level elements when <xsl:include> is invoked, such as references to relative URIs in the included elements and namespace declarations from the XSLT stylesheet being included.

The simplest way to think of the included elements when <xsl:include> is invoked is to remember that they retain all the characteristics of their “home” stylesheet. The included top-level elements function like top-level elements of the including stylesheet to begin with, but they retain the relative paths in their URIs. For example, if the included elements reference a file in the home directory in which the stylesheet being included is found, it keeps the reference to that file's location. They also retain namespace declarations and any version, extension-element-prefixes, and exclude-result-prefixes of the home stylesheet.

The only exception is in the case of an <xsl:import> top-level element that is part of the included elements. What happens if one of the top-level elements being included is an <xsl:import> element? Following the rules for <xsl:import>, discussed in Section 7.1.2, the imported elements among the included elements of the XSLT stylesheet referenced with <xsl:include> are treated as though they were imported in the original stylesheet.

For example, if stylesheet main.xsl has an <xsl:include> element that points to included.xsl, and included.xsl has an <xsl:import> element that points to imported.xsl, then any top-level elements from xsl.imported will be treated as though they were referenced by an <xsl:import> element in main.xsl. The imported elements referenced by included.xsl “leap-frog” the stylesheet, importing them to behave as though they were in the original main.xsl stylesheet in which the <xsl:include> element that triggered this triple-chain was invoked in the first place. We will discuss this in more detail in the comparisons between <xsl:include> and <xsl:import> in Section 7.1.3.

7.1.1.2. Using the <xsl:include> Top-Level Element

The use of <xsl:include> enables an enterprise to boilerplate certain features of its stylesheets. Grouping stylesheets based on their functionality allows them to be shared and reused. For instance, in the ongoing series of examples with Markup City, we may need to have several different versions of an XSLT stylesheet, perhaps to prepare reports for several different agencies. This might be the case again with the area of town accessed via the <parkway>. Instead of several different stylesheets, which may be very large and difficult to maintain, we could have several modular stylesheets, each with its own title format. In Example 7-1 we show one such module stylesheet being included into a “main” stylesheet.

Example 7-1. Using <xsl:include> to add a separate stylesheet.
							NPUT:

<?xml version="1.0"?>
<parkway>
      <thoroughfare name="Governor Drive" />
      <thoroughfare name="Whitesburg Drive">
           <sidestreet name="Bob Wallace Avenue">
           <block name="1st Street"></block>	
                 <block name="2nd Street"></block>
                 <block name="3rd Street"></block>
           </sidestreet>
           <sidestreet name="Woodridge Street">
           </sidestreet>
      </thoroughfare>
      <thoroughfare name="Bankhead Drive">
           <sidestreet name="Tollgate Road">
                 <block name="First Street"></block>
                 <block name="Second Street"></block>
                 <block name="Third Street"></block>
           </sidestreet>
           <sidestreet> Oak Drive </sidestreet>
      </thoroughfare>

</parkway>
MAIN STYLESHEET:

<?xml version="1.0"?>
<!-- FILE NAME main.xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
           version="1.0">
<xsl:include href="audit.xsl" />
<xsl:template match="parkway">
      <html>
      <body>
            <xsl:call-template name="doc-title" />
      <dl>
            <xsl:apply-templates/>
      </dl>
      </body>
      </html>
</xsl:template>
<xsl:template match="sidestreet">
            <dt>

                   <xsl:value-of select="@name | text()"/>
            </dt>
            <dd><ul>
                   <xsl:apply-templates select="block" />
            </ul></dd>
</xsl:template>
<xsl:template match="block">
      <li>
            <xsl:value-of select="@name | text()"/>
      </li>
</xsl:template>
      </xsl:stylesheet>
INCLUDED STYLESHEET:

<?xml version="1.0"?>
<!-- FILE NAME audit.xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0"
                        >
<xsl:template name="doc-title">
      <center>
            <h1>Prepared for the Auditor's Office</h1>
            <h2>Borough of Monte Sano Boulevard</h2>
      </center>
</xsl:template>
</xsl:stylesheet>

The person running the scripts only needs to change one line, the <xsl:include> element in the main XSLT stylesheet, to include the correct stylesheet for the title for each report. Additional title stylesheets, as shown in Example 7-2, can be easily swapped out using the correct value for <xsl:include>.

For all intents and purposes, the main stylesheet and the included stylesheet are combined into one by the XSLT processor. After the first pass through the XSLT processor, which checks the basic logical structure of the XSLT elements for being a well-formed XML data instance, the <xsl:include> element URIs are resolved, or “looked up.” The children of the document element of the included stylesheet—in other words, its top-level element(s)—are then inserted in place of the actual <xsl:include> element. This does not mean that the original XSLT stylesheet that used <xsl:include> has itself been transformed. Instead, to the processor's perception—or, more accurately, parsing—of the resulting XSLT stylesheet, there is a new template rule, extracted from the external stylesheet, in place of where <xsl:include> was to begin with.

7.1.2. The <xsl:import> Top-Level Element

The <xsl:import> top-level element is used to bring in elements from another stylesheet, similar to <xsl:include> discussed in the previous section. There are some basic differences between the two, however. The <xsl:import> top-level element must always come first among the children of the <xsl:stylesheet> or <xsl:transform> document element when it is used. Also, the templates found in an imported stylesheet have a lower precedence than templates found in an included stylesheet.

Example 7-2. Additional modular stylesheets for report titles.
						OPTIONAL STYLESHEET 1:

<?xml version="1.0"?>
<!-- FILE NAME mayor.xsl -->

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 version="1.0" >

<xsl:template name="doc-title">
      <center>
            <h1>Prepared for the Mayor's Office</h1>
            <h2>Borough of Monte Sano Boulevard</h2>
      </center>
</xsl:template>
</xsl:stylesheet>

OPTIONAL STYLESHEET 2:

<?xml version="1.0"?>
<!-- FILE NAME utilities.xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0" >

<xsl:template name="doc-title">
      <center>
             <h1>Prepared for the Water Utilities Office</h1>
             <h2>Borough of Monte Sano Boulevard</h2>
      </center>
</xsl:template>
</xsl:stylesheet>

The <xsl:import> top-level element is an empty element, which is optional and repeatable. It has one required attribute, href, as shown in the following element model definition:

<!-- Category: top-level-element -->
<xsl:import
  href = uri-reference />

The <xsl:import> element uses its single required href attribute to retrieve the contents of an external XSLT stylesheet. The href attribute value is a URI pointing to another XSLT stylesheet.

Before addressing any elements in a stylesheet, the XSLT processor builds a tree of the stylesheet. All <xsl:import> elements are retrieved from the location specified in the href attribute and placed in the tree at the point where the <xsl:import> element was found in the original stylesheet. Once this stylesheet tree is built, the processor continues.

7.1.2.1. The Import Process

The use of <xsl:import> is essentially the same as given above for <xsl:include>, except that the imported elements come first in the importing XSLT stylesheet. This does not mean that they come first in priority or precedence in the event of competing or conflicting template rules, as discussed in Section 7.2.2. In fact, imported top-level elements are automatically considered last in priority to any top-level elements of the calling stylesheet. Imported top-level elements are also prioritized below any top-level elements included with <xsl:include>.

The top-level elements referenced by <xsl:import> are placed first in the calling XSLT stylesheet. When an XSLT processor operates on an XSLT stylesheet, the order of procedure is as follows.

1.
The XSLT stylesheet is parsed and checked for whether it is a well-formed XML data instance.

2.
Any external stylesheets referenced by <xsl:import> are accessed and their corresponding top-level elements are imported, provided the imported XSLT stylesheet itself is a well-formed XML data instance.

3.
Any top-level elements of external stylesheets referenced by <xsl:include> are included.

4.
This complete set of top-level elements is checked for conflicts and resolved according to the conflict resolution model presented in Section 7.2.2.

The imported top-level elements retain their base URI, namespace declarations, version, and extension-element-prefix and exclude-result-prefix attribute characteristics declared in the <xsl:stylesheet> or <xsl:transform> document element of their home XSLT stylesheet.

Again, if any elements of the imported set of top-level elements are themselves imported elements, they are treated as though referenced by an <xsl:import> element in the original importing XSLT stylesheet.

7.1.3. Comparing the <xsl:import> and <xsl:include> Top-Level Elements

The comparison between <xsl:import> and <xsl:include> is primarily based on the matter of conflict resolution. The simplest summary of their difference is that top-level elements brought into an XSLT stylesheet using the <xsl:import> element have lower precedence than the importing stylesheet's top-level elements or any top-level elements included with the use of <xsl:include>.

Remember that <xsl:include> effectively inserts additional top-level elements into the stylesheet in which it is invoked. The href attribute of <xsl:include> directs the XSLT processor to go to the URI given as its value, and from the stylesheet at that URI, the top-level elements are taken and put in place of—in other words, at the same point in the including XSLT stylesheet—the <xsl:include> element. The <xsl:import> element does this also, but with two distinctions. First, the <xsl:import> element comes first in document order in the XSLT stylesheet in which it is invoked. Therefore, the top-level elements from the XSLT stylesheet being imported come first. Second, the <xsl:import> top-level elements are not ranked above any top-level elements of the importing stylesheet.

The top-level elements brought into an XSLT stylesheet using <xsl:import> and <xsl:include> are the same in that they both retain the base URI, relative URIs, namespace declarations, and so forth of the included or imported top-level elements. In other words, the top-level elements combined into any XSLT stylesheet always retain all of their home stylesheet's—the stylesheet from which they were either included or imported—characteristics. As noted, the top-level elements referenced by way of <xsl:import>, when <xsl:import> is part of the elements included with <xsl:include>, are treated differently.

The basic thing to remember is that all <xsl:import> elements are resolved and placed at the front of the importing stylesheet before any further processing of additional elements is done.

The best way to explain this set of contingencies for conflict resolution and general import, and include procedures, is with a simplified example.

Consider that we have a primary XSLT stylesheet, called primary.xsl, and three referenced stylesheets, as shown in Example 7-3. The additional stylesheets are located in the same directory as primary.xsl to simplify their reference.

Example 7-3. Using imported and included stylesheets.
						PRIMARY STYLESHEET:

<?xml version="1.0"?>
<!-- Primary Stylesheet primary.xsl -->
<xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
<xsl:import href="imported.xsl" />
<xsl:template match="/" priority="1">
      <p>I'm the content of the original
      template in primary.xsl.</p>
</xsl:template>
<xsl:include href="included.xsl" />
</xsl:stylesheet>

IMPORTED STYLESHEET:

<?xml version="1.0"?>
<!-- Imported Stylesheet imported.xsl -->
<xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
<xsl:template match="/">
      <p>I'm the content of imported.xsl. </p>
</xsl:template>
</xsl:stylesheet>

NCLUDED STYLESHEET:

<?xml version="1.0"?>
<!-- Included Stylesheet included.xsl -->
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:import href="import2.xsl" />
<xsl:template match="/">
      <p>I'm the content of included.xsl.</p>
</xsl:template>
</xsl:stylesheet>
2nd IMPORTED STYLESHEET:

<?xml version="1.0"?>
<!-- 2nd Imported Stylesheet import2.xsl -->
<xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
<xsl:template match="/" priority="2">
      <p>I'm the content of import2.xsl.</p>
</xsl:template>
</xsl:stylesheet>

In the primary stylesheet above, we declared a priority value of 1 for the template. Each of the additional three XSLT stylesheets is referenced directly or indirectly by the primary.xsl stylesheet. The imported.xsl and included.xsl stylesheets are referenced directly in the primary.xsl stylesheet, but their templates do not have a priority set. The second imported stylesheet, import2.xsl, is referenced in included.xsl, and contains a template with a priority of 2.

Now, we will look at what happens to primary.xsl when all the imports and includes are resolved. Example 7-4 gives all the resulting contents, the imported and included top-level elements of primary.xsl to which the conflict resolution model must be applied. It is important to remember that the following is not meant to indicate that primary.xsl itself has changed in any way, but that once resolved, the <xsl:import> and <xsl:include> top-level elements have been “replaced” by the top-level elements of the stylesheets to which their href attributes referred. Therefore, we have put those referenced top-level elements that are being included and imported in place of the <xsl:import> and <xsl:include> elements that referenced them. We've also added comments that would not normally result from this process, but that help orient you to the origin of the material. Note that Example 7-4 is for demonstration purposes only—to demonstrate how primary.xsl “looks” to the XSLT processor after imports and includes are done.

Example 7-4. The parsed primary.xsl stylesheet.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
<!-- The top-level elements from the imported.xsl XSLT
						stylesheet come first because the <xsl:import> element comes
						first itself. Therefore, from the perspective of the XSLT
						processor, this template rule, the only top-level element
						imported.xsl, has effectively "replaced" the <xsl:import>
						element which references it. -->
<xsl:template match="/"><p>I'm the content of imported.xsl. </p>
</xsl:template>

<!-- This is the import2.xsl file, which was referenced in
						the included.xsl file. It comes at the beginning in document
						order because imported top-level elements from included files
						are treated as if they were referenced by an <xsl:import>
						element in the original including stylesheet. In other words,
						in this case, the contents of import2.xsl, referenced by
						included.xsl, are presented as though primary.xsl itself
						contained the <xsl:import> element used in included.xsl. The
						other top-level elements of included.xsl come below in the
						same document order of primary.xsl, in which the
						<xsl:include> was declared.  -->
      <xsl:template match="/" priority="2">
            <p>I'm the content of import2.xsl.</p>
      </xsl:template>
<!-- This is the original template rule of primary.xsl -->
<xsl:template match="/" priority="1">
      <p>I'm the content of the only
template in primary.xsl.</p>
</xsl:template>
<!-- This is the top-level element from included.xsl, which was
						included by means of the <xsl:include> element in primary.xsl,
						last in document order. One of its top-level elements, this
						template rule, is included here in place of the <xsl:include>
						element that referenced it. The other top-level element, which
						referenced the import2.xsl stylesheet that was also part of
						included.xsl, was moved up in document order as though it was
						an <xsl:import> that was part of primary.xsl. -->
<xsl:template match="/">
      <p>I'm the content of included.xsl. </p>
</xsl:template>
</xsl:stylesheet>

Most of the criteria for determining which template rules are placed where in the resulting pseudo-stylesheet above were explained in the intervening comment sections.

Regarding the matter of conflict resolution, notice that in each case, the <xsl:template> element's match attribute is the same, matching the root or document root with / as an abbreviation. There are therefore four conflicting template rules. This can be simply resolved by the criteria mentioned in Section 7.2.2. In the case of both the imported.xsl template rule and the import2.xsl template rule, they are automatically removed from contention for top priority by virtue of being imported top-level elements. If there are no priority attributes defined, the last template rule in the stylesheet (after all includes and imports have been resolved) is selected. This “order rule” of template selection can be overridden using the <xsl:apply-imports> instruction element, discussed in Section 7.1.4, by effectively reinserting the imported template at that location.

Any imported top-level element that conflicts with another non-imported top-level element will always lose out. This is true even when the template has a priority value higher than any other template in the stylesheet, as in our example, where import2.xsl has a template with a declared priority of 2. Again, the fact that the template rule from import2.xsl is imported (by virtue of being an import into the included.xsl file) obviates any stated priority with the priority attribute. Also, using <xsl:apply-imports>, discussed in the next section, does not change this implicit priority. An imported template with a higher priority attribute value cannot override any conflicting non-imported template rule. Internal templates will always have priority over external templates—imported or included—regardless of the priority given to the imported or included templates.

This leaves the original template rules from primary.xsl and included.xsl as "contenders" for priority among the four templates. In the case of the declaration of priority, even if the number is 1—or, for that matter, 1000—a declared priority will take precedence over a template with no priority attribute. Therefore—the envelope, please…—the one template of all four that will be invoked is the content of the primary.xsl, which stipulates a priority attribute.

Note

Some parsers may not support more than two nested levels of included or imported files. For example, in the previous example, XT returns a different value when included.xsl contains an imported (import2.xsl) stylesheet.


7.1.4. The <xsl:apply-imports> Instruction Element

The <xsl:apply-imports> instruction element is used to effectively “requery” imported templates to find one that matches the current template rule's match. It allows a nesting of another template inside the calling template.

The <xsl:apply-imports> element has no attributes and is an empty element, as shown in the following element model definition. It can only be used inside a template, and is categorized as an instruction element.

<!-- Category: instruction -->
<xsl:apply-imports />

The <xsl:apply-imports> element searches for an imported template rule with the same match criteria as the <xsl:template> element that calls it. For example, if a template rule is matching on "thoroughfare," <xsl:apply-imports> in that template rule will search for an imported template with a match value of "thoroughfare," as shown in Example 7-5.

The main stylesheet is doing the basic formatting for the lists, and the imported templates add titles for each thoroughfare and boulevard. We add an <xsl:import> element to the main stylesheet to import title.xsl and an <xsl:apply-imports> in the thoroughfare and boulevard template rules to use the contents of the imported templates.

The <xsl:apply-imports> effectively takes the content of the template rule in the imported stylesheet and uses it at the point it is called. The imported template does not affect the contents of the original template rule. They are both processed in order.

If there are several imported template rules that match the same criteria, the processor uses the same priority selection rules as a normal stylesheet, except that only the imported templates are checked.

Example 7-5. The using <xsl:apply-imports> to call an imported template.
						MAIN STYLESHEET:

<?xml version="1.0"?>
<xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
<xsl:import href="title.xsl" />

<xsl:template match="/">
      <html>
      <body>
             <xsl:apply-templates/>
      </body>
      </html>
</xsl:template>

<xsl:template match="thoroughfare">

             <xsl:apply-imports/>
      <ul>
             <xsl:apply-templates/>
      </ul>
</xsl:template>

<xsl:template match="boulevard">

             <xsl:apply-imports/>
      <ul>
             <xsl:apply-templates/>
      </ul>
</xsl:template>


<xsl:template match="sidestreet | block">
      <li>
             <xsl:apply-templates/>
      </li>
</xsl:template>

</xsl:stylesheet>

IMPORTED STYLESHEET:
<?xml version="1.0"?>
<!-- imported stylesheet title.xsl -->
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="thoroughfare">
      <center>
             <h1>Listing for <xsl:value-of select="@name |
text()"/></h1>
      </center>
</xsl:template>
<xsl:template match="boulevard">
      <center>
             <h1>Listing for the Boulevard</h1>
      </center>
</xsl:template>
</xsl:stylesheet>

OUTPUT:

<html>
<body>
<center>
<h1>Listing for Governor Drive</h1>
</center>
<ul>Governor Drive</ul>
<center>
<h1>Listing for Whitesburg Drive</h1>
</center>
<ul>
<li>Bob Wallace Avenue</li>
<li>Woodridge Street</li>
</ul>
<center>
<h1>Listing for Bankhead</h1>
</center>
<ul>
<li>Tollgate Road</li>
<li>Oak Drive</li>
</ul>
<center>
<h1>Listing for the Boulevard</h1>
</center>
<ul>
<li>Panorama Street</li>
<li>Highland Plaza</li>
<li>Hutchens Avenue</li>
<li>Wildwood Drive</li>
<li>Old Chimney Road</li>
<li>Carrol Circle</li>
</ul>
</body>
</html>

The <xsl:apply-imports> element is not a recursive rule like <xsl:apply-templates>, which looks for the children of the current element. However, if the included template contains an <xsl:apply-templates> element, the children will be processed at that point.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.254.138