2
votes

Happy New Year to All!

I am learning XQuery with BaseX and face the following problem now.

I am parsing the factbook.xml file which is the part of the distribution.

The following query runs ok:

 for $country in db:open('factbook')//country
 where $country/@population < 1000000 and $country/@population > 500000
 return <country name="{$country/name}" population="{$country/@population}">
 {
   for $city in $country/city
   let $pop := number($city/population)
   order by $pop descending
    return <city  population="{$city/population/text()}"> {$city/name/text()}
    </city>
 }
 </country>

but while trying to generate a html running the second query - if I try to put the "{$country/@population}" in the <h2>Country population: </h2> tag I see an error message "Attribute must follow the root element".

 <html><head><title>Some Countries</title></head><body>
 {
  for $country in db:open('factbook')//country
 let $pop_c := $country/@population
 where $pop_c < 1000000 and $pop_c > 500000
 return
 <p>
 <h1>Country: {$country/name/text()}</h1>
 <h2>Country population: #error comes if I put it here!#</h2>
 {
 for $city in $country/city
 let $pop := number($city/population)
 order by $pop descending
 return ( <h3>City: {$city/name/text()}</h3>,
 <p>City population: {$city/population/text()}</p>
 )
 }
 </p>
 }
 </body></html>

Where is my mistake? Thank you!

2

2 Answers

4
votes

Just using:

{$country/@population}

copies the attribute population in the result. An attribute should follow immediately an element (or other attributes that follow the element) -- but this one follows a text node and this causes the error to be raised.

Use:

<h2>Country population: {string($country/@population)} </h2>
1
votes

When you write {$country/@population}, you do not insert the text of the population attribute, but the attribute itself. If you did not had the "Country population text before it", using {$country/@population} would create something like`

If you want its value, use:

{data($country/@population)}

Or

{data($pop_c)}

since you have already have it in a variable. (the number or string functions can also be used instead of data, but I think data is the fastest)