Q:

xQuery output by proceeding a heterogenous XML tree

I try to proceed multiple XML files with xQuery (very limited experience so far).  The important part of the XML can be presented like this:
<? xml version="1.0" encoding="UTF-8"? >
<ZOO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<Mammals>
<marsupials>
    <zoo>
        <kangaroo>
        <number>25</number>
            <red_kangaroo>
                <number>1</number>
            </red_kangaroo>
        </kangaroo>
    </zoo>
</marsupials>

<ruminants>
    <giraffe>
        <number>10</number>
        <comments>Comment Text.</comments>
    </giraffe>
    <antelope>
        <number>20</number>
        <comments>Comment Text.</comments>
    </antelope>
    <elk>
        <number>2</number>
        <comments>Comment Text.</comments>
    </elk>
    <mouflon>
        <number>3</number>
        <comments>Comment Text.</comments>
    </mouflon>
    <ibex>
        <number>2</number>
        <comments>Comment Text.</comments>
    </ibex>
    <ox>
        <number>5</number>
        <comments>Comment Text.</comments>
    </ox>
    <other_ruminants>
        <other_ruminant>
            <name>bison</name>
            <number>1</number>
            <comments>Comment Text.</comments>
        </other_ruminant>
        <other_ruminant>
            <name>musk ox</name>
            <number>2</number>
            <comments>Comment Text.</comments>
        </other_ruminant>
    </other_ruminants>
</ruminants>

<rodents>
    <rodent>
        <name>hamster</name>
        <number>10</number>
    </rodent>
    <rodent>
        <name>squirrel</name>
        <number>15</number>
        <comments>Comment Text.</comments>
    </rodent>
    <rodent>
        <other_rodent>
            <other_rodent_name>porcupine</other_rodent_name>
            <comment>Comment Text.</comment>
        </other_rodent>
        <number>1</number>
    </rodent>
    <rodent>
        <other_rodent>
            <other_rodent_name>beaver</other_rodent_name>
            <comment>Comment Text.</comment>
        </other_rodent>
        <number>2</number>
    </rodent>
</rodents>
</Mammals>

</ZOO>

As you see, the marsupials and the most of ruminants have their own tags.  The rodents however have only the tag <rodent> , they are named within with the tag <name> and there are different rodents in each file. 
My attempt to make a audit of the files looks like this ( I work wirh BaseX 7.5):
for $z in /ZOO, $m in $z/Mammals
return
<count>
<!--  file_id comes here later -->
<kangaroo>'{$z//kangaroo/number/text()}'</kangaroo>
<giraffe>'{$z//giraffe/number/text()}'</giraffe>
</count>

... but I cannot do it with rodents part of course since the number of different rodents and their names are different in the different files. 
The desired output would be (for the shown file fragment):
<count>
 <!--  file_id comes here later -->
 <kangaroo>'25'</kangaroo>
 <giraffe>'10'</giraffe>
 <!--  other animals with own tags come here - antelope, mouflon etc. -- >
 <!--  the problems begins here: how to output the rodents in the same way: -->
 <hamster>'10'</hamster>
 <squirrel>'15'</squirrel>
 <!--  the "other rodents" is the next story, but perhaps the solution could be similar? -- >
</count>

Is it possible?  Your help would be greatly appreciated! 
Update: in other words: how could I output the items which do not have their own tags (rodent do not while e.g. the most of ruminants do) and are different in number in different files? 
Update 2: I continued to try it myself in the meantime and here is what I've got now:
The query (only kangaroo, giraffe and rodents are interesting):
for $z in /ZOO, $m in $z/Mammals
return
<count>
<!--  file_id comes here later -->
<kangaroo>{$z//kangaroo/number/text()}</kangaroo>
<giraffe>{$z//giraffe/number/text()}</giraffe>
 { for $r in $m//rodent
  return 
  if ( $r//name/text() ) then
  <sp>{$r//name/text()};{$r//number/text()}</sp>
    else 
  <sp>{$r//other_rodent_name/text()};{$r//number/text()}</sp>
 }
</count>

The actual output:
 <count>
  <!--  file_id comes here later -->
  <kangaroo>25</kangaroo>
  <giraffe>10</giraffe>
  <sp>hamster;10</sp>
  <sp>squirrel;15</sp>
  <sp>porcupine;1</sp>
  <sp>beaver;2</sp>
 </count>

That is, I could somehow output the rodents (hamster, squirrel, porcupine and beaver) with the corresponding numbers as a workaround and I could edit the output later...
However I would prefer to have the tags named dynamically after the rodents, e.g. this way:
 <count>
  <!--  file_id comes here later -->
  <kangaroo>25</kangaroo>
  <giraffe>10</giraffe>
  <hamster>10</hamster>
  <squirrel>15</squirrel>
  <porcupine>1</porcupine>
  <beaver>2</beaver>
 </count>

or alternatively (less preferrable) to have the output this way:
 <count>
  <!--  file_id comes here later -->
  <kangaroo>25</kangaroo>
  <giraffe>10</giraffe>
    <sp>
     <name>hamster</name>
     <number>10</number>
    </sp>
    <sp>
      <name>squirrel</name>
      <number>15</number>
    </sp>
    <sp>
      <name>porcupine</name>
      <number>1</number>
    </sp>
    <sp>    
      <name>beaver</name>
      <number>2</number>
    </sp>
 </count>

How could I achieve this with xQuery? 
Update 3 (and the last update for tonight :-) ):
If I break away from the xml output and use the csv output, it seems that I have the solution now. 
The query:
 let $nl := "&#10;"
 for $z in /ZOO, $m in $z/Mammals
 return
 (
  string(
   concat
   (
     'kangaroo', ';', $m//kangaroo/number/text(),$nl,
     'giraffe', ';', $m//giraffe/number/text(), $nl
  )),

 for $r in $m//rodent
 return
 ( 
 if ( $r//name/text() ) then
 string( concat( $r//name/text(), ';', $r//number/text(), $nl ) )
 else
 string( concat( $r//other_rodent_name/text(), ';', $r//number/text(), $nl ) )
 )
 )

and the output:
 kangaroo;25
 giraffe;10
  hamster;10
  squirrel;15
  porcupine;1
  beaver;2

which can easily be processed further. 
A new small question here: where comes the indentation from?  Many thanks for your time. 

A:

The only way to identify an "animal" in your XML is the existence of the number element. 
/ZOO//*[number]

Once we have selected an animal, we can use this approach to get it's name:
if (fn:exists($animal/name))
then $animal/name/fn:string(.) 
else
  if (fn:exists($animal/other_rodent))
  then $animal/other_rodent/other_rodent_name/fn:string(.) 
  else fn:local-name($animal)

Adding element constructors and replacing the nested conditionals with union and sequence operations gives us a complete example:
element count {
  for $animal in /ZOO//*[number]
  let $name :=
    ( $animal/(name|other_rodent/other_rodent_name)/text(),
      fn:local-name($animal) )[1]
  let $number := $animal/number/fn:string(.) 
  return
    element { fn:replace($name, " ", "_") } {
      fn:concat("'", fn:concat($number, "'"))
    }
}

