[xquery-talk] renaming single attributes

Howard Katz howardk at fatdog.com
Mon Jun 20 14:01:12 PDT 2005


 > -----Original Message-----
 > From: Michael Kay [mailto:mhk at mhk.me.uk] 
 
 > > 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>
 > 
 > <xsl:template match="@att3">
 >   <xsl:attribute name="NEW-att3"><xsl:value-of 
 > select="."/></xsl:attribute> </xsl:template>
 > 
 > 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:
 
Yes, I was primarily interested in an XQuery solution. (Given the name of
the list, I didn't think I'd need to specify that.) Nevertheless I'm glad
you provided this code snippet since it raises one interesting question. Why
do the match and select attributes have a unioned value of "node() | @*"?
Doesn't the first term of the union subsume the second?

 > 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
 > }

Hmm, I'm having to go slow to parse the bit of code you've got packed into
the "case element() as $e" clause. Thanks -- seriously! -- for that bit of a
mental workout. I also hadn't seen "except" used in exactly that way before.
That's a much more natural usage than "intersect" in this particular
instance.

 > - 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)

That would indeed be very nice.

 > 
 > Michael Kay
 > http://www.saxonica.com/
 > 
 > 



More information about the talk mailing list