KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > event > Stripper


1 package net.sf.saxon.event;
2 import net.sf.saxon.Controller;
3 import net.sf.saxon.expr.XPathContext;
4 import net.sf.saxon.om.NodeInfo;
5 import net.sf.saxon.om.Orphan;
6 import net.sf.saxon.style.StandardNames;
7 import net.sf.saxon.trans.Mode;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.ComplexType;
10 import net.sf.saxon.type.SchemaType;
11 import net.sf.saxon.type.Type;
12 import net.sf.saxon.value.Whitespace;
13
14 /**
15   * The Stripper class maintains details of which elements need to be stripped.
16   * The code is written to act as a SAX-like filter to do the stripping.
17   * @author Michael H. Kay
18   */

19
20
21 public class Stripper extends ProxyReceiver {
22
23     private boolean preserveAll; // true if all elements have whitespace preserved
24
private boolean stripAll; // true if all whitespace nodes are stripped
25

26     // stripStack is used to hold information used while stripping nodes. We avoid allocating
27
// space on the tree itself to keep the size of nodes down. Each entry on the stack is two
28
// booleans, one indicates the current value of xml-space is "preserve", the other indicates
29
// that we are in a space-preserving element.
30

31     // We implement our own stack to avoid the overhead of allocating objects. The two booleans
32
// are held as the ls bits of a byte.
33

34     private byte[] stripStack = new byte[100];
35     private int top = 0;
36
37     // We use a collection of rules to determine whether to strip spaces; a collection
38
// of rules is known as a Mode. (We are reusing the code for template rule matching)
39

40     private Mode stripperMode;
41
42     // Mode expects to test an Element, so we create a dummy element for it to test
43
private Orphan element;
44
45     // Stripper needs a context (a) for evaluating patterns
46
// and (b) to provide reporting of rule conflicts.
47
private XPathContext context;
48
49     /**
50     * Default constructor for use in subclasses
51     */

52
53     protected Stripper() {}
54
55     /**
56     * create a Stripper and initialise variables
57     * @param stripperRules defines which elements have whitespace stripped. If
58     * null, all whitespace is preserved.
59     */

60
61     public Stripper(Mode stripperRules) {
62         stripperMode = stripperRules;
63         preserveAll = (stripperRules==null);
64         stripAll = false;
65     }
66
67     /**
68      * Get a clean copy of this stripper
69      */

70
71     public Stripper getAnother() {
72         Stripper clone = new Stripper(stripperMode);
73         clone.setPipelineConfiguration(getPipelineConfiguration());
74         clone.stripAll = stripAll;
75         clone.preserveAll = preserveAll;
76         return clone;
77     }
78
79
80     /**
81     * Specify that all whitespace nodes are to be stripped
82     */

83
84     public void setStripAll() {
85         preserveAll = false;
86         stripAll = true;
87     }
88
89     /**
90     * Determine if all whitespace is to be stripped (in this case, no further testing
91     * is needed)
92     */

93
94     public boolean getStripAll() {
95         return stripAll;
96     }
97
98     public void setPipelineConfiguration(PipelineConfiguration pipe) {
99         super.setPipelineConfiguration(pipe);
100         Controller controller = pipe.getController();
101         if (controller != null) {
102             context = controller.newXPathContext();
103         }
104         element = new Orphan(pipe.getConfiguration());
105         element.setNodeKind(Type.ELEMENT);
106     }
107
108     /**
109     * Decide whether an element is in the set of white-space preserving element types
110     * @param nameCode Identifies the name of the element whose whitespace is to
111      * be preserved
112      * @return ALWAYS_PRESERVE if the element is in the set of white-space preserving
113      * element types, ALWAYS_STRIP if the element is to be stripped regardless of the
114      * xml:space setting, and STRIP_DEFAULT otherwise
115     */

116
117
118
119     public byte isSpacePreserving(int nameCode) {
120         try {
121             if (preserveAll) return ALWAYS_PRESERVE;
122             if (stripAll) return STRIP_DEFAULT;
123             element.setNameCode(nameCode);
124             Object JavaDoc rule = stripperMode.getRule(element, context);
125             if (rule==null) return ALWAYS_PRESERVE;
126             return (((Boolean JavaDoc)rule).booleanValue() ? ALWAYS_PRESERVE : STRIP_DEFAULT);
127         } catch (XPathException err) {
128             return ALWAYS_PRESERVE;
129         }
130     }
131
132     public static final byte ALWAYS_PRESERVE = 0x01; // whitespace always preserved (e.g. xsl:text)
133
public static final byte ALWAYS_STRIP = 0x02; // whitespace always stripped (e.g. xsl:choose)
134
public static final byte STRIP_DEFAULT = 0x00; // no special action
135
public static final byte PRESERVE_PARENT = 0x04; // parent element specifies xml:space="preserve"
136
public static final byte CANNOT_STRIP = 0x08; // type annotation indicates simple typed content
137

138     /**
139     * Decide whether an element is in the set of white-space preserving element types.
140      * This version of the method is useful in cases where getting the namecode of the
141      * element is potentially expensive, e.g. with DOM nodes.
142      * @param element Identifies the element whose whitespace is possibly to
143      * be preserved
144      * @return ALWAYS_PRESERVE if the element is in the set of white-space preserving
145      * element types, ALWAYS_STRIP if the element is to be stripped regardless of the
146      * xml:space setting, and STRIP_DEFAULT otherwise
147     */

148
149     public byte isSpacePreserving(NodeInfo element) {
150         try {
151             if (preserveAll) return ALWAYS_PRESERVE;
152             if (stripAll) return STRIP_DEFAULT;
153             Object JavaDoc rule = stripperMode.getRule(element, context);
154             if (rule==null) return ALWAYS_PRESERVE;
155             return (((Boolean JavaDoc)rule).booleanValue() ? ALWAYS_PRESERVE : STRIP_DEFAULT);
156         } catch (XPathException err) {
157             return ALWAYS_PRESERVE;
158         }
159     }
160
161
162     /**
163     * Callback interface for SAX: not for application use
164     */

165
166     public void open () throws XPathException {
167         // System.err.println("Stripper#startDocument()");
168
top = 0;
169         stripStack[top] = ALWAYS_PRESERVE; // {xml:preserve = false, preserve this element = true}
170
super.open();
171     }
172
173     public void startElement (int nameCode, int typeCode, int locationId, int properties) throws XPathException
174     {
175         // System.err.println("startElement " + nameCode);
176
super.startElement(nameCode, typeCode, locationId, properties);
177
178         byte preserveParent = stripStack[top];
179         byte preserve = (byte)(preserveParent & PRESERVE_PARENT);
180
181         byte elementStrip = isSpacePreserving(nameCode);
182         if (elementStrip == ALWAYS_PRESERVE) {
183             preserve |= ALWAYS_PRESERVE;
184         } else if (elementStrip == ALWAYS_STRIP) {
185             preserve |= ALWAYS_STRIP;
186         }
187         if (preserve == 0 && typeCode != -1 && typeCode != StandardNames.XDT_UNTYPED) {
188             // if the element has simple content, whitespace stripping is disabled
189
SchemaType type = getConfiguration().getSchemaType(typeCode);
190             if (type.isSimpleType() || ((ComplexType)type).isSimpleContent()) {
191                 preserve |= CANNOT_STRIP;
192             }
193         }
194
195         // put "preserve" value on top of stack
196

197         top++;
198         if (top >= stripStack.length) {
199             byte[] newStack = new byte[top*2];
200             System.arraycopy(stripStack, 0, newStack, 0, top);
201             stripStack = newStack;
202         }
203         stripStack[top] = preserve;
204     }
205
206     public void attribute(int nameCode, int typeCode, CharSequence JavaDoc value, int locationId, int properties)
207     throws XPathException {
208
209         // test for xml:space="preserve" | "default"
210

211         if ((nameCode & 0xfffff) == StandardNames.XML_SPACE) {
212             if (value.toString().equals("preserve")) {
213                 stripStack[top] |= PRESERVE_PARENT;
214             } else {
215                 stripStack[top] &= ~PRESERVE_PARENT;
216             }
217         }
218         super.attribute(nameCode, typeCode, value, locationId, properties);
219     }
220
221     /**
222     * Handle an end-of-element event
223     */

224
225     public void endElement () throws XPathException
226     {
227         super.endElement();
228         top--;
229     }
230
231     /**
232     * Handle a text node
233     */

234
235     public void characters (CharSequence JavaDoc chars, int locationId, int properties) throws XPathException
236     {
237         // assume adjacent chunks of text are already concatenated
238

239         if (chars.length() > 0) {
240             if ((((stripStack[top] & (ALWAYS_PRESERVE | PRESERVE_PARENT | CANNOT_STRIP)) != 0) &&
241                   (stripStack[top] & ALWAYS_STRIP) == 0)
242                     || !Whitespace.isWhite(chars)) {
243                 super.characters(chars, locationId, properties);
244             }
245         }
246     }
247
248
249 }
250
251 //
252
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
253
// you may not use this file except in compliance with the License. You may obtain a copy of the
254
// License at http://www.mozilla.org/MPL/
255
//
256
// Software distributed under the License is distributed on an "AS IS" basis,
257
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
258
// See the License for the specific language governing rights and limitations under the License.
259
//
260
// The Original Code is: all this file.
261
//
262
// The Initial Developer of the Original Code is Michael H. Kay.
263
//
264
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
265
//
266
// Contributor(s): none.
267
//
268
Popular Tags