001: /*
002: * $Id: FastNamespaceSupport.java,v 1.5 2004/07/08 08:03:04 yuvalo Exp $
003: *
004: * (C) Copyright 2002-2004 by Yuval Oren. All rights reserved.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: package com.bluecast.xml;
020:
021: import com.bluecast.util.*;
022:
023: import java.util.Arrays;
024:
025: /**
026: * This class improves performance over NamespaceSupport by
027: * assuming that most XML documents have very few namespaces. Therefore,
028: * instead of performing expensive copying operations of hash tables,
029: * arrays and linear searches are used instead.
030: * <p/>
031: * NOTE: This class is not a drop-in replacement for NamespaceSupport. This
032: * class assumes that passed URIs are already internalized! Also, getURI()
033: * returns "" instead of null if a prefix is not found.
034: *
035: * @author Yuval Oren
036: * @version $Revision: 1.5 $
037: */
038:
039: public class FastNamespaceSupport {
040: public final static String XMLNS = "http://www.w3.org/XML/1998/namespace";
041:
042: private String[] prefixes = new String[20];
043: private String[] uris = new String[20];
044: private int prefixPos;
045:
046: private String defaultURI;
047: private StringStack defaultURIs = new StringStack(20);
048:
049: // How many prefixes are there in this context?
050: private int prefixCount;
051: private IntStack contextPrefixCounts = new IntStack(20);
052:
053: // For how many contexts is the current default URI valid?
054: private int defaultURIContexts;
055: private IntStack defaultURIContextCounts = new IntStack(20);
056:
057: public FastNamespaceSupport() {
058: reset();
059: }
060:
061: public void reset() {
062: defaultURIs.clear();
063: contextPrefixCounts.clear();
064: defaultURIContextCounts.clear();
065:
066: prefixPos = -1;
067: defaultURI = "";
068: prefixCount = 0;
069: defaultURIContexts = 0;
070: }
071:
072: public void pushContext() {
073: defaultURIContexts++;
074:
075: contextPrefixCounts.push(prefixCount);
076: prefixCount = 0;
077: }
078:
079: public void popContext() {
080: if (defaultURIContexts <= 0) {
081: defaultURIContexts = defaultURIContextCounts.pop();
082: defaultURI = defaultURIs.pop();
083: } else
084: defaultURIContexts--;
085:
086: prefixPos -= prefixCount;
087: prefixCount = contextPrefixCounts.pop();
088: }
089:
090: public void declarePrefix(String prefix, String uri) {
091: if (prefix.length() == 0) {
092: defaultURIContexts--; // The current tag isn't inheriting the parent's default ns after all
093: defaultURIContextCounts.push(defaultURIContexts);
094: defaultURIs.push(defaultURI);
095: defaultURIContexts = 0;
096: defaultURI = uri;
097: } else {
098: // First see if this prefix already exists in this context
099: for (int i = 0; i < prefixCount; i++) {
100: if (prefix == prefixes[prefixPos - i]) {
101: uris[prefixPos - i] = uri;
102: return;
103: }
104: }
105:
106: // Doesn't exist yet; declare this as a new prefix
107: prefixPos++;
108: prefixCount++;
109:
110: // First ensure the array length
111: if (prefixPos >= prefixes.length) {
112: int oldLength = prefixes.length;
113: int newLength = oldLength * 2;
114: String[] newPrefixes = new String[newLength];
115: String[] newURIs = new String[newLength];
116: System
117: .arraycopy(prefixes, 0, newPrefixes, 0,
118: oldLength);
119: System.arraycopy(uris, 0, newURIs, 0, oldLength);
120: prefixes = newPrefixes;
121: uris = newURIs;
122: }
123:
124: prefixes[prefixPos] = prefix;
125: uris[prefixPos] = uri;
126: }
127: }
128:
129: public String[] processName(String qName, String parts[],
130: boolean isAttribute) {
131: int colon = qName.indexOf(':');
132: parts[2] = qName;
133: if (colon < 0) {
134: parts[1] = qName;
135:
136: if (isAttribute) // Attributes don't use the default URI
137: parts[0] = "";
138: else
139: parts[0] = defaultURI;
140: return parts;
141: } else {
142: String prefix = qName.substring(0, colon);
143: parts[1] = qName.substring(colon + 1);
144: if ((parts[0] = getURI(prefix)) == "")
145: return null;
146: else
147: return parts;
148: }
149: }
150:
151: public String getDefaultURI() {
152: return defaultURI;
153: }
154:
155: public String getURI(String prefix) {
156: if (prefix == null || prefix.length() == 0)
157: return defaultURI;
158: else if (prefix == "xml")
159: return XMLNS;
160:
161: for (int i = prefixPos; i >= 0; i--) {
162: if (prefix == prefixes[i])
163: return uris[i];
164: }
165: return "";
166: }
167:
168: /// Returns the number of prefix mappings in the current context
169: public int getContextSize() {
170: return prefixCount
171: + ((defaultURIContexts == 0 && defaultURI != "") ? 1
172: : 0);
173: }
174:
175: public String getContextPrefix(int index) {
176: // Do they want the default context?
177: if (index == prefixCount
178: && (defaultURIContexts == 0 && defaultURI != ""))
179: return "";
180:
181: return prefixes[prefixPos - index];
182: }
183:
184: public String getContextURI(int index) {
185: // Do they want the default context?
186: if (index == prefixCount
187: && (defaultURIContexts == 0 && defaultURI != ""))
188: return defaultURI;
189:
190: return uris[prefixPos - index];
191: }
192:
193: /* Here are the methods from NamespaceSupport that we don't implement:
194: public Enumeration getPrefixes() {
195: }
196:
197: public String getPrefix(String uri) {
198: }
199:
200: public Enumeration getPrefixes(String uri) {
201: }
202:
203: public Enumeration getDeclaredPrefixes() {
204: }
205: */
206: }
|