tags:

views:

152

answers:

6

My xml is:

<record>
  <field name="f1"/>
  <id name="f2"/>
  <id name="f3"/>
  <field name="f4"/>
  <info/>
</record>

I want to loop through it in xquery like this:

for $i in $records/record/field | $records/record/id
return
   if ( .... $i is id .... ) then .... do something .... else ... do something else ...

Is this possible? How can distinguish when $i is id and when it is field?

A: 

You can use a function library or create your own user defined function. Something like this:

for $i in $records/record/field | $records/record/id
return
   if (name($i)="id") then .... do something .... else ... do something else ...

http://www.xqueryfunctions.com/xq/fn_name.html

brendan
I've never used XQuery, but it looks to me like you might mean `name($i)` rather than `name($1)`, unless XQuery is even weirder than it looks to me!
Dominic Rodger
yep, typo - thank!
brendan
A: 

Check out the local-name XQuery function - see the MSDN docs here.

Given a node or a node set, it should give you the node's name - the name of the tag. I guess that's what you're looking for, right??

E.g. if you do this:

DECLARE @input XML = '<record>
  <field name="f1"/>
  <id name="f2"/>
  <id name="f3"/>
  <field name="f4"/>
  <info/>
</record>'

SELECT 
    inp.nod.query('local-name(.)')
FROM 
    @input.nodes('//*') AS inp(nod)

You get an output like this:

record
field
id
id
field
info
marc_s
+1  A: 

Instead of those attempts with name() or local-name() I would use self::id e.g.

if ($i[self::id]) then ... else ...
Martin Honnen
+2  A: 

Another neat XQuery solution is to use typeswitch:

for $i in $records/record/field | $records/record/id
return
  typeswitch($i)
  case element(id) return ...
  case element(field) return ...
  default return ...
Oliver Hallam
Thank you, this is definitely what I need.
danatel
A: 

How about something simpler and more XQuery-like

for $i in $records/record/field return do something with field,
for $i in $records/record/id return do something with id

In this case, the values returned by the first for will be merged with the values from the 2nd for.

Tirno
The result will be field-field-id-id but I wanted field-id-id-field.
danatel
A: 

Use typeswitch:

let $record :=
<record>
  <field name="f1"/>
  <id name="f2"/>
  <id name="f3"/>
  <field name="f4"/>
  <info/>
</record>

for $e in $record/*
return
  typeswitch ($e) 
    case element(id) return concat("id",$e/@name)
    case element (field) return concat("field",$e/@name)
    default return "other"
Chris Wallace