[This local archive copy (text only) mirrored from the canonical site: http://www.microsoft.com/xml/xsl/tutorial/tutorial.htm, 980127; links may not have complete integrity, so use the canonical document at this URL if possible.]

XSL Tutorial

January 7, 1998

Lesson #1: What is XSL?

XSL is a stylesheet language designed to be used with XML data and documents. A few words about XML will help make the need for XSL clear.

XML allows data or content to be marked up using tags invented by the author. The tag names can then provide author-specified information about the content within the tags. For instance, if I wanted to add "change-date" information to an HTML document, I would have to put it in a paragraph, table cell, or some other element that HTML has already provided:

<P>3 October 1997</P>

However, when someone else (or some program) looks at the document, all they see is the paragraph or table cell with some text in it. Even if one could recognize the string '3 October 1997' as a date, one would have no idea what that date represents. Is that date a birth date? a creation date? an expiration date? In fact, the line above really only indicates that the string of characters '3 October 1997' should be displayed as a paragraph.

In an XML document, I can mark up the date with tags that better describe what that date is:

<change-date>3 October 1997</change-date>

Now when someone looks at my document, they can better tell the meaning of the string within the tags: it represents a "change date".

Such descriptive mark-up, or "semantic" mark-up, is a key goal of XML. With XML, Web authors can now mark up their content or data "semantically," according to the meaning of the data. Consequently, they can better communicate the relevance of their content or data.

Once the "change-date" has been "semantically" marked up, however, it no longer conveys any information about how the content is to be displayed. Should the date be presented as a paragraph or a table cell? Is it a data point in a graph? Should it be displayed at all? Unlike HTML, which defines the display behavior for each of its elements, XML says absolutely nothing about how the data is to be displayed.

This is where XSL comes in. XSL allows the author to apply formatting operations to XML elements. XSL is a language in which the author can indicate that the 'change-date' element should be displayed as a paragraph, in blue, and in italic. XSL is not the only way to display XML data. However, it provides you with a simple declarative solution. Also, because XSL syntax is XML itself, you don't have to learn a whole new syntax to begin writing XSL stylesheets.

What is the difference between a "tag" and an "element"?
In XML (and HTML), "tags" are used to define an "element." An element is comprised of 1) a "start tag" (such as <change-date>) which describes the contents of the element, 2) the contents of the element (such as the text "3 October 1997"), and 3) an "end tag" (such as </change-date>) which closes the element. Often, HTML authors refer to "elements" as "tags," but it is important to understand that a "tag" is only a part of the whole "element."
What is the difference between CSS and XSL?
CSS is a stylesheet language that may also be used with XML. But with CSS, the basic structure of the document cannot be dramatically altered. CSS essentially maps each XML element into a single display object with certain display characteristics (or properties). XSL, in comparison, allows a single XML source element to be mapped into a more complex hierarchy of display objects. For instance, XSL can add a legal disclaimer to the end of a document, generate a table of contents, and calculate and display chapter and section numbers. In addition, XSL is made extensible through script, flow object macros (not yet implemented) and extensible flow object types (not yet implemented).

Lesson #2: How does XSL work?

The XSL processor uses an XSL stylesheet to transform XML data into an HTML document. From the command line, the XSL processor is given an XML data file followed by an XSL stylesheet. It then takes those two files and uses them to produce an HTML file:

Figure 2: The XSL processor combines the content (XML) with presentation information (XSL) to generate an output document.

The content of the newly created HTML file comes from the XML data source; the display structure of the newly created HTML file comes from the XSL stylesheet. In processing the two files, the XSL processor examines the XSL stylesheet to discover which display structure applies to which XML source elements. As a result, the XSL processor creates a display structure that is driven by the content of the XML data source, and yet can be wholly independent of that source's structure.

The syntax for XSL is based on XML, and the display structures you will construct with XSL will consist of many familiar HTML flow objects. Learning XSL, therefore, does not require learning a new language. You can build on your existing knowledge of XML and HTML, enabling you to become fluent in XSL quite quickly.

Is HTML the only output format?
XSL is designed to apply style independently of the output format. Thus, a single stylesheet could be used to generate HTML, RTF, raw text, etc. In the Microsoft XSL Processor Technology Preview Release, we only support the generation of HTML output.
Note: The Microsoft XSL Processor is based on the Proposal for XSL submitted to the W3C (see http://www.w3.org/TR/NOTE-XSL.html Non-MS link). Areas not implemented in this release include children patterns, flow object macros, named styles, the DSSSL flow objects, class and id definitions, importance and priority attributes, units in ECMAScript, and the importing of stylesheets.

Lesson #3: What is an XSL Stylesheet?

The basic building block of XSL is the construction rule. A construction rule describes how a particular element is to be transformed into displayable output. The construction rule consists of two parts: a pattern identifying a type of XML source element and an action describing what to do with elements that match this pattern.

The graphic below represents the role of the construction rule in the process which transforms XML data into an HTML document. Notice how the pattern identifies a single source element at a time and the action transforms that single source element into a display structure within the HTML document. An important concept behind XSL is that it uses rules to create display structures from individual source elements.

Figure 3: A construction rule maps an element in the source document to a structure of output elements.

The following stylesheet is an example of an XSL stylesheet's basic structure. The stylesheet in this particular example has a single construction rule which displays the contents of a <change-date> element as a blue, italic paragraph:

<xsl> <rule> <target-element type="change-date"/> <P color="blue" font-style="italic"> <children/> </P> </rule> </xsl>

Note: The above example uses CSS properties on its flow objects. CSS properties may be applied directly as attributes. See the Flow Objects lesson for more information.

The pattern in the above case (<target-element type="change-date">) "targets" (applies to) <change-date> elements.

The action in the above case (<P color="blue" font-style="italic"><children/></P>) indicates that the contents of the <change-date> element should be placed within a <P> element and that the <P> element should have the attribute style="color:blue;font-style:italic".

Now let's see what happens when you process an XML document using an XSL stylesheet.

Processing the following XML document

<document> <change-date>3 October 1997</change-date> </document>

using the XSL stylesheet above, the <change-date> element will result in the following HTML code:

<P STYLE="color:blue; font-style:italic">3 October 1997</P>

The XML source document drives the transformation process. The XSL processor goes through the source document element by element and, for each one, looks through the stylesheet for an applicable rule. This is essentially a "recursive" process.

Recursion is a common programming technique that allows complex tasks to be broken down into manageable pieces. In XSL, the "manageable piece" is the construction rule, which defines how a single element is transformed into a piece of formatted output. Because of recursion, the XSL processor is able to construct complex final output from a few simple rules.

Do XSL construction rules cascade like CSS rules?
No. Since CSS is not changing the structure of the document, it is easy to describe how these properties can be merged, or "cascaded," into a single set of property values. XSL construction rules define a new structure for the output, so there is no easy way to merge structures and still get predictable results. Thus only one construction rule is processed per source element. The best rule is selected among applicable rules using an arbitration process. Although only one construction rule can be processed per element, style properties can still be merged using style rules. See the lessons on Rule Arbitration and Style Rules for more information.

Lesson #4: Defining a Pattern

The construction rule contains at least one <target-element> element. This <target-element> element identifies the elements from the XML source document to which the construction rule applies. The most basic form of a pattern matches XML source elements of a certain type without regard to the context of those elements:

<target-element type="title"/>

The above <target-element> element matches <title> elements in the XML source document. In the following example, the above pattern is combined with an action dictating that all elements that match the pattern are to be displayed in a italic span.

<rule> <target-element type="title"/> <SPAN font-style="italic"> <children/> </SPAN> </rule>

Often it is important to describe the element's context as well as its type. For the following XML document

<document> <change-date>3 October 1997</change-date> <section> <title>What's new?</title> <new-item> <title>Press Reports</title> </new-item> <new-item> <change-date>27 September 1997</change-date> <title>Schedule</title> </new-item> </section> </document>

we may want the <title> to be formatted differently depending on its position within the document. For instance, section titles should probably be formatted differently from new-item titles.

Ancestor relationships can be identified through the <element> element. If we include the parent of the target element in the pattern, we can distinguish between the title of the <section> element and the title of the <new-item> element. We can then apply distinct formatting characteristics to <title> elements in these different contexts. According to the following XSL stylesheet, the section title is to be formatted as a blue, italic paragraph, while the new-item title is to be formatted as a bold span.

<xsl> <rule> <!-- pattern matches only <title> elements within <section> elements --> <element type="section"> <target-element type="title"/> </element> <P color="blue" font-style="italic"> <children/> </P> </rule> <rule> <!-- pattern matches only <title> elements within <new-item> elements --> <element type="new-item"> <target-element type="title"/> </element> <SPAN font-weight="bold"> <children/> </SPAN> </rule> </xsl>

The <element> element used in the above stylesheet describes a parent relationship in the source context that must be present for the pattern to match.

While there can only be one <target-element> element in a pattern (after all, the pattern identifies a single type of XML source element), there may be multiple <element> elements, representing multiple levels of ancestors. The following pattern is valid XSL (although it would be unusual to create a pattern even this extensive):

<!-- pattern matches the <month> element of a <change-date> element which is a child of a <new-time> element that lies within a <section> element of a <document> element--> <element type="document"> <element type="section"> <element type="new-item"> <element type="change-date"> <target-element type="month"/> </element> </element> </element> </element>

Note: Currently, XSL only provides for parent-child relationships. Sibling relationships are not defined. This means that each <element> element may only have a single <element> or <target-element> child.

Patterns can also include attributes, wildcards, and other pattern qualifiers. We will learn more about these and the pattern's other features in later lessons.

Lesson #5: Defining an Action

When a pattern identifies (or matches) a type of XML source element, the action portion of the rule is used to create the formatted output. The action describes what the output structure should be, what formatting properties to apply, and how to process the children of the source element.

The following rule includes a basic action that places the contents of the target elements into <DIV> elements. <DIV> represents a specific kind of formatting operation or formatted output. In this case, <DIV> represents the functionality of the HTML <DIV> element.

<rule> <target-element/> <DIV> <children/> </DIV> </rule>

Now let's step through how the XSL processor would apply the above rule to the following XML source.

<document> <chapter> <title>XSL Overview</title> <topic>Overview of XSL and its extensibility</topic> </chapter> </document>

First, note that the pattern will match any element because an element type is not specified (see Wildcards Non-SBN link).

Second, the action (<DIV><children/><DIV>) will be applied to each matching element. The <children/> element informs the processor to "insert the results of processing the target element's children here" (in this case, within the <DIV> element). Beginning with the <document> element, the <children/> action outputs the "result of processing" the <chapter> element. Of course, in order to determine what this result will be, the processor must first process the <chapter> element according to the appropriate rule (in this case, the same one).

Here is where the recursive process really takes off. For, "the result of processing" the <chapter> element is "the result of processing" the <title> element followed by "the result of processing" the <topic> element.

Likewise, the result of processing the <title> element is "the result of processing" the text "XSL Overview." And, as you might now expect, the result of processing the <topic> element is "the result of processing" the text "Overview of XSL and its extensibility."

This process concludes with the processing of the text, which returns the text itself.

The XSL processor does quite a bit of work during the recursive process. And because it works so hard, we don't have to. In the above example, the recursive process allows us to write one rule and have our entire document processed. Even if this document contained many more chapters, thanks to the recursive process, we could still process the document using the same simple rule.

Let's now look at the final result of this process. The following code is the HTML created by the processor after it has completed the recursive process.

<DIV> <DIV>XSL Overview</DIV> <DIV>Overview of XSL and its extensibility</DIV> </DIV>

The above example may seem trivial, but what we have just done is transformed XML that is semantically marked up into a structure based on display characteristics. By just changing the type of output objects and their style properties, we can generate very complex output using the same simple set of rules. In addition, as our documents get more complex, the same simple rules remain adequate to process them.

Lesson #6: Flow Objects

The action does not directly create HTML, but it does create an intermediate structure consisting of flow objects, each describing a specific formatting task to apply to the content. The following rule contains three flow objects (<DIV>, <HR>, <P>):

<rule> <target-element type="short-story"/> <DIV font-size="12pt" font-family="Verdana"> <HR/> <children/> <HR/> <P text-align="center">The End</P> </DIV> </rule>

As you would expect, the above example will result in the creation of an HTML document with <DIV>, <HR>, and <P> elements. XSL's inclusion of the HTML/CSS flow objects (see DHTML Reference Non-SBN link) is designed to make it obvious what the final output will be (since we are familiar with the specific formatting tasks that HTML provides). However, it is important to note that although the flow objects can look like HTML elements, there are some subtle, yet critical, syntactic differences:

  1. HTML "flow object" elements must conform to XML syntax:
    • Elements with omitted end tags must be closed, e.g. <IMG src="image.jpg"/>.


    • End tags are required even where considered optional in HTML, e.g. <P>Text</P>.

      Affects: DD, DT, LI, OPTION, P, TD, TH, THEAD, TR.

    • All attribute values must be in quotes, e.g. <TD ALIGN="left">.
    • Valueless attributes must be assigned values, e.g. <OL COMPACT> becomes <OL COMPACT="">, <OL COMPACT="yes">, or <OL COMPACT="TRUE">. The value is not important; XML just requires that one be specified.


    • XML is case sensitive. Therefore, by convention all HTML tags and attribute names should be in uppercase.

      This convention ensures that all HTML tags and attributes can be passed through to the output and remain unchanged. Ignoring this convention with attributes risks conflicts in a few cases between HTML attributes and CSS properties of the same name (see below).

  2. For your convenience, CSS properties may be applied using the "STYLE" attribute, or they may be applied directly as attributes themselves. CSS properties must be in lowercase. Case differences between HTML attributes and CSS properties distinguish which output should be generated.

Attributes corresponding to CSS properties are listed below. The values of these attributes are detailed in the CSS specification and documentation (see Cascading Style Sheets in Internet Explorer 4.0).

CSS properties
font-family, font-style, font-variant, font-weight, font-size, font, letter-spacing, line-height, text-decoration, text-transform, text-align, text-indent, vertical-align, color, background-color, background-image, background-repeat, background-attachment, background-position, background, margin-top, margin-right, margin-bottom, margin-left, margin, padding-top, padding-right, padding-bottom, padding-left, padding, border-top-width, border-right-width, border-bottom-width, border-left-width, border-width, border-top-color, border-right-color, border-bottom-color, border-left-color, border-color, border-top-style, border-right-style, border-bottom-style, border-left-style, border-style, border-top, border-right, border-bottom, border-left, border, float, clear, display, list-style-type, list-style-image, list-style-position, list-style, clip, height, left, overflow, position, top, visibility, width, z-index, page-break-before, page-break-after, filter, word-spacing, white-space
Note: Described within the Proposal for XSL is an alternate set of flow objects that enable more powerful document processing. These flow objects are useful for processing complex documents that require high quality print formatting, multiple writing directions, etc. These objects are a subset of those available in the DSSSL stylesheet language. The DSSSL objects offer more flexible output options, including easier mapping to other output formats like RTF. The Microsoft XSL Processor does not currently support the DSSSL flow objects.

Lesson #7: The Root Rule

The XSL processor begins processing by looking for a special root rule in the stylesheet with which it can process the top-level element in the document.

The root rule is identified by the special predefined pattern <root/>. The following code is an example of a basic root rule.

<rule> <root/> <HTML> <BODY> <children/> </BODY> </HTML> </rule>

The root rule's action determines the top-level flow objects to create. As you've probably already noticed, the above rule would create the basic structure of an HTML document. A construction rule targeting the top-level element would mimic the functionality of the root rule. However, because the root rule is used for special purposes like the one in the above example, it is often convenient to have a <root/> pattern in the rule to allow the rule to stand out.

Are root rules always as simple as the above example?
No. Root rules can contain rather large actions. The above example could be expanded to include a <HEAD> element containing a <TITLE> element, as well as, any generated "front-matter" and "rear-matter" within the body. Often, the root rule defines nearly the entire page, with other rules just formatting certain XML source data for display within that page.

It might be useful at this point to take a look at the root rule in the sample.xsl and alternate.xsl stylesheets. Notice how the rather complex root rule in alternate.xsl describes the basic display structure of the entire document.

Lesson #8: Built-in Rules

If no other rule applies to an element, a built-in rule kicks in. This prevents unknown elements (ones with no appropriate XSL rule) from halting the recursive process. A default rule targets all source elements and applies no formatting to them:

<rule> <target-element/> <children/> </rule>

You don't have to include this default rule in your stylesheet (after all, it's built in). However, you may want to specify your own default rule which defines special processing for elements not handled elsewhere.

Here's one that not only displays in the color blue all unhandled elements, but allows you to run the mouse over the now blue contents of an unhandled element and view its tag name. I often use this during the development of a stylesheet to show me the source elements for which I still need to create rules.

<rule> <target-element/> <SPAN color="blue" title="='&lt;' + tagName + '&gt;'"> <children/> </SPAN> </rule>

Just as there is a built-in default rule, there is also a built-in root rule. If no root rule is specified, the following built-in one will be used.

<rule> <root/> <DIV> <children/> </DIV> </rule>

When generating an entire HTML document (not just a fragment), you will want to override the default root rule with something like this:

<rule> <root/> <HTML> <HEAD> <TITLE> </TITLE> </HEAD> <BODY> <children/> </BODY> </HTML> </rule>

A nice effect of XSL providing built-in default and root rules is that you are always assured of getting output even if your stylesheet is not complete or, even, completely empty.

Lesson #9: Rule Arbitration

When an element matches more than one pattern, the most specific pattern will be used. For instance, a stylesheet may contain the following rules:

<rule> <!-- pattern matches <stock> elements within a <watch-list> element --> <element type="watch-list"> <target-element type="stock"/> </element> <DIV> <HR/> <children/> </DIV> </rule> <rule> <!-- pattern matches any <stock> element --> <target-element type="stock"/> <DIV> <children/> </DIV> </rule>

If you look closely at the above rules, you'll notice that they each target <stock> elements. The question now is which of the two rules is most specific, and, therefore, the most appropriate to apply. Intuitively, the first pattern seems to describe a more specific pattern than the second, for describing an element as a <stock> element within a <watch-list> element seems more precise than simply describing the same element as a <stock> element. So we might expect that the first pattern should take precedence and its corresponding action applied.

Most of the time the decisions made by the XSL processor will match your intuition, as would have been the case with the previous example. However, in tricky situations it may be useful to know how the XSL processor chooses one particular rule over another.

The XSL processor first determines which rules actually apply to a specific element. If there is more than one, it analyzes the patterns in those rules to see which is the most specific. The processor's analysis of each pattern's "specificity" is based on a pre-determined set of criteria.

The XSL processor goes through these steps (in this order) when comparing the "specificity" of the patterns:

Note: The features described in steps 1, 2, 3, and 6 have yet to be implemented.
  1. the pattern with the highest importance value (set by the importance attribute).
  2. the pattern with the greater number of id attributes.
  3. the pattern with the greater number of class attributes.
  4. the pattern with the greater number of <element> or <target-element> elements having a type attribute.
  5. the pattern with fewer wildcards; a wildcard is an any element, an <element> element without a type attribute, or a <target-element> element without a type attribute.
  6. the pattern with the higher specified priority; the priority of a pattern is the priority of the rule that contains it; the priority of a pattern is the value of the priority attribute on the rule that contains it.
  7. the pattern with the greater number of only qualifiers.
  8. the pattern with the greater number of position qualifiers.
  9. the pattern with the greater number of attribute specifications.
Hint: In general, the more descriptive a pattern is (the more ancestors, attributes, qualifiers it has), the more specific the rule is judged to be.

Note that arbitration rules do not always guarantee that a single choice will be made. For instance, two identical patterns cannot be narrowed down to one by the arbitration process. In the case of two rules having identical patterns, the rule closest to the end of the XSL document takes precedence.

Lesson #10: Wildcards

Patterns can contain wildcards in their ancestor relationships. The pattern in the following rule matches every child of the <list> element, regardless of its element type.

<rule> <!-- pattern matches any child of a <list> element --> <element type="list"> <target-element/> </element> <DIV line-spacing="1.2"> <children/> </DIV> </rule>

It is important to point out that the above rule only applies to immediate children of the <list> element. A separate wildcard, <any>, matches zero or more elements in an ancestor context. The following example will match <title> elements that appear arbitrarily deep within the <rear-matter> element.

<rule> <element type="rear-matter"> <any> <target-element type="title"/> </any> </element> <DIV> <HR/> <children/> <HR/> </DIV> </rule>

The following examples show more allowed uses of wildcards.

<!-- pattern matches any element three levels deep in a <table> element --> <element type="table"> <element> <element> <target-element/> </element> </element> </element> <!-- pattern matches any element at all --> <target-element/>

Lesson #11: Attribute Matching

In addition to <element> and <target-element> elements, the pattern can include <attribute> elements. These <attribute> elements can refer to either the target element or to its ancestors.

The following XML document contains two <list> elements with specified attributes.

<list dingbat="step"> <title>How to learn XSL</title> <item>Do the tutorial</item> <item> <list dingbat="number" spacing="compact"> <title>Try it out</title> <item>Play around with sample stylesheets</item> <item>Write your own stylesheets</item> </list> </item> <item>Celebrate</item> </list>

In displaying the above document, we may want to format the <list dingbat="step"> element differently from the <list dingbat="number"> element. For instance, let's say we wanted to create the following output:

How to learn XSL
Step 1 : Do the tutorial
Step 2 : Try it out
( 1 ) Play around with sample stylesheets
( 2 ) Write your own stylesheets
Step 3 : Celebrate

In order to arrive at the above output, we will need to format each <list> element differently. We can do this if we distinguish between the two <list> elements by adding an <attribute> element to the pattern. With <attribute>, we can specify the attribute values that must be present for the pattern to match:

<!-- pattern matches <list dingbat="step"> elements --> <target-element type="list"> <attribute name="dingbat" value="step"/> </target-element> <!-- pattern matches <list dingbat="number"> elements --> <target-element type="list"> <attribute name="dingbat" value="number"/> </target-element>

Once we have distinguished between the two <list> elements, we can then identify <item> elements contained by <list> elements of a certain type:

<!-- pattern matches <item> elements within <list dingbat="number"> elements --> <element type="list"> <attribute name="dingbat" value="number"/> <target-element type="item"/> </element>

At this point, we can now write a stylesheet that will display our data the way we want it displayed:

<xsl> <rule> <target-element type="list"> <attribute name="dingbat" value="step"/> </target-element> <DIV> <children/> </DIV> </rule> <rule> <element type="list"> <attribute name="dingbat" value="step"/> <target-element type="item"/> </element> <DIV margin-left="2em"> Step <eval>childNumber(this)</eval> : <children/> </DIV> </rule> <rule> <target-element type="list"> <attribute name="dingbat" value="number"/> </target-element> <SPAN> <children/> </SPAN> </rule> <rule> <element type="list"> <attribute name="dingbat" value="number"/> <target-element type="item"/> </element> <DIV margin-left="3em"> ( <eval>childNumber(this)</eval> ) <children/> </DIV> </rule> </xsl>

As shown in the examples, <attribute> elements can be placed within any <element> or <target-element> elements. In addition to this, multiple <attribute> elements can be specified for each <element> or <target-element> element.

Once you begin writing XSL stylesheets, you will find it is often useful to know if an attribute has an assigned value without knowing the specific value of that attribute. To do so, instead of using value, use has-value. The possible values for has-value are "yes" or "no":

<!-- pattern matches <list> elements with a "spacing" attribute (of any value) --> <target-element type="list"> <attribute name="spacing" has-value="yes"/> </target-element>

Lesson #12: Qualifiers

There will be times when you will want to define special processing for the first or last elements in a group. XSL provides this functionality with the position qualifier. For instance, the last paragraph of a magazine article often terminates with a little square character or some other dingbat:

<rule> <target-element type="p" position="last-of-type"/> <DIV> <children/> <SPAN font-family="Wingdings">n</SPAN> </DIV> </rule>

In the above rule, the position attribute is used to isolate the last paragraph. Note that even if someone changed the source document (added more paragraphs), the above rule would still apply the desired formatting to the final paragraph. For another example of how the position qualifier can be used to dynamically format an XML document, let's look at the following XML data:

<investments> <bond> <symbol>US</symbol> <price>$100</price> </bond> <stock> <symbol>MSFT</symbol> <price>$136</price> </stock> <bond> <symbol>LA</symbol> <price>$50</price> </bond> <stock> <symbol>IBM</symbol> <price>$104</price> </stock> <stock> <symbol>INTL</symbol> <price>$92</price> </stock> </investments>

Through the use of the position qualifier, three separate rules could be created to apply different formatting to the first, last, and remaining items of a group. In the example below, the first <stock> element is formatted as a <DIV> element containing an <HR> (horizontal rule) element followed by the symbol and price. The middle stocks of the group have no horizontal rule, and the last stock contains the symbol and price followed by the horizontal rule.

<xsl> <rule> <!-- pattern matches the first <stock> element of the group --> <target-element type="stock" position="first-of-type"/> <DIV> <HR/> <children/> </DIV> </rule> <rule> <!-- pattern matches <stock> elements not processed by other rules --> <target-element type="stock"/> <DIV> <children/> </DIV> </rule> <rule> <!-- pattern matches the last <stock> element of the group --> <target-element type="stock" position="last-of-type"/> <DIV> <children/> <HR/> </DIV> </rule> <rule> <!-- don't process <bond> elements --> <target-element type="bond"/> <empty/> </rule> </xsl>

Processing the <investments> element using the above XSL stylesheet, will result in an HTML document that displays the following in your browser:


Of course, you could enhance your "stocks" style sheet by further formatting the <symbol> and <price> elements.

If also inclined, you could display the first child of the <investments> element differently than the rest with the position="first-of-any" attribute:

<rule> <element type="investments"> <target-element position="first-of-any"/> </element> <DIV color="blue"> <children/> </DIV> </rule>

Applying the above rule to the <investments> element would cause the first <stock> element's contents to be displayed in the color blue.

The values of the position qualifier are

  1. first-of-type
  2. last-of-type
  3. first-of-any
  4. last-of-any

The "-of-type" values indicate the element's position relative to sibling elements of the same type, and the "-of-any" values indicate the element's position relative to any sibling elements, regardless of their type.

In addition to position, a pattern may detect whether an element is an only child. This is often useful when applying special formatting for both the first and last items in a group. For instance, there might exist only one item in the group, meaning the item is both first and last. According to the following rule, when there is only one "stock" in the "stocks" group, horizontal rules are added both before and after the children.

<rule> <target-element type="stock" only="of-type"/> <DIV> <HR/> <children/> <HR/> </DIV> </rule>

The values of the only qualifier are:

  1. of-type
  2. of-any

As with the position qualifiers, the "of-type" value indicates uniqueness relative to sibling elements of the same type, and the "of-any" value indicates uniqueness relative to any sibling elements, regardless of their type.

Lesson #13: Multiple Patterns

For convenience, a rule may contain multiple patterns. If any one pattern matches, the action is applied. This saves some typing for similar rules.

<!-- Multiple situations that cause the same outcome --> <rule> <target-element type="emphasis"/> <target-element type="strong"/> <target-element type="defined-term"/> <SPAN font-weight="bold"> <children/> </SPAN> </rule>

Hint: The last element in the <rule> is always assumed to be the action.

Lesson #14: Filtering

One aspect of XSL that makes it so powerful is its ability to filter and reorder elements. The <select-elements> element enables this functionality allowing you to select which elements you would like to have processed.

The <select-elements> element is part of the action, its purpose being to replace the <children/> element with a more specific directive.

Through the same methods available within the pattern for the rule, the "filter pattern" within the <select-elements> element allows you to specify the context of the exact children you wish to process. For instance, within the following <select-elements> element is the <target-element/> wildcard which signals the selection of all types of elements (this <select-elements> element is therefore equivalent to the <children/> element):

<rule> <target-element/> <DIV> <select-elements> <target-element/> </select-elements> </DIV> </rule>

Hint: The <select-elements> element does contain a pattern, but this pattern is strictly for filtering children and must not be confused with the pattern for the rule.

Although it is possible to mimic the <children/> element using the <select-elements> element, most of the time you will want to use the <select-elements> element to filter out certain children and apply formatting to certain others. Making the pattern within the <select-elements> element more specific allows only certain children to be processed. The element below, for example, processes only <stock> children; no other children are processed at this time.

<select-elements> <target-element type="stock"/> </select-elements>

In the above example, it should be noted that the <stock> element must be an immediate child of the element targeted by the rule. In order to search arbitrarily deep within the source element, you must request this behavior with the from attribute:

<select-elements from="descendants"> <element type="investments"> <target-element type="stock"> <attribute type="watch-list" value="yes"/> </target-element> </element> </select-elements>

The from attribute may have the value "descendants" (search through my children, grandchildren, etc.) or the value "children" (search through my immediate children only). The default value is "children".

Hint: Remember, the <select-elements> element is replacing the <children/> element, and though it contains its own pattern, it is part of the action.

Lesson #15: Reordering

Source elements can be extracted and reordered using multiple <select-elements> elements. For example, with XSL we can extract certain data from the following XML document

<investments> <portfolio> <broker> <name>Charles Schwab</name> </broker> <stock> <shares>150</shares> <price>130</price> <ticker>MSFT</ticker> </stock> <stock> <shares>90</shares> <price>95</price> <ticker>INTC</ticker> </stock> </portfolio> </investments>

and present a particular "view" of that data. The stylesheet below extracts just the stock price and ticker symbol and formats them into a table.

<xsl> <rule> <!-- extracts <stock> elements --> <target-element type="portfolio"/> <TABLE> <TBODY> <select-elements> <target-element type="stock"/> </select-elements> </TBODY> </TABLE> </rule> <rule> <!-- extracts <ticker> and <price> elements --> <target-element type="stock"/> <TR> <TD> <select-elements> <target-element type="ticker"/> </select-elements> </TD> <TD> $ <select-elements> <target-element type="price"/> </select-elements> </TD> </TR> </rule> <rule> <!-- formats <ticker> elements --> <target-element type="ticker"/> <DIV font-weight="bold"><children/></DIV> </rule> <rule> <!-- formats <price> elements --> <target-element type="price"/> <SPAN color="blue"><children/></SPAN> </rule> </xsl>

This XSL stylesheet will result in the following HTML document:

<BODY> <TABLE> <TBODY> <TR> <TD> <DIV style = "font-weight : bold">MSFT</DIV> </TD> <TD> $ <SPAN style = "color : blue">130</SPAN> </TD> </TR> <TR> <TD> <DIV style = "font-weight : bold">INTC</DIV> </TD> <TD> $ <SPAN style = "color : blue">95</SPAN> </TD> </TR> </TBODY> </TABLE> </BODY>

Notice how far the flow object structure in the above HTML diverges from the structure of the XML source document. Also, notice how the information shown below (what you would see on your browser) is only a subset of the information available in the XML source document.

$ 130
$ 95

Lesson #16: Hiding Source Elements

There will be occasions when you will want to suppress or hide certain data contained within the source document. XSL provides this functionality.

Hiding is accomplished by simply not creating corresponding output for the element. In order to not create output, all you must do is suppress the processing of children. Leaving the <children/> element out of the action does just that.

<rule> <target-element type="top-secret"/> <SPAN>---- Removed by order of the CIA ----</SPAN> </rule>

In the above example, when <top-secret> elements are found and processed, the contents of the <SPAN> element is output instead of the contents of the <top-secret> element. Remember, without the <children/> or <select-elements> element, the recursive process does not take place. Therefore, the contents of the target elements (in this case, the contents of the <top-secret> elements) are not processed.

To remove something without a trace, the <empty/> element may be used, indicating the intentional lack of flow object output.

<rule> <target-element type="hidden"/> <empty/> </rule>

Lesson #17: Style Rules

CSS (Cascading Style Sheets) allows several rules to simultaneously apply to a particular source element. When this occurs, the style properties are merged or "cascaded" into a single set of properties. XSL supports this sort of merging, as well, but not by construction rules.

Attempting to merge construction rules poses some difficulties. If one rule specifies a table cell and another specifies a paragraph, how can we merge these two rules and still arrive at a predictable outcome? XSL gets around such difficulties by including another type of rule: the style rule.

The <style-rule> element, like the <rule> element, contains a pattern and an action. The syntax of the pattern is the same as it is for construction rules, but the action consists only of the <apply> element. It is within the <apply> element that style properties are defined. Since no output structure is created, the properties can be merged.

In their operation, XSL style rules are nearly identical to CSS rules. Take, for instance, the following two CSS rules:

price { font-weight: bold; color:blue } .new { font-style: italic; color:red }

If we were to apply them to the following XML source element

<stock> <price class="new">35.50</price> </stock>

the contents of the <price> element would be displayed with the properties font-weight:bold, font-style:italic, and color:red.

Likewise, if we were to apply the following two XSL style rules

<style-rule> <target-element type="price"/> <apply font-weight="bold" color="blue"/> </style-rule> <style-rule> <target-element type="price"> <attribute name="class" value="new"/> </target-element> <apply font-style="italic" color="red"/> </style-rule>

to the same source element, the same properties would be applied as in the CSS example above.

Style rules cause a set of style properties to be merged, but cannot specify output structure. In order for an XML source element to be displayed, a construction rule containing a flow object must apply to the element. Once a construction rule is found to match a source element, style properties from any style rule that also targets that type of element are merged and passed into the construction rule and applied to the flow object.

The following code is an example of two style rules working in combination with a construction rule.

<style-rule> <target-element type="price"/> <apply font-weight="bold" color="blue"/> </style-rule> <style-rule> <target-element> <attribute name="class" value="new"/> </target-element> <apply font-style="italic" color="red"/> </style-rule> <rule> <target-element type="price"/> <DIV margin-left="2em" font-style="normal"> <children/> </DIV> </rule>

Applying the above stylesheet to the <stock> element from the previous examples would result in the following HTML code:

<DIV style="color:red; font-weight:bold; font-style:italic; margin-left:2em"> 35.50 </DIV>

Note: Style rules follow the arbitration rules of XSL. The arbitration order is based on the "specificity" defined for CSS and thus supports the familiar cascading order of CSS.

Lesson #18: Scripting

Script can be used to augment the core functionality of XSL in the same manner that script is used to augment an HTML document. XSL specifies ECMAScript as the standard scripting language. Our implementation uses Microsoft JScript, which is ECMAScript and JavaScript compliant.

Scripting within XSL allows you to extend the capability of the language. Within an XSL stylesheet, you can write scripts that will execute during processing time or pass through to be run during browser run-time. Using both types of scripts, you can dynamically create HTML documents that, in turn, are dynamic themselves. For instance, you could write a script intended to execute during processing time that provides a unique ID value for each HTML element in the output document. You could then write a script intended to execute during browser run-time that changes the value of a certain HTML element's color attribute whenever the user runs the mouse over the contents of that element.

In addition to the standard JScript helper functions (see JScript Reference Non-SBN link), XSL includes a set of Built-in Functions and access to the XML Object Model. Each of these features will be explained in detail throughout the ensuing sections.

Lesson #19: Calculating Attribute Values

The easiest way to use scripting within XSL is in the calculation of flow object attribute values. Simply placing "=" as the first character of an attribute value tells the XSL processor that the attribute value should be calculated as a JScript expression. The following code represents the use of JScript to calculate an attribute value (in this case, to calculate a particular font size).

<rule> <target-element type="note"/> <DIV font-size="=10 * 1.5 - 2+'pt'"> <children/> </DIV> </rule>

Once the above rule is processed, the resulting HTML flow object will be as follows:

<DIV style="font-size:13pt">

Hint: Notice how the result of the expression was concatenated with the string 'pt' to produce the value for the property font-size. Because all attribute values are strings, such string concatenation is necessary.

Besides simple numeric expressions, attributes can also involve expressions containing functions and globally defined constants (see Defining Functions and Global Constants):

<rule> <target-element type="note"/> <DIV margin-left="=myMarginCalc()" background-color="=bgColor"> <children/> </DIV> </rule>

Often the expression contains values from the source document. In these cases, a simple object model provides access to the currently selected source element (referred to from script as "this"). Each element has a set of properties and methods that can be called to navigate to ancestors or children, peek into attribute values, or examine a chosen element's content. See XML Object Model for a list of the available properties and methods.

In order to fully understand how the object model can be used to discover certain information about the source element, let's take a look at an XML element with an attribute (<album>), that contains another XML element with an attribute (< photograph>):

<album width="300px"> <photograph image-url="ceremony.jpg">Wedding Ceremony</photograph> <photograph image-url="cake.jpg">Wedding Cake</photograph> </album>

The rule below targets <photograph> elements, setting the <IMG> flow object's src attribute to the value of the <photograph> element's image-url attribute and the <IMG> flow object's width attribute to the value of the <album> element's width attribute.

<rule> <target-element type="photograph"/> <IMG src='=getAttribute("image-url")' width='=parent.getAttribute("width")' /> </rule>

Lesson #20: Evaluating Expressions

Within XSL, JScript can be used to generate text in the output. This gives XSL the ability to number items such as paragraphs or list items, calculate totals, do numeric conversions, or re-format content at the text level.

To insert the result of an expression into the formatted output, enclose the expression to be evaluated inside <eval>. In the following example, the childNumber function determines an element's number in relation to its siblings, and the formatNumber function returns that number as a string. That string is then inserted into the formatted output.

<rule> <element type="number-list"> <target-element type="item"/> </element> <DIV> <eval>formatNumber(childNumber(this), "1")</eval>. <children/> </DIV> </rule>

Processing the XML source element below

<number-list> <item>First Item</item> <item>Second Item</item> <item>Third Item</item> </number-list>

using the XSL stylesheet discussed above, results in the following output:

1. First Item
2. Second Item
3. Third Item

Globally defined constants, user defined functions, built-in functions, and the XML Object Model are all available within <eval>, but multiline functions are not. Also, all <eval> elements should evaluate to a string.

Lesson #21: Defining Functions and Global Constants

Similar to the HTML <SCRIPT> element, the XSL <define-script> element contains functions and global constants. In general, the XSL stylesheet contains one <define-script> element, usually at the beginning of the stylesheet.

The following example involves a <define-script> element in which the function chartBarWidth is defined.

<xsl> <define-script><![CDATA[ function chartBarWidth(e) { // extract the contents of the "percent" child of the element, // and format it as a percentage return e.children.item("percent",0).text + "%"; }]]> </define-script> <rule> <target-element type="chart-bar"/> <DIV width="=chartBarWidth(this)" height="10px" background-color="orange"> <children/> </DIV> </rule> </xsl>

Hint: You probably couldn't help but notice that the function in the above example is marked as character data. All scripts that you will write in XSL should be treated as character data to ensure that they will be passed through to the output document as you intend.

Global variables are discouraged (and are actually not allowed in the official XSL spec) because they can cause "side-effects". For instance, XSL provides no guarantees that the stylesheet will be run only once, or in a particular order, or even in its entirety. If one rule sets a global variable and another rule uses this value, unexpected results can occur.

Global variables can, however, be used safely as constants. You may define these constants in the <define-script> section, set their initial values, and refer to them throughout your stylesheet. Just don't change them later!

The XSL stylesheet below contains both a <define-script> element in which three global constants are defined and a rule referring to those constants:

<xsl> <define-script><![CDATA[ var myPurple = "#DD00CC"; var baseFontSize = 10; var largeFontSize = baseFontSize + 2; ]]></define-script> <rule> <target-element type="chart-bar"/> <DIV font-size="=largeFontSize" background-color="=myPurple"> <children/> </DIV> </rule> </xsl>

Lesson #22: Creating Dynamic HTML

There will be times when your HTML documents will require dynamic behavior. XSL allows you to institute such dynamic behavior through the <SCRIPT> flow object. The <SCRIPT> flow object is treated as any other flow object - the contents are passed through to the output as text. These scripts can then be executed by the browser. The following XSL rule generates a <SCRIPT> element in the HTML document that allows the user to highlight an element by clicking on the output from that element.

<xsl> <rule> <root/> <HTML> <HEAD> <SCRIPT LANGUAGE="JSCRIPT"><![CDATA[ function hiLite(e) { if (e.style.backgroundColor != 'yellow') e.style.backgroundColor = 'yellow'; else e.style.backgroundColor = 'white'; } ]]></SCRIPT> </HEAD> <BODY> <children/> </BODY> </HTML> </rule> <rule> <target-element type="item"/> <DIV id='=tagName + formatNumber(childNumber(this),"1")' background-color="yellow" onClick='="hiLite("+ tagName + formatNumber(childNumber(this),"1")+")"'> <children/> </DIV> </rule> </xsl>

Hint: Notice that the onclick attribute is the subject of both the XSL script and describes display-time behavior. Like the contents of the <SCRIPT> flow object, XSL treats event attributes such as onclick as text. Consequently, XSL allows the values of event attributes to be calculated with the "=" syntax and the results of such calculations to be output to the HTML document.

If we were to process the following XML document

<grocery-list> <item>lettuce</item> <item>chicken</item> <item>onion</item> <item>cheese</item> <item>bread</item> </grocery-list>

using the above rule, the XML data would appear in your browser as it does below (Try clicking on some of the items in the list.):


It is important to understand that when you write scripts within a <SCRIPT> flow object, you are writing scripts that will be executed at browser run-time. This makes such scripts different than those in a <define-script> element. Scripts within a <define-script> element are executed during processing and are used to dynamically create an HTML document rather than make that HTML document dynamic itself.

The following XSL stylesheet incorporates both a <define-script> element and a <SCRIPT> flow object. During processing, the initialState function in the <define-script> element generates the initial state of "white" or "yellow" for each item. During browser run-time, the hiLite function in the <SCRIPT> flow object allows the user to then click on an item to change its color.

<xsl> <define-script><![CDATA[ function initialState(e) { if (childNumber(e) % 2 == 0) return "yellow"; else return "white"; } function uniqueID(e) { return tagName + formatNumberList(path(this), "1", "_"); } ]]></define-script> <rule> <root/> <HTML> <HEAD> <SCRIPT LANGUAGE="JSCRIPT"><![CDATA[ function hiLite(e) { if (e.style.backgroundColor != 'yellow') e.style.backgroundColor = 'yellow'; else e.style.backgroundColor = 'white'; } ]]></SCRIPT> </HEAD> <BODY> <children/> </BODY> </HTML> </rule> <rule> <target-element type="item"/> <DIV id='=uniqueID(this)' background-color="=initialState(this)" onClick='="hiLite("+ uniqueID(this) + ")"'> <children/> </DIV> </rule> </xsl>

If you were to apply the above stylesheet to the XML document from the previous example, the following would be displayed in the browser:


Let's now take a look at the HTML document behind the above output:

<HTML> <HEAD> <SCRIPT LANGUAGE="JSCRIPT"> function hiLite(e) { if (e.style.backgroundColor != 'yellow') e.style.backgroundColor = 'yellow'; else e.style.backgroundColor = 'white'; } </SCRIPT> </HEAD> <BODY> <DIV id="item1_1" onClick="hiLite(item1_1)" style="background-color: white"> lettuce </DIV><DIV id="item1_2" onClick="hiLite(item1_2)" style="background-color: yellow"> chicken </DIV><DIV id="item1_3" onClick="hiLite(item1_3)" style="background-color: white"> onion </DIV><DIV id="item1_4" onClick="hiLite(item1_4)" style="background-color: yellow"> cheese </DIV><DIV id="item1_5" onClick="hiLite(item1_5)" style="background-color: white"> bread </DIV> </BODY> </HTML>

Notice how the <SCRIPT> flow object gets passed through to the new HTML document. Also, notice how the function calls associated with the function defined in the <define-script> element have been replaced by strings.

Lesson #23: Built-in Functions

Besides the standard JavaScript functions, XSL makes available the following built-in functions:

Returns the nearest ancestor of the element with the requested element type. Returns null if there is no such ancestor or if the element is empty.
ancestor(elementType, element)
elementType The element type of the desired ancestor.
element The element from which to search for ancestors.
<!-- navigate up to the <chapter> element, then down to the <chapter-name> element --> <rule> <target-element type="insert-chapter-name"/> <eval>ancestor("chapter", this).children.item("chapter-name",0).text</> </rule>
Returns the number of an element relative to its siblings of the same type.
element The element for which the number is desired.
<!-- insert the number of the item in parentheses --> <rule> <target-element type="numbered-item"/> <DIV> ( <eval>formatNumber(childNumber(this), "1")</eval> ) <children/> </DIV> </rule>
Returns the number of the nearest ancestor of an element of the requested element type or null if there is no such ancestor.
ancestorChildNumber(elementType, element)
elementType The element type of the desired ancestor.
element The element from which to search for ancestors.
<!-- find the number of the current "chapter" and insert it --> <rule> <target-element type="insert-chapter-number"/> Chapter <eval>formatNumber(ancestorChildNumber("chapter", this), "1")</eval> </rule>
Returns an array which includes the number of an element with respect to all of its siblings (of its type), the number of the parent of that element with respect to its siblings, and so on until the document root is reached. Note that the length of this array represents the nesting depth of the element. The array is ordered with the last number representing the number of the element.
element The element representing one end of the path, the other end of the path is the document root.
<!-- generate a unique name for any element within an <examples> element --> <rule> <element type="examples"> <target-element/> </element> <DIV> <A name='=tagName + formatNumberList(path(this), "1", "_")'></A> <children/> </DIV> </rule>
Similar to the path function, but returns only the child numbers of elements of the requested elementType. This function is commonly used for creating section numbers in the "Section 1.3.2" format.
hierarchicalNumberRecursive(elementType, element)
elementType The element type of the ancestor elements to be considered by this function.
element The element representing one end of the path; the other end of the path is the document root.
<!-- generate (e.g.) "Section" before each "title" --> <rule> <target-element type="title"/> <DIV> Section <eval>formatNumberList( hierarchicalNumberRecursive("section", this), "1", ".") </eval>: <children/> </DIV> </rule>
Returns a string representation of a number "n". A variety of formats are available.
formatNumber(n, format)
n The number to format.
format A value specifying the desired format for the number:
  • "1" means use 0, 1, 2
  • "01" means use 00, 01, 02, 10, 11, 100, 101 and similarly for any number of leading zeros (not yet implemented)
  • "a" means use 0, a - z, aa - zz
  • "A" means use 0, A - Z, AA - zz
  • "i" means use 0, i, ii, iii, iv, v, vi, vii, viii, ix, x (not yet implemented)
  • "I" means use 0, I, II, III, IV, V, VI, VII, VIII, IX, X (not yet implemented)
<!-- generate "Chapter 1:", "Chapter 2:", etc. --> <rule> <element type="chapter"> <target-element type="title"/> </element> Chapter <eval>formatNumber(ancestorChildNumber("chapter", this), "1")</eval>: <children/> </rule> <!-- generate "Appendix A:", "Appendix B:", etc. --> <rule> <element type="appendix"> <target-element type="title"/> </element> Appendix <eval>formatNumber(ancestorChildNumber("appendix", this), "A")</eval>: <children/> </rule> <!-- generate the letter of this list item "a", "b", etc. --> <rule> <element type="list"> <target-element type="item"/> </element> <DIV> <SPAN width="1.5em"> <eval>formatNumber(childNumber(this), "a")</eval>. </SPAN> <children/> </DIV> </rule>
Returns a formatted representation of list, where list is an array of integers.
formatNumberList(list, format, separator)
list The array of numbers to format. Usually generated by the path function or the hierarchicalNumberRecursive function.
format Specifies the format to use for each number as described in formatNumber. It shall be either a single string specifying the format to use for all numbers or an array of strings with the same number of members as list each specifying the specific format to use for each number.
separator A string to be inserted as the separator between each formatted number. The separator shall contain either a single string or an array of strings with one fewer members than list.
<!-- generate a section number (e.g. "3.2.4") before each "title" --> <rule> <element type="div"> <target-element type="title"/> </element> <DIV> <DIV font-weight="bold"> <eval>formatNumberList( hierarchicalNumberRecursive("div", this), "1", "." )</eval> </DIV> <children/> </DIV> </rule>

Lesson #24: XML Object Model

The source element upon which a rule operates can be referred to from script as this. Within the context of an element, this may be omitted, and the properties and methods may be called directly. A read-only subset of the full XML Object Model is available for navigation of the source tree.

Returns the element type of the requested element.
<!-- mark each element with its tag name --> <rule> <target-element/> <DIV> <SPAN color="gray"> [ <eval>tagName</eval> ] </SPAN> <children/> </DIV> </rule>
Returns the immediate ancestor of the requested element.
<!-- navigate up from the <href> element to the parent, the <photo> element, and down again to the <caption> element; add this text as the alternate text --> <rule> <element type="photo"> <target-element type="href"/> </element> <IMG src="=text" alt='=this.parent.children.item("caption",0).text'/> </rule>
Returns the value of the specified attribute of the requested element.
attributeName The name of the attribute to retrieve.
<!-- pass the "href" through as the "src" attribute and pass the width and height through unchanged --> <rule> <target-element type="image"/> <IMG src='=getAttribute("href")' width='=getAttribute("width")' height='=getAttribute("height")'/> </rule>
Returns an enumeration of children elements of the requested element.
<!-- pass the <price> child of an <order> element to a user-defined summing function --> <rule> <target-element type="order"/> <DIV> <children/> <DIV font-weight="bold"> Total: <eval>sumPrices(this.children.item("price"))</eval> </DIV> </DIV> </rule>
Returns the text of the requested element. Any markup within the text of the element is stripped.
<!-- extract the "href" from a sub-element, and get the display name from another sub-element --> <rule> <target-element type="link"/> <A href='=this.children.item("href",0).text'> <eval>this.children.item("display-name",0).text</eval> </A> </rule>
Returns the length of an enumeration of elements.
<!-- calculate the percentage based on the current element number and the total number of siblings --> <rule> <target-element type="task"/> <DIV> Task: <children/> Percent of project: <eval>formatNumber( childNumber(this) / parent.children.length * 100, "1") </eval>% </DIV> </rule>
Returns the requested item or items from an enumeration. If only the "elementType" paramater is used, the result is an array of elements. If the "index" parameter is used, either alone or in conjunction with "elementType", the result is a single element.
this.children.item(elementType, index)
elementType The name of the element(s) to retrieve.
index The index of the element to retrieve.
<!-- generate a name from the <title> element within a <chapter> element --> <rule> <target-element type="chapter"/> <DIV> <A name='=this.children.item("title",0).text'> </A> <children/> </DIV> </rule>

© 1998 Microsoft Corporation. All rights reserved. Terms of use.