package org.xmlsh.internal.commands; import java.io.File; import java.io.IOException; import java.util.List; import org.xmlsh.core.Namespaces; import org.xmlsh.core.Options; import org.xmlsh.core.XCommand; import org.xmlsh.core.XValue; import org.xmlsh.sh.shell.Shell; import org.xmlsh.util.Util; import org.xmlsh.util.XFile; import net.sf.saxon.s9api.DocumentBuilder; import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.s9api.XPathCompiler; import net.sf.saxon.s9api.XPathExecutable; import net.sf.saxon.s9api.XPathSelector; import net.sf.saxon.s9api.XdmItem; import net.sf.saxon.s9api.XdmNode; /** * Renames one or more files based on an xpath expresion * * * */ public class xmove extends XCommand { @Override public int run(List<XValue> args) throws Exception { Options opts = new Options("x=xpath:,d=dir:,e=ext:,ns:+,f=force,mkdir,q"); opts.parse(args); String xpath = opts.getOptStringRequired("x"); String dir = opts.getOptString("d", "."); String ext = opts.getOptString("e", null); boolean bForce = opts.hasOpt("f"); boolean bQuiet = opts.hasOpt("q"); boolean bMkdir = opts.hasOpt("mkdir"); List<XValue> xargs = opts.getRemainingArgs(); /* * Precompile the xpath */ Processor processor = Shell.getProcessor(); XPathCompiler compiler = processor.newXPathCompiler(); Namespaces ns = null; /* * Add namespaces */ if(!opts.hasOpt("nons")) ns = getEnv().getNamespaces(); if(opts.hasOpt("ns")) { Namespaces ns2 = new Namespaces(); if(ns != null) ns2.putAll(ns); // Add custom name spaces for(XValue v : opts.getOptValues("ns")) ns2.declare(v); ns = ns2; } if(ns != null) { for(String prefix : ns.keySet()) { String uri = ns.get(prefix); compiler.declareNamespace(prefix, uri); } } XPathExecutable expr = compiler.compile(xpath); int failed = 0; for(XValue v : xargs) { XFile inFile = new XFile(getFile(v)); String extension = ext; if(extension == null) extension = inFile.getExt(); if(!move(inFile.getFile(), expr, dir, extension, bForce, bQuiet, bMkdir)) failed++; } return failed; } /** * Do the actual rename by * Evaluating the xpath expression as a string * Optionally adding the extension * * @throws IOException * @throws SaxonApiException */ private boolean move(File inFile, XPathExecutable expr, String dir, String ext, boolean force, boolean bQuiet, boolean bMkdir) throws IOException, SaxonApiException { expr.load(); DocumentBuilder builder = Shell.getProcessor().newDocumentBuilder(); XdmNode context = builder.build(inFile); XPathSelector eval = expr.load(); eval.setContextItem(context); XdmItem res = eval.evaluateSingle(); String base = res == null ? null : res.getStringValue(); if(Util.isBlank(base)) { this.printErr("XPath expression evalates to null string - skipping " + inFile.getName()); return false; } String toName = base + ext; File toFile = new File(getFile(dir), toName); if(!bQuiet) printErr( "Moving " + inFile.getName() + " to " + toFile.getAbsolutePath()); if(bMkdir) { File parent = toFile.getParentFile(); if(parent != null && !parent.exists()) parent.mkdirs(); } Util.moveFile(inFile, toFile, force); return true; } };