diff options
author | Jeremias Maerki <jeremias@apache.org> | 2003-03-11 13:05:43 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2003-03-11 13:05:43 +0000 |
commit | 1e5d512c216d329effa693b91ef64652945def6a (patch) | |
tree | 5bd3521ee8121eade7bf1909ceaf29cfc0263fd1 /src/java/org/apache/fop/tools | |
parent | 73c824d39411bf11ad0c2f4e1c57cd9c484665f9 (diff) | |
download | xmlgraphics-fop-1e5d512c216d329effa693b91ef64652945def6a.tar.gz xmlgraphics-fop-1e5d512c216d329effa693b91ef64652945def6a.zip |
Moved sources from src/org/** to src/java/org/**
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196061 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/tools')
-rw-r--r-- | src/java/org/apache/fop/tools/AreaTreeBuilder.java | 782 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/DocumentInputSource.java | 99 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/DocumentReader.java | 551 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/TestConverter.java | 391 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/anttasks/Compare.java | 235 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/anttasks/Fop.java | 503 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/anttasks/RunTest.java | 256 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/anttasks/SerializeHyphPattern.java | 197 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/xslt/TraxTransform.java | 194 | ||||
-rw-r--r-- | src/java/org/apache/fop/tools/xslt/XSLTransform.java | 215 |
10 files changed, 3423 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/tools/AreaTreeBuilder.java b/src/java/org/apache/fop/tools/AreaTreeBuilder.java new file mode 100644 index 000000000..c2f463dfa --- /dev/null +++ b/src/java/org/apache/fop/tools/AreaTreeBuilder.java @@ -0,0 +1,782 @@ +/* + * $Id: AreaTreeBuilder.java,v 1.16 2003/03/07 10:09:29 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools; + +// Java +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.StringTokenizer; + +// JAXP +import javax.xml.parsers.DocumentBuilderFactory; + +// DOM +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Element; +import org.w3c.dom.Document; + +// Batik +import org.apache.batik.dom.svg.SVGDOMImplementation; + +// FOP +import org.apache.fop.area.Area; +import org.apache.fop.area.AreaTree; +import org.apache.fop.area.AreaTreeModel; +import org.apache.fop.area.BeforeFloat; +import org.apache.fop.area.Block; +import org.apache.fop.area.BodyRegion; +import org.apache.fop.area.CTM; +import org.apache.fop.area.Flow; +import org.apache.fop.area.Footnote; +import org.apache.fop.area.LineArea; +import org.apache.fop.area.MainReference; +import org.apache.fop.area.Page; +import org.apache.fop.area.PageViewport; +import org.apache.fop.area.RegionReference; +import org.apache.fop.area.RegionViewport; +import org.apache.fop.area.Span; +import org.apache.fop.area.StorePagesModel; +import org.apache.fop.area.Title; +import org.apache.fop.area.Trait; +import org.apache.fop.area.inline.Character; +import org.apache.fop.area.inline.Container; +import org.apache.fop.area.inline.ForeignObject; +import org.apache.fop.area.inline.Image; +import org.apache.fop.area.inline.InlineArea; +import org.apache.fop.area.inline.Leader; +import org.apache.fop.area.inline.Space; +import org.apache.fop.area.inline.Viewport; +import org.apache.fop.area.inline.Word; +import org.apache.fop.layout.FontInfo; +import org.apache.fop.layout.FontState; +import org.apache.fop.render.Renderer; +import org.apache.fop.render.pdf.PDFRenderer; +import org.apache.fop.render.svg.SVGRenderer; +import org.apache.fop.render.xml.XMLRenderer; +import org.apache.fop.fo.FOUserAgent; +import org.apache.fop.fo.properties.RuleStyle; +import org.apache.fop.fonts.FontMetrics; + +// Avalon +import org.apache.avalon.framework.logger.ConsoleLogger; +import org.apache.avalon.framework.logger.AbstractLogEnabled; + + +/** + * Area tree tester. + * The purpose of this class is to create and render an area tree + * for the purpose of testing the area tree and rendering. + * This covers the set of possible properties that can be set + * on the area tree for rendering. + * As this is not for general purpose there is no attempt to handle + * invalid area tree xml. + * + * Tests: different renderers, saving and loading pages with serialization + * out of order rendering + */ +public class AreaTreeBuilder extends AbstractLogEnabled { + + /** + * Main method + * @param args command line arguments + */ + public static void main(String[] args) { + AreaTreeBuilder atb = new AreaTreeBuilder(); + atb.enableLogging(new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG)); + + atb.runTests(args[0], args[1], args[2]); + System.exit(0); + } + + /** + * Run the tests. + * @param in input filename + * @param type output format + * @param out output filename + */ + protected void runTests(String in, String type, String out) { + getLogger().debug("Starting tests"); + runTest(in, type, out); + getLogger().debug("Finished"); + } + + /** + * Run a test. + * @param in input filename + * @param type output format + * @param out output filename + */ + protected void runTest(String in, String type, String out) { + Renderer rend = null; + if ("xml".equals(type)) { + rend = new XMLRenderer(); + } else if ("pdf".equals(type)) { + rend = new PDFRenderer(); + } else if ("svg".equals(type)) { + rend = new SVGRenderer(); + } + setupLogger(rend); + FontInfo fi = new FontInfo(); + rend.setupFontInfo(fi); + FOUserAgent ua = new FOUserAgent(); + setupLogger(ua); + rend.setUserAgent(ua); + + StorePagesModel sm = AreaTree.createStorePagesModel(); + TreeLoader tl = new TreeLoader(fi); + setupLogger(tl); + tl.setTreeModel(sm); + try { + InputStream is = + new java.io.BufferedInputStream(new java.io.FileInputStream(in)); + tl.buildAreaTree(is); + renderAreaTree(sm, rend, out); + } catch (IOException e) { + getLogger().error("error reading file" + e.getMessage(), e); + } + } + + /** + * Renders an area tree to a target format using a renderer. + * @param sm area tree pages + * @param rend renderer to use for output + * @param out target filename + */ + protected void renderAreaTree(StorePagesModel sm, + Renderer rend, String out) { + try { + OutputStream os = + new java.io.BufferedOutputStream(new java.io.FileOutputStream(out)); + + rend.startRenderer(os); + + int count = 0; + int seqc = sm.getPageSequenceCount(); + while (count < seqc) { + Title title = sm.getTitle(count); + rend.startPageSequence(title); + int pagec = sm.getPageCount(count); + int c = 0; + while (c < pagec) { + PageViewport page = sm.getPage(count, c); + c++; + // save the page to a stream for testing + /*ObjectOutputStream tempstream = new ObjectOutputStream( + new BufferedOutputStream( + new FileOutputStream("temp.ser"))); + page.savePage(tempstream); + tempstream.close(); + File temp = new File("temp.ser"); + getLogger().debug("page serialized to: " + temp.length()); + temp = null; + ObjectInputStream in = new ObjectInputStream( + new BufferedInputStream( + new FileInputStream("temp.ser"))); + page.loadPage(in); + in.close();*/ + + rend.renderPage(page); + } + count++; + } + + rend.stopRenderer(); + os.close(); + } catch (Exception e) { + getLogger().error("error rendering output", e); + } + } + + +} + +// this loads an area tree from an xml file +// the xml format is the same as the xml renderer output +class TreeLoader extends AbstractLogEnabled { + private AreaTree areaTree; + private AreaTreeModel model; + private FontInfo fontInfo; + private FontState currentFontState; + + TreeLoader(FontInfo fi) { + fontInfo = fi; + } + + public void setTreeModel(AreaTreeModel mo) { + model = mo; + } + + public void buildAreaTree(InputStream is) { + Document doc = null; + try { + DocumentBuilderFactory fact = + DocumentBuilderFactory.newInstance(); + fact.setNamespaceAware(true); + doc = fact.newDocumentBuilder().parse(is); + } catch (Exception e) { + e.printStackTrace(); + } + Element root = null; + root = doc.getDocumentElement(); + + areaTree = new AreaTree(); + areaTree.setTreeModel(model); + + readAreaTree(root); + } + + public void readAreaTree(Element root) { + + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("pageSequence")) { + readPageSequence((Element) obj); + } + } + } + + public void readPageSequence(Element root) { + Title title = null; + boolean started = false; + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("title")) { + if (started) { + // problem + } else { + title = readTitle((Element) obj); + model.startPageSequence(title); + started = true; + } + } else if (obj.getNodeName().equals("pageViewport")) { + if (!started) { + model.startPageSequence(null); + started = true; + } + PageViewport viewport = readPageViewport((Element) obj); + areaTree.addPage(viewport); + } + } + } + + public Title readTitle(Element root) { + Title title = new Title(); + List childs = getInlineAreas(root); + for (int i = 0; i < childs.size(); i++) { + InlineArea obj = (InlineArea) childs.get(i); + title.addInlineArea(obj); + } + return title; + } + + public PageViewport readPageViewport(Element root) { + Rectangle2D bounds = getRectangle(root, "bounds"); + PageViewport viewport = null; + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("page")) { + Page page = readPage((Element) obj); + viewport = new PageViewport(page, bounds); + } + } + return viewport; + } + + public Page readPage(Element root) { + //String bounds = root.getAttribute("bounds"); + Page page = new Page(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("regionViewport")) { + readRegionViewport(page, (Element) obj); + } + } + return page; + } + + Rectangle2D getRectangle(Element root, String attr) { + String rect = root.getAttribute(attr); + StringTokenizer st = new StringTokenizer(rect, " "); + int x = 0, y = 0, w = 0, h = 0; + if (st.hasMoreTokens()) { + String tok = st.nextToken(); + x = Integer.parseInt(tok); + } + if (st.hasMoreTokens()) { + String tok = st.nextToken(); + y = Integer.parseInt(tok); + } + if (st.hasMoreTokens()) { + String tok = st.nextToken(); + w = Integer.parseInt(tok); + } + if (st.hasMoreTokens()) { + String tok = st.nextToken(); + h = Integer.parseInt(tok); + } + Rectangle2D r2d = new Rectangle2D.Float(x, y, w, h); + return r2d; + } + + public RegionViewport readRegionViewport(Page page, Element root) { + RegionViewport reg = new RegionViewport(getRectangle(root, "rect")); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("regionBefore")) { + reg.setRegion(readRegion((Element) obj, RegionReference.BEFORE)); + page.setRegion(RegionReference.BEFORE, reg); + } else if (obj.getNodeName().equals("regionStart")) { + reg.setRegion(readRegion((Element) obj, RegionReference.START)); + page.setRegion(RegionReference.START, reg); + } else if (obj.getNodeName().equals("regionBody")) { + reg.setRegion(readRegion((Element) obj, RegionReference.BODY)); + page.setRegion(RegionReference.BODY, reg); + } else if (obj.getNodeName().equals("regionEnd")) { + reg.setRegion(readRegion((Element) obj, RegionReference.END)); + page.setRegion(RegionReference.END, reg); + } else if (obj.getNodeName().equals("regionAfter")) { + reg.setRegion(readRegion((Element) obj, RegionReference.AFTER)); + page.setRegion(RegionReference.AFTER, reg); + } + } + + return reg; + } + + public RegionReference readRegion(Element root, int type) { + RegionReference reg; + if (type == RegionReference.BODY) { + BodyRegion br = new BodyRegion(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("beforeFloat")) { + BeforeFloat bf = readBeforeFloat((Element) obj); + br.setBeforeFloat(bf); + } else if (obj.getNodeName().equals("mainReference")) { + MainReference mr = readMainReference((Element) obj); + br.setMainReference(mr); + } else if (obj.getNodeName().equals("footnote")) { + Footnote foot = readFootnote((Element) obj); + br.setFootnote(foot); + } + } + reg = br; + } else { + reg = new RegionReference(type); + List blocks = getBlocks(root); + for (int i = 0; i < blocks.size(); i++) { + Block obj = (Block) blocks.get(i); + reg.addBlock(obj); + } + } + reg.setCTM(new CTM()); + return reg; + } + + public BeforeFloat readBeforeFloat(Element root) { + BeforeFloat bf = new BeforeFloat(); + List blocks = getBlocks(root); + for (int i = 0; i < blocks.size(); i++) { + Block obj = (Block) blocks.get(i); + bf.addBlock(obj); + } + return bf; + } + + public MainReference readMainReference(Element root) { + MainReference mr = new MainReference(); + List spans = getSpans(root); + for (int i = 0; i < spans.size(); i++) { + Span obj = (Span) spans.get(i); + mr.addSpan(obj); + } + return mr; + } + + List getSpans(Element root) { + List list = new java.util.ArrayList(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("span")) { + List flows = getFlows((Element) obj); + Span span = new Span(flows.size()); + for (int j = 0; j < flows.size(); j++) { + Flow flow = (Flow) flows.get(j); + span.addFlow(flow); + } + list.add(span); + } + } + return list; + } + + List getFlows(Element root) { + List list = new java.util.ArrayList(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("flow")) { + Flow flow = new Flow(); + List blocks = getBlocks((Element) obj); + for (int j = 0; j < blocks.size(); j++) { + Block block = (Block) blocks.get(j); + flow.addBlock(block); + } + list.add(flow); + } + } + return list; + } + + public Footnote readFootnote(Element root) { + Footnote foot = new Footnote(); + List blocks = getBlocks(root); + for (int i = 0; i < blocks.size(); i++) { + Block obj = (Block) blocks.get(i); + foot.addBlock(obj); + } + return foot; + } + + + List getBlocks(Element root) { + List list = new java.util.ArrayList(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("block")) { + Block block = new Block(); + addTraits((Element)obj, block); + addBlockChildren(block, (Element) obj); + list.add(block); + } + } + return list; + } + + protected void addBlockChildren(Block block, Element root) { + NodeList childs = root.getChildNodes(); + int type = -1; + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("block")) { + if (type == 2) { + // error + } + Block b = new Block(); + addBlockChildren(b, (Element) obj); + block.addBlock(b); + type = 1; + } else if (obj.getNodeName().equals("lineArea")) { + if (type == 1) { + // error + } + LineArea line = new LineArea(); + addTraits((Element) obj, line); + String height = ((Element) obj).getAttribute("height"); + int h = Integer.parseInt(height); + line.setHeight(h); + + List inlines = getInlineAreas((Element) obj); + for (int j = 0; j < inlines.size(); j++) { + InlineArea inline = (InlineArea) inlines.get(j); + line.addInlineArea(inline); + } + + block.addLineArea(line); + type = 2; + } + } + } + + // children of element are inline areas + List getInlineAreas(Element root) { + List list = new java.util.ArrayList(); + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("char")) { + Character ch = + new Character(getString((Element) obj).charAt(0)); + addTraits((Element) obj, ch); + String fname = fontInfo.fontLookup("sans-serif", "normal", FontInfo.NORMAL); + FontMetrics metrics = fontInfo.getMetricsFor(fname); + currentFontState = + new FontState(fname, metrics, 12000); + + ch.setWidth(currentFontState.getWidth(ch.getChar())); + ch.setOffset(currentFontState.getCapHeight()); + list.add(ch); + } else if (obj.getNodeName().equals("space")) { + Space space = new Space(); + String width = ((Element) obj).getAttribute("width"); + int w = Integer.parseInt(width); + space.setWidth(w); + list.add(space); + } else if (obj.getNodeName().equals("viewport")) { + Viewport viewport = getViewport((Element) obj); + if (viewport != null) { + list.add(viewport); + } + } else if (obj.getNodeName().equals("leader")) { + Leader leader = getLeader((Element) obj); + if (leader != null) { + list.add(leader); + } + } else if (obj.getNodeName().equals("word")) { + String fname = fontInfo.fontLookup("sans-serif", "normal", FontInfo.NORMAL); + FontMetrics metrics = fontInfo.getMetricsFor(fname); + currentFontState = + new FontState(fname, metrics, 12000); + Word word = getWord((Element) obj); + + word.addTrait(Trait.FONT_NAME, fname); + word.addTrait(Trait.FONT_SIZE, new Integer(12000)); + + if (word != null) { + list.add(word); + } + } else { + } + } + return list; + } + + Viewport getViewport(Element root) { + Area child = null; + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj.getNodeName().equals("container")) { + child = getContainer((Element) obj); + } else if (obj.getNodeName().equals("foreignObject")) { + child = getForeignObject((Element) obj); + } else if (obj.getNodeName().equals("image")) { + child = getImage((Element) obj); + } + } + if (child == null) { + return null; + } + Viewport viewport = new Viewport(child); + String str = root.getAttribute("width"); + if (str != null && !"".equals(str)) { + int width = Integer.parseInt(str); + viewport.setWidth(width); + } + return viewport; + } + + Container getContainer(Element root) { + Container cont = new Container(); + List blocks = getBlocks(root); + for (int i = 0; i < blocks.size(); i++) { + Block obj = (Block) blocks.get(i); + cont.addBlock(obj); + } + return cont; + } + + ForeignObject getForeignObject(Element root) { + Document doc; + String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI; + + NodeList childs = root.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + if (obj instanceof Element) { + //getLogger().debug(obj.getNodeName()); + Element rootEle = (Element) obj; + String space = rootEle.getAttribute("xmlns"); + if (svgNS.equals(space)) { + try { + DocumentBuilderFactory fact = + DocumentBuilderFactory.newInstance(); + fact.setNamespaceAware(true); + + doc = fact.newDocumentBuilder().newDocument(); + Node node = doc.importNode(obj, true); + doc.appendChild(node); + //DOMImplementation impl = + // SVGDOMImplementation.getDOMImplementation(); + // due to namespace problem attributes are not cloned + // serializing causes an npe + //doc = DOMUtilities.deepCloneDocument(doc, impl); + + ForeignObject fo = new ForeignObject(doc, svgNS); + return fo; + } catch (Exception e) { + e.printStackTrace(); + } + } else { + try { + DocumentBuilderFactory fact = + DocumentBuilderFactory.newInstance(); + fact.setNamespaceAware(true); + doc = fact.newDocumentBuilder().newDocument(); + Node node = doc.importNode(obj, true); + doc.appendChild(node); + ForeignObject fo = new ForeignObject(doc, space); + return fo; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + return null; + } + + Image getImage(Element root) { + String url = root.getAttribute("url"); + Image image = new Image(url); + return image; + } + + Leader getLeader(Element root) { + Leader leader = new Leader(); + String rs = root.getAttribute("ruleStyle"); + if ("solid".equals(rs)) { + leader.setRuleStyle(RuleStyle.SOLID); + } else if ("dotted".equals(rs)) { + leader.setRuleStyle(RuleStyle.DOTTED); + } else if ("dashed".equals(rs)) { + leader.setRuleStyle(RuleStyle.DASHED); + } else if ("double".equals(rs)) { + leader.setRuleStyle(RuleStyle.DOUBLE); + } else if ("groove".equals(rs)) { + leader.setRuleStyle(RuleStyle.GROOVE); + } else if ("ridge".equals(rs)) { + leader.setRuleStyle(RuleStyle.RIDGE); + } + String rt = root.getAttribute("ruleThickness"); + int thick = Integer.parseInt(rt); + leader.setRuleThickness(thick); + rt = root.getAttribute("width"); + if (rt != null && !"".equals(rt)) { + thick = Integer.parseInt(rt); + leader.setWidth(thick); + } + leader.setOffset(currentFontState.getCapHeight()); + addTraits(root, leader); + return leader; + } + + Word getWord(Element root) { + String str = getString(root); + Word word = new Word(); + word.setWord(str); + addTraits(root, word); + int width = 0; + for (int count = 0; count < str.length(); count++) { + width += currentFontState.getWidth(str.charAt(count)); + } + word.setWidth(width); + word.setOffset(currentFontState.getCapHeight()); + + return word; + } + + + public void addTraits(Element ele, Area area) { + String str = ele.getAttribute("props"); + StringTokenizer st = new StringTokenizer(str, ";"); + while (st.hasMoreTokens()) { + String tok = st.nextToken(); + int index = tok.indexOf(":"); + String id = tok.substring(0, index); + Object traitCode = Trait.getTraitCode(id); + if (traitCode != null) { + area.addTrait(traitCode, + Trait.makeTraitValue(traitCode, + tok.substring(index + 1))); + } else { + getLogger().error("Unknown trait: " + id); + } + } + } + + public List getRanges(Element ele) { + List list = new java.util.ArrayList(); + String str = ele.getAttribute("ranges"); + StringTokenizer st = new StringTokenizer(str, ";"); + while (st.hasMoreTokens()) { + /*String tok =*/ st.nextToken(); + } + return list; + } + + public String getString(Element ele) { + String str = ""; + NodeList childs = ele.getChildNodes(); + if (childs.getLength() == 0) { + return null; + } + for (int i = 0; i < childs.getLength(); i++) { + Node obj = childs.item(i); + str = str + obj.getNodeValue(); + } + return str; + } + +} + diff --git a/src/java/org/apache/fop/tools/DocumentInputSource.java b/src/java/org/apache/fop/tools/DocumentInputSource.java new file mode 100644 index 000000000..c4067cc17 --- /dev/null +++ b/src/java/org/apache/fop/tools/DocumentInputSource.java @@ -0,0 +1,99 @@ +/* + * $Id: DocumentInputSource.java,v 1.4 2003/03/07 10:09:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools; + +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +/** + * This is an InputSource to be used with DocumentReader. + * + * @author Kelly A Campbell + */ +public class DocumentInputSource extends InputSource { + + private Document document; + + /** + * Default constructor. + */ + public DocumentInputSource() { + super(); + } + + /** + * Main constructor + * @param document the DOM document to use as input + */ + public DocumentInputSource(Document document) { + this(); + setDocument(document); + } + + /** + * Returns the input document. + * @return the input DOM document. + */ + public Document getDocument() { + return this.document; + } + + /** + * Sets the input document. + * @param document the DOM document to use as input + */ + public void setDocument(Document document) { + this.document = document; + } + +} + + diff --git a/src/java/org/apache/fop/tools/DocumentReader.java b/src/java/org/apache/fop/tools/DocumentReader.java new file mode 100644 index 000000000..4c0f478ea --- /dev/null +++ b/src/java/org/apache/fop/tools/DocumentReader.java @@ -0,0 +1,551 @@ +/* + * $Id: DocumentReader.java,v 1.4 2003/03/07 10:09:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools; + +import java.io.IOException; + +// DOM +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +// SAX +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.AttributesImpl; + +/** + * This presents a DOM as an XMLReader to make it easy to use a Document + * with a SAX-based implementation. + * + * @author Kelly A Campbell + * + */ + +public class DocumentReader implements XMLReader { + + // ////////////////////////////////////////////////////////////////// + // Configuration. + // ////////////////////////////////////////////////////////////////// + private boolean namespaces = true; + private boolean namespacePrefixes = true; + + + /** + * Look up the value of a feature. + * + * <p>The feature name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a feature name but + * to be unable to return its value; this is especially true + * in the case of an adapter for a SAX1 Parser, which has + * no way of knowing whether the underlying parser is + * performing validation or expanding external entities.</p> + * + * <p>All XMLReaders are required to recognize the + * http://xml.org/sax/features/namespaces and the + * http://xml.org/sax/features/namespace-prefixes feature names.</p> + * + * <p>Some feature values may be available only in specific + * contexts, such as before, during, or after a parse.</p> + * + * <p>Typical usage is something like this:</p> + * + * <pre> + * XMLReader r = new MySAXDriver(); + * + * // try to activate validation + * try { + * r.setFeature("http://xml.org/sax/features/validation", true); + * } catch (SAXException e) { + * System.err.println("Cannot activate validation."); + * } + * + * // register event handlers + * r.setContentHandler(new MyContentHandler()); + * r.setErrorHandler(new MyErrorHandler()); + * + * // parse the first document + * try { + * r.parse("http://www.foo.com/mydoc.xml"); + * } catch (IOException e) { + * System.err.println("I/O exception reading XML document"); + * } catch (SAXException e) { + * System.err.println("XML exception reading document."); + * } + * </pre> + * + * <p>Implementors are free (and encouraged) to invent their own features, + * using names built on their own URIs.</p> + * + * @param name The feature name, which is a fully-qualified URI. + * @return The current state of the feature (true or false). + * @exception SAXNotRecognizedException When the + * XMLReader does not recognize the feature name. + * @exception SAXNotSupportedException When the + * XMLReader recognizes the feature name but + * cannot determine its value at this time. + * @see #setFeature + */ + public boolean getFeature(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + if ("http://xml.org/sax/features/namespaces".equals(name)) { + return namespaces; + } else if ("http://xml.org/sax/features/namespace-prefixes".equals(name)) { + return namespacePrefixes; + } else { + throw new SAXNotRecognizedException("Feature '" + name + + "' not recognized or supported by Document2SAXAdapter"); + } + + } + + + + /** + * Set the state of a feature. + * + * <p>The feature name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a feature name but + * to be unable to set its value; this is especially true + * in the case of an adapter for a SAX1 {@link org.xml.sax.Parser Parser}, + * which has no way of affecting whether the underlying parser is + * validating, for example.</p> + * + * <p>All XMLReaders are required to support setting + * http://xml.org/sax/features/namespaces to true and + * http://xml.org/sax/features/namespace-prefixes to false.</p> + * + * <p>Some feature values may be immutable or mutable only + * in specific contexts, such as before, during, or after + * a parse.</p> + * + * @param name The feature name, which is a fully-qualified URI. + * @param value The requested state of the feature (true or false). + * @exception SAXNotRecognizedException When the + * XMLReader does not recognize the feature name. + * @exception SAXNotSupportedException When the + * XMLReader recognizes the feature name but + * cannot set the requested value. + * @see #getFeature + */ + public void setFeature(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException { + if ("http://xml.org/sax/features/namespaces".equals(name)) { + namespaces = value; + } else if ("http://xml.org/sax/features/namespace-prefixes".equals(name)) { + namespacePrefixes = value; + } else { + throw new SAXNotRecognizedException("Feature '" + name + + "' not recognized or supported by Document2SAXAdapter"); + } + + } + + + + /** + * Look up the value of a property. + * + * <p>The property name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a property name but + * to be unable to return its state; this is especially true + * in the case of an adapter for a SAX1 {@link org.xml.sax.Parser + * Parser}.</p> + * + * <p>XMLReaders are not required to recognize any specific + * property names, though an initial core set is documented for + * SAX2.</p> + * + * <p>Some property values may be available only in specific + * contexts, such as before, during, or after a parse.</p> + * + * <p>Implementors are free (and encouraged) to invent their own properties, + * using names built on their own URIs.</p> + * + * @param name The property name, which is a fully-qualified URI. + * @return The current value of the property. + * @exception SAXNotRecognizedException When the + * XMLReader does not recognize the property name. + * @exception SAXNotSupportedException When the + * XMLReader recognizes the property name but + * cannot determine its value at this time. + * @see #setProperty + */ + public Object getProperty(String name) + throws SAXNotRecognizedException, SAXNotSupportedException { + throw new SAXNotRecognizedException("Property '" + name + + "' not recognized or supported by Document2SAXAdapter"); + } + + + + /** + * Set the value of a property. + * + * <p>The property name is any fully-qualified URI. It is + * possible for an XMLReader to recognize a property name but + * to be unable to set its value; this is especially true + * in the case of an adapter for a SAX1 {@link org.xml.sax.Parser + * Parser}.</p> + * + * <p>XMLReaders are not required to recognize setting + * any specific property names, though a core set is provided with + * SAX2.</p> + * + * <p>Some property values may be immutable or mutable only + * in specific contexts, such as before, during, or after + * a parse.</p> + * + * <p>This method is also the standard mechanism for setting + * extended handlers.</p> + * + * @param name The property name, which is a fully-qualified URI. + * @param value The requested value for the property. + * @exception SAXNotRecognizedException When the + * XMLReader does not recognize the property name. + * @exception SAXNotSupportedException When the + * XMLReader recognizes the property name but + * cannot set the requested value. + */ + public void setProperty(String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + throw new SAXNotRecognizedException("Property '" + name + + "' not recognized or supported by Document2SAXAdapter"); + } + + + + // ////////////////////////////////////////////////////////////////// + // Event handlers. + // ////////////////////////////////////////////////////////////////// + private EntityResolver entityResolver = null; + private DTDHandler dtdHandler = null; + private ContentHandler contentHandler = null; + private ErrorHandler errorHandler = null; + + + /** + * Allow an application to register an entity resolver. + * + * <p>If the application does not register an entity resolver, + * the XMLReader will perform its own default resolution.</p> + * + * <p>Applications may register a new or different resolver in the + * middle of a parse, and the SAX parser must begin using the new + * resolver immediately.</p> + * + * @param resolver The entity resolver. + * @see #getEntityResolver + */ + public void setEntityResolver(EntityResolver resolver) { + entityResolver = resolver; + } + + + + /** + * Return the current entity resolver. + * + * @return The current entity resolver, or null if none + * has been registered. + * @see #setEntityResolver + */ + public EntityResolver getEntityResolver() { + return entityResolver; + } + + + + /** + * Allow an application to register a DTD event handler. + * + * <p>If the application does not register a DTD handler, all DTD + * events reported by the SAX parser will be silently ignored.</p> + * + * <p>Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.</p> + * + * @param handler The DTD handler. + * @see #getDTDHandler + */ + public void setDTDHandler(DTDHandler handler) { + dtdHandler = handler; + } + + + + /** + * Return the current DTD handler. + * + * @return The current DTD handler, or null if none + * has been registered. + * @see #setDTDHandler + */ + public DTDHandler getDTDHandler() { + return dtdHandler; + } + + + + /** + * Allow an application to register a content event handler. + * + * <p>If the application does not register a content handler, all + * content events reported by the SAX parser will be silently + * ignored.</p> + * + * <p>Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.</p> + * + * @param handler The content handler. + * @see #getContentHandler + */ + public void setContentHandler(ContentHandler handler) { + contentHandler = handler; + } + + + + /** + * Return the current content handler. + * + * @return The current content handler, or null if none + * has been registered. + * @see #setContentHandler + */ + public ContentHandler getContentHandler() { + return contentHandler; + } + + + + /** + * Allow an application to register an error event handler. + * + * <p>If the application does not register an error handler, all + * error events reported by the SAX parser will be silently + * ignored; however, normal processing may not continue. It is + * highly recommended that all SAX applications implement an + * error handler to avoid unexpected bugs.</p> + * + * <p>Applications may register a new or different handler in the + * middle of a parse, and the SAX parser must begin using the new + * handler immediately.</p> + * + * @param handler The error handler. + * @see #getErrorHandler + */ + public void setErrorHandler(ErrorHandler handler) { + errorHandler = handler; + } + + /** + * Return the current error handler. + * + * @return The current error handler, or null if none + * has been registered. + * @see #setErrorHandler + */ + public ErrorHandler getErrorHandler() { + return errorHandler; + } + + + + // ////////////////////////////////////////////////////////////////// + // Parsing. + // ////////////////////////////////////////////////////////////////// + + /** + * Parse an XML DOM document. + * + * + * + * @param input The input source for the top-level of the + * XML document. + * @exception SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception IOException An IO exception from the parser, + * possibly from a byte stream or character stream + * supplied by the application. + * @see org.xml.sax.InputSource + * @see #parse(java.lang.String) + * @see #setEntityResolver + * @see #setDTDHandler + * @see #setContentHandler + * @see #setErrorHandler + */ + public void parse(InputSource input) throws IOException, SAXException { + if (input instanceof DocumentInputSource) { + Document document = ((DocumentInputSource)input).getDocument(); + if (contentHandler == null) { + throw new SAXException("ContentHandler is null. Please use setContentHandler()"); + } + + // refactored from org.apache.fop.apps.Driver + /* most of this code is modified from John Cowan's */ + + Node currentNode; + AttributesImpl currentAtts; + + /* temporary array for making Strings into character arrays */ + char[] array = null; + + currentAtts = new AttributesImpl(); + + /* start at the document element */ + currentNode = document; + while (currentNode != null) { + switch (currentNode.getNodeType()) { + case Node.DOCUMENT_NODE: + contentHandler.startDocument(); + break; + case Node.CDATA_SECTION_NODE: + case Node.TEXT_NODE: + String data = currentNode.getNodeValue(); + int datalen = data.length(); + if (array == null || array.length < datalen) { + /* + * if the array isn't big enough, make a new + * one + */ + array = new char[datalen]; + } + data.getChars(0, datalen, array, 0); + contentHandler.characters(array, 0, datalen); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + contentHandler.processingInstruction(currentNode.getNodeName(), + currentNode.getNodeValue()); + break; + case Node.ELEMENT_NODE: + NamedNodeMap map = currentNode.getAttributes(); + currentAtts.clear(); + for (int i = map.getLength() - 1; i >= 0; i--) { + Attr att = (Attr)map.item(i); + currentAtts.addAttribute(att.getNamespaceURI(), + att.getLocalName(), + att.getName(), "CDATA", + att.getValue()); + } + contentHandler.startElement(currentNode.getNamespaceURI(), + currentNode.getLocalName(), + currentNode.getNodeName(), + currentAtts); + break; + } + + Node nextNode = currentNode.getFirstChild(); + if (nextNode != null) { + currentNode = nextNode; + continue; + } + + while (currentNode != null) { + switch (currentNode.getNodeType()) { + case Node.DOCUMENT_NODE: + contentHandler.endDocument(); + break; + case Node.ELEMENT_NODE: + contentHandler.endElement(currentNode.getNamespaceURI(), + currentNode.getLocalName(), + currentNode.getNodeName()); + break; + } + + nextNode = currentNode.getNextSibling(); + if (nextNode != null) { + currentNode = nextNode; + break; + } + + currentNode = currentNode.getParentNode(); + } + } + + } else { + throw new SAXException("DocumentReader only supports parsing of a DocumentInputSource"); + } + + } + + + + /** + * DocumentReader requires a DocumentInputSource, so this is not + * implements and simply throws a SAXException. Use parse(DocumentInputSource) + * instead + * + * @param systemId The system identifier (URI). + * @exception SAXException Any SAX exception, possibly + * wrapping another exception. + * @exception IOException An IO exception from the parser, + * possibly from a byte stream or character stream + * supplied by the application. + * @see #parse(org.xml.sax.InputSource) + */ + public void parse(String systemId) throws IOException, SAXException { + throw new SAXException("DocumentReader only supports parsing of a DocumentInputSource"); + } + +} + + diff --git a/src/java/org/apache/fop/tools/TestConverter.java b/src/java/org/apache/fop/tools/TestConverter.java new file mode 100644 index 000000000..1f8449043 --- /dev/null +++ b/src/java/org/apache/fop/tools/TestConverter.java @@ -0,0 +1,391 @@ +/* + * $Id: TestConverter.java,v 1.23 2003/03/07 10:09:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools; + +import org.apache.fop.apps.Driver; +import org.apache.fop.apps.FOInputHandler; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.InputHandler; +import org.apache.fop.apps.XSLTInputHandler; +import org.apache.fop.fo.FOUserAgent; + +import org.apache.avalon.framework.logger.ConsoleLogger; +import org.apache.avalon.framework.logger.AbstractLogEnabled; + +import java.io.File; +import java.io.InputStream; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.XMLReader; +import org.xml.sax.SAXException; + +/** + * TestConverter is used to process a set of tests specified in + * a testsuite. + * This class retrieves the data in the testsuite and uses FOP + * to convert the xml and xsl file into either an xml representation + * of the area tree or a pdf document. + * The area tree can be used for automatic comparisons between different + * versions of FOP or the pdf can be view for manual checking and + * pdf rendering. + * + * Modified by Mark Lillywhite mark-fop@inomial.com to use the new Driver + * interface. + */ +public class TestConverter extends AbstractLogEnabled { + + private boolean failOnly = false; + private boolean outputPDF = false; + private File destdir; + private File compare = null; + private String baseDir = "./"; + private Map differ = new java.util.HashMap(); + + /** + * This main method can be used to run the test converter from + * the command line. + * This will take a specified testsuite xml and process all + * tests in it. + * The command line options are: + * -b to set the base directory for where the testsuite and associated files are + * -failOnly to process only the tests which are specified as fail in the test results + * -pdf to output the result as pdf + * @param args command-line arguments + */ + public static void main(String[] args) { + if (args == null || args.length == 0) { + System.out.println("test suite file name required"); + } + TestConverter tc = new TestConverter(); + tc.enableLogging(new ConsoleLogger(ConsoleLogger.LEVEL_ERROR)); + + String testFile = null; + for (int count = 0; count < args.length; count++) { + if (args[count].equals("-failOnly")) { + tc.setFailOnly(true); + } else if (args[count].equals("-pdf")) { + tc.setOutputPDF(true); + } else if (args[count].equals("-b")) { + tc.setBaseDir(args[count + 1]); + } else { + testFile = args[count]; + } + } + if (testFile == null) { + System.out.println("test suite file name required"); + } + + tc.runTests(testFile, "results", null); + } + + /** + * Controls whether to generate PDF or XML. + * @param pdf If True, PDF is generated, Area Tree XML otherwise. + */ + public void setOutputPDF(boolean pdf) { + outputPDF = pdf; + } + + /** + * Controls whether to process only the tests which are specified as fail + * in the test results. + * @param fail True if only fail tests should be processed + */ + public void setFailOnly(boolean fail) { + failOnly = fail; + } + + /** + * Sets the base directory. + * @param str base directory + */ + public void setBaseDir(String str) { + baseDir = str; + } + + /** + * Run the Tests. + * This runs the tests specified in the xml file fname. + * The document is read as a dom and each testcase is covered. + * @param fname filename of the input file + * @param dest destination directory + * @param compDir comparison directory + * @return Map a Map containing differences + */ + public Map runTests(String fname, String dest, String compDir) { + getLogger().debug("running tests in file:" + fname); + try { + if (compDir != null) { + compare = new File(baseDir + "/" + compDir); + } + destdir = new File(baseDir + "/" + dest); + destdir.mkdirs(); + File f = new File(baseDir + "/" + fname); + DocumentBuilderFactory factory = + DocumentBuilderFactory.newInstance(); + DocumentBuilder db = factory.newDocumentBuilder(); + Document doc = db.parse(f); + + NodeList suitelist = doc.getChildNodes(); + if (suitelist.getLength() == 0) { + return differ; + } + + Node testsuite = null; + testsuite = doc.getDocumentElement(); + + if (testsuite.hasAttributes()) { + String profile = + testsuite.getAttributes().getNamedItem("profile").getNodeValue(); + getLogger().debug("testing test suite:" + profile); + } + + NodeList testcases = testsuite.getChildNodes(); + for (int count = 0; count < testcases.getLength(); count++) { + Node testcase = testcases.item(count); + if (testcase.getNodeName().equals("testcases")) { + runTestCase(testcase); + } + } + } catch (Exception e) { + getLogger().error("Error while running tests", e); + } + return differ; + } + + /** + * Run a test case. + * This goes through a test case in the document. + * A testcase can contain a test, a result or more test cases. + * A test case is handled recursively otherwise the test is run. + * @param tcase Test case node to run + */ + protected void runTestCase(Node tcase) { + if (tcase.hasAttributes()) { + String profile = + tcase.getAttributes().getNamedItem("profile").getNodeValue(); + getLogger().debug("testing profile:" + profile); + } + + NodeList cases = tcase.getChildNodes(); + for (int count = 0; count < cases.getLength(); count++) { + Node node = cases.item(count); + String nodename = node.getNodeName(); + if (nodename.equals("testcases")) { + runTestCase(node); + } else if (nodename.equals("test")) { + runTest(tcase, node); + } else if (nodename.equals("result")) { + //nop + } + + } + + } + + /** + * Run a particular test. + * This runs a test defined by the xml and xsl documents. + * If the test has a result specified it is checked. + * This creates an XSLTInputHandler to provide the input + * for FOP and writes the data out to an XML are tree. + * @param testcase Test case to run + * @param test Test + */ + protected void runTest(Node testcase, Node test) { + String id = test.getAttributes().getNamedItem("id").getNodeValue(); + Node result = locateResult(testcase, id); + boolean pass = false; + if (result != null) { + String agreement = + result.getAttributes().getNamedItem("agreement").getNodeValue(); + pass = agreement.equals("full"); + } + + if (pass && failOnly) { + return; + } + + String xml = test.getAttributes().getNamedItem("xml").getNodeValue(); + Node xslNode = test.getAttributes().getNamedItem("xsl"); + String xsl = null; + if (xslNode != null) { + xsl = xslNode.getNodeValue(); + } + getLogger().debug("converting xml:" + xml + " and xsl:" + + xsl + " to area tree"); + + try { + File xmlFile = new File(baseDir + "/" + xml); + String baseURL = null; + try { + baseURL = xmlFile.getParentFile().toURL().toExternalForm(); + } catch (Exception e) { + getLogger().error("Error setting base directory"); + } + + InputHandler inputHandler = null; + if (xsl == null) { + inputHandler = new FOInputHandler(xmlFile); + } else { + inputHandler = new XSLTInputHandler(xmlFile, + new File(baseDir + "/" + + xsl)); + } + + XMLReader parser = inputHandler.getParser(); + setParserFeatures(parser); + + Driver driver = new Driver(); + setupLogger(driver, "fop"); + driver.initialize(); + FOUserAgent userAgent = new FOUserAgent(); + userAgent.setBaseURL(baseURL); + driver.setUserAgent(userAgent); + if (outputPDF) { + driver.setRenderer(Driver.RENDER_PDF); + } else { + driver.setRenderer(Driver.RENDER_XML); + } + + Map rendererOptions = new java.util.HashMap(); + rendererOptions.put("fineDetail", new Boolean(false)); + rendererOptions.put("consistentOutput", new Boolean(true)); + driver.getRenderer().setOptions(rendererOptions); + driver.getRenderer().setProducer("Testsuite Converter"); + + String outname = xmlFile.getName(); + if (outname.endsWith(".xml")) { + outname = outname.substring(0, outname.length() - 4); + } + driver.setOutputStream(new java.io.BufferedOutputStream( + new java.io.FileOutputStream(new File(destdir, + outname + (outputPDF ? ".pdf" : ".at.xml"))))); + getLogger().debug("ddir:" + destdir + " on:" + outname + ".pdf"); + driver.render(parser, inputHandler.getInputSource()); + + // check difference + if (compare != null) { + File f1 = new File(destdir, outname + ".at.xml"); + File f2 = new File(compare, outname + ".at.xml"); + if (!compareFiles(f1, f2)) { + differ.put(outname + ".at.xml", new Boolean(pass)); + } + } + } catch (Exception e) { + getLogger().error("Error while running tests", e); + } + } + + /** + * Compare files. + * @param f1 first file + * @param f2 second file + * @return true if equal + */ + protected boolean compareFiles(File f1, File f2) { + if (f1.length() != f2.length()) { + return false; + } + try { + InputStream is1 = new java.io.BufferedInputStream(new java.io.FileInputStream(f1)); + InputStream is2 = new java.io.BufferedInputStream(new java.io.FileInputStream(f2)); + while (true) { + int ch1 = is1.read(); + int ch2 = is2.read(); + if (ch1 == ch2) { + if (ch1 == -1) { + return true; + } + } else { + return false; + } + } + } catch (Exception e) { + getLogger().error("Error while comparing files", e); + } + + return false; + } + + private void setParserFeatures(XMLReader parser) throws FOPException { + try { + parser.setFeature("http://xml.org/sax/features/namespace-prefixes", + true); + } catch (SAXException e) { + throw new FOPException("Error in setting up parser feature namespace-prefixes\n" + + "You need a parser which supports SAX version 2", e); + } + } + + private Node locateResult(Node testcase, String id) { + NodeList cases = testcase.getChildNodes(); + for (int count = 0; count < cases.getLength(); count++) { + Node node = cases.item(count); + String nodename = node.getNodeName(); + if (nodename.equals("result")) { + String resultid = + node.getAttributes().getNamedItem("id").getNodeValue(); + if (id.equals(resultid)) { + return node; + } + } + } + return null; + } + +} diff --git a/src/java/org/apache/fop/tools/anttasks/Compare.java b/src/java/org/apache/fop/tools/anttasks/Compare.java new file mode 100644 index 000000000..ca3ab5182 --- /dev/null +++ b/src/java/org/apache/fop/tools/anttasks/Compare.java @@ -0,0 +1,235 @@ +/* + * $Id: Compare.java,v 1.5 2003/03/07 10:09:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools.anttasks; + +import java.util.Date; +import java.util.List; +import java.util.StringTokenizer; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; + +import org.apache.tools.ant.BuildException; +import java.text.DateFormat; + +/** + * This class is an extension of Ant, a script utility from + * http://ant.apache.org. + * It provides methods to compare two files. + */ + +public class Compare { + + private static final boolean IDENTICAL_FILES = true; + private static final boolean NOTIDENTICAL_FILES = false; + + private String referenceDirectory, testDirectory; + private String[] filenameList; + private String filenames; + private BufferedInputStream oldfileInput; + private BufferedInputStream newfileInput; + + /** + * Sets directory for test files. + * @param testDirectory the test directory + */ + public void setTestDirectory(String testDirectory) { + if (!(testDirectory.endsWith("/") | testDirectory.endsWith("\\"))) { + testDirectory += File.separator; + } + this.testDirectory = testDirectory; + } + + /** + * Sets directory for reference files. + * @param referenceDirectory the reference directory + */ + public void setReferenceDirectory(String referenceDirectory) { + if (!(referenceDirectory.endsWith("/") + | referenceDirectory.endsWith("\\"))) { + referenceDirectory += File.separator; + } + this.referenceDirectory = referenceDirectory; + } + + /** + * Sets the comma-separated list of files to process. + * @param filenames list of files, comma-separated + */ + public void setFilenames(String filenames) { + StringTokenizer tokens = new StringTokenizer(filenames, ","); + List filenameListTmp = new java.util.ArrayList(20); + while (tokens.hasMoreTokens()) { + filenameListTmp.add(tokens.nextToken()); + } + filenameList = new String[filenameListTmp.size()]; + filenameList = (String[])filenameListTmp.toArray(new String[0]); + } + + private boolean compareBytes(File oldFile, File newFile) { + try { + oldfileInput = + new BufferedInputStream(new java.io.FileInputStream(oldFile)); + newfileInput = + new BufferedInputStream(new java.io.FileInputStream(newFile)); + int charactO = 0; + int charactN = 0; + boolean identical = true; + + while (identical & (charactO != -1)) { + if (charactO == charactN) { + charactO = oldfileInput.read(); + charactN = newfileInput.read(); + } else { + return NOTIDENTICAL_FILES; + } + } + return IDENTICAL_FILES; + } catch (IOException io) { + System.err.println("Task Compare - Error: \n" + io.toString()); + } + return NOTIDENTICAL_FILES; + } + + private boolean compareFileSize(File oldFile, File newFile) { + if (oldFile.length() != newFile.length()) { + return NOTIDENTICAL_FILES; + } else { + return IDENTICAL_FILES; + } + } // end: compareBytes + + private boolean filesExist(File oldFile, File newFile) { + if (!oldFile.exists()) { + System.err.println("Task Compare - ERROR: File " + + referenceDirectory + oldFile.getName() + + " doesn't exist!"); + return false; + } else if (!newFile.exists()) { + System.err.println("Task Compare - ERROR: File " + testDirectory + + newFile.getName() + " doesn't exist!"); + return false; + } else { + return true; + } + } + + private void writeHeader(PrintWriter results) { + String dateTime = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, + DateFormat.MEDIUM).format(new Date()); + results.println("<html><head><title>Test Results</title></head><body>\n"); + results.println("<h2>Compare Results<br>"); + results.println("<font size='1'>created " + dateTime + + "</font></h2>"); + results.println("<table cellpadding='10' border='2'><thead>" + + "<th align='center'>reference file</th>" + + "<th align='center'>test file</th>" + + "<th align='center'>identical?</th></thead>"); + + + } + + /** + * Main method of task compare + * @throws BuildException If the execution fails. + */ + public void execute() throws BuildException { + boolean identical = false; + File oldFile; + File newFile; + try { + PrintWriter results = + new PrintWriter(new java.io.FileWriter("results.html"), true); + this.writeHeader(results); + for (int i = 0; i < filenameList.length; i++) { + oldFile = new File(referenceDirectory + filenameList[i]); + newFile = new File(testDirectory + filenameList[i]); + if (filesExist(oldFile, newFile)) { + identical = compareFileSize(oldFile, newFile); + if (identical) { + identical = compareBytes(oldFile, newFile); + } + if (!identical) { + System.out.println("Task Compare: \nFiles " + + referenceDirectory + + oldFile.getName() + " - " + + testDirectory + + newFile.getName() + + " are *not* identical."); + results.println("<tr><td><a href='" + + referenceDirectory + + oldFile.getName() + "'>" + + oldFile.getName() + + "</a> </td><td> <a href='" + + testDirectory + newFile.getName() + + "'>" + newFile.getName() + "</a>" + + " </td><td><font color='red'>No</font></td></tr>"); + } else { + results.println("<tr><td><a href='" + + referenceDirectory + + oldFile.getName() + "'>" + + oldFile.getName() + + "</a> </td><td> <a href='" + + testDirectory + newFile.getName() + + "'>" + newFile.getName() + "</a>" + + " </td><td>Yes</td></tr>"); + } + } + } + results.println("</table></html>"); + } catch (IOException ioe) { + System.err.println("ERROR: " + ioe); + } + } // end: execute() + +} + diff --git a/src/java/org/apache/fop/tools/anttasks/Fop.java b/src/java/org/apache/fop/tools/anttasks/Fop.java new file mode 100644 index 000000000..2dc3fd933 --- /dev/null +++ b/src/java/org/apache/fop/tools/anttasks/Fop.java @@ -0,0 +1,503 @@ +/* + * $Id: Fop.java,v 1.24 2003/03/07 10:09:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools.anttasks; + +// Ant +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.util.GlobPatternMapper; + +// SAX +import org.xml.sax.XMLReader; + +// Java +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.util.List; + +// FOP +import org.apache.fop.apps.Starter; +import org.apache.fop.apps.InputHandler; +import org.apache.fop.apps.FOInputHandler; +import org.apache.fop.apps.Driver; +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.FOUserAgent; + +// Avalon +import org.apache.avalon.framework.logger.ConsoleLogger; +import org.apache.avalon.framework.logger.Logger; + +/** + * Wrapper for FOP which allows it to be accessed from within an Ant task. + * Accepts the inputs: + * <ul> + * <li>fofile -> formatting objects file to be transformed</li> + * <li>format -> MIME type of the format to generate ex. "application/pdf"</li> + * <li>outfile -> output filename</li> + * <li>baseDir -> directory to work from</li> + * <li>userconfig -> file with user configuration (same as the "-c" command + * line option)</li> + * <li>messagelevel -> (error | warn | info | verbose | debug) level to output + * non-error messages</li> + * <li>logFiles -> Controls whether the names of the files that are processed + * are logged or not</li> + * </ul> + */ +public class Fop extends Task { + + private File foFile; + private List filesets = new java.util.ArrayList(); + private File outFile; + private File outDir; + private String format; //MIME type + private File baseDir; + private File userConfig; + private int messageType = Project.MSG_VERBOSE; + private boolean logFiles = true; + + /** + * Sets the filename for the userconfig.xml. + * @param userConfig Configuration to use + */ + public void setUserconfig(File userConfig) { + this.userConfig = userConfig; + } + + /** + * Returns the file for the userconfig.xml. + * @return the userconfig.xml file + */ + public File getUserconfig() { + return this.userConfig; + } + + /** + * Sets the input XSL-FO file. + * @param foFile input XSL-FO file + */ + public void setFofile(File foFile) { + this.foFile = foFile; + } + + /** + * Gets the input XSL-FO file. + * @return input XSL-FO file + */ + public File getFofile() { + return foFile; + } + + /** + * Adds a set of XSL-FO files (nested fileset attribute). + * @param set a fileset + */ + public void addFileset(FileSet set) { + filesets.add(set); + } + + /** + * Returns the current list of filesets. + * @return the filesets + */ + public List getFilesets() { + return this.filesets; + } + + /** + * Sets the output file. + * @param outFile File to output to + */ + public void setOutfile(File outFile) { + this.outFile = outFile; + } + + /** + * Gets the output file. + * @return the output file + */ + public File getOutfile() { + return this.outFile; + } + + /** + * Sets the output directory. + * @param outDir Directory to output to + */ + public void setOutdir(File outDir) { + this.outDir = outDir; + } + + /** + * Gets the output directory. + * @return the output directory + */ + public File getOutdir() { + return this.outDir; + } + + /** + * Sets output format (MIME type). + * @param format the output format + */ + public void setFormat(String format) { + this.format = format; + } + + /** + * Gets the output format (MIME type). + * @return the output format + */ + public String getFormat() { + return this.format; + } + + /** + * Sets the message level to be used while processing. + * @param messageLevel (error | warn| info | verbose | debug) + */ + public void setMessagelevel(String messageLevel) { + if (messageLevel.equalsIgnoreCase("info")) { + messageType = Project.MSG_INFO; + } else if (messageLevel.equalsIgnoreCase("verbose")) { + messageType = Project.MSG_VERBOSE; + } else if (messageLevel.equalsIgnoreCase("debug")) { + messageType = Project.MSG_DEBUG; + } else if (messageLevel.equalsIgnoreCase("err") + || messageLevel.equalsIgnoreCase("error")) { + messageType = Project.MSG_ERR; + } else if (messageLevel.equalsIgnoreCase("warn")) { + messageType = Project.MSG_WARN; + } else { + log("messagelevel set to unknown value \"" + messageLevel + + "\"", Project.MSG_ERR); + throw new BuildException("unknown messagelevel"); + } + } + + /** + * Returns the message type corresponding to Project.MSG_* + * representing the current message level. + * @see org.apache.tools.ant.Project + */ + public int getMessageType() { + return messageType; + } + + /** + * Sets the base directory; currently ignored. + * @param baseDir File to use as a working directory + */ + public void setBasedir(File baseDir) { + this.baseDir = baseDir; + } + + /** + * Gets the base directory. + * @return the base directory + */ + public File getBasedir() { + return (baseDir != null) ? baseDir : project.resolveFile("."); + } + + /** + * Controls whether the filenames of the files that are processed are logged + * or not. + * @param logFiles True if the feature should be enabled + */ + public void setLogFiles(boolean logFiles) { + this.logFiles = logFiles; + } + + /** + * Returns True if the filename of each file processed should be logged. + * @return True if the filenames should be logged. + */ + public boolean getLogFiles() { + return this.logFiles; + } + + /** + * @see org.apache.tools.ant.Task#execute() + */ + public void execute() throws BuildException { + int logLevel = ConsoleLogger.LEVEL_INFO; + switch (getMessageType()) { + case Project.MSG_DEBUG : logLevel = ConsoleLogger.LEVEL_DEBUG; break; + case Project.MSG_INFO : logLevel = ConsoleLogger.LEVEL_INFO; break; + case Project.MSG_WARN : logLevel = ConsoleLogger.LEVEL_WARN; break; + case Project.MSG_ERR : logLevel = ConsoleLogger.LEVEL_ERROR; break; + case Project.MSG_VERBOSE: logLevel = ConsoleLogger.LEVEL_DEBUG; break; + } + Logger log = new ConsoleLogger(logLevel); + try { + Starter starter = new FOPTaskStarter(this); + starter.enableLogging(log); + starter.run(); + } catch (FOPException ex) { + throw new BuildException(ex); + } + + } + +} + +class FOPTaskStarter extends Starter { + + private Fop task; + private String baseURL = null; + + FOPTaskStarter(Fop task) throws FOPException { + this.task = task; + } + + private int determineRenderer(String format) { + if ((format == null) + || format.equalsIgnoreCase("application/pdf") + || format.equalsIgnoreCase("pdf")) { + return Driver.RENDER_PDF; + } else if (format.equalsIgnoreCase("application/postscript") + || format.equalsIgnoreCase("ps")) { + return Driver.RENDER_PS; + } else if (format.equalsIgnoreCase("application/vnd.mif") + || format.equalsIgnoreCase("mif")) { + return Driver.RENDER_MIF; + } else if (format.equalsIgnoreCase("application/msword") + || format.equalsIgnoreCase("application/rtf") + || format.equalsIgnoreCase("rtf")) { + return Driver.RENDER_RTF; + } else if (format.equalsIgnoreCase("application/vnd.hp-PCL") + || format.equalsIgnoreCase("pcl")) { + return Driver.RENDER_PCL; + } else if (format.equalsIgnoreCase("text/plain") + || format.equalsIgnoreCase("txt")) { + return Driver.RENDER_TXT; + } else if (format.equalsIgnoreCase("text/xml") + || format.equalsIgnoreCase("at") + || format.equalsIgnoreCase("xml")) { + return Driver.RENDER_XML; + } else { + String err = "Couldn't determine renderer to use: " + format; + throw new BuildException(err); + } + } + + private String determineExtension(int renderer) { + switch (renderer) { + case Driver.RENDER_PDF: + return ".pdf"; + case Driver.RENDER_PS: + return ".ps"; + case Driver.RENDER_MIF: + return ".mif"; + case Driver.RENDER_RTF: + return ".rtf"; + case Driver.RENDER_PCL: + return ".pcl"; + case Driver.RENDER_TXT: + return ".txt"; + case Driver.RENDER_XML: + return ".xml"; + default: + String err = "Unknown renderer: " + renderer; + throw new BuildException(err); + } + } + + private File replaceExtension(File file, String expectedExt, + String newExt) { + String name = file.getName(); + if (name.toLowerCase().endsWith(expectedExt)) { + name = name.substring(0, name.length() - expectedExt.length()); + } + name = name.concat(newExt); + return new File(file.getParentFile(), name); + } + + /** + * @see org.apache.fop.apps.Starter#run() + */ + public void run() throws FOPException { + //Setup configuration + if (task.getUserconfig() != null) { + /**@todo implement me */ + } + + //Set base directory + if (task.getBasedir() != null) { + try { + this.baseURL = task.getBasedir().toURL().toExternalForm(); + } catch (MalformedURLException mfue) { + getLogger().error("Error creating base URL from base directory", mfue); + } + } else { + try { + if (task.getFofile() != null) { + this.baseURL = task.getFofile().getParentFile().toURL(). + toExternalForm(); + } + } catch (MalformedURLException mfue) { + getLogger().error("Error creating base URL from XSL-FO input file", mfue); + } + } + + task.log("Using base URL: " + baseURL, Project.MSG_DEBUG); + + int rint = determineRenderer(task.getFormat()); + String newExtension = determineExtension(rint); + + int actioncount = 0; + + // deal with single source file + if (task.getFofile() != null) { + if (task.getFofile().exists()) { + File outf = task.getOutfile(); + if (outf == null) { + throw new BuildException("outfile is required when fofile is used"); + } + if (task.getOutdir() != null) { + outf = new File(task.getOutdir(), outf.getName()); + } + render(task.getFofile(), outf, rint); + actioncount++; + } + } + + GlobPatternMapper mapper = new GlobPatternMapper(); + mapper.setFrom("*.fo"); + mapper.setTo("*" + newExtension); + + // deal with the filesets + for (int i = 0; i < task.getFilesets().size(); i++) { + FileSet fs = (FileSet) task.getFilesets().get(i); + DirectoryScanner ds = fs.getDirectoryScanner(task.getProject()); + String[] files = ds.getIncludedFiles(); + + for (int j = 0; j < files.length; j++) { + File f = new File(fs.getDir(task.getProject()), files[j]); + + File outf = null; + if (task.getOutdir() != null && files[j].endsWith(".fo")) { + String[] sa = mapper.mapFileName(files[j]); + outf = new File(task.getOutdir(), sa[0]); + } else { + outf = replaceExtension(f, ".fo", newExtension); + if (task.getOutdir() != null) { + outf = new File(task.getOutdir(), outf.getName()); + } + } + + try { + if (this.baseURL == null) { + this.baseURL = fs.getDir(task.getProject()).toURL(). + toExternalForm(); + } + + } catch (Exception e) { + task.log("Error setting base URL", Project.MSG_DEBUG); + } + + render(f, outf, rint); + actioncount++; + } + } + + if (actioncount == 0) { + task.log("No files processed. No files were selected by the filesets " + + "and no fofile was set." , Project.MSG_WARN); + } + } + + private void render(File foFile, File outFile, + int renderer) throws FOPException { + InputHandler inputHandler = new FOInputHandler(foFile); + XMLReader parser = inputHandler.getParser(); + setParserFeatures(parser); + + OutputStream out = null; + try { + out = new java.io.FileOutputStream(outFile); + } catch (Exception ex) { + throw new BuildException("Failed to open " + outFile, ex); + } + + if (task.getLogFiles()) { + task.log(foFile + " -> " + outFile, Project.MSG_INFO); + } + + try { + Driver driver = new Driver(); + setupLogger(driver); + driver.initialize(); + FOUserAgent userAgent = new FOUserAgent(); + userAgent.setBaseURL(this.baseURL); + userAgent.enableLogging(getLogger()); + driver.setUserAgent(userAgent); + driver.setRenderer(renderer); + driver.setOutputStream(out); + driver.render(parser, inputHandler.getInputSource()); + } catch (Exception ex) { + throw new BuildException(ex); + } finally { + try { + out.close(); + } catch (IOException ioe) { + getLogger().error("Error closing output file", ioe); + } + } + } + +} + diff --git a/src/java/org/apache/fop/tools/anttasks/RunTest.java b/src/java/org/apache/fop/tools/anttasks/RunTest.java new file mode 100644 index 000000000..1fa6d00dc --- /dev/null +++ b/src/java/org/apache/fop/tools/anttasks/RunTest.java @@ -0,0 +1,256 @@ +/* + * $Id: RunTest.java,v 1.8 2003/03/07 10:09:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools.anttasks; + +// Ant +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Task; + +// Java +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URLClassLoader; +import java.net.URL; +import java.net.MalformedURLException; +import java.util.Iterator; +import java.util.Map; + + +/** + * Testing ant task. + * This task is used to test FOP as a build target. + * This uses the TestConverter (with weak code dependancy) to run the tests + * and check the results. + */ +public class RunTest extends Task { + + private String basedir; + private String testsuite = ""; + private String referenceJar = ""; + private String refVersion = ""; + + /** + * Sets the test suite name. + * @param str name of the test suite + */ + public void setTestSuite(String str) { + testsuite = str; + } + + /** + * Sets the base directory. + * @param str base directory + */ + public void setBasedir(String str) { + basedir = str; + } + + /** + * Sets the reference directory. + * @param str reference directory + */ + public void setReference(String str) { + referenceJar = str; + } + + /** + * Sets the reference version. + * @param str reference version + */ + public void setRefVersion(String str) { + refVersion = str; + } + + /** + * This creates the reference output, if required, then tests + * the current build. + * @see org.apache.tools.ant.Task#execute() + */ + public void execute() throws BuildException { + runReference(); + testNewBuild(); + } + + /** + * Test the current build. + * This uses the current jar file (in build/fop.jar) to run the + * tests with. + * The output is then compared with the reference output. + */ + protected void testNewBuild() { + try { + ClassLoader loader = new URLClassLoader(new URL[] { + new URL("file:build/fop.jar") + }); + Map diff = runConverter(loader, "areatree", + "reference/output/"); + if (diff != null && !diff.isEmpty()) { + System.out.println("===================================="); + System.out.println("The following files differ:"); + boolean broke = false; + for (Iterator keys = diff.keySet().iterator(); + keys.hasNext();) { + Object fname = keys.next(); + Boolean pass = (Boolean)diff.get(fname); + System.out.println("file: " + fname + + " - reference success: " + pass); + if (pass.booleanValue()) { + broke = true; + } + } + if (broke) { + throw new BuildException("Working tests have been changed."); + } + } + } catch (MalformedURLException mue) { + mue.printStackTrace(); + } + } + + /** + * Run the tests for the reference jar file. + * This checks that the reference output has not already been + * run and then checks the version of the reference jar against + * the version required. + * The reference output is then created. + * @throws BuildException if an error occurs + */ + protected void runReference() throws BuildException { + // check not already done + File f = new File(basedir + "/reference/output/"); + // if(f.exists()) { + // need to check that files have actually been created. + // return; + // } else { + try { + ClassLoader loader = new URLClassLoader(new URL[] { + new URL("file:" + referenceJar) + }); + boolean failed = false; + + try { + Class cla = Class.forName("org.apache.fop.apps.Options", + true, loader); + /*Object opts =*/ cla.newInstance(); + cla = Class.forName("org.apache.fop.apps.Version", true, + loader); + Method get = cla.getMethod("getVersion", new Class[]{}); + if (!get.invoke(null, new Object[]{}).equals(refVersion)) { + throw new BuildException("Reference jar is not correct version it must be: " + + refVersion); + } + } catch (IllegalAccessException iae) { + failed = true; + } catch (IllegalArgumentException are) { + failed = true; + } catch (InvocationTargetException are) { + failed = true; + } catch (ClassNotFoundException are) { + failed = true; + } catch (InstantiationException are) { + failed = true; + } catch (NoSuchMethodException are) { + failed = true; + } + if (failed) { + throw new BuildException("Reference jar could not be found in: " + + basedir + "/reference/"); + } + f.mkdirs(); + runConverter(loader, "reference/output/", null); + } catch (MalformedURLException mue) { + mue.printStackTrace(); + } + // } + } + + /** + * Run the Converter. + * Runs the test converter using the specified class loader. + * This loads the TestConverter using the class loader and + * then runs the test suite for the current test suite + * file in the base directory. + * @param loader the class loader to use to run the tests with + * @param dest destination directory + * @param compDir comparison directory + * @return A Map with differences + */ + protected Map runConverter(ClassLoader loader, String dest, + String compDir) { + String converter = "org.apache.fop.tools.TestConverter"; + + Map diff = null; + try { + Class cla = Class.forName(converter, true, loader); + Object tc = cla.newInstance(); + Method meth; + + meth = cla.getMethod("setBaseDir", new Class[] { + String.class + }); + meth.invoke(tc, new Object[] { + basedir + }); + + meth = cla.getMethod("runTests", new Class[] { + String.class, String.class, String.class + }); + diff = (Map)meth.invoke(tc, new Object[] { + testsuite, dest, compDir + }); + } catch (Exception e) { + e.printStackTrace(); + } + return diff; + } + +} diff --git a/src/java/org/apache/fop/tools/anttasks/SerializeHyphPattern.java b/src/java/org/apache/fop/tools/anttasks/SerializeHyphPattern.java new file mode 100644 index 000000000..8a15847a1 --- /dev/null +++ b/src/java/org/apache/fop/tools/anttasks/SerializeHyphPattern.java @@ -0,0 +1,197 @@ +/* + * $Id: SerializeHyphPattern.java,v 1.5 2003/03/07 10:09:30 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools.anttasks; + +// Java +import java.io.File; +import java.io.IOException; +import java.io.ObjectOutputStream; + +// Ant +import org.apache.tools.ant.taskdefs.MatchingTask; +import org.apache.tools.ant.DirectoryScanner; + +// FOP +import org.apache.fop.layout.hyphenation.HyphenationTree; +import org.apache.fop.layout.hyphenation.HyphenationException; + +/** + * SerializeHyphPattern + */ + + +public class SerializeHyphPattern extends MatchingTask { + private File sourceDir, targetDir; + private boolean errorDump = false; + + /** + * @see org.apache.tools.ant.Task#execute() + */ + public void execute() throws org.apache.tools.ant.BuildException { + DirectoryScanner ds = this.getDirectoryScanner(sourceDir); + String[] files = ds.getIncludedFiles(); + for (int i = 0; i < files.length; i++) { + processFile(files[i].substring(0, files[i].length() - 4)); + } + } // end execute + + + /** + * Sets the source directory. + * @param sourceDir source directory + */ + public void setSourceDir(String sourceDir) { + File dir = new File(sourceDir); + if (!dir.exists()) { + System.err.println("Fatal Error: source directory " + sourceDir + + " for hyphenation files doesn't exist."); + System.exit(1); + } + this.sourceDir = dir; + } + + /** + * Sets the target directory + * @param targetDir target directory + */ + public void setTargetDir(String targetDir) { + File dir = new File(targetDir); + this.targetDir = dir; + } + + /** + * Controls the amount of error information dumped. + * @param errorDump True if more error info should be provided + */ + public void setErrorDump(boolean errorDump) { + this.errorDump = errorDump; + } + + + /* + * checks whether input or output files exists or the latter is older than input file + * and start build if necessary + */ + private void processFile(String filename) { + File infile = new File(sourceDir, filename + ".xml"); + File outfile = new File(targetDir, filename + ".hyp"); + //long outfileLastModified = outfile.lastModified(); + boolean startProcess = true; + + startProcess = rebuild(infile, outfile); + if (startProcess) { + buildPatternFile(infile, outfile); + } + } + + /* + * serializes pattern files + */ + private void buildPatternFile(File infile, File outfile) { + System.out.println("Processing " + infile); + HyphenationTree hTree = new HyphenationTree(); + try { + hTree.loadPatterns(infile.toString()); + if (errorDump) { + System.out.println("Stats: "); + hTree.printStats(); + } + } catch (HyphenationException ex) { + System.err.println("Can't load patterns from xml file " + infile + + " - Maybe hyphenation.dtd is missing?"); + if (errorDump) { + System.err.println(ex.toString()); + } + } + // serialize class + try { + ObjectOutputStream out = new ObjectOutputStream( + new java.io.BufferedOutputStream( + new java.io.FileOutputStream(outfile))); + out.writeObject(hTree); + out.close(); + } catch (IOException ioe) { + System.err.println("Can't write compiled pattern file: " + + outfile); + System.err.println(ioe); + } + } + + /** + * Checks for existence of output file and compares + * dates with input and stylesheet file + */ + private boolean rebuild(File infile, File outfile) { + if (outfile.exists()) { + // checks whether output file is older than input file + if (outfile.lastModified() < infile.lastModified()) { + return true; + } + } else { + // if output file does not exist, start process + return true; + } + return false; + } // end rebuild + + /* + * //quick access for debugging + * public static void main (String args[]) { + * SerializeHyphPattern ser = new SerializeHyphPattern(); + * ser.setIncludes("*.xml"); + * ser.setSourceDir("\\xml-fop\\hyph\\"); + * ser.setTargetDir("\\xml-fop\\hyph\\"); + * ser.execute(); + * } + */ + + +} diff --git a/src/java/org/apache/fop/tools/xslt/TraxTransform.java b/src/java/org/apache/fop/tools/xslt/TraxTransform.java new file mode 100644 index 000000000..c2d227b1a --- /dev/null +++ b/src/java/org/apache/fop/tools/xslt/TraxTransform.java @@ -0,0 +1,194 @@ +/* + * $Id: TraxTransform.java,v 1.5 2003/03/07 10:09:31 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools.xslt; + +import java.io.InputStream; +import java.io.Writer; +import java.util.Map; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; + +import org.w3c.dom.Document; + +/** + * Handles xslt tranformations via Trax (xalan2) + */ +public class TraxTransform { + + /** + * Cache of compiled stylesheets (filename, StylesheetRoot) + */ + private static Map stylesheetCache = new java.util.Hashtable(); + + /** + * Gets a Trax transformer + * @param xsltFilename Filename of the XSLT file + * @param cache True, if caching of the stylesheet is allowed + * @return Transformer the Trax transformer + */ + public static Transformer getTransformer(String xsltFilename, + boolean cache) { + try { + if (cache && stylesheetCache.containsKey(xsltFilename)) { + Templates cachedStylesheet = + (Templates)stylesheetCache.get(xsltFilename); + return cachedStylesheet.newTransformer(); + } + + Source xslSheet = + new javax.xml.transform.stream.StreamSource(xsltFilename); + + + /* + * System.out.println("****************************"); + * System.out.println("trax compile \nin: " + xsltFilename); + * System.out.println("****************************"); + */ + TransformerFactory factory = TransformerFactory.newInstance(); + + Templates compiledSheet = factory.newTemplates(xslSheet); + if (cache) { + stylesheetCache.put(xsltFilename, compiledSheet); + } + return compiledSheet.newTransformer(); + } catch (TransformerConfigurationException ex) { + ex.printStackTrace(); + } + return null; + + } + + /** + * Transforms an XML file using XSLT. + * @param xmlSource Filename of the source XML file + * @param xslURL Filename of the XSLT filename + * @param outputFile Target filename + */ + public static void transform(String xmlSource, String xslURL, + String outputFile) { + transform(new javax.xml.transform.stream.StreamSource(xmlSource), + new javax.xml.transform.stream.StreamSource(xslURL), + new javax.xml.transform.stream.StreamResult(outputFile)); + } + + /** + * Transforms an XML file using XSLT. + * @param xmlSource Source DOM Document + * @param xslURL Filename of the XSLT filename + * @param outputFile Target filename + */ + public static void transform(Document xmlSource, String xslURL, + String outputFile) { + + transform(new javax.xml.transform.dom.DOMSource(xmlSource), + new javax.xml.transform.stream.StreamSource(xslURL), + new javax.xml.transform.stream.StreamResult(outputFile)); + + } + + /** + * Transforms an XML file using XSLT. + * @param xmlSource Filename of the source XML file + * @param xslURL Filename of the XSLT filename + * @param output Target Writer instance + */ + public static void transform(String xmlSource, String xslURL, + Writer output) { + transform(new javax.xml.transform.stream.StreamSource(xmlSource), + new javax.xml.transform.stream.StreamSource(xslURL), + new javax.xml.transform.stream.StreamResult(output)); + } + + /** + * Transforms an XML file using XSLT. + * @param xmlSource Source DOM Document + * @param xsl Filename of the XSLT filename + * @param outputDoc Target DOM document + */ + public static void transform(Document xmlSource, InputStream xsl, + Document outputDoc) { + transform(new javax.xml.transform.dom.DOMSource(xmlSource), + new javax.xml.transform.stream.StreamSource(xsl), + new javax.xml.transform.dom.DOMResult(outputDoc)); + } + + /** + * Transforms an XML file using XSLT. + * @param xmlSource XML Source + * @param xslSource XSLT Source + * @param result Target Result + */ + public static void transform(Source xmlSource, Source xslSource, + Result result) { + try { + Transformer transformer; + if (xslSource.getSystemId() == null) { + TransformerFactory factory = TransformerFactory.newInstance(); + transformer = factory.newTransformer(xslSource); + } else { + transformer = getTransformer(xslSource.getSystemId(), true); + } + transformer.transform(xmlSource, result); + } catch (TransformerConfigurationException ex) { + ex.printStackTrace(); + } catch (TransformerException ex) { + ex.printStackTrace(); + } + + } + +} diff --git a/src/java/org/apache/fop/tools/xslt/XSLTransform.java b/src/java/org/apache/fop/tools/xslt/XSLTransform.java new file mode 100644 index 000000000..9f76567a9 --- /dev/null +++ b/src/java/org/apache/fop/tools/xslt/XSLTransform.java @@ -0,0 +1,215 @@ +/* + * $Id: XSLTransform.java,v 1.5 2003/03/07 10:09:31 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber <jtauber@jtauber.com>. For more information on the Apache + * Software Foundation, please see <http://www.apache.org/>. + */ +package org.apache.fop.tools.xslt; + +import java.io.InputStream; +import java.io.Writer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Class for transforming XML using XSLT. Wraps either Trax (JAXP) or Xalan 1.x. + */ +public class XSLTransform { + + /** + * Transforms an XML file using XSLT. + * @param xmlSource Filename of the source XML file + * @param xslURL Filename of the XSLT filename + * @param outputFile Target filename + * @throws Exception If the conversion fails + */ + public static void transform(String xmlSource, String xslURL, + String outputFile) throws Exception { + Class[] argTypes = { + String.class, String.class, String.class + }; + Object[] params = { + xmlSource, xslURL, outputFile + }; + transform(params, argTypes); + } + + /** + * Transforms an XML file using XSLT. + * @param xmlSource Source DOM Document + * @param xslURL Filename of the XSLT filename + * @param outputFile Target filename + * @throws Exception If the conversion fails + */ + public static void transform(org.w3c.dom.Document xmlSource, + String xslURL, + String outputFile) throws Exception { + Class[] argTypes = { + org.w3c.dom.Document.class, String.class, String.class + }; + + Object[] params = { + xmlSource, xslURL, outputFile + }; + transform(params, argTypes); + + } + + /** + * Transforms an XML file using XSLT. + * @param xmlSource Filename of the source XML file + * @param xslURL Filename of the XSLT filename + * @param outputWriter Target Writer instance + * @throws Exception If the conversion fails + */ + public static void transform(String xmlSource, String xslURL, + Writer outputWriter) throws Exception { + Class[] argTypes = { + String.class, String.class, Writer.class + }; + Object[] params = { + xmlSource, xslURL, outputWriter + }; + transform(params, argTypes); + + } + + /** + * Transforms an XML file using XSLT. + * @param xmlSource Source DOM Document + * @param xsl Filename of the XSLT filename + * @param outputDoc Target DOM document + * @throws Exception If the conversion fails + */ + public static void transform(org.w3c.dom.Document xmlSource, + InputStream xsl, + org.w3c.dom.Document outputDoc) throws Exception { + Class[] argTypes = { + org.w3c.dom.Document.class, InputStream.class, + org.w3c.dom.Document.class + }; + Object[] params = { + xmlSource, xsl, outputDoc + }; + transform(params, argTypes); + + } + + + private static void transform(Object[] args, + Class[] argTypes) throws Exception { + Class transformer = getTransformClass(); + if (transformer != null) { + Method transformMethod = getTransformMethod(transformer, + argTypes); + if (transformMethod != null) { + try { + transformMethod.invoke(null, args); + } catch (InvocationTargetException ex) { + ex.printStackTrace(); + } + } else { + throw new Exception("transform method not found"); + } + } else { + throw new Exception("no transformer class found"); + } + + } + + + private static Class getTransformClass() { + try { + // try trax first + Class transformer = + Class.forName("javax.xml.transform.Transformer"); + // ok, make sure we have a liaison to trax + transformer = + Class.forName("org.apache.fop.tools.xslt.TraxTransform"); + return transformer; + + } catch (ClassNotFoundException ex) { + //nop + } + // otherwise, try regular xalan1 + try { + Class transformer = + Class.forName("org.apache.xalan.xslt.XSLTProcessor"); + // get the liaison + transformer = + Class.forName("org.apache.fop.tools.xslt.Xalan1Transform"); + return transformer; + } catch (ClassNotFoundException ex) { + //nop + } + return null; + + } + + + private static Method getTransformMethod(Class c, Class[] argTypes) { + // System.out.println("transformer class = "+c); + + try { + // Class[] argTypes = new Class[args.length]; + for (int i = 0; i < argTypes.length; i++) { + // argTypes[i] = args[i].getClass(); + // System.out.println("arg["+i+"] type = "+argTypes[i]); + + } + + Method transformer = c.getMethod("transform", argTypes); + return transformer; + + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + + } + return null; + } + +} |