Рекурсивная копия папки с XQuery

Мне нужно скопировать всю папку проекта на сервер MarkLogic, и вместо того, чтобы делать это вручную, я решил сделать это с помощью рекурсивной функции, но это становится худшей идеей, которая у меня когда-либо была. У меня проблемы с транзакциями и синтаксисом, но, будучи новичком, я не нахожу правильного способа решить эту проблему. Вот мой код, спасибо за помощь!

import module namespace dls = "http://marklogic.com/xdmp/dls" at "/MarkLogic/dls.xqy";

declare option xdmp:set-transaction-mode "update";

declare function local:recursive-copy($filesystem as xs:string, $uri as xs:string)
{
  for $e in xdmp:filesystem-directory($filesystem)/dir:entry
  return 
    if($e/dir:type/text() = "file")
        then dls:document-insert-and-manage($e/dir:filename, fn:false(), $e/dir:pathname)
    else
      (
          xdmp:directory-create(concat(concat($uri, data($e/dir:filename)), "/")),
          local:recursive-copy($e/dir:pathname, $uri)
      )

};

let $filesystemfolder := 'C:\Users\WB523152\Downloads\expath-ml-console-0.4.0\src'
let $uri := "/expath_console/"

return local:recursive-copy($filesystemfolder, $uri)

person MissArmstrong    schedule 29.08.2017    source источник
comment
Сколько документов вы копируете? Хорошие решения сужаются, если ваш набор данных очень велик. Кроме того, вы уверены, что вам нужны длс? Возможно, вас устроит старый добрый xdmp:document-insert?   -  person Sam Mefford    schedule 29.08.2017
comment
@SamMefford Ну, я пытаюсь скопировать весь вложенный проект, который действует как консоль пользовательского интерфейса, чтобы увидеть иерархию файлов и папок внутри самого сервера, так что нет, использование только xdmp:document-insert не поможет. Нет, я не уверен насчет dls, я просто пытаюсь найти решение. Я также пытался использовать команду mlcp, но она не может связаться с сервером.   -  person MissArmstrong    schedule 29.08.2017


Ответы (1)


MLCP было бы неплохо использовать. Однако вот моя версия:

declare option xdmp:set-transaction-mode "update";

declare variable $prefix-replace := ('C:/', '/expath_console/');

declare function local:recursive-copy($filesystem as xs:string){
   for $e in xdmp:filesystem-directory($filesystem)/dir:entry
    return 
      if($e/dir:type/text() = "file")
         then 
           let $source := $e/dir:pathname/text()
           let $dest := fn:replace($source, $prefix-replace[1], $prefix-replace[2]) 
           let $_ := xdmp:document-insert($source,
              <options xmlns="xdmp:document-load">
                <uri>{$dest}</uri>
              </options>)
           return <record>
                     <from>{$source}</from>
                     <to>{$dest}</to>
                  </record>
         else
           local:recursive-copy($e/dir:pathname)

};

let $filesystemfolder := 'C:\Temp'

return <results>{local:recursive-copy($filesystemfolder)}</results> 

Обратите внимание на следующее:

  • Я изменил свой образец на каталог C:\Temp
  • Выходные данные представляют собой XML только потому, что по соглашению я стараюсь делать это на случай, если мне нужно проанализировать результаты. Именно так я обнаружил ошибку, связанную с конфликтующими обновлениями.
  • Я решил определить простую замену префикса в URI.
  • Я не увидел необходимости в длс в вашем описании
  • Я не видел необходимости в явном создании каталогов в вашем случае использования
  • Причина, по которой вы получали конфликтующие обновления, заключалась в том, что вы использовали только имя файла в качестве URI. Во всей структуре каталогов эти имена не были уникальными — отсюда и конфликтующие обновления при двойной вставке одного и того же URI.
  • This is not solid code:
    • You would have to ensure that a URI is valid. Not all filesystem paths/names are OK for a URI, so you would want to test for this and escape chars if needed.
    • Large filesystems would time-out, so spawning in batches may be useful.
      • A an example, I might gather the list of docs as in my XML and then process that list by spawning a new task for every 100 documents. This could be accomplished by a simple loop over xdmp:spawn-function or using a library such as taskbot by @mblakele
person David Ennis    schedule 29.08.2017
comment
Я признаю, что код не самого лучшего качества, и я понимаю его ограничения, но, поскольку проект довольно маленький, я не думал о больших файловых системах. С другой стороны, проект не настолько мал, чтобы копировать его вручную, так что это была попытка автоматизировать копирование. Я также пробовал с mlcp, но в настоящее время у меня проблемы с тем, чтобы сказать ему, в какую конкретную базу данных копировать файлы, единственное решение, которое я нашел, - это изменить базу данных, на которую ссылается сервер по умолчанию, который является App-Services. Я знаю, что это довольно жестокий подход, но будучи новичком в этих вещах, я пытаюсь решать проблемы, как могу. - person MissArmstrong; 30.08.2017
comment
В любом случае, спасибо за ваше решение, я попробую его в ближайшее время! - person MissArmstrong; 30.08.2017
comment
mlcp может быть запущен через порт 8000 и имеет параметр -output_database. См. раздел 2.4 здесь: docs.marklogic.com/guide/mlcp.pdf. - person David Ennis; 30.08.2017
comment
в руководстве по marklogic на веб-сайте была возможность запустить команду для определенного порта, но она замаскирована, поэтому я могу запустить ее только на порту 8000, но спасибо за другой вариант, это кажется разумным способом решения проблемы. Я нашел! - person MissArmstrong; 06.09.2017