docbook stylesheets are hard

2008-06-03T17:01:21Z
Dave Pawson.  link
Home

docbook stylesheets are hard

docbook stylesheets are hard

I'm just about ready to give up. I've had around 4FT equivalent days reading Makefiles, tweaking stylesheets and building a relax NG schema. I'm trying to lift the docbook build process used for tdg over to a more general purpose schema. I've got to the point of integrating the detailed element/attribute documentation and I've come unstuck. The makefiles are complex, the stylesheets are complex and there's no hint of any documentation. So far, so good, but the break point was when I simply couldn't see a way of progressing. It works on docbook, fails on my 20 line schema and I can't see why. Enough is enough.

Emacs and Twitter

I've taken to Tweeting a little recently, via Pidgin, the IM client installed by default on FC9. Some reason the 'friend', twitter at twitter.com has been off line for the last few weeks. I started to look round for another IM client with twitter support and found references to an emacs minor mode. Installed, just for fun and hey presto it works, using the REST interface to twitter. Even shows recent tweets for those I'm following. Really should stop calling it an editor and remember it is a programming environment.

One of the surprises when reading the docbook build kit was finding Beanshell in use in an alternative ant script. I'd never heard of it. Installed it today and used it to solve a problem I've noted. Docbook needs to collate the files in a directory, wrap them in xInclude statements and process them as part of the tdg build. I tried to do a simpler case using netbeans and it comes out quite neatly.



bsh=/usr/share/java
java -cp $bsh/bsh-2.0b4.jar bsh.Interpreter $*

to run the script.



The script:

import nu.xom.Element;
import nu.xom.Attribute;
import nu.xom.Comment;
import nu.xom.Document;
import nu.xom.Serializer;
import java.util.Vector;
import java.io.File;
import java.io.IOException;
import java.io.FileOutputStream;


// Adjust to locate xom.jar
// Sourced http://www.xom.nu/
addClassPath("/myjava/xom-1.2b1.jar");


/**
 *
 * @author dpawson
 */
public class BuildXML {

    /**
     * element to use for filename
     */
    private final String FELEMENT = "file";
    /**
     * element to use for directory
     */
    private final String DELEMENT = "dir";
    /**
     * Attribute to use for directory name
     */
    private final String NATTRIB = "dir";

   
    /**
     * List a directory as an XML structure
     * @param dirName directory to list
     * @param extn file extension sought
     * @return
     */
    public Document lstDir(String dirName, String extn) {
        Element dir = new Element(DELEMENT);
        Comment comment = new Comment("BuildXML version 1.0");
        comment = new Comment("Directory list of " + dirName);
        dir.appendChild(comment);
        Attribute att = new Attribute(this.NATTRIB, dirName);
        dir.addAttribute(att);
        dir = xmlfiles(dirName, extn, dir);
        Document doc = new Document(dir);
        return doc;
    }

    /**
     * 
     * @param dirName - directory name to list
     * @param extn - file name extensions sought
     * @param dir - Element to which content must be added
     * @return Element Built xom structure
     */
    Element xmlfiles(String dirName, String extn, Element dir) {
        Element res = dir;
        Element tmp;
        File d = new File(dirName);

        if (!(d.exists())) {  // not found
            return res;
        }


        if (d.isDirectory()) {
            File[] dirlist = d.listFiles(); // List the files
            for (int i = 0; i < dirlist.length; i++) {
                //iterate through the directory
                File f = dirlist[i];
                if (f.isDirectory()) {
                    Element subdir = new Element(this.DELEMENT);
                    String dname = f.getAbsolutePath();
                    Attribute att = new Attribute(this.NATTRIB, dname);
                    subdir.addAttribute(att);
                    Element subdirFilled = xmlfiles(dname, extn, subdir);
                    if (subdirFilled.getChildElements().size() > 0) {
                        res.appendChild(subdirFilled); // append subdirectory
                    }
                } else {   // found a file, add (filtered by extn)
                    String fn = f.getName();
                    if (fn.endsWith(extn)) {
                        tmp = new Element(this.FELEMENT);
                        tmp.appendChild(fn);
                        res.appendChild(tmp);
                    }
                }
            }
            return res;
        } else { // passed a file instead of a directory
            String fn = d.getName();
            if (fn.endsWith(extn)) {
                tmp = new Element(this.FELEMENT);
                tmp.appendChild(fn);
                res.appendChild(tmp);
            }
            return res;
        }
    }

    /**
     * Serialize the Document to file
     * @param doc input xml document
     * @param filename Filename of file to write to
     */
    public void serialize(Document doc, String filename) {
        String result = doc.toXML();

        try {
            java.io.File tmp = new File(filename);
            FileOutputStream fos = new FileOutputStream(tmp);
            Serializer serializer = new Serializer(fos, "utf-8");
            serializer.setIndent(4);
            serializer.setMaxLength(64);
            serializer.write(doc);
            serializer.flush();
            fos.close();
        } catch (IOException ex) {
            System.err.println(ex);
        }


    //System.out.println(result);
    //System.out.println("See " + filename);
    }

    /**
     * Dump xml file to screen
     * @param f
     */
    void dumpXML(String f) {
        System.out.println(f);

    }

    /**
     * 
     * @param f
     * @param extn
     * @return
     */
    private Element prFile(File f, String extn) {
        Element retval = null;
        String fname = f.getName();
        if (fname.endsWith(extn)) {
            retval = new Element("file");
            retval.appendChild(fname);
        }
        return retval;
    }

   
}




 //Input args are in bsh.args

/** Usage:
bs2.bsh inputDirectory(Full Path String), extention(String), outputFile(string)

    //print(bsh.args[1]);
    **/
if (bsh.args.length != 3){
    print("Only "+bsh.args.length+" args");
    print("Usage: bs2.bsh inputDirectory(Full Path String), \n"+
	  "extension(String), \n"+
	  "outputFile(string)\n");
    print("E.g. bsh /temp xml output.xml");
    System.exit(2);

}

String dir = bsh.args[0]; // Cmd line args
String extn = bsh.args[1];
String opfilename=bsh.args[2];
        String extn="xml";
        BuildXML bld = new BuildXML();
        Document d=bld.lstDir(dir, extn);
        if (d != null) {
            //System.out.println("****Resolved");
            bld.serialize(d, opfilename);
        } else {
            System.out.println("Directory" +
                    dir +
                    " not found");
        }







/**
 * Copyright (C) 2008  Dave Pawson
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 **/




I have now found a way to pass parameters into the script, so I now have a command line where I can pipe the output to any file, or further wrap it in other xml. Just waiting for Norms xproc to plug it into!

The Python equivalent is longer, but deals with parameters and encoding slightly better.


#
#
#
version="1.1"
outfile=""
prog ="dirlist"
debug=7

def recurse_dir(path,writer,d):
    d=d+1
    for cdir, subdirs, files in os.walk(path):
        writer.startElement(u'directory', attributes={u'name': unicode(cdir)})
        for f in files:
            writer.simpleElement(u'file', attributes={u'name': unicode(f)})
        for subdir in subdirs: recurse_dir(os.path.join(cdir, subdir), writer,d)
        writer.endElement(u'directory')
        break

#
#Obtain a list of notes in a given directory
#returns a possibly empty dictionary of NNN:dir/noteNNN.txt
#
def genXML(dir,out):
    print "Processing %s" % dir
    writer = MarkupWriter(out, indent=u"yes")
    writer.startDocument()
    recurse_dir(dir,writer,0)
    




#
# Print usage instructions
#
def usage():
    print "%s.py Version %s" % (prog,version)
    print "Usage: \n python %s.py  -d Directory -o XMLFile " % prog
    print "\t\t Produces an XML file in the output, listing the Directory "





#
# Main program entry
#

def main():
    if len(sys.argv) < 2:
        usage()
        sys.exit(2)
    print "%s Version %s, " % (prog,version)
    outfile=sys.stdout
    directory = None
    try:
        opts, args = getopt.getopt(sys.argv[1:], "h:d:o:", ["help","directory=" ,"output="])
    except getopt.GetoptError:
        usage()  # print help information and exit:
        sys.exit(2)
    if (len(opts) < 2):
        usage()
        sys.exit(2)
    for o,a in opts:
        if o in ("-d","--directory"):
            directory=os.path.realpath(a)
            print "Directory is ",directory
        if o in ("-o","--output"):
            outfile=a
        if o in ("-h", "--help"):
            usage()
            sys.exit()
    if not( os.path.isdir(directory)):
        sys.stderr.write ("\t\t Error, '%s' is not a directory\n" % directory) 
        sys.exit(2)
    if (os.path.isfile(outfile)):
        sys.stderr.write ("\t\t Warning: %s will be overwritten \n" % outfile) 
        sys.stderr.write("Press Ctl-C within 2 secs to kill\n\n\t\t ......\n");
        import time
        time.sleep(1)
    try:
        if (outfile is not sys.stdout):
            if (os.path.isdir(outfile)):
                sys.stderr.write("Output file must be a writable file\n\n")
                sys.exit(2)
            out = open(outfile,'w')
        else:
            out = sys.stdout
    except EnvironmentError:
        sys.stderr.write("%s not writable, Quitting" %outfile)
        sys.exit(2)    
    if debug > 6:
        print "main: %s Version %s, Processing %s to %s" % (prog,version,directory,outfile)
    genXML(directory,out)
    out.close()

if __name__ == '__main__':
    main()







Again general purpose, this time more flexible with the filter on extensions

Keywords: emacs, docbook

Comments (View)

Return to main index