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