選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

FOTreeBuilder.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * $Id$
  3. * ============================================================================
  4. * The Apache Software License, Version 1.1
  5. * ============================================================================
  6. *
  7. * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without modifica-
  10. * tion, are permitted provided that the following conditions are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright notice,
  13. * this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if any, must
  20. * include the following acknowledgment: "This product includes software
  21. * developed by the Apache Software Foundation (http://www.apache.org/)."
  22. * Alternately, this acknowledgment may appear in the software itself, if
  23. * and wherever such third-party acknowledgments normally appear.
  24. *
  25. * 4. The names "FOP" and "Apache Software Foundation" must not be used to
  26. * endorse or promote products derived from this software without prior
  27. * written permission. For written permission, please contact
  28. * apache@apache.org.
  29. *
  30. * 5. Products derived from this software may not be called "Apache", nor may
  31. * "Apache" appear in their name, without prior written permission of the
  32. * Apache Software Foundation.
  33. *
  34. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  35. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  36. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  37. * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  38. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
  39. * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  40. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  41. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  43. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. * ============================================================================
  45. *
  46. * This software consists of voluntary contributions made by many individuals
  47. * on behalf of the Apache Software Foundation and was originally created by
  48. * James Tauber <jtauber@jtauber.com>. For more information on the Apache
  49. * Software Foundation, please see <http://www.apache.org/>.
  50. */
  51. package org.apache.fop.fo;
  52. // FOP
  53. import org.apache.fop.apps.FOPException;
  54. import org.apache.fop.apps.StreamRenderer;
  55. import org.apache.fop.fo.pagination.PageSequence;
  56. import org.apache.fop.extensions.ExtensionObj;
  57. // Avalon
  58. import org.apache.avalon.framework.logger.Logger;
  59. // SAX
  60. import org.xml.sax.helpers.DefaultHandler;
  61. import org.xml.sax.SAXException;
  62. import org.xml.sax.Attributes;
  63. import org.xml.sax.Locator;
  64. // Java
  65. import java.util.HashMap;
  66. import java.util.ArrayList;
  67. /**
  68. * SAX Handler that builds the formatting object tree.
  69. *
  70. * Modified by Mark Lillywhite mark-fop@inomial.com. Now uses
  71. * StreamRenderer to automagically render the document as
  72. * soon as it receives a page-sequence end-tag. Also,
  73. * calls methods to set up and shut down the renderer at
  74. * the beginning and end of the FO document. Finally,
  75. * supresses adding the PageSequence object to the Root,
  76. * since it is parsed immediately.
  77. */
  78. public class FOTreeBuilder extends DefaultHandler implements TreeBuilder {
  79. /**
  80. * table mapping element names to the makers of objects
  81. * representing formatting objects
  82. */
  83. protected HashMap fobjTable = new HashMap();
  84. protected ArrayList namespaces = new ArrayList();
  85. /**
  86. * class that builds a property list for each formatting object
  87. */
  88. protected HashMap propertylistTable = new HashMap();
  89. /**
  90. * current formatting object being handled
  91. */
  92. protected FObj currentFObj = null;
  93. /**
  94. * the root of the formatting object tree
  95. */
  96. protected FObj rootFObj = null;
  97. /**
  98. * set of names of formatting objects encountered but unknown
  99. */
  100. protected HashMap unknownFOs = new HashMap();
  101. /**
  102. *
  103. * The class that handles formatting and rendering to a stream
  104. * (mark-fop@inomial.com)
  105. */
  106. private StreamRenderer streamRenderer;
  107. private Logger log;
  108. private Locator locator;
  109. public FOTreeBuilder() {}
  110. public void setLogger(Logger logger) {
  111. log = logger;
  112. }
  113. public void setStreamRenderer(StreamRenderer streamRenderer) {
  114. this.streamRenderer = streamRenderer;
  115. }
  116. public StreamRenderer getStreamRenderer() {
  117. return this.streamRenderer;
  118. }
  119. /**
  120. * add a mapping from element name to maker.
  121. *
  122. * @param namespaceURI namespace URI of formatting object element
  123. * @param maker Maker for class representing formatting object
  124. */
  125. public void addMapping(String namespaceURI, HashMap table) {
  126. this.fobjTable.put(namespaceURI, table);
  127. this.namespaces.add(namespaceURI.intern());
  128. }
  129. /**
  130. * add a mapping from element name to maker.
  131. *
  132. * @param namespaceURI namespace URI of formatting object element
  133. * @param maker Maker for class representing formatting object
  134. */
  135. public void addPropertyList(String namespaceURI, HashMap list) {
  136. PropertyListBuilder plb;
  137. plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
  138. if (plb == null) {
  139. plb = new PropertyListBuilder();
  140. plb.addList(list);
  141. this.propertylistTable.put(namespaceURI, plb);
  142. } else {
  143. plb.addList(list);
  144. }
  145. }
  146. /**
  147. * add a mapping from element name to maker.
  148. *
  149. * @param namespaceURI namespace URI of formatting object element
  150. * @param localName local name of formatting object element
  151. * @param maker Maker for class representing formatting object
  152. */
  153. public void addElementPropertyList(String namespaceURI, String localName,
  154. HashMap list) {
  155. PropertyListBuilder plb;
  156. plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
  157. if (plb == null) {
  158. plb = new PropertyListBuilder();
  159. plb.addElementList(localName, list);
  160. this.propertylistTable.put(namespaceURI, plb);
  161. } else {
  162. plb.addElementList(localName, list);
  163. }
  164. }
  165. public void addPropertyListBuilder(String namespaceURI,
  166. PropertyListBuilder propbuilder) {
  167. PropertyListBuilder plb;
  168. plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
  169. if (plb == null) {
  170. this.propertylistTable.put(namespaceURI, propbuilder);
  171. } else {
  172. // Error already added
  173. }
  174. }
  175. /**
  176. * SAX Handler for characters
  177. */
  178. public void characters(char data[], int start, int length) {
  179. if(currentFObj != null) {
  180. currentFObj.addCharacters(data, start, length);
  181. }
  182. }
  183. /**
  184. * SAX Handler for the end of an element
  185. */
  186. public void endElement(String uri, String localName, String rawName)
  187. throws SAXException {
  188. currentFObj.end();
  189. //
  190. // mark-fop@inomial.com - tell the stream renderer to render
  191. // this page-sequence
  192. //
  193. if(currentFObj instanceof PageSequence) {
  194. streamRenderer.render((PageSequence) currentFObj);
  195. } else if(currentFObj instanceof ExtensionObj) {
  196. if(!(currentFObj.getParent() instanceof ExtensionObj)) {
  197. streamRenderer.addExtension((ExtensionObj)currentFObj);
  198. }
  199. }
  200. currentFObj = (FObj)currentFObj.getParent();
  201. }
  202. /**
  203. * SAX Handler for the start of the document
  204. */
  205. public void startDocument()
  206. throws SAXException {
  207. rootFObj = null; // allows FOTreeBuilder to be reused
  208. log.info("building formatting object tree");
  209. streamRenderer.startRenderer();
  210. }
  211. public void endDocument()
  212. throws SAXException {
  213. log.info("Parsing of document complete, stopping renderer");
  214. streamRenderer.stopRenderer();
  215. }
  216. public void setDocumentLocator(Locator locator) {
  217. this.locator = locator;
  218. }
  219. /**
  220. * SAX Handler for the start of an element
  221. */
  222. public void startElement(String uri, String localName, String rawName,
  223. Attributes attlist) throws SAXException {
  224. /* the formatting object started */
  225. FObj fobj;
  226. /* the maker for the formatting object started */
  227. FObj.Maker fobjMaker = null;
  228. /* look up Maker for the element */
  229. HashMap table = (HashMap)fobjTable.get(uri);
  230. if(table != null) {
  231. fobjMaker = (FObj.Maker)table.get(localName);
  232. }
  233. PropertyListBuilder currentListBuilder =
  234. (PropertyListBuilder)this.propertylistTable.get(uri);
  235. boolean foreignXML = false;
  236. String systemId=null;
  237. int line = -1;
  238. int column = -1;
  239. if (locator!=null) {
  240. systemId = locator.getSystemId();
  241. line = locator.getLineNumber();
  242. column = locator.getColumnNumber();
  243. }
  244. if (fobjMaker == null) {
  245. String fullName = uri + "^" + localName;
  246. if (!this.unknownFOs.containsKey(fullName)) {
  247. this.unknownFOs.put(fullName, "");
  248. log.error("Unknown formatting object "
  249. + fullName);
  250. }
  251. if(namespaces.contains(uri.intern())) {
  252. // fall back
  253. fobjMaker = new Unknown.Maker();
  254. } else {
  255. fobjMaker = new UnknownXMLObj.Maker(uri, localName);
  256. foreignXML = true;
  257. }
  258. }
  259. try {
  260. PropertyList list = null;
  261. if (currentListBuilder != null) {
  262. list =
  263. currentListBuilder.makeList(uri, localName, attlist,
  264. (currentFObj == null) ? null
  265. : currentFObj.properties, currentFObj);
  266. } else if(foreignXML) {
  267. list = new DirectPropertyListBuilder.AttrPropertyList(attlist);
  268. } else {
  269. if(currentFObj == null) {
  270. throw new FOPException("Invalid XML or missing namespace",
  271. systemId, line, column);
  272. }
  273. list = currentFObj.properties;
  274. }
  275. fobj = fobjMaker.make(currentFObj, list, systemId, line, column);
  276. fobj.setLogger(log);
  277. } catch (FOPException e) {
  278. throw new SAXException(e);
  279. }
  280. if (rootFObj == null) {
  281. rootFObj = fobj;
  282. if (!fobj.getName().equals("fo:root")) {
  283. throw new SAXException(new FOPException("Root element must"
  284. + " be root, not "
  285. + fobj.getName(),
  286. systemId, line, column));
  287. }
  288. } else if(!(fobj instanceof org.apache.fop.fo.pagination.PageSequence)) {
  289. currentFObj.addChild(fobj);
  290. }
  291. currentFObj = fobj;
  292. }
  293. public void reset() {
  294. currentFObj = null;
  295. rootFObj = null;
  296. streamRenderer = null;
  297. }
  298. public boolean hasData() {
  299. return (rootFObj != null);
  300. }
  301. }