Large Wiki Export 3

Last modified by Ludovic Dubost on 2026/06/02 17:54

cogScript allowing a large Wiki export, using filter streams api with failsafe mecanism
Type
Category
Developed by

Ludovic Dubost

Rating
0 Votes
LicenseGNU Lesser General Public License 2.1

Table of contents

Description

This code will use the XWiki filter streams export API including versioning but running it page by page and saving each file as an individual file on disk.

It also includes some failsafe mecanism:

    It continues in case of exception for one specific page
    It will not retry exporting if the file already exists on disk, thus allowing to restart in case of failure (after Wiki crash) or run in multiple batches
    It logs in the app server log in case of timeout if the export process is too long

You can specific a maximum number of pages to include in the export (this allows to test for 10 pages and/or run in multiple steps by increasing the number progressively)

The usage of the filter streams API will allow for handling some specific cases of very large pages which won't be handled properly by LargeXARExport 2

This export has been tested in a 12.10 XWiki

{{groovy}}
import com.xpn.xwiki.*;
import com.xpn.xwiki.doc.*;
import com.xpn.xwiki.plugin.packaging.*;
import java.util.zip.*;
import com.xpn.xwiki.util.Util;
import org.xwiki.filter.type.FilterStreamType;

def getXAR(String filename, XWikiContext context, nb) { 
    def request = xcontext.getRequest();
    def count = 0;
    def fail = 0;
    def importRedirects = true;
    def noRedirectsHql = (importRedirects) ? "" : "and doc.fullName not in (select obj.name from BaseObject as obj where obj.className='XWiki.RedirectClass')"
    def hql = "where 1=1 $noRedirectsHql order by doc.fullName"
    query = services.query.xwql(hql).setLimit(nb)
    def list = query.execute()
    System.out.println("Exporting ${list.size()} pages");
        for(docName in list){
            try {
             def itemdoc = xwiki.getDocument(docName)
             if (importRedirects || !itemdoc.getObject("XWiki.RedirectClass")) {
              count++;
              def docName2 = xwiki.clearName(docName)
              docName2 = "" + count + "-" + docName2 + ".xar"
              println "* Exporting ${count} ${docName} to ${docName2}"
              System.out.println("Exporting ${count} ${docName} to ${docName2}")
              docFile = new File(filename, docName2)
              if (!docFile.exists()) {
                def erefset = services.filter.instance.newEntityReferenceSet()
                erefset.includes(itemdoc.getDocumentReference())
                def inputProperties = [ "entities" : erefset ]
                def outputProperties = [ "target" : "file://${filename}/${docName2}" ]
                def job = services.filter.convert(FilterStreamType.XWIKI_INSTANCE, inputProperties, FilterStreamType.XWIKI_XAR_CURRENT, outputProperties)
                // wait for job completion
                job.join()
                if (job.getStatus().getError()) {
                   fail++;
                   println "* Failed to export ${count} ${docName}: ${job.getStatus().getError()}"
                   System.out.println("Failed to export ${count} ${docName}: ${job.getStatus().getError()}")
                } else {
                  println "* Exported ${count} ${docName}"
                  System.out.println("Exported ${count} ${docName}")
                }
              } else {
                println "* Already exported ${count} ${docName}"
                System.out.println("Already exported ${count} ${docName}")
              }
             } else {
                println "* Not exporting redirect ${docName}"
                System.out.println("Not exporting redirect ${docName}")
             }
            } catch (e) {
              fail++;
              println "* Failed to export ${count} ${docName}."
              System.out.println("Failed to export ${count} ${docName}")
              e.printStackTrace()
              System.out.println("${fail} failed documents")
            } 
        }
        System.out.println("${count} exported documents")
        System.out.println("${fail} failed documents")
}

if (request.filename) {
 def nb = 10
 if (request.nb)
  nb = Integer.parseInt(request.nb)
 getXAR(request.filename,xcontext.getContext(), nb)
 println "{{success}}Export is now finished. Check in the logs for any error{{/success}}"
} else {
 println "== Large Export =="
}
{{/groovy}}


 {{html clean="false" wiki="true"}}
 <form action="" method="post">
 <table border="0">
 <tr>
 <td>File/directory to write to:</td><td><input type="text" name="filename" size="60" value="/tmp/full-export" /></td>
 </tr>
 <tr>
 <td>Nb:</td><td><input type="text" name="nb" size="10" value="10" /></td>
 </tr>
 </table>
 <input type="submit" name="Export" />
 </form>
 {{/html}}

Get Connected