Taking a Close Look at Other XSLT Statements


Taking a Close Look at Other XSLT Statements

XSLT is like a functional programming language in that XSLT has loops, conditions, and selection statements. In this part of the chapter, you experiment with these XSLT constructs. To experiment with these constructs, a modified version of the XML document employed previously is used again. The modifications are added to make the results more interesting. For this section the modified XML document is as follows:

<data>     <child>         <elements haselements=”false”>Hello</elements>     </child>     <elements haselements=”true”>World<sub>         <elements haselements=”false”>Embedded</elements></sub>     </elements> </data>

Repetition with xsl:for-each

The core instruction for iterating through a node set is the xsl:for-each statement. The xsl:for-each statement does not require an already-selected node set, but selects a node based on the select attribute. To iterate all the descendant nodes, the following XSLT can be executed:

<xsl:stylesheet version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>     <xsl:template match=”/”>         <xsl:for-each select=”descendant::*”>             node name (<xsl:value-of select=”name()” />)             node value (<xsl:value-of select=”text()”/>)         </xsl:for-each>     </xsl:template>     <xsl:template match=”text()”>     </xsl:template> </xsl:stylesheet>

When this XSLT is executed on the XML document, the following content is generated:

<?xml version="1.0" encoding="UTF-8"?>                      node name (data)                      node value ()                               node name (child)                      node value ()                               node name (elements)                      node value (Hello)                               node name (elements)                      node value (World)                               node name (sub)                      node value ()                               node name (elements)                      node value (Embedded)

If you cross-reference the output with the XML document, the generated output iterates every XML node and outputs the associated XML text values. In the xsl:for-each statement, the select attribute is required and must result in a node set. For example, the following XPath in the select attribute causes an error:

<xsl:for-each select=”descendant::*/attribute::haselements=’true’”>     node name (<xsl:value-of select=”name()” />)     node value (<xsl:value-of select=”text()”/>) </xsl:for-each>

The preceding generates an error because the XPath, with the inclusion of the equal character, performs a conditional test that generates a true or false result. A true or false result is not a node set. The following shows a modified XPath with a conditional test that is legal and implements a filter in which the haselements XML attribute is true:

<xsl:for-each select=”descendant::*[@haselements=’true’]”>     node name (<xsl:value-of select=”name()” />)     node value (<xsl:value-of select=”text()”/>) </xsl:for-each>

The conditional test is removed and added as a filter, which queries a node to see if a specific condition is true. This is the desired effect because the filter is defined by the square brackets, which should return either a true or false value. The filter does not need to only query attributes, but it could be used to test for any condition that can be defined using an XPath expression.

Using xsl:template and xsl: for-each TOGETHER

In this next set of examples, you search for embedded elements XML nodes. The purpose of these examples is to show that an XSLT repetition and a template match can be used to accomplish the exact same thing as what you did when I initially explained the purpose of xsl:for-each. To find the various embedded element tags, the following XPATH can be used in the XSLT:

<xsl:template match="/">     <xsl:for-each select="descendant::elements[ancestor::elements]">         node name (<xsl:value-of select="name()" />)         node value (<xsl:value-of select="text()"/>)     </xsl:for-each> </xsl:template> 

When executed, this code results in the following output:

<?xml version=”1.0” encoding=”UTF-8”?>     node name (elements)     node value (Embedded)

Notice that the xsl:template match attribute is set to the root XML node. Then a selection in the xsl:for-each iterates through all the descendant nodes with an XML node identifier of elements. The filter ancestor::elements ensures that the found elements XML node is embedded in another elements XML node. The search strategy is not to find an elements XML node and then check for embedded elements XML nodes, but the inverse.

The same result can be achieved using the following modified xsl:template match:

<xsl:template match=”elements”>     <xsl:for-each select=”descendant::elements”>         node name (<xsl:value-of select=”name()” />)         node value (<xsl:value-of select=”text()”/>)     </xsl:for-each> </xsl:template>

In this example XSLT, the xsl:template match is not the root element, but the individual elements XML nodes. And the xsl:for-each select attribute is set to find all embedded elements XML nodes. Notice the use of the descendant axis specifier so that all child elements XML nodes are iterated. In contrast to the previous selection, a specific element is found and then the various subchildren elements XML nodes are selected.

After you study both these examples, you might want to clarify which method of selecting nodes is better. The answer is that neither way is better. To a large degree, the method you use is a matter of personal preference. The only real difference between them is that the second approach (selecting an individual node) distinctly separates the various functionalities of the XSLT. For example, in the root node match example, there could be various xsl:for-each matches. By using function calls and references, you can compensate for the downside of this method. To repeat, in the end, it is really a matter of personal preference.

Conditional processing with an xsl:if

Another approach to solving the embedded elements XML node problem is to use a condition. As in the second approach where the various elements nodes are iterated, a test is made if there is a parent elements XML node. The XSLT would be as follows:

<xsl:template match=”elements”>     <xsl:apply-templates />     <xsl:if test=”ancestor::elements”>             node name (<xsl:value-of select=”name()” />)             node value (<xsl:value-of select=”text()”/>)     </xsl:if> </xsl:template>

When executed, this code results in the following output:

<?xml version=”1.0” encoding=”UTF-8”?>      node name (elements)      node value (Embedded)

This is desired output, but it is only possible if the xsl:apply-templates XSL instruction is added. Remember from previous discussions that without this instruction, the embedded elements XML nodes are not iterated because those elements are marked as read. This effect did not occur in the previous example because the various elements nodes were manually iterated.

The xsl:if XSL instruction uses a Boolean result to know whether or not to execute the contained instructions. If the XPath contained within the test attribute is a non-zero result, the test is considered true. Otherwise, the test is considered false. The way that results are converted to true or false is by using the same rules applied when a value is converted to an XSLT Boolean type. After a true result, the XML nodes within the xsl:if statement are executed. The test attribute does not change the location of the current context, even though tests of other XML nodes can be executed.

Tip

Late at night, I was writing this conditional processing code and forgot the xsl:apply-templates XSL instruction. The XSLT processor initially did not return the correct result. As an experiment, I used the XPath not(ancestor::elements), which returned all elements that I expected. This puzzled me, and I quickly decided to use the XMLSPY XSLT debugger. Within a few seconds the problem was solved. The moral of the story? Use the XMLSPY XSLT debugger to figure out why your code is not working and your life will be simpler.

In the example, the xsl:if the test was simple: Does a node set exist or not? The not function can be used to invert the result. A not converts a false value into a true, and a true value into a false. The following is a list of available operators (note that not all can be used in the context of an XSL condition):

  • not: Converts the contained result value to the inverse value. The function not returns either a Boolean true or false and not a node set. If a populated node set is inverted, a false is returned. If an empty node set is inverted, a true is returned.

  • =: Equality comparison. Typically used to compare two different values to see if they are identical. The equality operator does not modify the original data types, but converts each to a similar type, which when compared returns either a true for a match or false for no match.

  • !=: Inequality comparison. Typically used to compare two different values to see if they are not identical. The equality operator does not modify the original data types, but converts each to a similar type, which when compared returns either a true for a mismatch or false for a match.

  • <, <=: Less-than and less-than-or-equal-to operator. This tests to see if a value is less than another. For example, 1 is less than 2. Typically this operator is used on numeric values because strings or node sets return odd results that are not entirely useful.

  • >, >=: Greater-than and greater-than-or-equal-to operator. This tests to see if a value is greater than another. For example, 2 is greater than 1. Typically, this operator is used on numeric values because strings or node sets return odd results that are not entirely useful.

  • and: The and operator is a bit type operator that combines two values and returns a value. When used in a condition, that value is converted into a Boolean value.

  • or: The or operator is a bit type operator that combines two values and returns a value. When used in a condition, that value is converted into a Boolean value.

  • |: The vertical bar operator is also an or operator. But it is not an abbreviated or because the result is different. When using a vertical bar and the results are two node sets, the two node sets are concatenated into one node set. When using the formal or operator a Boolean result is returned. If either or is used in a condition, the same result is returned because both results are converted to Booleans.

Conditional processing with an xsl:choose

The xsl:if statement is a single condition test. Typically, in other programming languages, you have the capability to test a condition and, if that condition does not work, to test another condition. In XSLT that same approach is possible, but the xsl:choose instruction must be used as in the following example:

<xsl:template match=”elements”>     <xsl:apply-templates />     <xsl:choose>        <xsl:when test=”@haselements = ‘true’”>            node value (<xsl:value-of select=”text()” />)            true value        </xsl:when>        <xsl:when test=”@haselements = ‘false’”>            node value (<xsl:value-of select=”text()” />)            false value        </xsl:when>     </xsl:choose> </xsl:template>

The xsl:choose instruction is the start of a block of contained xsl:when instructions. Each xsl:when instruction has a test attribute, which performs a test identical to the xsl:if instruction. When the first xsl:when test returns a value of true, the XML nodes within the xsl:when instruction are executed. At the end of the executed xsl:when block, the XSLT processor jumps out of the xsl:choose block and continues executing other XSLT instructions.

You can write the same conditions using the xsl:if instruction as follows:

<xsl:template match=”elements”>      <xsl:apply-templates />      <xsl:if test=”@haselements = ‘true’”>          node value (<xsl:value-of select=”text()” />)          true value      </xsl:if>      <xsl:if test=”@haselements = ‘false’”>          node value (<xsl:value-of select=”text()” />)          false value      </xsl:if> </xsl:template>

In contrast to the xsl:choose instruction, if the first xsl:if results in a true value, the second xsl:if may be executed as well. Of course in the example shown, that cannot be the case because the attribute haselements cannot have the value true and false at the same time. What is more likely to happen if a test is executed is that a different test may execute as well. Therefore, knowing which condition to choose in an XSLT is simple. In a single condition test, use xsl:if; in a multicondition test, use xsl:choose.

The other additional option with xsl:choose is the xsl:otherwise instruction. The xsl:otherwise option is executed when no xsl:when condition matches true. For example, you could write the following XSLT:

<xsl:template match=”*”>       <xsl:apply-templates />       <xsl:choose>             <xsl:when test=”@haselements = ‘true’”>                 node value (<xsl:value-of select=”text()” />)                 true value             </xsl:when>             <xsl:when test=”@haselements = ‘false’”>                 node value (<xsl:value-of select=”text()” />)                 false value             </xsl:when>             <xsl:otherwise>                 node name (<xsl:value-of select=”name()” />)                 node value (<xsl:value-of select=”text()” />)             </xsl:otherwise>       </xsl:choose> </xsl:template>

In this example of xsl:choose, there are two tests and a default execution. This multicondition xsl:choose executes the logic that if the found XML node has a true or false value, do something. Otherwise, perform the default of printing out the XML node identifier and value. In a real business application, this logic could be an error generation to indicate a condition that should not have occurred.

In the case of either xsl:if or xsl:choose, it is possible to embed one condition within another. For example, if an xsl:if results in a true, there could be an xsl:choose instruction within the xsl:if. This is also true for an xsl:choose, except that the embedded xsl:if must be embedded within an xsl:when.

The sort feature

By default, when executing a repetition or a templates application, the order of the nodes is dependent on their position in the XML document. There are situations in which a node set should be sorted according to specific criteria. The xsl:sort instruction is responsible for sorting the data. A simple example of sorting all the elements XML nodes is as follows:

<xsl:template match="/">     <xsl:for-each select="descendant::elements">         <xsl:sort select="text()" data-type="text"              order="ascending" />             node name (<xsl:value-of select="name()" />)             node value (<xsl:value-of select="text()"/>)     </xsl:for-each> </xsl:template> 

The xsl:sort instruction is a child of the xsl:for-each or xsl:apply-templates instruction. Although the specification indicates that only the xsl:sort instruction must be a child, placing the xsl:sort instruction as a child of position index > 1 causes the sort to be ignored. If you check the XSLT specification, it is not clear if this is a correct interpretation of the XMLSPY XSLT processor. Therefore, the XMLSPY interpretation is assumed to be correct.

Each xsl:sort instruction represents a sort order to the node set that has been selected. Multiple xsl:sort instructions can be present, but each additional xsl:sort instruction represents an additional sort order. If, in the previous sort example, another xsl:sort instruction were added, the sorting would be first to the text() value and then to the added xsl:sort critieria.

In most cases, every xsl:sort should have three individual attributes that specify how the sort should occur. The full specification is as follows:

  • select: Expression used as a key for sorting purposes. Typically, the expression should not be another node set. The select should return a string or something that can be converted to a string and be used as a unique key. Usable commands are those that return positions, true/false values, or string buffers.

  • lang: Specifies the language of the keys. This is useful when manipulating XML documents not written in English.

  • data-type: Sorting of the data according to the data type, which can be text, number, and XML QNames. The default sort data type is text. If the sort data type is number, the string is converted into a numeric value.

  • order: Specifies how the nodes in the node set will be sorted. They can be in either ascending or descending order.

  • case-order: The case-order is a small but important consideration. When text is sorted, a sorting will happen according to the case. Therefore, if there is a hello and Hello, the locations in the node set may not necessarily be the same as just illustrated. The order of the words according to case depends on the language.

In the explanation of the xsl:sort select attribute in the preceding list, I explain that all keys used for the sorting must be string based. The XPath must, therefore, generate a string and not a node set. Consider the following XPath that generates a node set:

ancestor::* 

When this XPath is used in the context of an xsl:sort, the node set is converted into a string. Consider the following XSLT, which demonstrates how this happens:

<xsl:template match=”/”>     <xsl:for-each select=”descendant::elements”>         <xsl:sort select=”ancestor::*” data-type=”text”              order=”ascending” />         (<xsl:value-of select=”ancestor::*” />)         node name (<xsl:value-of select=”name()” />)         node value (<xsl:value-of select=”text()”/>)     </xsl:for-each>         </xsl:template>

When the XSLT is executed the following result is output:

<?xml version=”1.0” encoding=”UTF-8”?>     (Embedded)     node name (elements)     node value (Embedded)              (Hello)      node name (elements)     node value (Hello)              (HelloWorldEmbedded)     node name (elements)     node value (World)

Notice that the node set that is selected as a key, when converted into a string, uses the default template generation of individual nodes. Is this a useful feature? Probably not, but it does show the automatic conversion of a node set into a string buffer.

Tip

Sorting is a powerful feature. But sorting has its issues, mainly with respect to multiple languages. I speak English, German, and French, all of which have funny characters that have special sorting rules. If you speak languages only expressible in Unicode, you are probably familiar with the ignorance of many developers regarding Unicode languages. XMLSPY is a tool that understands Unicode and, hence, uses sorting rules according to the Unicode specification. If you are a developer who speaks solely a non-Unicode language, check out the Unicode specification to fully understand Unicode sorting.

Text, variables, and data

Thus far, all the XSLT I have discussed relates to writing programs that process XML content. I have not discussed how to generate output from an XSLT process. The output generation has basic identifiers and text values. But output generation such as XSL:FOP is an entire subject on its own and beyond the scope of this book. As an example, notice how the various XSLT outputs shown in this chapter are neatly formatted with carriage returns and how they start on the next line in the correct column. This feature is both desirable and undesirable.

Understanding and Using Whitespace

To understand whitespace, consider the following XSLT:

<xsl:template match=”*”>     <xsl:apply-templates />     node name (<xsl:value-of select=”name()” />) </xsl:template>

Executing this XSLT document on the original XML document generates the following output:

<?xml version=”1.0” encoding=”UTF-8”?>     node name (elements)          node name (child)          node name (elements)          node name (sub)          node name (elements)          node name (data)

Notice the use of whitespace, which includes spaces, carriage returns, and line feeds. The indent of individual node name texts occurs because of the indent of the text in the XSLT. What is not clear is where the line feeds are coming from. The lines result from the line feeds in the XSLT. To get rid of the empty lines, you need to rewrite the XSLT like this:

<xsl:template match="*">     <xsl:apply-templates />     node name (<xsl:value-of select="name()" />)</xsl:template> 

Executing this XSLT document on the original XML document generates the following output:

<?xml version=”1.0” encoding=”UTF-8”?>     node name (elements)     node name (child)     node name (elements)     node name (sub)     node name (elements)     node name (data)

Now all the output is generated in a nice, neat, table formation. The cost of doing this operation is mucking up of the formatting of the XSLT document. The current positioning of the closing xsl:template XML node is not aligned for easy reading of the code.

This is where the problem of whitespace and XML exists. When XSLT code is nicely aligned for easy code reading comprehension, it adds whitespace that the parser cannot simply ignore. Consider the following XML:

<data>     <embedded>         <pre> embedded               text         </pre>     </embedded> </data>

The pre-XML node in XML terms means nothing; but when presented to an HTML parser, the line feed present in the embedded text means a line feed when rendering the document. Hence, the XML parser cannot willy-nilly get rid of the whitespace. The objective is to create XSLT code that encapsulates the XML tags to remove unwanted line feeds but is still easy to read. One rather unorthodox solution for the XSLT is as follows:

<xsl:template match=”*”>     <xsl:apply-templates />     node name (<xsl:value-of select=”name()” />)</xsl:template >

In this solution, there is no space between the individual characters; but where whitespace is disregarded, a line feed is introduced. In XML terms, whitespace is ignored within the declaration of an XML node. Many programmers have proposed this solution, and yet people have not flocked to it. My guess is that it has to do with the formatting look that, although it is better, takes getting used to.

Another solution, used more often, is to use the xsl:text instruction as in the following example:

<xsl:template match=”*”>     <xsl:apply-templates />     <xsl:text>node name (</xsl:text>     <xsl:value-of select=”name()” />     <xsl:text>)</xsl:text> </xsl:template>

Executing this XSLT document on the original XML document generates the following output:

<?xml version=”1.0” encoding=”UTF-8”?>node name (elements)node name (child)node name (elements)node name (sub)node name (elements)node name (data)

So instead of having the text formatted neatly in a table format, all the text is output as single stream. It would appear from first glance that the XSLT processor sometimes ignores whitespace and line feeds and other times does not. But that’s not the case. The result has to do with significant whitespace versus insignificant whitespace. Significant whitespace is whitespace that contains something other than line feeds, carriage returns, spaces, and tabs. In the modified XSLT, there is no significant whitespace.

Escaping Characters

The xsl:text instruction is a special instruction that tells the XSLT processor to output the embedded text as formatted text. The single attribute that can be applied to an xsl:text is disable-output-escaping. To understand what this attribute does, consider the following XSLT:

<xsl:template match=”/”>     <xsl:text disable-output-escaping=”yes”> &lt; hello &gt; </xsl:text> </xsl:template>

Executing this XSLT document on the original XML document generates the following output:

<?xml version=”1.0” encoding=”UTF-8”?><hello>

Using this attribute, it is possible to dynamically create XML content. Within the XML specification, it is possible to create reserved characters using an escaped character buffer. In the case of the example XSLT, the characters &lt; represent the less-than character and the characters &gt; represent the greater-than character. It is not possible to do this in a generic XSLT stream as the following XSLT shows:

 <xsl:template match="/">     &lt;<xsl:value-of select="name()" />&gt; </xsl:template> 

Executing this XSLT document on the original XML document generates the following output:

<?xml version=”1.0” encoding=”UTF-8”?>        &lt;data;&gt;

In the xsl:text instruction, the default value for the disable-output-escaping attribute is No. A reason for escaping XML tags is because you might want to build up XML incrementally, but doing that would violate the rules of XML. Consider the following XSLT:

<xsl:template match=”elements”>     <xsl:apply-templates />     <xsl:if test=”@title = ‘true’”>         <title>     </xsl:if>     <!-- some instructions -->     <xsl:if test=”@title = ‘true’”>         </title>     </xsl:if> </xsl:template>

This XSLT is very common in that you do a test to determine whether or not to generate a block header start. If you must generate a block header, generate the title XML tag. After the condition, the other elements are created and output. To make the generated XML legal, the closing title XML tag is generated. But the problem is that the title tag violates the rules for the XML parser because the title tag starts in one XML block and ends in another XML block. To get around this problem, set the xsl:text with the disable-output-escaping to true. The modified XSLT is as follows:

<xsl:template match="elements">     <xsl:apply-templates />     <xsl:if test="@title = ‘true’">     <xsl:text         disable-output-escaping="yes"> &lt; title &gt; </xsl:text>     </xsl:if>     <!-- some instructions -->     <xsl:if test="@title = ‘true’">         <xsl:text           disable-output-escaping="yes"> &lt; /title &gt; </xsl:text>     </xsl:if> </xsl:template> 

The disable-output-escaping attribute can also be applied to the xsl:value-of instruction, with the same effects.

Another way of generating simple XML elements is to use the xsl:element instruction, as shown in the following example:

<xsl:template match=”elements”>     <xsl:apply-templates />     <xsl:element name=”{@haselements}”>hello</xsl:element> </xsl:template> <xsl:template match=”text()”> </xsl:template>

Executing this XSLT document on the original XML document generates the following output:

<?xml version=”1.0”?><false>hello</false><false>hello</false><true>hello</true>

The XML nodes false and true mean very little, but what was shown in the previous code is that an attribute can serve as an identifier for an XML element. The advantage of the using the xsl:element instruction is that it is simpler and cleaner. Within the xsl:element instruction there is an attribute name, which identifies the name of the element.

Child Elements

It is not possible to add any xsl instructions as child XML nodes of the xsl:text instruction. The XSLT processor generates an error if xsl instructions do exist. For example, it may be tempting to write the following incorrect XSLT:

<xsl:text>{<xsl:value-of select=”name()” />}</xsl:text>

A correct XSLT solution is

<xsl:text>{</xsl:text> <xsl:value-of select=”name()” /> <xsl:text>}</xsl:text>

But if the XSLT text to be added is simple, a better solution would be to use the following XSLT:

<xsl:value-of select=”concat( ‘{‘, name(), ‘}’)” />

The function concat is used to build a buffer that is generated. This way of coding is cleaner and more comprehensible.

Overall Output Control

When the XSLT processor executes, it is possible to control the overall output generation using the xsl:output instruction. Reading the purpose of the xsl:output in the XSLT specification is extremely boring, and you are left scratching your head about what it means. The simplest way to illustrate what xsl:output represents is to consider the following XSLT:

<xsl:stylesheet version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>     <xsl:output method=”html” />     <xsl:template match=”*”>     <xsl:apply-templates />         <xsl:text disable-output-escaping=”yes”> &lt; node name (</xsl:text>             <xsl:value-of select=”concat( ‘{‘, name(), ‘}’)” />         <xsl:text>)</xsl:text>     </xsl:template>     <xsl:template match=”text()”>     </xsl:template> </xsl:stylesheet>

Right after the xsl:stylesheet instruction is the xsl:output instruction, which has the attribute method, which has the value html. In all the examples shown thus far, the output method has defaulted to xml. This time the output should be generated for html. When the XSLT document is executed, the following output is generated:

< node name ({elements}) < node name ({child}) < node name ({elements}) < node name ({sub}) < node name ({elements}) < node name ({data})

What is apparent is that the XML prolog is missing. That makes sense because an HTML document has no idea what to do with the xml prolog. This is a simple example of the purpose of the xsl:output instruction. The following attributes can defined when using xsl:output:

  • method: Specifies how the XSL generated content should be output. Possible options are xml, html, text, qname.

  • version: Specifies the version of the output method.

  • encoding: Specifies the preferred output encoding that the XSLT processor should use to encode the data. In the case of HTML, that could mean escaping text from a Unicode source to a Central European language.

  • standalone: Specifies whether the output document should have a standalone declaration within the document.

  • omit-xml-declaration: Removes the XML declaration at the top of the generated XML buffer.

  • doctype-public: Specifies the system identifier to be used in the document type declaration.

  • doctype-system: Specifies the public identifier to be used in the document type declaration.

  • cdata-section-elements: Specific identifiers that appear in the output in CDATA sections.

  • indent: Specifies whether XSLT processor should add additional whitespace indents in the output.

  • media-type: Specifies the MIME content type of the output to be sent.

In the xsl:output the attributes encoding and cdata-section-elements are useful because they allow fine-tuning of the output data. To show how the cdata-section-elements functions consider the following XSLT:

<xsl:stylesheet version=”1.0” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>     <xsl:output method=”xml” cdata-section-elements=”true” />     <xsl:template match=”elements”>         <xsl:apply-templates />         <xsl:element name=”{@haselements}”>hello</xsl:element>     </xsl:template>     <xsl:template match=”text()”>     </xsl:template> </xsl:stylesheet>

When the XSLT document is executed, the following output is generated:

<?xml version=”1.0” encoding=”UTF-8”?><false>hello</false><false>hello</false><true><![CDATA[hello]]></true>

Looking at the original declaration of the xsl:output instruction, the attribute cdata-section-elements has a value of true. That value is not a true in the Boolean sense, but a string true value. And the attribute value says that whenever true as a node appears, put a CDATA section around the embedded text. If you look in the output, you see that did indeed occur.

To show how the encoding example functions, the XML document needs to be rewritten to the following:

<?xml version="1.0" encoding="ISO-8859-1"?> <data> <html>       <head>            <title>HTMLOutput</title>       </head>       <body>            Stu ndlich        </body>  </html>  </data>  

Notice in this text the special Western European character, which is the u with umlaut. Now consider the following XSLT that takes the original node and copies the node to the output using xsl:copy-of instruction:

<xsl:stylesheet version = ‘1.0’       xmlns:xsl=’http://www.w3.org/1999/XSL/Transform’>     <xsl:output method=”html” encoding=”UTF-8”/>      <xsl:template match=”/”>           <xsl:copy-of select=”/data/*”/>      </xsl:template> </xsl:stylesheet> 

When the XSLT document is executed, the following output is generated:

<html><head><META http-equiv=”Content-Type” content=”text/html; charset=UTF-8”><title>HTMLOutput</title></head><body>            StA˜1/4ndlich        </body></html>

Notice how the Stu ndlich text has been changed to the text StA˜1/4ndlich. This would appear to be an error, but is not. The original encoding of the XML document was ISO-8859-1, which is Western European encoding. To convert that encoding to UTF-8, as per the xsl:output instruction, the text is converted, and the HTML meta tag is added with the encoding. The browser will then load the content and interpret it properly as per the original XML document.

A new XSLT instruction used in the example was xsl:output. The xsl:output instruction copies a selected node to the destination buffer. In this example, it is especially important because a copy operation does not change any of the values.




The XMLSPY Handbook
The Official XMLSPY Handbook
ISBN: 764549642
EAN: 2147483647
Year: 2001
Pages: 121
Authors: Larry Kim

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net