В XQuery, как я могу рекурсивно фильтровать потомков на основе данного предиката? - PullRequest
3 голосов
/ 27 октября 2011

Учитывая этот фрагмент XML:

<root> <!-- $root points here -->
  <!-- ... -->
  <A visible="true">
    <B visible="false">
      <C visible="true"/> <!-- but effectively false! -->
    </B>
    <D visible="true">
      <E visible="true" />
      <F visible="false" />
    </D>
  </A>
  <!-- ... -->
</root>

выполнение запроса $root//A даст мне A и всех его потомков. Пока все хорошо.

Вместо этого я хочу отфильтровать потомков A по предикату, скажем [@visible=true]. Я ожидаю, что запрос вернет

  <A visible="true">
    <D visible="true">
      <E visible="true" />
    </D>
  </A>

вместо этого, т.е. отфильтровать все дочерние элементы, которые не соответствуют предикату (или чьи родители не соответствуют ему).

Представьте себе систему графического интерфейса, которая описана в XML, как описано выше, и где я отфильтровываю дерево на предмет видимых элементов при его рендеринге.

Я думаю, это было бы тривиально с XSLT, но я обязан использовать XQuery.

Ответы [ 2 ]

2 голосов
/ 27 октября 2011

Это можно сделать и в XQuery без особых усилий. Просто имейте функцию, рекурсивно переписывающую квалифицированные узлы, применяя фильтр:

declare function local:rewrite($node as node()) as node()?
{
    typeswitch ($node)
    case element() return
        if (local:filter($node)) then
            element {node-name($node)}
            {
                $node/@*,
                for $child in $node/node() return local:rewrite($child)
            }
        else
            ()
    default return
        $node
};

declare function local:filter($node as element()) as xs:boolean
{
    $node/@visible
};

Затем с помощью выражения пути выберите A и примените функцию к результату:

for $a in $root//A return local:rewrite($a)

Функция использует общий шаблон для использования XQuery для обработки указанных задач XSLT. На самом деле, я думаю, что это тоже очень приемлемо. Со своей стороны, я благодарен за то, что здесь нет необходимости оставлять нотацию XQuery ...

1 голос
/ 27 октября 2011

Вы можете сделать это, используя XQuery Update и удалив все невидимые:

copy $c:=$root
modify delete node $c//*[@visible="false"]
return $c
...