Ошибка "неопределенная переменная в noteLine" в выражении FLWOR при возврате нескольких узлов

У меня очень странная проблема с циклом FLWOR, который работает в одну сторону, но не в другую. Цель состоит в том, чтобы взять строку любой длины и разбить ее на узлы XML, каждый из которых может содержать только 80 символов. Итак, во-первых, это прекрасно работает:

    for $noteLine in $noteLineArr
    where $noteLine != ''

    return
    if (fn:string-length(fn:normalize-space($noteLine)) < 80) then (
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 1, 80)}</Descr>
    </NTE>  
    ) else if (fn:string-length(fn:normalize-space($noteLine)) > 80 and fn:string-length(fn:normalize-space($noteLine)) <= 160) then (
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 1, 80)}</Descr>
    </NTE>,
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 81, 80)}</Descr>
    </NTE>
    ) else if (fn:string-length(fn:normalize-space($noteLine)) > 160 and fn:string-length(fn:normalize-space($noteLine)) <= 240) then (
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 1, 80)}</Descr>
    </NTE>,
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 81, 80)}</Descr>
    </NTE>,
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 161, 80)}</Descr>
    </NTE>
    ) else()            

Итак, я понимаю, что это не очень элегантно. Я пытаюсь очистить его, переместив первый элемент из if, поскольку он всегда должен использоваться, верно? Меньше кода таким образом? Итак, вот что я попробовал:

for $noteLine in $noteLineArr
where $noteLine != ''

return

    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 1, 80)}</Descr>
    </NTE>, 
    if (fn:string-length(fn:normalize-space($noteLine)) > 80 and fn:string-length(fn:normalize-space($noteLine)) <= 160) then (
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 81, 80)}</Descr>
    </NTE>
    ) else if (fn:string-length(fn:normalize-space($noteLine)) > 160 and fn:string-length(fn:normalize-space($noteLine)) <= 240) then (
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 81, 80)}</Descr>
    </NTE>,
    <NTE>
        <NoteRefCd>WHI</NoteRefCd>
        <Descr>{fn:substring(fn:normalize-space($noteLine), 161, 80)}</Descr>
    </NTE>
    ) else()    

И теперь синтаксический анализатор сообщает мне "неопределенная переменная в noteLine", указывающая на первую строку "если". Что мне здесь не хватает? (обратите внимание, что да, у меня есть другие идеи о том, как убрать это еще больше, но это был первый простой шаг, и когда он потерпел неудачу, я запаниковал).

Решение (спасибо Jens Erat) Блок возврата должен быть заключен в круглые скобки, чтобы заставить его выполнять полную оценку на каждой итерации цикла flwor. Thusly:

for $noteLine in $noteLineArr
where $noteLine != ''

return
    (
        <NTE>
            <NoteRefCd>WHI</NoteRefCd>
            <Descr>{fn:substring(fn:normalize-space($noteLine), 1, 80)}</Descr>
        </NTE>, 
        if (fn:string-length(fn:normalize-space($noteLine)) > 80 and fn:string-length(fn:normalize-space($noteLine)) <= 160) then (
        <NTE>
            <NoteRefCd>WHI</NoteRefCd>
            <Descr>{fn:substring(fn:normalize-space($noteLine), 81, 80)}</Descr>
        </NTE>
        ) else if (fn:string-length(fn:normalize-space($noteLine)) > 160 and fn:string-length(fn:normalize-space($noteLine)) <= 240) then (
        <NTE>
            <NoteRefCd>WHI</NoteRefCd>
            <Descr>{fn:substring(fn:normalize-space($noteLine), 81, 80)}</Descr>
        </NTE>,
        <NTE>
            <NoteRefCd>WHI</NoteRefCd>
            <Descr>{fn:substring(fn:normalize-space($noteLine), 161, 80)}</Descr>
        </NTE>
        ) else()
    )

1 ответ

Решение

Это незначительная проблема синтаксиса. Вы должны поставить круглые скобки вокруг элементов, созданных в return пункт. Чтобы более подробно объяснить проблему, я приведу аналогичный, но упрощенный пример:

for $i in 1 to 3
return
    <foo />,
    <bar />

Вы ожидаете получить следующий результат (два элемента повторяются три раза):

<foo/>
<bar/>
<foo/>
<bar/>
<foo/>
<bar/>

Но вместо этого вы получаете

<foo/>
<foo/>
<foo/>
<bar/>

Это потому, что запрос фактически оценивается как

(
  for $i in 1 to 3
  return
      <foo />
),
<bar />

В вашем коде вы получаете не неожиданный вывод, а сообщение об ошибке. Это потому что $noteLine не определяется после первой запятой ,, Вы получите похожее сообщение об ошибке для следующего запроса:

for $i in 1 to 3
return
    <foo>{ $i }</foo>,
    <bar>{ $i }</foo>

Вот, $i не связан для <bar/> элемент, так как запрос оценивается как

(
  for $i in 1 to 3
  return
      <foo>{ $i }</foo>
),
<bar>{ $i }</foo> (: obivously, $i is not defined here :)
Другие вопросы по тегам