Hi Kendall,

I saw that conversation over on talk@x-query; I'm not sure if I'll have a problem here - all of the documents in this case are short, and we'll be iterating over them individually. I wonder about longer documents, but I haven't had to deal with anything like that (yet).

Best,
Bridger


On Fri, Feb 16, 2018 at 4:35 PM, Kendall Shaw <kendall.shaw@workday.com> wrote:
Hi Christian and all,

Something interesting about this is that I think I saw that a direct recursion like this in BaseX or Saxon  is not suitable for tail call optimization. Or, I ran out of memory trying this once. I wonder if something like SAX for XQuery implemented in XQuery is a useful idea for an extreme case of needing an identity transform.

Kendall

On 2/16/18, 8:56 AM, "basex-talk-bounces@mailman.uni-konstanz.de on behalf of Christian Grün" <basex-talk-bounces@mailman.uni-konstanz.de on behalf of christian.gruen@gmail.com> wrote:

    Hi Bridger,

    Questions like this are welcome!

    A switch approach, as suggested by Liam, might look as follows:

      declare function local:dispatch(
        $nodes as node()*
      ) as item()* {
        for $node in $nodes
        return if (not($node instance of element())) then (
          $node
        ) else switch(name($node))
          case 'docs'   return local:passthru($node)
          case 'doc'    return local:docf($node)
          case 'title'  return local:title($node)
          case 'author' return local:author($node)
          case 'fields' return local:passthru($node)
          case 'field'  return (
            if($node/@name='first') then local:field-1($node) else
            if($node/@name='second') then local:field-2($node) else ()
          )
          default return ()
      };

    The nested if conditions for the 'field' element could be rewritten to
    a switch clause as well.

    In most cases, I tend to use XQuery for transforming existing XML
    nodes. The 'update' keyword gives you a concise syntax for updating
    existing nodes [1]:

      declare %updating function local:rename($node, $name) {
        rename node $node as $name
      };
      $input/* update {
        local:rename(., 'new'),
        .//(title, author) ! (rename node . as 'new-' || name()),
        insert node element new-subject {
          .//field[@name = 'first']/text()
        } into .,
        insert node element new-section {
          element new-entry { .//field[@name = 'second']/text() }
        } into .,
        delete node .//fields
      }

    In this little example, I have accommodated various different ways to
    modify existing nodes (calling a function, using paths and the simple
    map expression, …). As you can easily see, the approach is pretty
    different to the identity transformation in XSLT: Instead of building
    a new document, you are updating existing nodes. This can be both very
    powerful and concise, because you can address and update descendant
    nodes with a simple path expression, but it is mostly appropriate if
    your old and new documents look similar.

    If you want to stick with the official XQuery Update 1.0 syntax, you
    can also use the more verbose copy/modiy/return statements (see the
    same link).

    Hope this helps, feel free to ask for more details,
    Christian

    [1] https://urldefense.proofpoint.com/v2/url?u=http-3A__docs.basex.org_wiki_XQuery-5FUpdate-23update&d=DwIFaQ&c=DS6PUFBBr_KiLo7Sjt3ljp5jaW5k2i9ijVXllEdOozc&r=JgwnBEpN1c-DDmq-Up2QMq9rrGyfWK0KtSpT7dxRglA&m=CoL2BpluuEvyW-WdbNgt2gSoIHO77nRzlVsE_agjRO4&s=zf5U1x9A37aU0FMwZDLFgizGEI8ALjn0uGST2cZGCdw&e=