001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.xml.stream;
031:
032: import com.caucho.vfs.WriteStream;
033:
034: import org.w3c.dom.*;
035:
036: import static javax.xml.XMLConstants.*;
037: import javax.xml.namespace.NamespaceContext;
038: import javax.xml.namespace.QName;
039: import java.io.IOException;
040: import java.util.ArrayList;
041: import java.util.HashMap;
042: import java.util.Iterator;
043: import java.util.LinkedHashMap;
044: import java.util.Map;
045:
046: /**
047: * Maintains a stack of namespace contexts
048: */
049: public class NamespaceWriterContext extends NamespaceContextImpl {
050: // map from URIs -> NamespaceBinding
051: private final LinkedHashMap<String, NamespaceBinding> _bindings = new LinkedHashMap<String, NamespaceBinding>();
052:
053: // xml/310w
054: private ArrayList<NamespaceBinding> _duplicatePrefixes = new ArrayList<NamespaceBinding>();
055: private int _uniqueId = 0;
056: private NamespaceBinding _nullBinding = new NamespaceBinding(null,
057: null, 0);
058:
059: private boolean _repair = false;
060:
061: public NamespaceWriterContext() {
062: this (false);
063: }
064:
065: public NamespaceWriterContext(boolean repair) {
066: super ();
067:
068: _repair = repair;
069: }
070:
071: protected void remove(String prefix, String uri) {
072: _bindings.remove(uri);
073: }
074:
075: public boolean getRepair() {
076: return _repair;
077: }
078:
079: public void setRepair(boolean repair) {
080: _repair = repair;
081: }
082:
083: public void declare(String prefix, String uri) {
084: declare(prefix, uri, false);
085: }
086:
087: /**
088: * declares a new namespace prefix in the current context
089: */
090: public void declare(String prefix, String uri, boolean forceEmit) {
091: NamespaceBinding binding;
092:
093: if (uri == null)
094: binding = _nullBinding;
095:
096: else {
097: binding = _bindings.get(uri);
098:
099: if (binding != null && binding.getPrefix() != null
100: && binding.getPrefix().equals(prefix)) {
101: // for writing, ignore matching prefixes
102: if (forceEmit)
103: binding.setEmit(true);
104:
105: return;
106: } else if (binding == null) {
107: // set the URI to null so that addOldBinding registers that there
108: // was no previous binding
109: binding = new NamespaceBinding(prefix, null, _version);
110:
111: _bindings.put(uri, binding);
112: }
113: }
114:
115: ElementBinding eltBinding = _stack.get(_stack.size() - 1);
116:
117: if (eltBinding == null) {
118: eltBinding = new ElementBinding();
119:
120: _stack.set(_stack.size() - 1, eltBinding);
121: }
122:
123: eltBinding
124: .addOldBinding(binding, prefix, binding.getUri(), uri);
125:
126: if (binding.isEmit() && !prefix.equals(binding.getPrefix())) {
127: NamespaceBinding copy = new NamespaceBinding(binding
128: .getPrefix(), binding.getUri(), binding
129: .getVersion());
130: copy.setEmit(true);
131: _duplicatePrefixes.add(copy);
132: }
133:
134: _version++;
135: binding.setPrefix(prefix);
136: binding.setUri(uri);
137: binding.setVersion(_version);
138: binding.setEmit(forceEmit);
139: }
140:
141: /**
142: * declares a new namespace prefix in the current context; the
143: * auto-allocated prefix is returned
144: */
145: public String declare(String uri) {
146: NamespaceBinding binding = _bindings.get(uri);
147:
148: // without an explicit prefix, don't add a new prefix
149: if (binding != null)
150: return binding.getPrefix();
151:
152: String prefix = "ns" + _uniqueId++;
153:
154: declare(prefix, uri, _repair);
155:
156: return prefix;
157: }
158:
159: /**
160: * looks up the uri, returns the prefix it corresponds to
161: */
162: public String getPrefix(String uri) {
163: NamespaceBinding binding = _bindings.get(uri);
164:
165: if (binding == null)
166: return null;
167:
168: return binding.getPrefix();
169: }
170:
171: public String getNamespaceURI(String prefix) {
172: for (NamespaceBinding binding : _bindings.values()) {
173: if (prefix.equals(binding.getPrefix()))
174: return binding.getUri();
175: }
176:
177: return null;
178: }
179:
180: public Iterator getPrefixes(String uri) {
181: ArrayList<String> prefixes = new ArrayList<String>();
182:
183: for (NamespaceBinding binding : _bindings.values()) {
184: if (uri.equals(binding.getUri()))
185: prefixes.add(binding.getPrefix());
186: }
187:
188: return prefixes.iterator();
189: }
190:
191: public void emitDeclarations(WriteStream ws) throws IOException {
192: for (NamespaceBinding binding : _bindings.values())
193: binding.emit(ws);
194:
195: for (int i = 0; i < _duplicatePrefixes.size(); i++)
196: _duplicatePrefixes.get(i).emit(ws);
197:
198: _duplicatePrefixes.clear();
199: }
200:
201: public String toString() {
202: StringBuilder sb = new StringBuilder();
203:
204: sb.append("NamespaceWriterContext:\n");
205:
206: for (Map.Entry<String, NamespaceBinding> entry : _bindings
207: .entrySet())
208: sb.append(entry.getKey() + "->" + entry.getValue() + "\n");
209:
210: return sb.toString();
211: }
212: }
|