Recipe8.1.Converting Attributes to Elements


Recipe 8.1. Converting Attributes to Elements

Problem

You have a document that encodes information with attributes, and you would like to use child elements instead.

Solution

XSLT 1.0

This problem is tailor-made for what the introduction to this chapter calls the overriding copy idiom. This example transforms attributes to elements globally:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:import href="copy.xslt"/>     <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>     <xsl:template match="@*">   <xsl:element name="{local-name(.)}" namespace="{namespace-uri(..)}">     <xsl:value-of select="."/>   </xsl:element>   </xsl:template>     </xsl:stylesheet>

The stylesheet works by overriding the copy behavior for attributes. It replaces the behavior with a template that converts an attribute into an element (of the same name) whose content is the attribute's value. It also assumes that this new element should be in the same namespace as the attribute's parent. If you prefer not to make assumptions, then use the following code:

<xsl:template match="@*">   <xsl:variable name="namespace">     <xsl:choose>       <!--Use namespsace of attribute, if there is one -->       <xsl:when test="namespace-uri( )">         <xsl:value-of select="namespace-uri( )" />       </xsl:when>       <!--Otherwise use parents namespace -->       <xsl:otherwise>         <xsl:value-of select="namespace-uri(..)" />       </xsl:otherwise>     </xsl:choose>   </xsl:variable>   <xsl:element name="{name( )}" namespace="{$namespace}">     <xsl:value-of select="." />   </xsl:element> </xsl:template>

You'll often want to be selective when transforming attributes to elements (see Example 8-1 to Example 8-3).

Example 8-2. Input
<people which="MeAndMyFriends">   <person firstname="Sal" lastname="Mangano" age="38" height="5.75"/>   <person firstname="Mike" lastname="Palmieri" age="28" height="5.10"/>   <person firstname="Vito" lastname="Palmieri" age="38" height="6.0"/>   <person firstname="Vinny" lastname="Mari" age="37" height="5.8"/> </people>

Example 8-3. A stylesheet that transforms person attributes only
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:import href="copy.xslt"/>     <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>     <xsl:template match="person/@*">   <xsl:element name="{local-name(.)}" namespace="{namespace-uri(..)}">     <xsl:value-of select="."/>   </xsl:element>   </xsl:template>     </xsl:stylesheet>

Example 8-4. Output
<people which="MeAndMyFriends">        <person>       <firstname>Sal</firstname>       <lastname>Mangano</lastname>       <age>38</age>       <height>5.75</height>    </person>        <person>       <firstname>Mike</firstname>       <lastname>Palmieri</lastname>       <age>28</age>       <height>5.10</height>    </person>        <person>       <firstname>Vito</firstname>       <lastname>Palmieri</lastname>       <age>38</age>       <height>6.0</height>    </person>        <person>       <firstname>Vinny</firstname>       <lastname>Mari</lastname>       <age>37</age>       <height>5.8</height>    </person>     </people>

XSLT 2.0

In XSLT 2.0, the solution can be streamlined but the recipe remains essentially the same. Here you can replace the awkward xsl:choose with an XPath 2.0 if-expression.

<xsl:template match="@*">   <xsl:variable name="namespace"                  select="if (namespace-uri( )) then namespace-uri( )                                               else namespace-uri(..)"/>   <xsl:element name="{name( )}" namespace="{$namespace}">     <xsl:value-of select="." />   </xsl:element> </xsl:template>

Discussion

This section and Recipe 8.2 address the problems that arise when a document designer makes a poor choice between encoding information in attributes versus elements. The attribute-versus-element decision is one of the most controversial aspects of document design.[1] These examples are helpful because they allow you to correct your own or others' (perceived) mistakes.

[1] The only other stylistic issue I have seen software developers get more passionate about is where to put the curly braces in C-like programming languages (e.g., C++ and Java).




XSLT Cookbook
XSLT Cookbook: Solutions and Examples for XML and XSLT Developers, 2nd Edition
ISBN: 0596009747
EAN: 2147483647
Year: 2003
Pages: 208
Authors: Sal Mangano

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