6.3. Creating Attributes with the <xsl:attribute> Instruction Element

One of the most useful instruction elements is the <xsl:attribute> element, which, as its name indicates, creates attributes. It has two attributes, as shown in the following element model definition: the name attribute, which establishes the new attribute's name, and the namespace attribute, which can give a namespace URI for the attribute, if necessary.

<!-- Category: instruction -->

<xsl:attribute

  name = { qname }

  namespace = { uri-reference }>

  <!-- Content: template -->

</xsl:attribute>

Using <xsl:attribute> is a good example of how XSLT stylesheets, as well-formed XML data instances themselves, benefit from and can be interpreted by means of XML syntax rules for the logical syntax of their structure. Based on the placement of the <xsl:attribute> element, the attributes created will be inserted into the element whether an LRE or otherwise in which the <xsl:attribute> instruction element is nested, as Example 6-3 illustrates. Assume that we want to add an address attribute to the houses in our previous example.

Example 6-3. Adding attributes with <xsl:attribute>.
					TEMPLATE RULE:

<xsl:template match="block">
    <block>
    <xsl:element name="house">
          <xsl:attribute name="address">1</xsl:attribute>
    </xsl:element>
    <xsl:element name="house">
          <xsl:attribute name="address">2</xsl:attribute>
    </xsl:element>
    <xsl:element name="house">
          <xsl:attribute name="address">3</xsl:attribute>
    </xsl:element>
    <xsl:element name="house">
          <xsl:attribute name="address">4</xsl:attribute>
    </xsl:element>
    <xsl:element name="house">
          <xsl:attribute name="address">5</xsl:attribute>
    </xsl:element>
    </block>
</xsl:template>
OUTPUT:

<block>
    <house address="1"/>
    <house address="2"/>
    <house address="3"/>
    <house address="4"/>
    <house address="5"/>
</block>

The result of this stylesheet adds the address attribute to each new house. Note that the XSLT processor automatically converts empty elements to the proper format.

Again, this example can be accomplished using a few LREs, but the usage demonstrated in the previous section with AVTs also applies to <xsl:attribute>. The name attribute value can be an expression when used as an AVT by adding curly braces {}. As an added bonus, the content of the attribute value to be generated can now be calculated using any of the XSLT elements that are valid within a template. This is because the content of the <xsl:attribute> element is defined as a template.

A more complex usage, as shown in Example 6-4, might involve generating an address using the position() function to find out which <block> the houses are on. See Section 5.2.6.1 for an explanation of how context affects the value of the position().

Example 6-4. Creating house numbers with <xsl:attribute> using concat(), and position().
					TEMPLATE:

<xsl:template match="block">
<block>
<xsl:element name="house">
<xsl:attribute name="address"><xsl:value-of
select="concat(position(),
'01')"/></xsl:attribute>
</xsl:element>
<xsl:element name="house">
<xsl:attribute name="address"><xsl:value-of
select="concat(position(), '02')"/></xsl:attribute>
</xsl:element>
<xsl:element name="house">
<xsl:attribute name="address"><xsl:value-of
select="concat(position(), '03')"/></xsl:attribute>
</xsl:element>
<xsl:element name="house">
<xsl:attribute name="address"><xsl:value-of
select="concat(position(), '04')"/></xsl:attribute>
</xsl:element>
<xsl:element name="house">
<xsl:attribute name="address"><xsl:value-of
select="concat(position(), '05')"/></xsl:attribute>
</xsl:element>
</block>
</xsl:template>
OUTPUT:

<?xml version="1.0" encoding="utf-8"?>
<block>
<house address="101"/>
<house address="102"/>
<house address="103"/>
<house address="104"/>
<house address="105"/>
</block>
<block>
<house address="201"/>
<house address="202"/>
<house address="203"/>
<house address="204"/>
<house address="205"/>
</block>
<block>
<house address="301"/>
<house address="302"/>
<house address="303"/>
<house address="304"/>
<house address="305"/>
</block>
<block>
<house address="401"/>
<house address="402"/>
<house address="403"/>
<house address="404"/>
<house address="405"/>
</block>
<block>
<house address="501"/>
<house address="502"/>
<house address="503"/>
<house address="504"/>
<house address="505"/>
</block>
<block>
<house address="601"/>
<house address="602"/>
<house address="603"/>
<house address="604"/>
<house address="605"/>
</block>

The resulting XML file contains the new <house>s with their appropriate number, based on the number of the <block> they are on. The position() function gets the number of the current <block>, and the concat() function combines it with the number of the house for each <house>.

Some of the city planners have approved the addition of several homes and addresses to Woodridge Street, and we want to make Woodridge Street the value of a name attribute for <sidestreet>, so that <sidestreet> can also contain several <house> elements, as shown in Example 6-5.

Example 6-5. Creating attributes with <xsl:attribute>.
					TEMPLATE RULE:

<xsl:template match="//sidestreet[contains(., 'Woodridge')]">
<sidestreet>
<xsl:attribute name="name"><xsl:value-of
select="text()"/></xsl:attribute>
      <house><xsl:attribute name="address">1100</
xsl:attribute>
      </house>
      <house><xsl:attribute name="address">1101</
xsl:attribute>
      </house>
      <house><xsl:attribute name="address">1102</
xsl:attribute>
      </house>
</sidestreet>
</xsl:template>
OUTPUT:

<sidestreet name="Woodridge Street">
<house address="1100"/>
<house address="1101"/>
<house address="1102"/>
</sidestreet>

Here we are using LREs to create the houses, and adding the attribute directly to each LRE with the <xsl:attribute> element. We could then add other contents to the <house> elements as needed. Notice that we did not use <xsl:apply-templates>, and so the original text data or PCDATA that listed Woodridge Street as the only content of <sidestreet> was not output again as content of the new <sidestreet>.

The nesting of <xsl:attribute> in the <house> LREs serves to situate the resulting address attribute inside, or as part of, the <house> in the output result tree. Remember from Chapter 1 that the parent of an attribute is the element that contains it, but at the same time, the attribute is not and cannot be considered a child of the element itself. Accordingly, then, nesting the <xsl:attribute> element within the element makes the attribute part of the new element.

Note

The <xsl:attribute> element must always appear first inside an LRE or <xsl:element>, prior to any additional LREs or instruction elements; otherwise, the attribute being defined is ignored in the output.


6.3.1. Using <xsl:attribute> with Namespaces

The <xsl:attribute> instruction provides a way to declare a namespace for the attribute being created, using the optional namespace attribute to declare it. The value of the namespace attribute can be an expression, in the form of an AVT, but it should resolve to a URI.

There is no special provision (no attribute) for declaring a prefix for the namespace that is being declared, but it can be added in the name attribute, using the form name="prefix:element-name" as the declaration. However, the XSLT processor decides whether to use a prefix defined in this manner. If the prefix defined for an attribute happens to be xmlns, the XSLT processor will not generate the namespace in the result tree. The xmlns is a reserved prefix and should not be used in an <xsl:attribute> name attribute. In Example 6-6, we add a namespace when declaring an attribute by simply adding the namespace attribute to the <xsl:attribute> element; but in this case, we do not add a prefix.

The resulting <font> element has the XSLT processor specific prefix (generated by James Clark's XT) automatically inserted as shown in bold. The namespace URI, http://www.our_company.com, is clear, as is the defined attribute name, "our_company_color," but the prefix is still up in the air. In fact, the temptation to make the attribute declaration stipulate the prefix'namespace="xmlns:WRONG='http://www.our_company.com'"' may seem logical, but is not correct. Example 6-7 shows the proper way to declare a prefix for a namespaced attribute.

Example 6-6. Creating a series of HTML font attributes with <xsl:attribute> inside LREs.
						TEMPLATE RULE:

<xsl:template match="/">
<font>
      <xsl:attribute name="fontface">courier</xsl:attribute>
      <xsl:attribute name="size">4</xsl:attribute>
      <xsl:attribute name="our_company_color"
      namespace="http://www.our_company.com">quadraseptic-
chartreuse-
      taupe</xsl:attribute>
</font>
</xsl:template>
OUTPUT:

<font fontface="courier" size="4"
ns0:our_company_color="quadraseptic-chartreuse-taupe"
xmlns:ns0="http://www.our_company.com"/>

Example 6-7. Adding a prefix to a namespace with <xsl:attribute>.
<font>
<xsl:attribute name="fontface">courier</xsl:attribute>
<xsl:attribute name="size">4</xsl:attribute>
<xsl:attribute name="myprefix:our_company_color"
namespace="http://www.our_company.com">quadraseptic-chartreuse-
taupe</xsl:attribute>
</font>

So, the author of the XSLT stylesheet creating a namespaced attribute with <xsl:attribute> is at the mercy of the chosen processor as to what prefix will result, even if it is defined correctly. Happily, XT does pick up on the prefix value defined in the name attribute, resulting in:

<font fontface="courier" size="4"
myprefix:our_company_color="quadraseptic-chartreuse-taupe"
xmlns:myprefix="http://www.our_company.com"/>

Regardless of the range of uses for <xsl:attribute>, the variety of possible namespace prefixes, or the values or names for the created attributes being specified, this element provides indispensable functionality for a range of contexts. Most applicably, for industrial-strength applications of XSLT stylesheets, the <xsl:attribute-set> element offers additional versatility.

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

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