saxon xpath 3.1, доступ к переменным при создании карты

У меня есть следующий XML

<customers>
   <continent>NA</continent>
   <Type>Regular<Type>
   <customer>
      <name>John Smith</name>
      <address>123 Oak St.</address>
      <state>WA</state>
      <phone>(206) 123-4567</phone>
   </customer>
   <customer>
      <name>Zack Zwyker</name>
      <address>368 Elm St.</address>
      <state>WA</state>
      <phone>(206) 423-4537</phone>
   </customer>
<customers>

Я пытаюсь построить объект карты для каждого клиента следующим образом:

for $customer in //customers
return 
map {
'continent': //continent/string(),
'type': //Type/string(),
'name': $customer/name/string(),
'address': $customer/address/string(),
'state': $customer/state/string(),
'phone': $customer/phone/string()
}

но для каждой итерации я использую один и тот же континент и тип, которые одинаковы для каждого клиента.

Как я могу построить свой xpath так, чтобы элементы continent и type генерировались только один раз, и к ним можно было получить доступ на каждой карте.

1 ответ

Я думаю ты намеревался for $customer in //customer (не //customers).

Оптимизатор Saxon-EE автоматически вытянет выражения //continent/string() а также //Type/string() вне цикла for, но если вы хотите выполнить эту оптимизацию вручную, вы можете написать:

let $continent := //continent/string(), $type := //Type/string()
return
  for $customer in //customers
  return 
    map {
     'continent': $continent,
     'type': $type,
     'name': $customer/name/string(),
     'address': $customer/address/string(),
     'state': $customer/state/string(),
     'phone': $customer/phone/string()
   }

В качестве альтернативы, я бы написал это без переменных

(//customer) !
    map {
     'continent': string(..!continent),
     'type': string(..!type),
     'name': string(name),
     'address': string(address),
     'state': string(state),
     'phone': string(phone)
   }

но для каждой итерации я использую один и тот же континент и тип, которые одинаковы для каждого клиента.

как я могу построить свой xpath так, чтобы элементы континента и типа генерировались только один раз, и к ним можно было получить доступ на каждой карте.

Я бы сначала создал другой mapи присвойте его переменной:

let $common := map
{
 'continent' : /customers/continent/string(.),
 'type' : /customers/Type/string(.)
}
 return
  for $customer in /customers/customer
  return 
    map {
     'continent': $common?continent,
     'type': $common?type,
     'name': $customer/name/string(),
     'address': $customer/address/string(),
     'state': $customer/state/string(),
     'phone': $customer/phone/string()
   } 

Или можно просто хранить $commonна каждой карте - это означает, что всякий раз, когдаcontinent или type необходимы с любой карты (скажем, содержащейся в переменной $theMap), они будут доступны как:

$theMap?common?continent

а также

$theMap?common?type

Если вы предпочитаете этот дизайн, то код для создания карт будет:

let $common := map
{
 'continent' : /customers/continent/string(.),
 'type' : /customers/Type/string(.)
}
 return
  for $customer in /customers/customer
  return 
    map {
     'common': $common,
     'name': $customer/name/string(),
     'address': $customer/address/string(),
     'state': $customer/state/string(),
     'phone': $customer/phone/string()
   } 
Другие вопросы по тегам