1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
|
/*
* $Id$
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources.
*/
package org.apache.fop.fo;
// FOP
import org.apache.fop.layout.AreaTree;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.StreamRenderer;
import org.apache.fop.fo.pagination.Root;
import org.apache.fop.system.BufferManager;
import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.extensions.ExtensionObj;
import org.apache.log.Logger;
// SAX
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
import org.xml.sax.Attributes;
// Java
import java.util.Hashtable;
import java.util.Stack;
import java.io.IOException;
/**
* SAX Handler that builds the formatting object tree.
*
* Modified by Mark Lillywhite mark-fop@inomial.com. Now uses
* StreamRenderer to automagically render the document as
* soon as it receives a page-sequence end-tag. Also,
* calls methods to set up and shut down the renderer at
* the beginning and end of the FO document. Finally,
* supresses adding the PageSequence object to the Root,
* since it is parsed immediately.
*/
public class FOTreeBuilder extends DefaultHandler implements TreeBuilder {
/**
* table mapping element names to the makers of objects
* representing formatting objects
*/
protected Hashtable fobjTable = new Hashtable();
/**
* class that builds a property list for each formatting object
*/
protected Hashtable propertylistTable = new Hashtable();
/**
* current formatting object being handled
*/
protected FObj currentFObj = null;
/**
* the root of the formatting object tree
*/
protected FObj rootFObj = null;
public BufferManager bufferManager;
/**
* set of names of formatting objects encountered but unknown
*/
protected Hashtable unknownFOs = new Hashtable();
/**
*
* The class that handles formatting and rendering to a stream
* (mark-fop@inomial.com)
*/
private StreamRenderer streamRenderer;
private Logger log;
public FOTreeBuilder() {}
public void setLogger(Logger logger) {
log = logger;
}
public void setStreamRenderer(StreamRenderer streamRenderer) {
this.streamRenderer = streamRenderer;
}
/**
* add a mapping from element name to maker.
*
* @param namespaceURI namespace URI of formatting object element
* @param localName local name of formatting object element
* @param maker Maker for class representing formatting object
*/
public void addMapping(String namespaceURI, String localName,
FObj.Maker maker) {
this.fobjTable.put(namespaceURI + "^" + localName, maker);
}
/**
* add a mapping from element name to maker.
*
* @param namespaceURI namespace URI of formatting object element
* @param localName local name of formatting object element
* @param maker Maker for class representing formatting object
*/
public void addPropertyList(String namespaceURI, Hashtable list) {
PropertyListBuilder plb;
plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
if (plb == null) {
plb = new PropertyListBuilder();
plb.addList(list);
this.propertylistTable.put(namespaceURI, plb);
} else {
plb.addList(list);
}
}
/**
* add a mapping from element name to maker.
*
* @param namespaceURI namespace URI of formatting object element
* @param localName local name of formatting object element
* @param maker Maker for class representing formatting object
*/
public void addElementPropertyList(String namespaceURI, String localName,
Hashtable list) {
PropertyListBuilder plb;
plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
if (plb == null) {
plb = new PropertyListBuilder();
plb.addElementList(localName, list);
this.propertylistTable.put(namespaceURI, plb);
} else {
plb.addElementList(localName, list);
}
}
public void addPropertyListBuilder(String namespaceURI,
PropertyListBuilder propbuilder) {
PropertyListBuilder plb;
plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
if (plb == null) {
this.propertylistTable.put(namespaceURI, propbuilder);
} else {
// Error already added
}
}
/**
* SAX Handler for characters
*/
public void characters(char data[], int start, int length) {
if(currentFObj != null) {
currentFObj.addCharacters(data, start, start + length);
}
}
/**
* SAX Handler for the end of an element
*/
public void endElement(String uri, String localName, String rawName)
throws SAXException {
currentFObj.end();
//
// mark-fop@inomial.com - tell the stream renderer to render
// this page-sequence
//
if(currentFObj instanceof PageSequence) {
streamRenderer.render((PageSequence) currentFObj);
} else if(currentFObj instanceof ExtensionObj) {
if(!(currentFObj.getParent() instanceof ExtensionObj)) {
streamRenderer.addExtension((ExtensionObj)currentFObj);
}
}
currentFObj = (FObj)currentFObj.getParent();
}
/**
* SAX Handler for the start of the document
*/
public void startDocument()
throws SAXException {
rootFObj = null; // allows FOTreeBuilder to be reused
log.info("building formatting object tree");
streamRenderer.startRenderer();
}
public void endDocument()
throws SAXException {
log.info("Parsing of document complete, stopping renderer");
streamRenderer.stopRenderer();
}
/**
* SAX Handler for the start of an element
*/
public void startElement(String uri, String localName, String rawName,
Attributes attlist) throws SAXException {
/* the formatting object started */
FObj fobj;
/* the maker for the formatting object started */
FObj.Maker fobjMaker;
// String fullName = mapName(rawName);
String fullName = uri + "^" + localName;
fobjMaker = (FObj.Maker)fobjTable.get(fullName);
PropertyListBuilder currentListBuilder =
(PropertyListBuilder)this.propertylistTable.get(uri);
if (fobjMaker == null) {
if (!this.unknownFOs.containsKey(fullName)) {
this.unknownFOs.put(fullName, "");
log.error("Unknown formatting object "
+ fullName);
}
fobjMaker = new Unknown.Maker(); // fall back
}
try {
PropertyList list = null;
if (currentListBuilder != null) {
list =
currentListBuilder.makeList(fullName, attlist,
(currentFObj == null) ? null
: currentFObj.properties, currentFObj);
} else {
if(currentFObj == null) {
throw new FOPException("Invalid XML or missing namespace");
}
list = currentFObj.properties;
}
fobj = fobjMaker.make(currentFObj, list);
fobj.setLogger(log);
} catch (FOPException e) {
throw new SAXException(e);
}
if (rootFObj == null) {
rootFObj = fobj;
rootFObj.setBufferManager(this.bufferManager);
if (!fobj.getName().equals("fo:root")) {
throw new SAXException(new FOPException("Root element must"
+ " be root, not "
+ fobj.getName()));
}
} else if(!(fobj instanceof org.apache.fop.fo.pagination.PageSequence)) {
currentFObj.addChild(fobj);
}
currentFObj = fobj;
}
/**
* format this formatting object tree
*
* @param areaTree the area tree to format into
*/
/* public void format(AreaTree areaTree) throws FOPException {
log.info("formatting FOs into areas");
this.bufferManager.readComplete();
((Root)this.rootFObj).format(areaTree);
}
*/
public void reset() {
currentFObj = null;
rootFObj = null;
streamRenderer = null;
}
public boolean hasData() {
return (rootFObj != null);
}
public void setBufferManager(BufferManager bufferManager) {
this.bufferManager = bufferManager;
}
}
|