[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Copying nested tags and adding attributes

Subject: Re: Copying nested tags and adding attributes
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Tue, 30 Jan 2007 10:31:22 +0100
Re:  Copying nested tags and adding attributes
graeme.ludwig@xxxxxx wrote:
<description>See how <b>cans</b> are made into model cars, planes, bikes, etc. at <a href="http://www.tincanmodels.com/" target="_self">Tin Can Models</a>.
</description>
and transform it into
See how <b>cans</b> are made into model cars, planes, bikes, etc. at <a href="http://www.tincanmodels.com/" alt="Tin Can Models" target="_self">Tin Can Models</a>.
i.e. I want to add an alt attribute to the hyperlink and set it to the text of the link itself. The bold attribute should remain unchanged.
<xsl:template match="description">
<xsl:copy-of select="node()"/>
</xsl:template>
('bold' is not an attribute, but a node)

If you want to do a copy and you want to change some things, the best method to use is the identity template, or copying template. Sel Mangano in his "XSLT Cookbook" calls this technique the "Overriding Copy Idiom" (chapter "XML to XML").

The trick is simple, but when beginning with XSLT a little confusing: you create a "rule" (in xslt terms: a template) that makes a shallow copy of the current node and applies all templates for all children nodes. In XSLT, only the most specific rule is used, which makes it easy to override (that's why 'Overriding Copy Idiom') this general rule with more specific ones.

The general template looks like this:

<xsl:template match="node( ) | @*">
  <xsl:copy>
     <xsl:apply-templates select="@* | node( )"/>
  </xsl:copy>
</xsl:template>

This template has been thoroughly discussed several times in the archive, so I leave it to this for now. Note the difference between "copy-of" and "copy". The first copies everything, including all children, and *does not* let you override anything. The second only copies the current node and gives you the option to do whatever you want with it (like adding children like attributes, texts, other nodes whatever).

After you have added the above template, all you need to do is adding specific templates. In your case, you seem to want to remove the 'description' node (well, the tag, as you may put it) but you want to keep its children:

<xsl:template match="description">
   <xsl:apply-templates select="@* | node()" />
</xsl:template>

Run it with only these two and watch the effect. Note the absence of "xsl:copy".
Next, you'd like to change the 'a'-node, in particular, you want to add an attribute 'alt' to the 'a'-node. This can be done in several ways, I show you one:


<xsl:template match="a">
<xsl:copy>
<xsl:attribute name="alt"><xsl:value-of select="." /></xsl:attribute>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>


Run it, with only this and the copy template and watch the effect. Its intent is to copy itself ('a'), add an attribute, and then add the children (the text, the attributes). Note that it will give a dynamic error if you place xsl:attribute after the xsl:apply-templates. This is because attributes must be created before any children of a node are created (the child is here: the text of the 'a' node).

If you place all templates inside a stylesheet (order is not important), and run it with your source, you will get the desired result, because the XSLT processor will automatically choose the matching templates for 'a' and 'description' when it encounters them in the source tree.



to get the text out as per solution 12, but am unsure how to generate the extra alt attribute for any <a> elements that occur within the text. I believe I am using an XSLT 1.0 processor.

If you are unsure, run the following stylesheet, it will print the version for you (also see the List Guidelines at MulberryTech's):


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>


<xsl:template match="/">
<xsl:text>My XSLT Version: </xsl:text>
<xsl:value-of select="system-property('xsl:version')"/>
</xsl:template>
</xsl:stylesheet>



The output will look like:


My XSLT Version: 1.0



Cheers,
-- Abel Braaksma
  http://www.nuntia.nl

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.