001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002: *
003: * ***** BEGIN LICENSE BLOCK *****
004: * Version: MPL 1.1/GPL 2.0
005: *
006: * The contents of this file are subject to the Mozilla Public License Version
007: * 1.1 (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: * http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the
014: * License.
015: *
016: * The Original Code is Rhino code, released
017: * May 6, 1999.
018: *
019: * The Initial Developer of the Original Code is
020: * Netscape Communications Corporation.
021: * Portions created by the Initial Developer are Copyright (C) 1997-2000
022: * the Initial Developer. All Rights Reserved.
023: *
024: * Contributor(s):
025: * Milen Nankov
026: *
027: * Alternatively, the contents of this file may be used under the terms of
028: * the GNU General Public License Version 2 or later (the "GPL"), in which
029: * case the provisions of the GPL are applicable instead of those above. If
030: * you wish to allow use of your version of this file only under the terms of
031: * the GPL and not to allow others to use your version of this file under the
032: * MPL, indicate your decision by deleting the provisions above and replacing
033: * them with the notice and other provisions required by the GPL. If you do
034: * not delete the provisions above, a recipient may use your version of this
035: * file under either the MPL or the GPL.
036: *
037: * ***** END LICENSE BLOCK ***** */
038:
039: package org.mozilla.javascript.xml.impl.xmlbeans;
040:
041: import java.util.*;
042: import org.apache.xmlbeans.XmlCursor;
043:
044: import org.mozilla.javascript.*;
045:
046: class NamespaceHelper {
047: private XMLLibImpl lib;
048: private final Map prefixToURI = new HashMap();
049: private final Map uriToPrefix = new HashMap();
050: // A set of URIs that are used without explicit namespace declaration in scope.
051: private final Set undeclared = new HashSet();
052:
053: private NamespaceHelper(XMLLibImpl lib) {
054: this .lib = lib;
055: // Insert the default namespace
056: prefixToURI.put("", "");
057: Set prefixes = new HashSet();
058: prefixes.add("");
059: uriToPrefix.put("", prefixes);
060: }
061:
062: /**
063: * Declared a new namespace
064: *
065: * @param prefix
066: * @param uri
067: * @param declarations
068: */
069: private void declareNamespace(String prefix, String uri,
070: ObjArray declarations) {
071: Set prefixes = (Set) uriToPrefix.get(uri);
072: if (prefixes == null) {
073: prefixes = new HashSet();
074: uriToPrefix.put(uri, prefixes);
075: }
076:
077: if (!prefixes.contains(prefix)) {
078: String oldURI = (String) prefixToURI.get(prefix);
079:
080: // Add the new mapping
081: prefixes.add(prefix);
082: prefixToURI.put(prefix, uri);
083: if (declarations != null)
084: declarations.add(new Namespace(lib, prefix, uri));
085:
086: if (oldURI != null) {
087: // Update the existing mapping
088: prefixes = (Set) uriToPrefix.get(oldURI);
089: prefixes.remove(prefix);
090: }
091: }
092: }
093:
094: /**
095: * Updates the internal state of this NamespaceHelper to reflect the
096: * existance of the XML token pointed to by the cursor.
097: */
098: private void processName(XmlCursor cursor, ObjArray declarations) {
099: javax.xml.namespace.QName qname = cursor.getName();
100: String uri = qname.getNamespaceURI();
101: Set prefixes = (Set) uriToPrefix.get(uri);
102: if (prefixes == null || prefixes.size() == 0) {
103: undeclared.add(uri);
104: if (declarations != null)
105: declarations.add(new Namespace(lib, uri));
106: }
107: }
108:
109: /**
110: * Updates the internal state of this NamespaceHelper with the
111: * namespace information of the element pointed to by the cursor.
112: */
113: private void update(XmlCursor cursor, ObjArray declarations) {
114: // Process the Namespace declarations
115: cursor.push();
116: while (cursor.toNextToken().isAnyAttr()) {
117: if (cursor.isNamespace()) {
118: javax.xml.namespace.QName name = cursor.getName();
119: String prefix = name.getLocalPart();
120: String uri = name.getNamespaceURI();
121:
122: declareNamespace(prefix, uri, declarations);
123: }
124: }
125: cursor.pop();
126:
127: // Process the element
128: processName(cursor, declarations);
129:
130: // Process the attributes
131: cursor.push();
132: boolean hasNext = cursor.toFirstAttribute();
133: while (hasNext) {
134: processName(cursor, declarations);
135: hasNext = cursor.toNextAttribute();
136: }
137: cursor.pop();
138: }
139:
140: /**
141: * @return Object[] array of Namespace objects in scope at the cursor.
142: */
143: public static Object[] inScopeNamespaces(XMLLibImpl lib,
144: XmlCursor cursor) {
145: ObjArray namespaces = new ObjArray();
146: NamespaceHelper helper = new NamespaceHelper(lib);
147:
148: cursor.push();
149:
150: int depth = 0;
151: while (cursor.hasPrevToken()) {
152: if (cursor.isContainer()) {
153: cursor.push();
154: depth++;
155: }
156:
157: cursor.toParent();
158: }
159:
160: for (int i = 0; i < depth; i++) {
161: cursor.pop();
162: helper.update(cursor, null);
163: }
164:
165: Iterator i = helper.prefixToURI.entrySet().iterator();
166: while (i.hasNext()) {
167: Map.Entry entry = (Map.Entry) i.next();
168: Namespace ns = new Namespace(lib, (String) entry.getKey(),
169: (String) entry.getValue());
170: namespaces.add(ns);
171: }
172:
173: i = helper.undeclared.iterator();
174: while (i.hasNext()) {
175: Namespace ns = new Namespace(lib, (String) i.next());
176: namespaces.add(ns);
177: }
178:
179: cursor.pop();
180:
181: return namespaces.toArray();
182: }
183:
184: static Namespace getNamespace(XMLLibImpl lib, XmlCursor cursor,
185: Object[] inScopeNamespaces) {
186: String uri;
187: String prefix;
188:
189: if (cursor.isProcinst()) {
190: uri = "";
191: prefix = "";
192: } else {
193: javax.xml.namespace.QName qname = cursor.getName();
194: uri = qname.getNamespaceURI();
195: prefix = qname.getPrefix();
196: }
197:
198: if (inScopeNamespaces == null)
199: return new Namespace(lib, prefix, uri);
200:
201: Namespace result = null;
202: for (int i = 0; i != inScopeNamespaces.length; ++i) {
203: Namespace ns = (Namespace) inScopeNamespaces[i];
204: if (ns == null)
205: continue;
206:
207: String nsURI = ns.uri();
208: if (nsURI.equals(uri)) {
209: if (prefix.equals(ns.prefix())) {
210: result = ns;
211: break;
212: }
213:
214: if (result == null
215: || (result.prefix() == null && ns.prefix() != null))
216: result = ns;
217: }
218: }
219:
220: if (result == null)
221: result = new Namespace(lib, prefix, uri);
222:
223: return result;
224: }
225:
226: /**
227: * @return List of Namespace objects that are declared in the container pointed to by the cursor.
228: */
229: public static Object[] namespaceDeclarations(XMLLibImpl lib,
230: XmlCursor cursor) {
231: ObjArray declarations = new ObjArray();
232: NamespaceHelper helper = new NamespaceHelper(lib);
233:
234: cursor.push();
235:
236: int depth = 0;
237: while (cursor.hasPrevToken()) {
238: if (cursor.isContainer()) {
239: cursor.push();
240: depth++;
241: }
242:
243: cursor.toParent();
244: }
245:
246: for (int i = 0; i < depth - 1; i++) {
247: cursor.pop();
248: helper.update(cursor, null);
249: }
250:
251: if (depth > 0) {
252: cursor.pop();
253: helper.update(cursor, declarations);
254: }
255:
256: cursor.pop();
257:
258: return declarations.toArray();
259: }
260:
261: /**
262: * @return Prefix to URI map of all namespaces in scope at the cursor.
263: */
264: public static Map getAllNamespaces(XMLLibImpl lib, XmlCursor cursor) {
265: NamespaceHelper helper = new NamespaceHelper(lib);
266:
267: cursor.push();
268:
269: int depth = 0;
270: while (cursor.hasPrevToken()) {
271: if (cursor.isContainer()) {
272: cursor.push();
273: depth++;
274: }
275:
276: cursor.toParent();
277: }
278:
279: for (int i = 0; i < depth; i++) {
280: cursor.pop();
281: helper.update(cursor, null);
282: }
283:
284: cursor.pop();
285:
286: return helper.prefixToURI;
287: }
288:
289: public static void getNamespaces(XmlCursor cursor, Map prefixToURI) {
290: cursor.push();
291: while (cursor.toNextToken().isAnyAttr()) {
292: if (cursor.isNamespace()) {
293: javax.xml.namespace.QName name = cursor.getName();
294: String prefix = name.getLocalPart();
295: String uri = name.getNamespaceURI();
296:
297: prefixToURI.put(prefix, uri);
298: }
299: }
300: cursor.pop();
301: }
302:
303: public static void removeNamespace(XmlCursor cursor, String prefix) {
304: cursor.push();
305: while (cursor.toNextToken().isAnyAttr()) {
306: if (cursor.isNamespace()) {
307: javax.xml.namespace.QName name = cursor.getName();
308: if (name.getLocalPart().equals(prefix)) {
309: cursor.removeXml();
310: break;
311: }
312: }
313: }
314: cursor.pop();
315: }
316: }
|