The XML Files
XSLT Keys, Select vs. Match, Conflict Resolution, and More
Aaron Skonnard
Q How do keys work in XSLT?
Q How do keys work in XSLT?
A Keys in XSLT are similar to IDs in Document Type Definitions (DTDs). If you define an attribute of type ID in a DTD, the attribute value must be unique in the document. You can also define attributes of type IDREF. In this case, the attribute value must refer to a unique ID value somewhere else in the document. With this type of DTD information in place, you can then use XPath's id function in order to resolve IDs and IDREF relationships in a document at run time. For example, let's consider an XML document with an internal DTD (see Figure 1).
A Keys in XSLT are similar to IDs in Document Type Definitions (DTDs). If you define an attribute of type ID in a DTD, the attribute value must be unique in the document. You can also define attributes of type IDREF. In this case, the attribute value must refer to a unique ID value somewhere else in the document. With this type of DTD information in place, you can then use XPath's id function in order to resolve IDs and IDREF relationships in a document at run time. For example, let's consider an XML document with an internal DTD (see Figure 1).
Figure 1 Internal DTD
<!DOCTYPE courses [ <!ELEMENT courses (course*, employees)> <!ELEMENT course EMPTY> <!ELEMENT employees (employee*)> <!ELEMENT employee EMPTY> <!ATTLIST course instructors IDREF #REQUIRED name CDATA #REQUIRED > <!ATTLIST employee id ID #REQUIRED name CDATA #REQUIRED > ]> <courses> <course instructors="e101 e102 e103 e104" name="EWS.NET"/> <course instructors="e101 e102 e105" name="GWS.NET"/> <employees> <employee id='e101' name="Aaron Skonnard"/> <employee id='e102' name="Simon Horrell"/> <employee id='e103' name="Dan Sullivan"/> <employee id='e104' name="Scott Bloom"/> <employee id='e105' name="Bob Beauchemin"/> </employees> </courses>
The following XPath expression identifies the element with an ID of e104, which in this particular case is an employee element with the name of Scott Bloom:
id('e104')
The following XPath expression identifies the elements with ID values of e101, e102, and e104, which in this case happens to be the employee elements that have the names of Aaron Skonnard, Dan Sullivan, and Scott Bloom:
id('e101 e103 e104')
And finally, the following XPath expression identifies the employees who teach the "GWS.NET" course (specifically Aaron Skonnard, Simon Horrell, and Bob Beauchemin) through the instructors IDREF attribute:
id(/courses/course[2]/@instructors)
As you can see, this technique makes it possible to establish relationships between different elements based on their ID values. The problem with the ID/IDREF technique is that it requires DTD information to be present at run time and it's limited to attributes. To help alleviate these restrictions, XSLT introduced a new concept, called keys, which provides the same basic functionality but with more flexibility. You use the key element to define a key in an XSLT document. It has the following structure:
<xsl:key name="qname" match="pattern" use="expression"/>
You give the key a qualified name so that you can refer to it later from the key function (which behaves like the XPath id function described earlier). You also specify a pattern, which identifies the nodes to which the key applies. Finally, you use the "use" attribute to specify an XPath expression that is evaluated (relative to the nodes identified by the match expression) to produce the actual key value. For example, consider the XML document in Figure 2.
Figure 2 An XML Document
<courses> <course> <name>EWS.NET</name> <instructors> <instructor>e101</instructor> </instructors> </course> <course> <name>GWS.NET</name> <instructors> <instructor>e101</instructor> <instructor>e102</instructor> <instructor>e103</instructor> </instructors> </course> <employees> <employee id='e101'> <name>Aaron Skonnard</name> </employee> <employee id='e102'> <name>Simon Horrell</name> </employee> <employee id='e103'> <name>Dan Sullivan</name> </employee> </employees> </courses>
In this case, you probably want to create a key based on the employee element's id attribute, as illustrated here:
<xsl:key name="employeeId" match="employee" use="@id"/>
This creates a key for all employee elements within the document; the key value is evaluated from the employee element's id attribute. With the key defined, you can then use the key function to retrieve nodes with a given key. For example, the following XSLT fragment illustrates how to retrieve the instructors who teach a given course:
<xsl:template match="course"> <h2><xsl:value-of select="name"/></h2> <h3>Instructors</h3> <ul> <xsl:for-each select="key('employeeId', ./instructors/*)"> <li><xsl:value-of select="."/></li> </xsl:for-each> </ul> </xsl:template>
The previous fragment will emit the following HTML, assuming the input document shown in Figure 2:
<h2>EWS.NET</h2> <h3>Instructors</h3> <ul> <li>Aaron Skonnard </li> </ul> <h2>GWS.NET</h2> <h3>Instructors</h3> <ul> <li>Aaron Skonnard</li> <li>Simon Horrell</li> <li>Dan Sullivan</li> </ul>
As you can see, keys don't require DTD information to be used and they're not limited to attributes as with ID/IDREF. The fact that keys can be assigned to nodes that match an arbitrary pattern also gives you an extra degree of flexibility.
Q What's the difference between the match and select attributes in XSLT? What do they do, exactly?
Q What's the difference between the match and select attributes in XSLT? What do they do, exactly?
A In XSLT, there are various elements that come with a match attribute (such as template and key) and others that come with select attribute (value-of, for-each, apply-templates, and so on). At first glance, both seem to take XPath expressions, but in fact they're quite different.
A In XSLT, there are various elements that come with a match attribute (such as template and key) and others that come with select attribute (value-of, for-each, apply-templates, and so on). At first glance, both seem to take XPath expressions, but in fact they're quite different.
Select does indeed expect an XPath expression, which is used to select a nodeset for further processing. In the following example, the for-each expression identifies a set of nodes to be iterated over while the nested value-of expression writes the value of each node to the output tree:
<xsl:for-each select="//item"> <xsl:value-of select="."/> </xsl:for-each>
The match attribute, on the other hand, takes what's called a pattern. A pattern looks like an XPath expression because it shares the same syntax, but it's treated differently by the XSLT processor. A pattern is used for matching nodes in the tree against the specified criteria. For example, the following template matches any element node that has a grandparent named foo:
<xsl:template match="foo/*/*"> ••• </xsl:template>
In other words, a pattern describes an "is a" relationship with the nodes in question (that is, is this node an element that has a grandparent named foo?). Here's a more sophisticated example:
<xsl:template match="f:foo[@id > 323]//text()"> ••• </xsl:template>
In this case, the pattern identifies all text nodes that have an ancestor element named foo from the namespace identified by f, and with an id attribute with a numeric value greater than 323.
Q Why does SelectNodes always return the nodes in document order irrespective of the axis direction (forward/reverse) that was used in the query?
Q Why does SelectNodes always return the nodes in document order irrespective of the axis direction (forward/reverse) that was used in the query?
A Consider the following XML document, which I'll call foo.xml:
<foo depth='1'> <foo depth='2'> <foo depth='3'> <bar/> </foo> </foo> </foo>
A Consider the following XML document, which I'll call foo.xml:
<foo depth='1'> <foo depth='2'> <foo depth='3'> <bar/> </foo> </foo> </foo>
Now consider the following code that evaluates slightly different XPath expressions against the loaded foo.xml document:
XmlDocument doc = new XmlDocument(); doc.Load("foo.xml"); XmlElement b, f1, f2; b = (XmlElement)doc.SelectSingleNode("//bar"); f1 = (XmlElement)b.SelectSingleNode("ancestor::foo[1]"); f2 = (XmlElement)b.SelectNodes("ancestor::foo")[0]; Console.WriteLine(f1.GetAttribute("depth")); Console.WriteLine(f2.GetAttribute("depth"));
You might expect the console output to be the same in both cases, but it's actually different. The first Console.WriteLine outputs "3" while the second outputs "1". The reason it works this way is that axis direction, as defined by the XPath specification, is only significant within XPath predicates. In fact, XPath nodesets are by definition unordered so it's up to the XPath implementation to determine in what order to deliver nodesets.
In the call to SelectSingleNode, however, I asked for the first node in the ancestor axis within a predicate. This guarantees that I'll get the first ancestor node (in reverse document order) starting from the bar element (the foo element with depth='3'). In the call to SelectNodes, on the other hand, I asked for all ancestor foo elements and the implementation returned an XmlNodeList collection with the nodes in document order (completely legal according to the specification). Then, my code asked for the first item in the collection, which happens to be the foo element where depth='1'. Since XPath doesn't specify the order in which nodes are returned, languages that build on XPath often define additional semantics of their own. For example, in the case of XSLT, nodesets are always processed in document order.
Q How do you query a paragraph of text to determine whether it contains a <SCRIPT> element?
Q How do you query a paragraph of text to determine whether it contains a <SCRIPT> element?
A The answer to this question depends on what you mean when you ask if the paragraph contains a <SCRIPT> element. Consider the following document:
<item> <name>Something</name> <desc>This is a description that contains a <SCRIPT language="Javascript" src="script.js"/> element.</desc> </item>
If the document looks like this, you would use a normal XPath expression that queries against the document's logical data model. For example, the following XPath expression identifies all element nodes in the document tree that contain a child SCRIPT element (in this case, the <desc> element):
//*[SCRIPT]
A The answer to this question depends on what you mean when you ask if the paragraph contains a <SCRIPT> element. Consider the following document:
<item> <name>Something</name> <desc>This is a description that contains a <SCRIPT language="Javascript" src="script.js"/> element.</desc> </item>
If the document looks like this, you would use a normal XPath expression that queries against the document's logical data model. For example, the following XPath expression identifies all element nodes in the document tree that contain a child SCRIPT element (in this case, the <desc> element):
//*[SCRIPT]
Now, consider the following document, which uses special entity references for the less-than (<) and greater-than (>) characters within the <desc> element:
<item> <name>Something</name> <desc>This is a description that contains a <SCRIPT language="Javascript" src="script.js"/> element.</desc> </item>
When an XML processor parses this document, it replaces "<" with the < character and replaces ">" with the > character. Hence, the <desc> element contains the following text when you query it using XPath:
This is a description that contains a <SCRIPT language="Javascript" src="script.js"/> element.
So you would use the following XPath expression
//*[contains(.,'<SCRIPT')]
in order to search this document for all elements that contain "<SCRIPT".
Q When multiple XSLT patterns match a given node, how does the processor decide which to use?
Q When multiple XSLT patterns match a given node, how does the processor decide which to use?
A When a node matches more than one pattern found in your XSLT templates (also known as rules), the processor follows the conflict resolution guidelines outlined by the XSLT specification to determine which one to use. These guidelines state that the template with the highest priority will be called when conflicts occur. The algorithm for determining the actual priority of a template, however, requires some additional explanation.
A When a node matches more than one pattern found in your XSLT templates (also known as rules), the processor follows the conflict resolution guidelines outlined by the XSLT specification to determine which one to use. These guidelines state that the template with the highest priority will be called when conflicts occur. The algorithm for determining the actual priority of a template, however, requires some additional explanation.
To determine which node has the highest priority, the processor first eliminates all templates that were imported (using the xsl:import element); imported templates automatically have a lower priority than the templates in the importing transformation. The processor then determines the priority values of the remaining templates.
Priorities can be explicitly assigned to a template through the priority attribute. For example, the following template has been assigned a priority of 1:
<xsl:template match="/foo/bar" priority="1"> <!-- do something interesting --> </xsl:template>
If a priority has been assigned to a template, then that's the value used by the processor to determine which template has the highest priority. If a priority has not been explicitly assigned, the processor calculates a default for the template. The default priorities assigned by the processor can range from -0.5 to +0.5. Basically, more specific patterns receive higher default priorities. Since the range is -0.5 to +0.5, assigning an explicit priority of 1 to a template will always win over a default priority.
Figure 3 outlines exactly how the default priorities are assigned for the different types of patterns that exist. Patterns that only contain node tests by type (such as *, node, comment, text, and so forth) are the most generic, so they receive a default priority of -0.5. Patterns that only contain namespace wildcards (ns:*) are a bit more specific, so they receive a default priority of -0.25. Patterns that only contain a qualified name test or a literal processing instruction test (such as foo, ns:foo, @bar, processing-instruction('foo'), and so on) receive a default priority of 0. Every other pattern that's more specific than these receives a default priority of 0.5. This means that any pattern with more than one location step, or with a predicate, automatically receives a default priority of 0.5.
Figure 3 Default Priorities
Pattern Type | Default Priority | Examples |
---|---|---|
Node test by type | -0.50 | * |
@* | ||
node | ||
comment | ||
text | ||
processing-instruction | ||
Namespace wildcard | -0.25 | ns:* |
QName | 0.00 | foo |
ns:foo | ||
@bar | ||
@ns:bar | ||
Processing instruction tests by literal | 0.00 | processing-instruction('foo') |
Everything else | 0.50 | ns:foo/bar |
ns:foo[@bar] | ||
foo[contains(.,'Aaron')] | ||
//foo | ||
Multiple patterns (pattern1 | pattern2) | Treated as distinct templates, whose priorities are calculated independently | |
Once the default priorities for all templates have been evaluated, the processor chooses the one with the highest priority. For example, in the following XSLT fragment there are two templates that may match a given bar element (assuming it has a parent foo element). When this occurs, the processor will automatically choose the second template because it has a higher default priority:
<xsl:template match='bar' > <!-- default priority = 0 --> </xsl:template> <xsl:template match='foo/bar' > <!-- default priority = .5 --> </xsl:template>
There are still situations in which there may be multiple templates with the same priority that match a given node. When this occurs, the processor may either signal an error or choose to use the last template in the document. This is the usual choice. For example, the following XSLT fragment contains two templates that could match the same foo element (one that has both a child bar element and a parent bar element). Since both templates have a default priority of 0.5, the XSLT processor will either signal an error or choose the last template in the document, in this case the one matching bar/foo elements:
<xsl:template match='foo[bar]' > <!-- default priority = .5 --> </xsl:template> <xsl:template match='bar/foo'> <!-- default priority = .5 --> </xsl:template>
Of course, you're better off avoiding these situations altogether. If you want the processor to always use the first template when these conflicts occur, you simply need to set its priority to 1, as illustrated in the following code:
<xsl:template match='foo[bar]' priority='1'> <!-- would have a default priority = .5 --> </xsl:template> <xsl:template match='foo/bar' > <!-- default priority = .5 --> </xsl:template>
As you can see, XSLT has an extensive process for determining which templates to call in the case of conflicts. Understanding these rules is crucial when making copious use of XSLT's declarative programming model.
Q What happens when there isn't a template matching a node that is being processed?
Q What happens when there isn't a template matching a node that is being processed?
A XSLT defines several templates that are built into every transformation by default, whether you provide them explicitly or not. These are referred to as XSLT's built-in templates. There is a built-in template for every type of node that might be processed in an XML document (elements, attributes, processing instructions, comments, and so on). These built-in templates, however, have the lowest priority possible, so they'll never be used before a user-provided template that also matches the same node (see the previous question on conflict resolution). They're only used when no other template matching a specific node is present.
A XSLT defines several templates that are built into every transformation by default, whether you provide them explicitly or not. These are referred to as XSLT's built-in templates. There is a built-in template for every type of node that might be processed in an XML document (elements, attributes, processing instructions, comments, and so on). These built-in templates, however, have the lowest priority possible, so they'll never be used before a user-provided template that also matches the same node (see the previous question on conflict resolution). They're only used when no other template matching a specific node is present.
The functionality of the built-in templates can be expressed with the following template definitions:
<!-- built-in templates --> <xsl:template match="*|/"> <xsl:apply-templates select="node()"/> </xsl:template> <xsl:template match="text()|@*"> <xsl:value-of select="."/> </xsl:template> <xsl:template match="processing-instruction()|comment()"/>
In the case of the root node or element nodes, the processor automatically applies templates to the current node's children (but not its attributes since the call uses child::node()). In the case of text or attribute nodes, the processor automatically outputs the node's value to the result tree. In the case of processing instructions or comments, the processor does nothing—it simply ignores them.
This default functionality turns out to be quite useful with the declarative programming model offered by XSLT. It basically allows you to walk recursively through the tree until a node is matched against one of the provided templates. When the processor encounters a text or attribute node, it prints the node's value to the result tree at the right place.
To illustrate this process, try running the following transformation against any XML input document:
<xsl:transform version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" />
This transformation doesn't contain any user-provided templates, so the built-in templates will be used instead. For example, try it against the following document:
<foo bar="hi"> <bar>hello</bar> <bar> <baz>world</baz> </bar> </foo>
In this case, the XSLT processor will output "helloworld". It recursively walks the tree and outputs the text node values, thanks to the built-in templates. The attribute node is never encountered due to the way xsl:apply-templates is called by the built-in template for elements. If your transformation ever outputs more text than you want it to, it's probably because the processor is recursively walking the tree and hitting text nodes unintentionally. In order to avoid this, you can always override the built-in template for text nodes. For example, the following is a new version of the last transformation with a new template for text nodes:
<xsl:transform version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" > <!-- override built-in template to do nothing --> <xsl:template match="text()|@*" /> </xsl:transform>
With this in modification, text nodes will never be output unless you explicitly do so through xsl:value-of. Try running the sample document through this transformation and you'll see that it doesn't output anything. In addition, if you don't want the processor to even walk the tree, you could override the built-in template for elements to do nothing, as shown here:
<xsl:transform version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" > <!-- override built-in template to do nothing --> <xsl:template match="*" /> </xsl:transform>
With this in place, the processor won't walk the tree, so it never makes it to the text nodes. If you run the sample document through this transformation, you'll see that it doesn't output anything either. If you override this template, it means that you must be more precise about which nodes you want to process when calling xsl:apply-templates.
Q What's the difference between xsl:include and xsl:import?
Q What's the difference between xsl:include and xsl:import?
A The xsl:include element makes it possible to include templates from one transformation into another. When you use xsl:include, it has to be a top-level element or, in other words, an immediate child of xsl:transform. Then you simply specify the location of the transformation you'd like to include using the href attribute, as illustrated here:
<xsl:transform version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" > <!-- include templates from foo.xsl here --> <xsl:include href="https://foo.xsl"/> ... </xsl:transform>
A The xsl:include element makes it possible to include templates from one transformation into another. When you use xsl:include, it has to be a top-level element or, in other words, an immediate child of xsl:transform. Then you simply specify the location of the transformation you'd like to include using the href attribute, as illustrated here:
<xsl:transform version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" > <!-- include templates from foo.xsl here --> <xsl:include href="https://foo.xsl"/> ... </xsl:transform>
Using xsl:include has no effect on the priority of the included templates. The templates included into the new transformation are treated as if they were defined inline. This is where xsl:import is different.
The xsl:import element also allows you to include templates from one transformation into another. But when doing so, the imported templates automatically receive a lower precedence (that is, a lower default priority) than the templates in the including transformation (see the earlier question on conflict resolution guidelines). This is one of the main differences between xsl:include and xsl:import.
Like xsl:include, xsl:import must also be a top-level element, and you specify the location of the transformation to be imported using the href attribute:
<xsl:transform version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" > <!-- import templates from foo.xsl here --> <!-- imported templates have lower priority --> <xsl:import href="https://foo.xsl"/> ... </xsl:transform>
XSLT also provides an xsl:apply-imports element (similar to xsl:apply-templates), which allows you to process a set of nodes against the imported templates only. This facilitates overriding templates like you would override a method in object-oriented code. For example, consider the example in Figure 4 which overrides the employee template with additional details.
Figure 4 Overriding a Template
<!-- global.xsl --> ••• <xsl:template match="employee"> Name: <xsl:value-of select="name"/> </xsl:template> ••• <!-- employee.xsl --> ••• <xsl:import href="https://global.xsl"/> <xsl:template match="employee"> <xsl:apply-imports/> Title: <xsl:value-of select="title"/> </xsl:template>
In this example, employee.xsl imports global.xsl and overrides the employee template. Inside the employee template, it first calls xsl:apply-imports to process the imported employee template (shown in global.xsl), then it continues processing the employee element by outputting its title element. The output from running employee.xsl will look something like this:
Name: Bob Smith Title: President
Q Does XSLT provide an if/else statement?
Q Does XSLT provide an if/else statement?
A XSLT provides an if statement (xsl:if), but an else clause doesn't come with it. The xsl:if statement takes a Boolean expression in its test attribute, as shown here:
<xsl:if test="spouse and count(child) > 0"> Married with children </xsl:if>
A XSLT provides an if statement (xsl:if), but an else clause doesn't come with it. The xsl:if statement takes a Boolean expression in its test attribute, as shown here:
<xsl:if test="spouse and count(child) > 0"> Married with children </xsl:if>
If the test expression evaluates to true, the content within the xsl:if element is instantiated and processed. If you need an else clause, you have to use a different construct called xsl:choose, which is similar to a switch statement. The xsl:choose statement allows you to specify multiple test expressions, and the first one that evaluates to true (starting from the top) is instantiated and processed:
<xsl:choose> <xsl:when test="spouse and count(child) = 0"> Just married </xsl:when> <xsl:when test="not(spouse) and count(child) > 0"> Just kids </xsl:when> <xsl:when test="spouse and count(child) > 0"> Married with children </xsl:when> </xsl:choose>
The xsl:choose also allows you to have an xsl:otherwise statement, which is instantiated if none of the test expressions evaluate to true. This is what you'd use to implement a traditional if/else statement, as illustrated here:
<xsl:choose> <xsl:when test="spouse and count(child) > 0"> Married with children </xsl:when> <xsl:otherwise> You must have plenty of free time </xsl:otherwise> </xsl:choose>
I can't count the number of times I've started writing an xsl:if statement only to realize that I also needed an else clause, which forces me to start over using xsl:choose. So every time you start using xsl:if, ask yourself if you also need an else.
Q Does XSLT provide a way to control how the output of a transformation is serialized? If so, what options does it provide?
Q Does XSLT provide a way to control how the output of a transformation is serialized? If so, what options does it provide?
A Yes, XSLT provides the xsl:output element for exactly this purpose. It's a top-level element that should be an immediate child of xsl:transformation. The xsl:output element provides a wide range of options that control how the result tree is serialized. The following shows the syntax for xsl:output:
<xsl:output method = "xml" | "html" | "text" | qname version = nmtoken encoding = string omit-xml-declaration = "yes" | "no" standalone = "yes" | "no" doctype-public = string doctype-system = string cdata-section-elements = qnames indent = "yes" | "no" media-type = string />
A Yes, XSLT provides the xsl:output element for exactly this purpose. It's a top-level element that should be an immediate child of xsl:transformation. The xsl:output element provides a wide range of options that control how the result tree is serialized. The following shows the syntax for xsl:output:
<xsl:output method = "xml" | "html" | "text" | qname version = nmtoken encoding = string omit-xml-declaration = "yes" | "no" standalone = "yes" | "no" doctype-public = string doctype-system = string cdata-section-elements = qnames indent = "yes" | "no" media-type = string />
As the XSLT processor runs a transformation, it builds a temporary result tree consisting of what's written to the output, either through static text within a template or through explicit calls to xsl:value-of. Then, the processor serializes the result tree to the output stream. Using xsl:output, you can influence how the XSLT processor performs this final step.
You can use the method attribute to indicate whether you're trying to output XML, HTML, or just plain text. The XML output method always outputs well-formed XML. The HTML output method, on the other hand, allows the processor to make several adjustments to the output in order to produce friendlier HTML documents. For example, empty elements in HTML usually don't have end tags, and script and style tags don't require escape characters. These adjustments make it possible to produce HTML that will be easier to handle for most browsers. The text output method simply outputs all of the text nodes in the result document without any surrounding markup whatsoever.
If you don't specify the output method, the processor will automatically select one based on the temporary result tree. If the root element is named "html" (case insensitive), it chooses the HTML output method; otherwise it defaults to the XML output method. To change the default, you need to specify exactly which output method you want to use via xsl:output, as shown here:
<xsl:transform version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" > <xsl:output method="text"/> ...
You can also specify the version for the output method in use. The default version for XML is 1.0 and for HTML it is 4.0 (versioning doesn't apply to the text mode). For example, the following xsl:output element specifies that the output should use HTML 3.0:
<xsl:transform version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" > <xsl:output method="html" version="3.0"/> •••
You can also specify which character encoding you'd like the processor to use during serialization. This setting hints to the processor how it should transform the character stream into a byte stream. Although XSLT processors typically follow this hint, they're not required to do so. The encoding indicated in the transformation can be overidden by the processor or certain APIs, which often leads to confusion.
In addition to these settings, you can specify if you'd like to have an XML declaration in the output, along with standalone and DTD identifiers. You can also specify the names of any elements that should be enclosed within CDATA sections in case they contain numerous unsafe XML characters. You can even tell the processor to pretty-print the result using indentations, making the output easier for people to read. Here's a final example:
<xsl:transform xmlns:xsl='https://www.w3.org/1999/XSL/Transform' version='1.0'> <xsl:output method="xml" version="1.0" omit-xml-declaration="yes" indents="yes" encoding="iso-8859-1" cdata-section-elements="codefrag syntax"/> ••• </xsl:transform>
This example indicates that the output should be serialized as XML 1.0 with an XML declaration at the top. It also indicates that the processor should use both the iso-8859-1 character encoding and indentations, and enclose all codefrag and syntax elements within CDATA sections.
Send your questions and comments for Aaron to xmlfiles@microsoft.com.
Aaron Skonnard is an instructor/researcher at DevelopMentor, where he develops the XML and Web Service-related curriculum. Aaron coauthored Essential XML Quick Reference (Addison-Wesley, 2001) and Essential XML (Addison-Wesley, 2000).