Index: pom.xml =================================================================== --- pom.xml (revision 3044) +++ pom.xml (working copy) @@ -9,7 +9,7 @@ docbook-maven-plugin maven-plugin Maven Docbook plugin - 1.0.0-alpha-1-SNAPSHOT + 1.0.0-alpha-5-Mindquarry This plugin adds support for Docbook transformations to Maven. http://mojo.codehaus.org/maven-docbook-plugin @@ -20,6 +20,13 @@ http://www.openinput.com/ +1 + + Lars Trieloff + lars.trieloff@mindquarry.com + Mindquarry GmbH + http://www.mindquarry.com/ + +1 + @@ -42,6 +49,29 @@ UTF-8 + + org.codehaus.mojo + docbook-maven-plugin + + + + linux + linux + + + windows + windows + + + nonlinux + + windows + macosx + + + + + @@ -52,6 +82,17 @@ test + org.docbook + docbook-xsl + 1.72.0 + runtime + + + xml-resolver + xml-resolver + 1.2 + + org.apache.maven maven-plugin-api 2.0 @@ -80,7 +121,17 @@ xerces xercesImpl - 2.6.2 + 2.7.1 + + + org.apache.xmlgraphics + fop + 0.93 + + + commons-logging + commons-logging + 1.1 runtime @@ -92,4 +143,17 @@ + + + + mindquarry.releases + Mindquarry Repository + scp://www.mindquarry.org/var/lib/maven/releases + + + mindquarry.snapshots + Mindquarry Snapshots Repository + scp://www.mindquarry.org/var/lib/maven/snapshots + + Index: src/docbook/nested/UCS3.xml =================================================================== --- src/docbook/nested/UCS3.xml (revision 3044) +++ src/docbook/nested/UCS3.xml (working copy) @@ -1,6 +1,6 @@ - +
Nombre del proyecto - Cliente 3 Index: src/docbook/other/pass/UCS2.xml =================================================================== --- src/docbook/other/pass/UCS2.xml (revision 3044) +++ src/docbook/other/pass/UCS2.xml (working copy) @@ -1,6 +1,6 @@ - +
Nombre del proyecto - Cliente 2 Index: src/docbook/other/UCS1.xml =================================================================== --- src/docbook/other/UCS1.xml (revision 3044) +++ src/docbook/other/UCS1.xml (working copy) @@ -1,6 +1,6 @@ - +
Nombre del proyecto - Cliente 1 Index: src/docbook/SRS.xml =================================================================== --- src/docbook/SRS.xml (revision 3044) +++ src/docbook/SRS.xml (working copy) @@ -1,6 +1,6 @@ - +
Nombre del proyecto - Cliente @@ -36,7 +36,7 @@ -
+
Introducción La introducción del documento de especificación de requerimientos @@ -124,7 +124,7 @@
-
+
Descripción general Esta sección de la Especificación de Requerimientos Software @@ -157,7 +157,7 @@
-
+
Requerimientos específicos Esta sección de la Especificación de Requerimientos Software Index: src/main/java/org/codehaus/mojo/docbook/DocumentTransformer.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/DocumentTransformer.java (revision 3044) +++ src/main/java/org/codehaus/mojo/docbook/DocumentTransformer.java (working copy) @@ -23,8 +23,11 @@ */ package org.codehaus.mojo.docbook; +import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; @@ -29,7 +32,9 @@ import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import javax.xml.transform.Result; @@ -35,12 +40,17 @@ import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.MimeConstants; import org.apache.maven.plugin.logging.Log; import org.codehaus.plexus.compiler.util.scan.InclusionScanException; import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner; @@ -49,10 +59,15 @@ import org.codehaus.plexus.util.FileUtils; /** + * A helper class for transforming DocBook documents into different output + * formats. + * * @author jgonzalez + * @author Lars Trieloff */ -public class DocumentTransformer -{ +public class DocumentTransformer { + private Set sourcePatterns; + protected Log log; protected File sourceDirectory; @@ -65,6 +80,16 @@ protected URI stylesheetLocation; + private boolean generateHtml; + + private boolean generatePdf; + + private MojoURIResolver mojoResolver; + + private String xslfoCustomization; + + private String xhtmlCustomization; + /** * @param log * @param sourceDirectory @@ -69,19 +94,35 @@ * @param log * @param sourceDirectory * @param outputDirectory + * @param customizations */ - public DocumentTransformer( Log log, File sourceDirectory, File resourceDirectory, File databaseDirectory, - File outputDirectory, URI stylesheetLocation ) - { - this.log = log; - this.sourceDirectory = sourceDirectory; - this.resourceDirectory = resourceDirectory; - this.databaseDirectory = databaseDirectory; - this.outputDirectory = outputDirectory; - this.stylesheetLocation = stylesheetLocation; + public DocumentTransformer(Log log, File sourceDirectory, + File resourceDirectory, File databaseDirectory, + File outputDirectory, URI stylesheetLocation, Map customizations) { + this.log = log; + this.sourceDirectory = sourceDirectory; + this.resourceDirectory = resourceDirectory; + this.databaseDirectory = databaseDirectory; + this.outputDirectory = outputDirectory; + this.stylesheetLocation = stylesheetLocation; + this.mojoResolver = new MojoURIResolver(); + + this.xslfoCustomization = (String) customizations.get("pdf"); + this.xhtmlCustomization = (String) customizations.get("xhtml"); + + this.sourcePatterns = new HashSet(2); + this.sourcePatterns.add("*.xml"); + this.sourcePatterns.add("**/*xml"); + } + + public void transform() throws TransformerFactoryConfigurationError, + TransformerException, IOException, URISyntaxException, + InclusionScanException { + this.transform(null); } /** + * @param transformProfile * @throws TransformerException * @throws TransformerFactoryConfigurationError * @throws URISyntaxException @@ -88,32 +129,54 @@ * @throws IOException * @throws InclusionScanException */ - public void transform() - throws TransformerFactoryConfigurationError, TransformerException, IOException, URISyntaxException, - InclusionScanException - { - StaleSourceScanner scanner = new StaleSourceScanner( 0, Collections.singleton( "**/*.xml" ), - Collections.EMPTY_SET ); - scanner.addSourceMapping( new SuffixMapping( ".xml", ".html" ) ); - Set staleDocbookFiles = scanner.getIncludedSources( this.sourceDirectory, this.outputDirectory ); + public void transform(TransformProfile transformProfile) + throws TransformerFactoryConfigurationError, TransformerException, + IOException, URISyntaxException, InclusionScanException { + StaleSourceScanner scanner = new StaleSourceScanner(0, + this.sourcePatterns, Collections.EMPTY_SET); + String profile = getFileExtension(transformProfile); + if (generateHtml) { + scanner + .addSourceMapping(new SuffixMapping(".xml", profile + + "html")); + } + if (generatePdf) { + scanner + .addSourceMapping(new SuffixMapping(".xml", profile + "pdf")); + } + Set staleDocbookFiles = scanner.getIncludedSources( + this.sourceDirectory, this.outputDirectory); + + if (staleDocbookFiles.size() > 0) { + DirectoryScanner docbookScanner = new DirectoryScanner(); + docbookScanner.setBasedir(this.sourceDirectory); + docbookScanner.setFollowSymlinks(true); + docbookScanner.setIncludes(new String[] { "**/*.xml", "*.xml" }); + docbookScanner.scan(); + String[] docbookFiles = docbookScanner.getIncludedFiles(); - if ( staleDocbookFiles.size() > 0 ) - { - DirectoryScanner docbookScanner = new DirectoryScanner(); - docbookScanner.setBasedir( this.sourceDirectory ); - docbookScanner.setFollowSymlinks( true ); - docbookScanner.setIncludes( new String[] { "**/*.xml" } ); - docbookScanner.scan(); - String[] docbookFiles = docbookScanner.getIncludedFiles(); + this.prepareFileSystem(docbookFiles); + this.transformDocuments(staleDocbookFiles, transformProfile); + } else { + this.log.info("Generated docbook files up to date"); + } + if (this.resourceDirectory.exists()) { + FileUtils.copyDirectoryStructure(this.resourceDirectory, + this.outputDirectory); + } else { + this.outputDirectory.mkdirs(); + this.log.warn("Specified resource directory does not exist: " + + this.resourceDirectory.toString()); + } + } - this.prepareFileSystem( docbookFiles ); - this.transformDocuments( staleDocbookFiles ); - } - else - { - this.log.info( "Generated docbook files up to date" ); - } - FileUtils.copyDirectoryStructure( this.resourceDirectory, this.outputDirectory ); + private String getFileExtension(TransformProfile transformProfile) { + StringBuffer profile = new StringBuffer("."); + if (transformProfile != null) { + profile.append(transformProfile.getId()); + profile.append("."); + } + return profile.toString(); } /** @@ -119,67 +182,211 @@ /** * @param docbookFiles */ - protected void prepareFileSystem( String[] docbookFiles ) - { - this.log.debug( "Creating output directories for the following files - " - + Arrays.asList( docbookFiles ).toString() ); - // TODO: This should be a bit smarter also, shouldn't it? - for ( int fileIndex = 0; fileIndex < docbookFiles.length; fileIndex++ ) - { - String docbookFile = docbookFiles[fileIndex]; - int lastFileSeparator = docbookFile.lastIndexOf( File.separator ); - if ( lastFileSeparator > 0 ) - { - File directory = new File( this.outputDirectory, docbookFile.substring( 0, lastFileSeparator ) ); - directory.mkdirs(); - } - } + protected void prepareFileSystem(String[] docbookFiles) { + this.log.debug("Creating output directories for the following files - " + + Arrays.asList(docbookFiles).toString()); + this.outputDirectory.mkdirs(); + // TODO: This should be a bit smarter also, shouldn't it? + for (int fileIndex = 0; fileIndex < docbookFiles.length; fileIndex++) { + String docbookFile = docbookFiles[fileIndex]; + int lastFileSeparator = docbookFile.lastIndexOf(File.separator); + if (lastFileSeparator > 0) { + File directory = new File(this.outputDirectory, docbookFile + .substring(0, lastFileSeparator)); + directory.mkdirs(); + } + } + } + + protected void transformDocuments(Set docbookFiles, + TransformProfile transformProfile) throws TransformerException, + URISyntaxException { + this.log.info("Transforming " + docbookFiles.size() + + " Docbook stale file(s)"); + Transformer xhtmlTransformer = null; + Transformer xslfoTransformer = null; + FopFactory fopFactory = null; + URI olinkDBURI = new File(this.databaseDirectory + File.separator + + "olinkdb.xml").toURI(); + + if (generateHtml) { + xhtmlTransformer = createXHTMLTransformer(olinkDBURI, + transformProfile); + } + if (generatePdf) { + xslfoTransformer = createXSLFOTransformer(olinkDBURI, + transformProfile); + fopFactory = FopFactory.newInstance(); + fopFactory.setURIResolver(this.mojoResolver); + } + Iterator filesIterator = docbookFiles.iterator(); + while (filesIterator.hasNext()) { + File docbookFile = (File) filesIterator.next(); + if (generateHtml) { + transformXhtml(xhtmlTransformer, docbookFile, transformProfile); + } + if (generatePdf) { + transformPdf(xslfoTransformer, docbookFile, fopFactory, + transformProfile); + } + } } - protected void transformDocuments( Set docbookFiles ) - throws TransformerException, URISyntaxException - { - this.log.info( "Transforming " + docbookFiles.size() + " Docbook stale file(s)" ); - Source docbookStyleSheetSource = new StreamSource( this.stylesheetLocation.resolve( "xhtml/docbook.xsl" ) - .toString() ); - Transformer documentTransformer = TransformerFactory.newInstance().newTransformer( docbookStyleSheetSource ); - URI olinkDBURI = new File( this.databaseDirectory + File.separator + "olinkdb.xml" ).toURI(); - documentTransformer.setParameter( "target.database.document", olinkDBURI.toString() ); - documentTransformer.setParameter( "generate.toc", "" ); - this.log.debug( "Style sheet loaded." ); + private Transformer createXSLFOTransformer(URI olinkDBURI, + TransformProfile transformProfile) + throws TransformerFactoryConfigurationError, TransformerException, + TransformerConfigurationException { + Transformer xslfoTransformer; + TransformerFactory xslfoTf = TransformerFactory.newInstance(); + xslfoTf.setURIResolver(this.mojoResolver); + Source docbookStyleSheetSource; + if ((this.xslfoCustomization == null) && (transformProfile == null)) { + docbookStyleSheetSource = this.mojoResolver.resolve("docbook.xsl", + this.stylesheetLocation.toASCIIString() + "fo/"); + } else if ((this.xslfoCustomization == null) + && (transformProfile != null)) { + docbookStyleSheetSource = this.mojoResolver.resolve( + "profile-docbook.xsl", this.stylesheetLocation + .toASCIIString() + + "fo/"); + } else { + docbookStyleSheetSource = this.mojoResolver.resolve( + this.xslfoCustomization, this.sourceDirectory.toURI() + .toString()); + } + xslfoTransformer = xslfoTf.newTransformer(docbookStyleSheetSource); + xslfoTransformer.setParameter("target.database.document", olinkDBURI + .toString()); - Iterator filesIterator = docbookFiles.iterator(); - while ( filesIterator.hasNext() ) - { - File docbookFile = (File) filesIterator.next(); - this.log.debug( "Processing " + this.sourceDirectory + File.separator + docbookFile ); - Source source = new StreamSource( docbookFile ); - String relativePath = docbookFile.getAbsolutePath().substring( - (int) this.sourceDirectory.getAbsolutePath() - .length() ); - File resultFile = new File( this.outputDirectory, relativePath - .substring( 0, relativePath.lastIndexOf( '.' ) ) - + ".html" ); - Result result = new StreamResult( resultFile.getAbsolutePath() ); + if (transformProfile != null) { + transformProfile.setParameters(xslfoTransformer); + } - documentTransformer.setParameter( "current.docid", OLinkDBUpdater.computeFileID( relativePath ) ); - // TODO: Parametrize this !!!! - documentTransformer - .setParameter( "html.stylesheet", this.pathToResources( relativePath ) + "css/xhtml.css" ); - documentTransformer.transform( source, result ); - this.log.debug( "Generated " + this.databaseDirectory + File.separator + docbookFile ); - } + this.log.debug("XSL:FO Style sheet loaded."); + return xslfoTransformer; } - protected String pathToResources( String relativePath ) - { - StringBuffer pathToResources = new StringBuffer(); - int separatorIndex = relativePath.indexOf( File.separator, 1 ); - while ( separatorIndex != -1 ) - { - pathToResources.append( "../" ); - separatorIndex = relativePath.indexOf( File.separator, separatorIndex + 1 ); - } - return pathToResources.toString(); + private Transformer createXHTMLTransformer(URI olinkDBURI, + TransformProfile transformProfile) + throws TransformerFactoryConfigurationError, TransformerException, + TransformerConfigurationException { + Transformer xhtmlTransformer; + TransformerFactory xhtmlTf = TransformerFactory.newInstance(); + xhtmlTf.setURIResolver(this.mojoResolver); + Source docbookStyleSheetSource; + if ((this.xslfoCustomization == null) && (transformProfile == null)) { + docbookStyleSheetSource = this.mojoResolver.resolve("docbook.xsl", + this.stylesheetLocation.toASCIIString() + "xhtml/"); + } else if ((this.xslfoCustomization == null) + && (transformProfile != null)) { + docbookStyleSheetSource = this.mojoResolver.resolve( + "profile-docbook.xsl", this.stylesheetLocation + .toASCIIString() + + "xhtml/"); + } else { + docbookStyleSheetSource = this.mojoResolver.resolve( + this.xhtmlCustomization, this.sourceDirectory.toURI() + .toString()); + } + xhtmlTransformer = xhtmlTf.newTransformer(docbookStyleSheetSource); + xhtmlTransformer.setParameter("target.database.document", olinkDBURI + .toString()); + xhtmlTransformer.setParameter("generate.toc", ""); + + if (transformProfile != null) { + transformProfile.setParameters(xhtmlTransformer); + } + + this.log.debug("XHTML Style sheet loaded."); + return xhtmlTransformer; + } + + private void transformXhtml(Transformer documentTransformer, + File docbookFile, TransformProfile transformProfile) + throws TransformerException { + this.log.debug("Processing " + this.sourceDirectory + File.separator + + docbookFile); + Source source = this.mojoResolver.resolve(docbookFile.toURI() + .toString(), null); + String relativePath = docbookFile.getAbsolutePath().substring( + (int) this.sourceDirectory.getAbsolutePath().length()); + + File resultFile = new File(this.outputDirectory, relativePath + .substring(0, relativePath.lastIndexOf('.')) + + getFileExtension(transformProfile) + "html"); + Result result = new StreamResult(resultFile.getAbsolutePath()); + + documentTransformer.setParameter("current.docid", OLinkDBUpdater + .computeFileID(relativePath)); + // TODO: Parametrize this !!!! + documentTransformer.setParameter("html.stylesheet", this + .pathToResources(relativePath) + + "css/xhtml.css"); + documentTransformer.transform(source, result); + this.log.debug("Generated " + this.databaseDirectory + File.separator + + docbookFile); + } + + private void transformPdf(Transformer documentTransformer, + File docbookFile, FopFactory fopFactory, + TransformProfile transformProfile) throws TransformerException { + this.log.debug("Processing " + this.sourceDirectory + File.separator + + docbookFile); + Source source = this.mojoResolver.resolve(docbookFile.toURI() + .toString(), null); + String relativePath = docbookFile.getAbsolutePath().substring( + (int) this.sourceDirectory.getAbsolutePath().length()); + File resultFile = new File(this.outputDirectory, relativePath + .substring(0, relativePath.lastIndexOf('.')) + + getFileExtension(transformProfile) + "pdf"); + this.mojoResolver.setDocumentUri(docbookFile.toURI()); + documentTransformer.setParameter("current.docid", OLinkDBUpdater + .computeFileID(relativePath)); + try { + OutputStream out = new BufferedOutputStream(new FileOutputStream( + resultFile.getAbsolutePath())); + try { + Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out); + Result intermediate = new SAXResult(fop.getDefaultHandler()); + + documentTransformer.transform(source, intermediate); + } catch (FOPException e) { + this.log.error(e); + } finally { + out.close(); + } + } catch (Exception e) { + this.log.error(e); + } + this.log.debug("Generated " + this.databaseDirectory + File.separator + + docbookFile); + } + + protected String pathToResources(String relativePath) { + StringBuffer pathToResources = new StringBuffer(); + int separatorIndex = relativePath.indexOf(File.separator, 1); + while (separatorIndex != -1) { + pathToResources.append("../"); + separatorIndex = relativePath.indexOf(File.separator, + separatorIndex + 1); + } + return pathToResources.toString(); + } + + /** + * Enables a specified output format. + * + * @param format + * the format + */ + public void enableOutputFormat(String format) { + if ("xhtml".equalsIgnoreCase(format)) { + generateHtml = true; + } + if ("pdf".equalsIgnoreCase(format)) { + generatePdf = true; + } + } + } Index: src/main/java/org/codehaus/mojo/docbook/MojoURIResolver.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/MojoURIResolver.java (revision 0) +++ src/main/java/org/codehaus/mojo/docbook/MojoURIResolver.java (revision 0) @@ -0,0 +1,95 @@ +package org.codehaus.mojo.docbook; + +import java.io.InputStream; +import java.net.URI; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; + +import org.apache.xml.resolver.tools.CatalogResolver; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; + +public class MojoURIResolver extends CatalogResolver implements URIResolver, EntityResolver { + private URI documentUri = null; + + public InputSource resolveEntity(final String href, final String base) { + InputSource result; + String fullUri = makeFullUri(href, base); + if (fullUri.startsWith("resource://")) { + result = new InputSource(getResourceAsStream(fullUri)); + } else { + result = super.resolveEntity(href, base); + } + if (result==null) { + result = new InputSource(fullUri); + } + if (result==null) { + System.out.println("can't handle this"); + } + result.setSystemId(fullUri); + return result; + } + + public Source resolve(final String href, final String base) throws TransformerException { + Source result; + String fullUri = makeFullUri(href, base); + try { + XMLReader reader; + // get a SAXParserFactory instance + SAXParserFactory SAXpf = SAXParserFactory.newInstance(); + // enabling the namespaces processing + SAXpf.setNamespaceAware(true); + // get a SAXParser object + SAXParser SAXparser = SAXpf.newSAXParser(); + // get the XMLReader + reader = SAXparser.getXMLReader(); + reader.setEntityResolver(this); + // creating the SAXSource + InputSource insrc = this.resolveEntity(href, base); + result = new SAXSource(reader, insrc); + } catch (javax.xml.parsers.ParserConfigurationException e) { + result = new StreamSource(getResourceAsStream(fullUri)); + } catch (org.xml.sax.SAXException e) { + result = new StreamSource(getResourceAsStream(fullUri)); + } + result.setSystemId(fullUri); + return result; + } + + private InputStream getResourceAsStream(String fullUri) { + return MojoURIResolver.class.getResourceAsStream(fullUri.substring(10)); + } + + private String makeFullUri(final String href, final String base) { + String fullUri = href; + //if it is no absolute url starting with scheme:/ + if ((href!=null)&&(base!=null)) { + try { + fullUri = URI.create(base).resolve(href).toString(); + } catch (IllegalArgumentException use) { + fullUri = base; + } + } else if ((href!=null)&&(href.indexOf(":/")!=-1)) { + fullUri = href; + } else if (base!=null) { + fullUri = base; + } else if (this.documentUri!=null) { + fullUri = documentUri.resolve(href).toString(); + } else { + fullUri = href; + } + return fullUri; + } + + public void setDocumentUri(URI documentUri) { + this.documentUri = documentUri; + } + +} Index: src/main/java/org/codehaus/mojo/docbook/OLinkDBUpdater.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/OLinkDBUpdater.java (revision 3044) +++ src/main/java/org/codehaus/mojo/docbook/OLinkDBUpdater.java (working copy) @@ -43,6 +43,8 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; @@ -142,9 +144,16 @@ throws TransformerFactoryConfigurationError, TransformerException { this.log.info( "Loading olink database generation stylesheet" ); - Source docbookStyleSheetSource = new StreamSource( this.stylesheetLocation.resolve( "xhtml/docbook.xsl" ) - .toString() ); - Transformer olinkDBGenerator = TransformerFactory.newInstance().newTransformer( docbookStyleSheetSource ); + TransformerFactory tf = TransformerFactory.newInstance(); + MojoURIResolver resolver = new MojoURIResolver(); + Source docbookStyleSheetSource = resolver.resolve( "docbook.xsl", this.stylesheetLocation.toASCIIString() + "xhtml/" ); + tf.setURIResolver(resolver); + if (tf.getFeature(SAXSource.FEATURE)) { + SAXTransformerFactory stf = + ((SAXTransformerFactory) tf); + + } + Transformer olinkDBGenerator = tf.newTransformer( docbookStyleSheetSource ); olinkDBGenerator.setParameter( "collect.xref.targets", "only" ); olinkDBGenerator.setParameter( "generate.toc", "" ); Index: src/main/java/org/codehaus/mojo/docbook/TransformMojo.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/TransformMojo.java (revision 3044) +++ src/main/java/org/codehaus/mojo/docbook/TransformMojo.java (working copy) @@ -27,6 +27,8 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactoryConfigurationError; @@ -40,17 +42,14 @@ import org.codehaus.plexus.compiler.util.scan.InclusionScanException; /** - * Transforms a set of Docbook files into XHTML output. Currently there is only support for - * XHTML output, though is planned to add all kind of outputs available in the standard - * stylesheets. + * Transforms a set of Docbook files into XHTML and PDF output. * * @author jgonzalez + * @author Lars Trieloff * @goal transform * @description Transform Docbook files into XHTML output */ -public class TransformMojo - extends AbstractMojo -{ +public class TransformMojo extends AbstractMojo { private static String XERCES_PARSER_CONFIG = "org.apache.xerces.xni.parser.XMLParserConfiguration"; private static String XERCES_XINCLUDE_PARSER = "org.apache.xerces.parsers.XIncludeParserConfiguration"; @@ -55,9 +54,13 @@ private static String XERCES_XINCLUDE_PARSER = "org.apache.xerces.parsers.XIncludeParserConfiguration"; + private static String XERCES_RESOLVER_CONFIG = "org.apache.xerces.xni.parser.XMLEntityResolver"; + + private static String DOCBOOK_MOJO_RESOVER = "org.codehaus.mojo.docbook.MojoURIResolver"; + /** * Directory where the source Docbook files are located. - * + * * @parameter expression="${basedir}/src/docbook" * @required */ @@ -65,7 +68,7 @@ /** * Directory where the resource files are located. - * + * * @parameter expression="${basedir}/src/docbook/resources" * @required */ @@ -95,10 +98,107 @@ private String outputEncoding; /** - * Specifies the stylesheet location, useful if you want to use a local copy or a - * specific version instead of the current release from the Internet. + * Specifies the list of desired output formats. Example: + * <outputFormats> <param>xhtml</param> + * <param>pdf</param> </outputFormats> + * + * @parameter + */ + private String[] outputFormats = new String[] { "xhtml", "pdf" }; + /** + *

+ * Specifies a list of customization stylesheets for the specified output + * formats. The default value is to use no customizations, but you can point + * this configuration parameter to your own stylesheets that set parameters + * or override templates. + *

+ *

+ * An example configuration that changes the pdf stylesheet: + *

* - * @parameter expression="${stylesheetLocation}" default-value="http://docbook.sourceforge.net/release/xsl/current/" + *
+     * <customizations>
+     *   <pdf>src/main/resources/docbook2pdf.xsl</pdf>
+     * </customizations>
+     * 
+ * + *

+ * All relative URLs are resolved against resourcePath + *

+ * + * @parameter + */ + private Map customizations = new HashMap(); + + /** + *

+ * Specifies a list of transformation profiles, e.g. + *

+ * + *
+     * <profiles>
+     *  <transformProfile>
+     *    <id>linux</id>
+     *    <os>linux</os>
+     *  </transformProfile>
+     *  <transformProfile>
+     *    <id>windows</id>
+     *    <os>windows</os>
+     *  </transformProfile>
+     *  <transformProfile>
+     *    <id>nonlinux</id>
+     *    <operatingsystems>
+     *      <os>windows</os>
+     *      <os>macosx</os>
+     *    </operatingsystems>
+     *  </transformProfile>
+     * </profiles>
+     * 
+ * + *

+ * This examples creates three profiles: one containing only content marked + * for linux, one containing only content marked for windows and a third + * with content marked for either windows or mac os x. The id element is + * required for each profile, as the resulting files will have the pattern + * $filename.$profile.$ext. You can combine profile conditions e.g. having + * an os element and an arch element in place and you can profile for + * multiple values as shown in the nonlinux profile. + *

+ *

+ * All available filtering elements are: + *

+ *
    + *
  • arch/architectures
  • + *
  • condition/conditions
  • + *
  • conformance/conformances
  • + *
  • lang/languages
  • + *
  • os/operatingsystems
  • + *
  • revision/revisions
  • + *
  • security/securities
  • + *
  • userlevel/userlevels
  • + *
  • vendor/vendors
  • + *
+ *

+ * Additionally there is support for attribute-based filtering, which + * requires the use of attribute and value elements. For more information + * about DocBook profiling, see Chapter 25. + * Profiling (conditional text) in Bob Stayton's DocBook XSL: The + * Complete Guide. + *

+ * + * @parameter + */ + private TransformProfile[] profiles = new TransformProfile[] {}; + + /** + * Specifies the stylesheet location, useful if you want to use a local copy + * or a specific version instead of the current release from the maven + * repository. + * + * @parameter expression="${stylesheetLocation}" + * default-value="resource://net/sourceforge/docbook/" */ private String stylesheetLocation; @@ -114,84 +214,85 @@ * * @see org.apache.maven.plugin.Mojo#execute() */ - public void execute() - throws MojoExecutionException, MojoFailureException - { - Log log = this.getLog(); + public void execute() throws MojoExecutionException, MojoFailureException { + Log log = this.getLog(); - Proxy activeProxy = this.settings.getActiveProxy(); - String httpProxyHost = System.getProperty( "http.proxyHost" ); - String httpProxyPort = System.getProperty( "http.proxyPort" ); - String httpNonProxyHosts = System.getProperty( "http.nonProxyHosts" ); - if ( activeProxy != null ) - { - System.setProperty( "http.proxyHost", activeProxy.getHost() ); - System.setProperty( "http.proxyPort", new Integer( activeProxy.getPort() ).toString() ); - System.setProperty( "http.nonProxyHosts", activeProxy.getNonProxyHosts() ); - } + Proxy activeProxy = this.settings.getActiveProxy(); + String httpProxyHost = System.getProperty("http.proxyHost"); + String httpProxyPort = System.getProperty("http.proxyPort"); + String httpNonProxyHosts = System.getProperty("http.nonProxyHosts"); + if (activeProxy != null) { + System.setProperty("http.proxyHost", activeProxy.getHost()); + System.setProperty("http.proxyPort", new Integer(activeProxy + .getPort()).toString()); + System.setProperty("http.nonProxyHosts", activeProxy + .getNonProxyHosts()); + } - // Set XInclude Xerces parser so we're able to process master olink database file - String xercesParser = System.getProperty( TransformMojo.XERCES_PARSER_CONFIG ); - System.setProperty( TransformMojo.XERCES_PARSER_CONFIG, TransformMojo.XERCES_XINCLUDE_PARSER ); + // Set XInclude Xerces parser so we're able to process master olink + // database file + String xercesParser = System + .getProperty(TransformMojo.XERCES_PARSER_CONFIG); + System.setProperty(TransformMojo.XERCES_PARSER_CONFIG, + TransformMojo.XERCES_XINCLUDE_PARSER); + String entityResolver = System + .getProperty(TransformMojo.XERCES_RESOLVER_CONFIG); + System.setProperty(TransformMojo.XERCES_RESOLVER_CONFIG, + TransformMojo.DOCBOOK_MOJO_RESOVER); - try - { - URI stylesheetLocationURI = new URI( this.stylesheetLocation ); - OLinkDBUpdater olinkDBUpdater = new OLinkDBUpdater( log, this.sourceDirectory, this.databaseDirectory, - stylesheetLocationURI ); - DocumentTransformer documentTransformer = new DocumentTransformer( log, this.sourceDirectory, - this.resourceDirectory, - this.databaseDirectory, - this.outputDirectory, - stylesheetLocationURI ); - olinkDBUpdater.update(); - documentTransformer.transform(); - } - catch ( TransformerFactoryConfigurationError exc ) - { - throw new MojoExecutionException( exc.getLocalizedMessage(), exc ); - } - catch ( TransformerException exc ) - { - throw new MojoFailureException( exc.getLocalizedMessage() ); - } - catch ( URISyntaxException exc ) - { - throw new MojoExecutionException( exc.getLocalizedMessage(), exc ); - } - catch ( IOException exc ) - { - throw new MojoExecutionException( exc.getLocalizedMessage(), exc ); - } - catch ( InclusionScanException exc ) - { - throw new MojoExecutionException( exc.getLocalizedMessage(), exc ); - } - finally - { - // Reset XInclude Xerces parser to previous value - if ( xercesParser != null ) - { - System.setProperty( TransformMojo.XERCES_PARSER_CONFIG, xercesParser ); - } - else - { - // In 1.4 there's no clear property method... is this correct? - System.setProperty( TransformMojo.XERCES_PARSER_CONFIG, "" ); - } + try { + if (this.sourceDirectory.exists()) { + URI stylesheetLocationURI = new URI(this.stylesheetLocation); + OLinkDBUpdater olinkDBUpdater = new OLinkDBUpdater(log, + this.sourceDirectory, this.databaseDirectory, + stylesheetLocationURI); + DocumentTransformer documentTransformer = new DocumentTransformer( + log, this.sourceDirectory, this.resourceDirectory, + this.databaseDirectory, this.outputDirectory, + stylesheetLocationURI, this.customizations); + for (int i = 0; i < outputFormats.length; i++) { + documentTransformer.enableOutputFormat(outputFormats[i]); + } + olinkDBUpdater.update(); + documentTransformer.transform(); + if (this.profiles.length != 0) { + for (int i = 0; i < profiles.length; i++) { + documentTransformer.transform(this.profiles[i]); + } + } + } + } catch (TransformerFactoryConfigurationError exc) { + throw new MojoExecutionException(exc.getLocalizedMessage(), exc); + } catch (TransformerException exc) { + throw new MojoExecutionException(exc.getLocalizedMessage(), exc); + } catch (URISyntaxException exc) { + throw new MojoExecutionException(exc.getLocalizedMessage(), exc); + } catch (IOException exc) { + throw new MojoExecutionException(exc.getLocalizedMessage(), exc); + } catch (InclusionScanException exc) { + throw new MojoExecutionException(exc.getLocalizedMessage(), exc); + } finally { + // Reset XInclude Xerces parser to previous value + if (xercesParser != null) { + System.setProperty(TransformMojo.XERCES_PARSER_CONFIG, + xercesParser); + System.setProperty(TransformMojo.XERCES_RESOLVER_CONFIG, + entityResolver); + } else { + // In 1.4 there's no clear property method... is this correct? + System.setProperty(TransformMojo.XERCES_PARSER_CONFIG, ""); + System.setProperty(TransformMojo.XERCES_RESOLVER_CONFIG, ""); + } - if ( httpProxyHost != null ) - { - System.setProperty( "http.proxyHost", httpProxyHost ); - System.setProperty( "http.proxyPort", httpProxyPort ); - System.setProperty( "http.nonProxyHosts", httpNonProxyHosts ); - } - else - { - System.setProperty( "http.proxyHost", "" ); - System.setProperty( "http.proxyPort", "" ); - System.setProperty( "http.nonProxyHosts", "" ); - } - } + if (httpProxyHost != null) { + System.setProperty("http.proxyHost", httpProxyHost); + System.setProperty("http.proxyPort", httpProxyPort); + System.setProperty("http.nonProxyHosts", httpNonProxyHosts); + } else { + System.setProperty("http.proxyHost", ""); + System.setProperty("http.proxyPort", ""); + System.setProperty("http.nonProxyHosts", ""); + } + } } } Index: src/main/java/org/codehaus/mojo/docbook/TransformProfile.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/TransformProfile.java (revision 0) +++ src/main/java/org/codehaus/mojo/docbook/TransformProfile.java (revision 0) @@ -0,0 +1,388 @@ +package org.codehaus.mojo.docbook; + +import javax.xml.transform.Transformer; + +/** + * A holder of profiling information, like operating system, architecture or + * vendor. + * + * @author Lars Trieloff + */ +public class TransformProfile { + /** + * A unique id for the profile + */ + private String id; + + /** + * The attribute to profile for (attribute-based profiling) + */ + private String attribute; + /** + * The attribute's value to profile for (for attribute-based profiling) + */ + private String value; + + /** + * For profiling for a single hardware architecture + */ + private String arch; + /** + * For profiling for multiple hardware architectures + */ + private String[] archictectures; + /** + * For profiling for a single condition + */ + private String condition; + /** + * For profiling for multiple conditions + */ + private String[] conditions; + /** + * For profiling for a single conformance + */ + private String conformance; + /** + * For profiling for multiple conformances + */ + private String[] conformances; + /** + * For profiling for a single language + */ + private String lang; + /** + * For profiling for multiple languages + */ + private String[] languages; + /** + * For profiling for a single operating system + */ + private String os; + /** + * For profiling for multiple operating systems + */ + private String[] operatingsystems; + /** + * For profiling for a single revision + */ + private String revision; + /** + * For profiling for multiple revisions + */ + private String[] revisions; + /** + * For profiling for a single role + */ + private String role; + /** + * For profiling for multiple roles + */ + private String[] roles; + /** + * For profiling for a single security level + */ + private String security; + /** + * For profiling for multiple profiling levels + */ + private String[] securities; + /** + * For profiling for a single user level + */ + private String userlevel; + /** + * For profiling for multiple user levels + */ + private String[] userlevels; + /** + * For profiling for a single vendor + */ + private String vendor; + /** + * For profiling for multiple vendors + */ + private String vendors[]; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAttribute() { + return attribute; + } + + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getArch() { + return arch; + } + + public void setArch(String arch) { + this.arch = arch; + } + + public String[] getArchictectures() { + return archictectures; + } + + public void setArchictectures(String[] archictectures) { + this.archictectures = archictectures; + } + + public String getCondition() { + return condition; + } + + public void setCondition(String condition) { + this.condition = condition; + } + + public String[] getConditions() { + return conditions; + } + + public void setConditions(String[] conditions) { + this.conditions = conditions; + } + + public String getConformance() { + return conformance; + } + + public void setConformance(String conformance) { + this.conformance = conformance; + } + + public String[] getConformances() { + return conformances; + } + + public void setConformances(String[] conformances) { + this.conformances = conformances; + } + + public String getLang() { + return lang; + } + + public void setLang(String lang) { + this.lang = lang; + } + + public String[] getLanguages() { + return languages; + } + + public void setLanguages(String[] languages) { + this.languages = languages; + } + + public String getOs() { + return os; + } + + public void setOs(String os) { + this.os = os; + } + + public String[] getOperatingsystems() { + return operatingsystems; + } + + public void setOperatingsystems(String[] operatingsystems) { + this.operatingsystems = operatingsystems; + } + + public String getRevision() { + return revision; + } + + public void setRevision(String revision) { + this.revision = revision; + } + + public String[] getRevisions() { + return revisions; + } + + public void setRevisions(String[] revisions) { + this.revisions = revisions; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String[] getRoles() { + return roles; + } + + public void setRoles(String[] roles) { + this.roles = roles; + } + + public String getSecurity() { + return security; + } + + public void setSecurity(String security) { + this.security = security; + } + + public String[] getSecurities() { + return securities; + } + + public void setSecurities(String[] securities) { + this.securities = securities; + } + + public String getUserlevel() { + return userlevel; + } + + public void setUserlevel(String userlevel) { + this.userlevel = userlevel; + } + + public String[] getUserlevels() { + return userlevels; + } + + public void setUserlevels(String[] userlevels) { + this.userlevels = userlevels; + } + + public String getVendor() { + return vendor; + } + + public void setVendor(String vendor) { + this.vendor = vendor; + } + + public String[] getVendors() { + return vendors; + } + + public void setVendors(String[] vendors) { + this.vendors = vendors; + } + + /** + * Concatenates all profile values. + * + * @return concatenated string conatining all profile values; + */ + private String concatenateValues() { + StringBuffer buf = new StringBuffer(); + append(buf, this.arch); + append(buf, this.archictectures); + append(buf, this.attribute); + append(buf, this.condition); + append(buf, this.conditions); + append(buf, this.conformance); + append(buf, this.conformances); + append(buf, this.lang); + append(buf, this.languages); + append(buf, this.operatingsystems); + append(buf, this.os); + append(buf, this.revision); + append(buf, this.revisions); + append(buf, this.role); + append(buf, this.roles); + append(buf, this.securities); + append(buf, this.security); + append(buf, this.userlevel); + append(buf, this.userlevels); + append(buf, this.vendor); + append(buf, this.vendors); + return buf.toString(); + } + + private void append(StringBuffer buf, String string) { + if (string == null) { + return; + } + buf.append(string); + } + + private void append(StringBuffer buf, String[] strings) { + if (strings == null) { + return; + } + for (int i = 0; i < strings.length; i++) { + buf.append(strings[i]); + } + } + + public String getSeparator() { + int startchar = 33; + String values = this.concatenateValues(); + while (values.indexOf(startchar) != -1) { + startchar++; + } + return new String(new byte[] { (byte) startchar }); + } + + public void setParameters(Transformer t) { + String s = this.getSeparator(); + t.setParameter("profile.separator", s); + setParameter(t, "profile.arch", arch, archictectures, s); + setParameter(t, "profile.condition", condition, conditions, s); + setParameter(t, "profile.conformance", conformance, conformances, s); + setParameter(t, "profile.lang", lang, languages, s); + setParameter(t, "profile.os", os, operatingsystems, s); + setParameter(t, "profile.revision", revision, revisions, s); + setParameter(t, "profile.role", role, roles, s); + setParameter(t, "profile.security", security, securities, s); + setParameter(t, "profile.userlevel", userlevel, userlevels, s); + setParameter(t, "profile.vendor", vendor, vendors, s); + + if (attribute != null && attribute.length() != 0 && value != null + && value.length() != 0) { + t.setParameter("profile.attribute", attribute); + t.setParameter("profile.value", value); + } + } + + public static void setParameter(Transformer transformer, String parameter, + String singlevalue, String[] multivalue, String separator) { + if ((multivalue == null || multivalue.length == 0) + && (singlevalue != null) && (!"".equals(singlevalue))) { + transformer.setParameter(parameter, singlevalue); + } else if (multivalue != null && multivalue.length != 0) { + transformer.setParameter(parameter, join(multivalue, separator)); + } + } + + private static String join(String[] strings, String separator) { + StringBuffer joined = new StringBuffer(); + for (int i = 0; i < strings.length; i++) { + if (i != 0) { + joined.append(separator); + } + joined.append(strings[i]); + } + return joined.toString(); + } +} Index: src/test/java/org/codehas/mojo/docbook/TransformProfileTest.java =================================================================== --- src/test/java/org/codehas/mojo/docbook/TransformProfileTest.java (revision 0) +++ src/test/java/org/codehas/mojo/docbook/TransformProfileTest.java (revision 0) @@ -0,0 +1,18 @@ +package org.codehas.mojo.docbook; + +import org.codehaus.mojo.docbook.TransformProfile; + +import junit.framework.TestCase; + +public class TransformProfileTest extends TestCase { + + public void testGetSeparator() { + TransformProfile profile = new TransformProfile(); + + profile.setOs("linux!"); + profile.setArch("\""); + + System.out.println(profile.getSeparator()); + } + +}