[xquery-talk] renaming single attributes

Michael Kay mhk at mhk.me.uk
Mon Jun 20 20:07:39 PDT 2005

> What's the easiest and/or most concise way of effecting a 
> transformation
> that renames a single named attribute, if present, and leaves 
> everything
> else the same?  For example, I might want to rename every 
> occurrence of
> @att3 (two instances below) as @NEW-att3. Here's some sample 
> "before" data:
>     <record att1="att1" att3="att3" att4="att4">content1</record>
>     <record att3="att3" att4="att4">content2</record>
>     <record att4="att4" att5="att5">content3</record>
> Here's the "after" version of the same. Note that all nodes 
> except @att3
> remains the same:
>     <record att1="att1" NEW-att3="att3" att4="att4">content1</record>
>     <record NEW-att3="att3" att4="att4">content2</record>
>     <record att4="att4" att5="att5">content3</record>
> What's the simplest document tranformation that will 
> accomplish this goal?

This probably isn't the solution you were looking for, but:

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

<xsl:template match="@att3">
  <xsl:attribute name="NEW-att3"><xsl:value-of select="."/></xsl:attribute>

If you add the constraint that you want an XQuery solution, then (in the
absence of an update facility) you essentially have to simulate the same
kind of recursive descent, copying everything except the one thing you want
to change. It's just a bit more tedious without apply-templates:

declare function f:identity($n as node()) {
  typeswitch ($n)
  case element() as $e return
    element {node-name($e)} 
       {$e/(@* except @att3),
        if (@att3) then attribute {"NEW-att3"} {string(@att3)} else (),
        for $c in $e/node() return f:identity($c)
  case comment() as $c return $c
  case processing-instruction() as $p return $p
  case text() as $t return $t

- and you lose any namespace nodes because there's no way of copying them.

This kind of thing would become much easier in XQuery with higher-order
functions. One could then have a standard tree-walking function that applies
a supplied function to each node. Something like this:

declare function f:rename-att3($n as node()) {
  if ($n instance of attribute(att3))
  then attribute {"NEW-att3"} {string($n)}
  else $n

tree-walk(/, f:rename-att3)

Michael Kay

More information about the talk mailing list