Re: [xsl] moving an element and then converting it to an attribute

Subject: Re: [xsl] moving an element and then converting it to an attribute
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Wed, 15 Aug 2012 15:47:11 -0400
Hi Jonina,

On 8/15/2012 2:13 PM, Jonina Dames wrote:
Hi, I'm pretty new to XSLT and I'm having some trouble with a project.

I have the following XML:

<media.block id="fun1">
<caption>
<para>
<txt>
<image-size>
spread
</image-size>
</txt>
</para>
</caption>
<media filename="1234567"/>
</media.block>

What I want is to turn the image-size node into an attribute of the
media element, so it looks like this:

<media.block id="fun1">
<caption>
<para>
<txt>
<image-size>
spread
</image-size>
</txt>
</para>
</caption>
<media filename="0801_75750-rm" image-size="spread"/>
</media.block>

But I keep getting stuck. I was thinking I might need to move the
image-size node somewhere before I could turn it into an attribute of
the media element? Can anyone help me with this? I'm just using version
1, not 2.

You're not actually going to move anything.


Instead, you're going to add something somewhere based on the presence of something somewhere else. (You might also want to remove something, but your sample doesn't actually show this.)

You're probably going to use a modified identity transform, right? (I hope so.) If so, you'll have something like this:

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

This single template has the effect of copying your document, by copying every node in it.

To this, you want to add a single template overriding it for the element you want to modify:

<xsl:template match="media">
<!-- copy the element -->
<xsl:copy>
<!-- process the 'image-size' element in a special mode -->
<xsl:apply-templates select="../caption/para/txt/image-size" mode="size-attribute"/>
<!-- copy the media's attributes and content -->
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>


Then a new template to make the new attribute:

<xsl:template match="image-size" mode="size-attribute">
  <!-- making an attribute -->
  <xsl:attribute name="image-size">
    <!-- trimming extra white space from the value -->
    <xsl:value-of select="normalize-space()"/>
  </xsl:attribute>
</xsl:template>

One could do the same thing in just one template with a conditional test, but this is easier to read and more extensible.

(Or I should say it's easier to read if you know how templates work. But if you're going to use XSLT, you'd better. :-)

BTW, I'm assuming your @filename attribute doesn't have to change, as your sample shows. But if it does, you can include a template to do so.

I hope this helps,
Wendell

======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================

Current Thread