KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.event;
2 import net.sf.saxon.om.NamePool;
3 import net.sf.saxon.om.NamespaceConstant;
4 import net.sf.saxon.om.NamespaceResolver;
5 import net.sf.saxon.trans.XPathException;
6
7 import java.util.ArrayList JavaDoc;
8 import java.util.Iterator JavaDoc;
9 import java.util.List JavaDoc;
10
11 /**
12   * NamespaceReducer is a ProxyReceiver responsible for removing duplicate namespace
13   * declarations. It also ensures that an xmlns="" undeclaration is output when
14   * necessary. Used on its own, the NamespaceReducer simply eliminates unwanted
15   * namespace declarations. It can also be subclassed, in which case the subclass
16   * can use the services of the NamespaceReducer to resolve QNames.
17   * <p>
18   * The NamespaceReducer also validates namespace-sensitive content.
19   */

20
21 public class NamespaceReducer extends ProxyReceiver implements NamespaceResolver
22 {
23     // TODO: this class could extend StartTagBuffer and re-use some of the code.
24

25 // private int nscodeXML ;
26
// private int nscodeNull;
27

28     // We keep track of namespaces to avoid outputting duplicate declarations. The namespaces
29
// vector holds a list of all namespaces currently declared (organised as pairs of entries,
30
// prefix followed by URI). The stack contains an entry for each element currently open; the
31
// value on the stack is an Integer giving the number of namespaces added to the main
32
// namespace stack by that element.
33

34     private int[] namespaces = new int[50]; // all namespace codes currently declared
35
private int namespacesSize = 0; // all namespaces currently declared
36
private int[] countStack = new int[50];
37     private int depth = 0;
38
39     // Creating an element does not automatically inherit the namespaces of the containing element.
40
// When the DISINHERIT property is set on startElement(), this indicates that the namespaces
41
// on that element are not to be automatically inherited by its children. So startElement()
42
// stacks a boolean flag indicating whether the children are to disinherit the parent's namespaces.
43

44     private boolean[] disinheritStack = new boolean[50];
45
46     private int[] pendingUndeclarations = null;
47
48     /**
49     * startElement. This call removes redundant namespace declarations, and
50     * possibly adds an xmlns="" undeclaration.
51     */

52
53     public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException {
54
55         super.startElement(nameCode, typeCode, locationId, properties);
56
57         // If the parent element specified inherit=no, keep a list of namespaces that need to be
58
// undeclared
59

60         if (depth>0 && disinheritStack[depth-1]) {
61             pendingUndeclarations = new int[namespacesSize];
62             System.arraycopy(namespaces, 0, pendingUndeclarations, 0, namespacesSize);
63         } else {
64             pendingUndeclarations = null;
65         }
66
67         // Record the current height of the namespace list so it can be reset at endElement time
68

69         countStack[depth] = 0;
70         disinheritStack[depth] = (properties & ReceiverOptions.DISINHERIT_NAMESPACES) != 0;
71         if (++depth >= countStack.length) {
72             int[] newstack = new int[depth*2];
73             System.arraycopy(countStack, 0, newstack, 0, depth);
74             boolean[] disStack2 = new boolean[depth*2];
75             System.arraycopy(disinheritStack, 0, disStack2, 0, depth);
76             countStack = newstack;
77             disinheritStack = disStack2;
78         }
79
80
81         // Ensure that the element namespace is output, unless this is done
82
// automatically by the caller (which is true, for example, for a literal
83
// result element).
84

85         if ((properties & ReceiverOptions.NAMESPACE_OK) == 0) {
86             namespace(getNamePool().allocateNamespaceCode(nameCode), 0);
87         }
88
89     }
90
91     public void namespace(int namespaceCode, int properties) throws XPathException {
92
93         // Keep the namespace only if it is actually needed
94

95         if (isNeeded(namespaceCode)) {
96             addToStack(namespaceCode);
97             countStack[depth - 1]++;
98             super.namespace(namespaceCode, properties);
99         }
100     }
101
102     /**
103      * Handle an attribute
104      */

105
106 // public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties)
107
// throws XPathException {
108
// if (typeCode != -1 && (properties & ReceiverOptions.NEEDS_PREFIX_CHECK) != 0) {
109
// // checking has been deferred until the namespace context is available
110
// SimpleType type = (SimpleType)getConfiguration().getSchemaType(typeCode);
111
// XPathException err = type.validateContent(value, this, getConfiguration());
112
// if (err != null) {
113
// throw err;
114
// }
115
// properties &= (~ReceiverOptions.NEEDS_PREFIX_CHECK);
116
// }
117
// super.attribute(nameCode, typeCode, value, locationId, properties);
118
// }
119

120     /**
121     * Determine whether a namespace declaration is needed
122     */

123
124     private boolean isNeeded(int nscode) {
125         if (nscode==NamespaceConstant.XML_NAMESPACE_CODE) {
126                 // Ignore the XML namespace
127
return false;
128         }
129
130         // First cancel any pending undeclaration of this namespace prefix (there may be more than one)
131

132         if (pendingUndeclarations != null) {
133             for (int p=0; p<pendingUndeclarations.length; p++) {
134                 if ((nscode>>16) == (pendingUndeclarations[p]>>16)) {
135                     pendingUndeclarations[p] = -1;
136                     //break;
137
}
138             }
139         }
140
141         for (int i=namespacesSize-1; i>=0; i--) {
142             if (namespaces[i]==nscode) {
143                 // it's a duplicate so we don't need it
144
return false;
145             }
146             if ((namespaces[i]>>16) == (nscode>>16)) {
147                 // same prefix, different URI, so we do need it
148
return true;
149             }
150         }
151
152         // we need it unless it's a redundant xmlns=""
153
return (nscode != NamespaceConstant.NULL_NAMESPACE_CODE);
154     }
155
156     /**
157     * Add a namespace declaration to the stack
158     */

159
160     private void addToStack(int nscode) {
161         // expand the stack if necessary
162
if (namespacesSize+1 >= namespaces.length) {
163             int[] newlist = new int[namespacesSize*2];
164             System.arraycopy(namespaces, 0, newlist, 0, namespacesSize);
165             namespaces = newlist;
166         }
167         namespaces[namespacesSize++] = nscode;
168     }
169
170     /**
171      * startContent: Add any namespace undeclarations needed to stop
172      * namespaces being inherited from parent elements
173      */

174
175     public void startContent() throws XPathException {
176
177         if (pendingUndeclarations != null) {
178             for (int i=0; i<pendingUndeclarations.length; i++) {
179                 int nscode = pendingUndeclarations[i];
180                 if (nscode != -1) {
181                     namespace(nscode & 0xffff0000, 0);
182                     // relies on the namespace() method to prevent duplicate undeclarations
183
}
184             }
185         }
186         pendingUndeclarations = null;
187         super.startContent();
188     }
189
190     /**
191     * endElement: Discard the namespaces declared on this element.
192     */

193
194
195     public void endElement () throws XPathException
196     {
197         if (depth-- == 0) {
198             throw new IllegalStateException JavaDoc("Attempt to output end tag with no matching start tag");
199         }
200
201         int nscount = countStack[depth];
202         namespacesSize -= nscount;
203
204         super.endElement();
205
206     }
207
208     /**
209      * Get the URI code corresponding to a given prefix code, by searching the
210      * in-scope namespaces. This is a service provided to subclasses.
211      * @param prefixCode the 16-bit prefix code required
212      * @return the 16-bit URI code, or -1 if the prefix is not found
213      */

214
215     protected short getURICode(short prefixCode) {
216         for (int i=namespacesSize-1; i>=0; i--) {
217             if ((namespaces[i]>>16) == (prefixCode)) {
218                 return (short)(namespaces[i]&0xffff);
219             }
220         }
221         if (prefixCode == 0) {
222             return 0; // by default, no prefix means no namespace URI
223
} else {
224             return -1;
225         }
226     }
227
228     /**
229      * Get the namespace URI corresponding to a given prefix. Return null
230      * if the prefix is not in scope.
231      *
232      * @param prefix the namespace prefix
233      * @param useDefault true if the default namespace is to be used when the
234      * prefix is ""
235      * @return the uri for the namespace, or null if the prefix is not in scope
236      */

237
238     public String JavaDoc getURIForPrefix(String JavaDoc prefix, boolean useDefault) {
239         NamePool pool = getNamePool();
240         if ("".equals(prefix) && !useDefault) {
241             return "";
242         } else if ("xml".equals(prefix)) {
243             return NamespaceConstant.XML;
244         } else {
245             short prefixCode = pool.getCodeForPrefix(prefix);
246             short uriCode = getURICode(prefixCode);
247             if (uriCode == -1) {
248                 return null;
249             }
250             return pool.getURIFromURICode(uriCode);
251         }
252     }
253
254     /**
255      * Get an iterator over all the prefixes declared in this namespace context. This will include
256      * the default namespace (prefix="") and the XML namespace where appropriate
257      */

258
259     public Iterator JavaDoc iteratePrefixes() {
260         NamePool pool = getNamePool();
261         List JavaDoc prefixes = new ArrayList JavaDoc(namespacesSize);
262         for (int i=namespacesSize-1; i>=0; i--) {
263             String JavaDoc prefix = pool.getPrefixFromNamespaceCode(namespaces[i]);
264             if (!prefixes.contains(prefix)) {
265                 prefixes.add(prefix);
266             }
267         }
268         prefixes.add("xml");
269         return prefixes.iterator();
270     }
271 }
272
273 //
274
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
275
// you may not use this file except in compliance with the License. You may obtain a copy of the
276
// License at http://www.mozilla.org/MPL/
277
//
278
// Software distributed under the License is distributed on an "AS IS" basis,
279
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
280
// See the License for the specific language governing rights and limitations under the License.
281
//
282
// The Original Code is: all this file.
283
//
284
// The Initial Developer of the Original Code is Michael H. Kay.
285
//
286
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
287
//
288
// Contributor(s): none.
289
//
290
Popular Tags