001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.builder.xml;
018
019 import java.util.HashMap;
020 import java.util.HashSet;
021 import java.util.Iterator;
022 import java.util.Map;
023 import java.util.Map.Entry;
024 import java.util.Set;
025 import javax.xml.namespace.NamespaceContext;
026 import javax.xml.xpath.XPathFactory;
027
028 import org.apache.camel.spi.NamespaceAware;
029 import org.apache.camel.util.CastUtils;
030
031 /**
032 * An implementation of {@link NamespaceContext} which uses a simple Map where
033 * the keys are the prefixes and the values are the URIs
034 */
035 public class DefaultNamespaceContext implements NamespaceContext, NamespaceAware {
036
037 private final Map<String, String> map;
038 private final NamespaceContext parent;
039
040 public DefaultNamespaceContext() {
041 this(XPathFactory.newInstance());
042 }
043
044 public DefaultNamespaceContext(XPathFactory factory) {
045 this.parent = factory.newXPath().getNamespaceContext();
046 this.map = new HashMap<String, String>();
047 }
048
049 public DefaultNamespaceContext(NamespaceContext parent, Map<String, String> map) {
050 this.parent = parent;
051 this.map = map;
052 }
053
054 /**
055 * A helper method to make it easy to create newly populated instances
056 */
057 public DefaultNamespaceContext add(String prefix, String uri) {
058 map.put(prefix, uri);
059 return this;
060 }
061
062 public String getNamespaceURI(String prefix) {
063 String answer = map.get(prefix);
064 if (answer == null && parent != null) {
065 return parent.getNamespaceURI(prefix);
066 }
067 return answer;
068 }
069
070 public String getPrefix(String namespaceURI) {
071 for (Entry<String, String> entry : map.entrySet()) {
072 if (namespaceURI.equals(entry.getValue())) {
073 return entry.getKey();
074 }
075 }
076 if (parent != null) {
077 return parent.getPrefix(namespaceURI);
078 }
079 return null;
080 }
081
082 public Iterator<String> getPrefixes(String namespaceURI) {
083 Set<String> set = new HashSet<String>();
084 for (Entry<String, String> entry : map.entrySet()) {
085 if (namespaceURI.equals(entry.getValue())) {
086 set.add(entry.getKey());
087 }
088 }
089 if (parent != null) {
090 Iterator<String> iter = CastUtils.cast(parent.getPrefixes(namespaceURI));
091 while (iter.hasNext()) {
092 set.add(iter.next());
093 }
094 }
095 return set.iterator();
096 }
097
098 public void setNamespaces(Map<String, String> namespaces) {
099 map.putAll(namespaces);
100 }
101
102 /**
103 * toString() implementation that outputs the namespace mappings with the following format: "[me: {prefix -> value}, {prefix -> value}], [parent: {prefix -> value}, {prefix -> value}].
104 * Recurses up the parent's chain.
105 */
106 @Override
107 public String toString() {
108 StringBuilder sb = new StringBuilder("[me: ");
109 for (Entry<String, String> nsEntry : map.entrySet()) {
110 sb.append("{" + nsEntry.getKey() + " -> " + nsEntry.getValue() + "},");
111 }
112 if (!map.isEmpty()) {
113 // remove the last comma
114 sb.deleteCharAt(sb.length() - 1);
115 }
116 sb.append("]");
117
118 // Get the parent's namespace mappings
119 if (parent != null) {
120 sb.append(", [parent: ");
121 sb.append(parent.toString());
122 sb.append("]");
123 }
124 return sb.toString();
125 }
126
127 }